fuel-astute/lib/astute/cobbler_manager.rb

184 lines
6.3 KiB
Ruby

# Copyright 2013 Mirantis, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
module Astute
class CobblerManager
def initialize(engine_attrs, reporter)
raise "Settings for Cobbler must be set" if engine_attrs.blank?
begin
Astute.logger.info("Trying to instantiate cobbler engine:\n#{engine_attrs.pretty_inspect}")
@engine = Astute::Provision::Cobbler.new(engine_attrs)
rescue => e
Astute.logger.error("Error occured during cobbler initializing")
reporter.report({
'status' => 'error',
'error' => 'Cobbler can not be initialized',
'progress' => 100
})
raise e
end
end
def add_nodes(nodes)
nodes.each do |node|
cobbler_name = node['slave_name']
begin
Astute.logger.info("Adding #{cobbler_name} into cobbler")
@engine.item_from_hash('system', cobbler_name, node, :item_preremove => true)
rescue RuntimeError => e
Astute.logger.error("Error occured while adding system #{cobbler_name} to cobbler")
raise e
end
end
ensure
sync
end
def remove_nodes(nodes, retries=3, interval=2)
nodes_to_remove = nodes.map {|node| node['slave_name']}.uniq
Astute.logger.info("Total list of nodes to remove: #{nodes_to_remove.pretty_inspect}")
retries.times do
nodes_to_remove.select! do |name|
unless @engine.system_exists?(name)
Astute.logger.info("System is not in cobbler: #{name}")
next
else
Astute.logger.info("Trying to remove system from cobbler: #{name}")
@engine.remove_system(name)
end
@engine.system_exists?(name)
end
return if nodes_to_remove.empty?
sleep(interval) if interval > 0
end
ensure
Astute.logger.error("Cannot remove nodes from cobbler: #{nodes_to_remove.pretty_inspect}") if nodes_to_remove.present?
sync
end
def reboot_nodes(nodes)
splay = calculate_splay_between_nodes(nodes)
nodes.inject({}) do |reboot_events, node|
cobbler_name = node['slave_name']
Astute.logger.debug("Trying to reboot node: #{cobbler_name}")
#Sleep up to splay seconds before reboot for load balancing
sleep splay
reboot_events.merge(cobbler_name => @engine.power_reboot(cobbler_name))
end
end
def check_reboot_nodes(reboot_events)
begin
Astute.logger.debug("Waiting for reboot to be complete: nodes: #{reboot_events.keys}")
failed_nodes = []
Timeout::timeout(Astute.config.reboot_timeout) do
while not reboot_events.empty?
reboot_events.each do |node_name, event_id|
event_status = @engine.event_status(event_id)
Astute.logger.debug("Reboot task status: node: #{node_name} status: #{event_status}")
if event_status[2] =~ /^failed$/
Astute.logger.error("Error occured while trying to reboot: #{node_name}")
reboot_events.delete(node_name)
failed_nodes << node_name
elsif event_status[2] =~ /^complete$/
Astute.logger.debug("Successfully rebooted: #{node_name}")
reboot_events.delete(node_name)
end
end
sleep(5)
end
end
rescue Timeout::Error => e
Astute.logger.debug("Reboot timeout: reboot tasks not completed for nodes #{reboot_events.keys}")
raise e
end
failed_nodes
end
def edit_nodes(nodes, data)
nodes.each do |node|
cobbler_name = node['slave_name']
begin
Astute.logger.info("Changing cobbler system #{cobbler_name}")
@engine.item_from_hash('system', cobbler_name, data, :item_preremove => false)
rescue RuntimeError => e
Astute.logger.error("Error occured while changing cobbler system #{cobbler_name}")
raise e
end
end
ensure
sync
end
def netboot_nodes(nodes, state)
nodes.each do |node|
cobbler_name = node['slave_name']
begin
Astute.logger.info("Changing node netboot state #{cobbler_name}")
@engine.netboot(cobbler_name, state)
rescue RuntimeError => e
Astute.logger.error("Error while changing node netboot state #{cobbler_name}")
raise e
end
end
ensure
sync
end
def get_existent_nodes(nodes)
existent_nodes = []
nodes.each do |node|
cobbler_name = node['slave_name']
if @engine.system_exists?(cobbler_name)
Astute.logger.info("Update #{cobbler_name}, node already exists in cobbler")
existent_nodes << node
end
end
existent_nodes
end
def get_mac_duplicate_names(nodes)
mac_duplicate_names = []
nodes.each do |node|
Astute.logger.info("Trying to find MAC duplicates for node #{node['slave_name']}")
if node['interfaces']
node['interfaces'].each do |iname, ihash|
if ihash['mac_address']
Astute.logger.info("Trying to find system with MAC: #{ihash['mac_address']}")
found_node = @engine.system_by_mac(ihash['mac_address'])
mac_duplicate_names << found_node['name'] if found_node
end
end
end
end
mac_duplicate_names.uniq
end
def sync
Astute.logger.debug("Cobbler syncing")
@engine.sync
end
private
def calculate_splay_between_nodes(nodes)
# For 20 nodes, 120 iops and 180 splay_factor splay will be 1.5749
(nodes.size + 1) / Astute.config.iops.to_f * Astute.config.splay_factor / nodes.size
end
end
end