class Dopi::Step
Constants
- DEFAULT_MAX_IN_FLIGHT
- DEFAULT_MAX_PER_ROLE
Attributes
Public Class Methods
# File lib/dopi/step.rb, line 16 def initialize(step_parser, plan) @step_parser = step_parser @plan = plan @nodes = filter_nodes(plan.nodes, step_parser) @next_mutex = Mutex.new @notify_mutex = Mutex.new @queue = Queue.new command_sets.each{|command_set| state_add_child(command_set)} end
Public Instance Methods
# File lib/dopi/step.rb, line 49 def command_sets @command_sets ||= @nodes.map do |node| delete_plugin_defaults set_plugin_defaults Dopi::CommandSet.new(@step_parser, self, node) end end
# File lib/dopi/step.rb, line 78 def load_state(state_hash) command_sets.each do |command_set| command_set_state = state_hash[command_set.name] || [] command_set.load_state(command_set_state) end end
# File lib/dopi/step.rb, line 35 def name @step_parser.name end
# File lib/dopi/step.rb, line 57 def run(run_options) if state_done? Dopi.log.info("Step '#{name}' is in state 'done'. Skipping") return end Dopi.log.info("Starting to run step '#{name}'") nodes_to_run = filter_nodes(@nodes, run_options[:run_for_nodes]) command_sets_to_run = command_sets.select {|cs| nodes_to_run.include?(cs.node)} unless run_options[:noop] run_canary(run_options, command_sets_to_run) if canary_host run_command_sets(run_options, command_sets_to_run) unless state_failed? else command_sets_to_run.each{|command_set| command_set.run(run_options[:noop])} end Dopi.log.info("Step '#{name}' successfully finished.") if state_done? Dopi.log.error("Step '#{name}' failed! Stopping execution.") if state_failed? end
# File lib/dopi/step.rb, line 85 def state_hash command_sets_hash = {} command_sets.each do |command_set| command_sets_hash[command_set.name] = command_set.state_hash end command_sets_hash end
Loading queue object from yaml files results in not properly initialized queue and a type error when using it. Skip queue when converting to yaml. Will be nil after loading from yaml and must be re-created.
Dopi::State#to_yaml_properties
# File lib/dopi/step.rb, line 31 def to_yaml_properties super - [:@queue] end
# File lib/dopi/step.rb, line 39 def valid? if @nodes.empty? Dopi.log.error("Step '#{name}': Nodes list is empty") return false end # since they are identical in respect to parsing # we only have to check one of them command_sets.first.valid? end
Private Instance Methods
# File lib/dopi/step.rb, line 171 def canary_host @canary_host ||= @step_parser.canary_host || @plan.canary_host end
# File lib/dopi/step.rb, line 175 def delete_plugin_defaults if @step_parser.delete_plugin_defaults == :all # Wipe all the defaults PluginManager.plugin_klass_list('^dopi/command/').each do |plugin_klass| @nodes.each{|node| plugin_klass.delete_plugin_defaults(node.name)} end else @step_parser.delete_plugin_defaults.each do |entry| plugin_list(entry[:plugins]).each do |plugin_klass| if entry[:delete_keys] == :all @nodes.each{|node| plugin_klass.delete_plugin_defaults(node.name)} else entry[:delete_keys].each do |key| @nodes.each{|node| plugin_klass.delete_plugin_default(node.name, key)} end end end end end end
check if a node is runnable or if there are constrains which prevent it from running
# File lib/dopi/step.rb, line 143 def is_runnable?(node) if max_per_role > 0 running_groups[node.role] < max_per_role else true end end
# File lib/dopi/step.rb, line 163 def max_in_flight @max_in_flight ||= @step_parser.max_in_flight || @plan.max_in_flight || DEFAULT_MAX_IN_FLIGHT end
# File lib/dopi/step.rb, line 167 def max_per_role @max_per_role ||= @step_parser.max_per_role || @plan.max_per_role || DEFAULT_MAX_PER_ROLE end
This method returns the next command_set which is ready to run. If no node is ready because of constrains it will block the thread until notify_done
was called from a finishing thread. If no command_set is in the state ready it will return nil.
# File lib/dopi/step.rb, line 122 def next_command_set(command_sets_to_run) @next_mutex.synchronize do ready_command_sets = command_sets_to_run.select{|n| n.state == :ready} return nil if ready_command_sets.empty? loop do return nil if state_failed? or signals[:stop] @notify_mutex.synchronize do queue.clear next_command_set = ready_command_sets.find{|cs| is_runnable?(cs.node)} unless next_command_set.nil? next_command_set.state_start return next_command_set end end queue.pop # wait until a thread notifies it has finished end end end
notify the waiting thread that a command_set has finished it's run
# File lib/dopi/step.rb, line 111 def notify_done @notify_mutex.synchronize do queue.push(1) end end
# File lib/dopi/step.rb, line 206 def plugin_list(plugin_filter_list) if plugin_filter_list == :all PluginManager.plugin_klass_list('^dopi/command/') else all_plugin_names = PluginManager.plugin_name_list('^dopi/command/').map{|p| p.sub('dopi/command/', '')} selected_plugin_names = plugin_filter_list.map do |filter| case filter when Regexp then all_plugin_names.select{|p| p =~ filter} else all_plugin_names.select{|p| p == filter} end end selected_plugin_names.flatten.uniq.map{|p| PluginManager.plugin_klass('dopi/command/' + p)} end end
Will be skipped when dumping yaml, therefore nil after loading from yaml.
# File lib/dopi/step.rb, line 222 def queue @queue ||= Queue.new end
# File lib/dopi/step.rb, line 95 def run_canary(run_options, command_sets_to_run) pick = rand(command_sets_to_run.length - 1) command_sets_to_run[pick].run(run_options[:noop]) end
# File lib/dopi/step.rb, line 100 def run_command_sets(run_options, command_sets_to_run) in_threads = max_in_flight == -1 ? command_sets_to_run.length : max_in_flight pick = lambda { next_command_set(command_sets_to_run) || Parallel::Stop } Parallel.each(pick, :in_threads => in_threads) do |command_set| plan.context_logger.log_context = command_set.node.name command_set.run(run_options[:noop]) notify_done end end
return a hash with the group names as keys and the amount of running nodes as value
# File lib/dopi/step.rb, line 153 def running_groups role_counter = Hash.new(0) command_sets.each do |command_set| if [:running, :starting].include? command_set.state role_counter[command_set.node.role] += 1 end end role_counter end
# File lib/dopi/step.rb, line 196 def set_plugin_defaults @step_parser.set_plugin_defaults.each do |entry| defaults_hash = entry.dup defaults_hash.delete(:plugins) plugin_list(entry[:plugins]).each do |plugin_klass| @nodes.each{|node| plugin_klass.set_plugin_defaults(node.name, defaults_hash)} end end end