module Dopi::Cli

Public Class Methods

command_add(base) click to toggle source
# File lib/dopi/cli/command_add.rb, line 4
def self.command_add(base)
  base.class_eval do

    desc 'Add a new plan file to the plan cache'
    arg_name 'plan_file'
    command :add do |c|
      c.desc 'update the plan if it already exists'
      c.default_value false
      c.switch [:update, :u]

      c.action do |global_options,options,args|
        help_now!('Specify a plan file to add') if args.empty?
        help_now!('You can only add one plan') if args.length > 1
        plan_file = args[0]
        begin
          puts Dopi.add(plan_file)
        rescue DopCommon::PlanExistsError => e
          if options[:update]
            puts Dopi.update_plan(plan_file, {})
          else
            raise e
          end
                                            end
      end
    end

  end
end
command_list(base) click to toggle source
# File lib/dopi/cli/command_list.rb, line 4
def self.command_list(base)
  base.class_eval do

    desc 'Show the list of plans in the dopi plan cache'
    command :list do |c|
      c.action do |global_options,options,args|
        puts Dopi.list
      end
    end

  end
end
command_remove(base) click to toggle source
# File lib/dopi/cli/command_remove.rb, line 4
def self.command_remove(base)
  base.class_eval do

    desc 'Remove an existing plan from the plan cache'
    arg_name 'name'
    command :remove do |c|
      c.desc 'Keep the DOPi state file'
      c.default_value false
      c.switch [:keep_dopi_state]

      c.desc 'Remove the DOPv state file (THIS WILL REMOVE THE DISK INFO)'
      c.default_value false
      c.switch [:remove_dopv_state]

      c.action do |global_options,options,args|
        help_now!('Specify a plan name to remove') if args.empty?
        help_now!('You can only remove one plan') if args.length > 1
        plan_name = args[0]
        Dopi.remove(plan_name, !options[:keep_dopi_state], options[:remove_dopv_state])
      end
    end

  end
end
command_reset(base) click to toggle source
# File lib/dopi/cli/command_reset.rb, line 4
def self.command_reset(base)
  base.class_eval do

    desc 'Reset a failed plan'
    arg_name 'name'
    command :reset do |c|
      c.desc 'Force reset the states back to ready from every state'
      c.default_value false
      c.switch [:force, :f]

      c.action do |global_options,options,args|
        help_now!('Specify a plan name to run') if args.empty?
        help_now!('You can only run one plan') if args.length > 1
        plan_name = args[0]
        Dopi.reset(plan_name, options[:force])
      end
    end

  end
end
command_run(base) click to toggle source
# File lib/dopi/cli/command_run.rb, line 17
def self.command_run(base)
  base.class_eval do

    desc 'Run the plan'
    arg_name 'id'
    command :run do |c|
      run_options(c)
      c.action do |global_options,options,args|
        help_now!('Specify a plan name to run') if args.empty?
        help_now!('You can only run one plan') if args.length > 1
        options[:run_for_nodes] = DopCommon::Cli.parse_node_select_options(options)
        plan_name = args[0]
        begin
          Dopi.run(plan_name, options)
        rescue Dopi::StateTransitionError => e
          Dopi.log.error(e.message)
          exit_now!("Some steps are in a state where they can't be started again. Try to reset the plan.")
        ensure
          print_state(plan_name)
          exit_now!('Errors during plan run detected!') if Dopi.show(plan_name).state_failed?
        end
      end
    end

    desc 'Add a plan, run it and then remove it again (This is mainly for testing)'
    arg_name 'plan_file'
    command :oneshot do |c|
      run_options(c)
      c.action do |global_options,options,args|
        help_now!('Specify a plan file to add') if args.empty?
        help_now!('You can only add one plan') if args.length > 1
        options[:run_for_nodes] = DopCommon::Cli.parse_node_select_options(options)
        plan_file = args[0]
        plan_name = Dopi.add(plan_file)
        begin
          Dopi.run(plan_name, options)
        ensure
          print_state(plan_name)
          failed = Dopi.show(plan_name).state_failed?
          Dopi.remove(plan_name, true)
          exit_now!('Errors during plan run detected!') if failed
        end
      end
    end

  end
end
command_show(base) click to toggle source
# File lib/dopi/cli/command_show.rb, line 5
def self.command_show(base)
  base.class_eval do

    desc 'Show plan details and state'
    arg_name 'name'
    command :show do |c|
      c.desc 'Do not exit and continuously update the display'
      c.default_value false
      c.switch [:follow, :f]

      c.desc 'Display all details of the tree'
      c.default_value false
      c.switch [:detailed, :d]

      c.action do |global_options,options,args|
        help_now!('Specify a plan name to show') if args.empty?
        help_now!('You can only show one plan') if args.length > 1
        plan_name = args[0]
        if options[:follow]
          begin
            Curses.noecho
            Curses.curs_set(0)
            Curses.init_screen
            Curses.start_color
            Curses.init_pair(1, Curses::COLOR_BLACK, Curses::COLOR_WHITE)
            Curses.init_pair(2, Curses::COLOR_WHITE, Curses::COLOR_BLACK)
            Curses.init_pair(3, Curses::COLOR_BLUE, Curses::COLOR_BLACK)
            Curses.init_pair(4, Curses::COLOR_GREEN, Curses::COLOR_BLACK)
            Curses.init_pair(5, Curses::COLOR_YELLOW, Curses::COLOR_BLACK)
            Curses.init_pair(6, Curses::COLOR_RED, Curses::COLOR_BLACK)
            draw_screen(plan_name, options[:detailed])
            Curses.refresh
            Dopi.on_state_change(plan_name) do
              Curses.clear
              draw_screen(plan_name, options[:detailed])
              Curses.refresh
            end
          ensure
            Curses.close_screen
          end
        else
          print_state(plan_name, options[:detailed])
        end
      end
    end

  end
end
command_update(base) click to toggle source
# File lib/dopi/cli/command_update.rb, line 4
def self.command_update(base)
  base.class_eval do

    desc 'Update the plan and/or the plan state for a given plan yaml or plan name.'
    arg_name 'plan'
    command :update do |c|
      c.desc 'Remove the existing DOPi state and start with a clean state'
      c.default_value false
      c.switch [:clear, :c]

      c.desc 'Ignore the update and keep the state as it is, only update the internal version string'
      c.default_value false
      c.switch [:ignore, :i]

      c.action do |global_options,options,args|
        help_now!('Specify a plan name or  to update') if args.empty?
        help_now!('You can only update one plan') if args.length > 1
        plan = args[0]
        if Dopi.list.include?(plan)
          Dopi.update_state(plan, options)
        elsif File.exists?(plan)
          Dopi.update_plan(plan, options)
        else
          help_now!("the provided plan '#{plan}' is not an existing file or plan name")
        end
      end
    end

  end
end
command_validate(base) click to toggle source
# File lib/dopi/cli/command_validate.rb, line 4
def self.command_validate(base)
  base.class_eval do

    desc 'Validate a plan file'
    arg_name 'plan_file'
    command :validate do |c|
      c.action do |global_options,options,args|
        help_now!('Specify a plan file to add') if args.empty?
        help_now!('You can only add one plan') if args.length > 1
        plan_file = args[0]
        if Dopi.valid?(plan_file)
          puts "Plan is valid"
        else
          exit_now!("Plan is NOT valid")
        end
      end
    end

  end
end
draw_command_set(command_set, detailed) click to toggle source
# File lib/dopi/cli/command_show.rb, line 98
def self.draw_command_set(command_set, detailed)
  str_state_color(command_set.state, "     - [ #{command_set.state.to_s} ] #{command_set.node.name}\n")
  if detailed or command_set.state_running? or command_set.state_children_partial?
    command_set.commands.each do |command|
      str_state_color(command.state, "       - [ #{command.state.to_s} ] #{command.title}\n")
    end
  end
end
draw_screen(plan_name, detailed) click to toggle source
# File lib/dopi/cli/command_show.rb, line 68
def self.draw_screen(plan_name, detailed)
  plan = Dopi.show(plan_name)
  Curses.setpos(0, 0)
  Curses.attrset(Curses.color_pair(1))
  Curses.addstr("DOPi #{Dopi::VERSION} - #{plan.name} [ #{plan.state.to_s} ]".ljust(Curses.cols))
  Curses.setpos(1, 0)
  Curses.attrset(Curses.color_pair(2))
  plan.step_sets.each do |step_set|
    draw_step_set(step_set, detailed)
  end
end
draw_step(step, detailed) click to toggle source
# File lib/dopi/cli/command_show.rb, line 89
def self.draw_step(step, detailed)
  str_state_color(step.state, '   - [' + step.state.to_s + '] ' + step.name + "\n")
  if detailed or step.state_running? or step.state_children_partial?
    step.command_sets.each do |command_set|
      draw_command_set(command_set, detailed)
    end
  end
end
draw_step_set(step_set, detailed) click to toggle source
# File lib/dopi/cli/command_show.rb, line 80
def self.draw_step_set(step_set, detailed)
  str_state_color(step_set.state, ' - [' + step_set.state.to_s + '] ' + step_set.name + "\n")
  if detailed or step_set.state_running? or step_set.state_children_partial?
    step_set.steps.each do |step|
      draw_step(step, detailed)
    end
  end
end
global_options(base) click to toggle source
# File lib/dopi/cli/global_options.rb, line 8
def self.global_options(base)
  base.class_eval do
    desc 'Use Hiera to get the role for the nodes'
    default_value DopCommon.config.use_hiera
    switch [:use_hiera, :h]

    desc 'Specify the hiera configuration file'
    default_value DopCommon.config.hiera_yaml
    arg_name 'YAML'
    flag [:hiera_yaml]

    desc 'Try to load the scope for the nodes from existing facts'
    default_value DopCommon.config.load_facts
    switch [:load_facts]

    desc 'Specify the directory where dopi can find facts'
    default_value DopCommon.config.facts_dir
    arg_name 'DIR'
    flag [:facts_dir]

    desc 'Set the name of the variable DOPi should use as the roles variable'
    default_value DopCommon.config.role_variable
    arg_name 'VARIABLE_NAME'
    flag [:role_variable]

    desc 'Set the default value for the node role'
    default_value DopCommon.config.role_default
    arg_name 'ROLE'
    flag [:role_default]

    desc 'Set the MCollective client configuration.'
    default_value DopCommon.config.mco_config
    arg_name 'FILE'
    flag [:mco_config]

    desc 'Use the DOPi logger to capture MCollective logs (this is enabled by default)'
    default_value DopCommon.config.mco_dopi_logger
    switch [:mco_dopi_logger]

    desc 'Time until a connection check is marked as failure'
    default_value DopCommon.config.connection_check_timeout
    arg_name 'SECONDS'
    flag [:connection_check_timeout]
  end
end
print_state(plan_name, detailed = false) click to toggle source
run_options(command) click to toggle source
# File lib/dopi/cli/command_run.rb, line 4
def self.run_options(command)
  DopCommon::Cli.node_select_options(command)

  command.desc 'Show only stuff the run would do but don\'t execute commands (verify commands will still be executed)'
  command.default_value false
  command.switch [:noop, :n]

  command.desc 'Select the step set to run (if nothing is specified it will try to run the step set "default")'
  command.default_value 'default'
  command.arg_name 'STEPSET'
  command.flag [:step_set, :s]
end
state(plan_name, detailed = false) click to toggle source
# File lib/dopi/cli/log.rb, line 8
def self.state(plan_name, detailed = false)
  plan = Dopi.show(plan_name)
  result = "[#{plan.state.to_s}] #{plan.name}\n"
  plan.step_sets.each do |step_set|
    result << "  [#{step_set.state.to_s}] #{step_set.name}\n"
    step_set.steps.each do |step|
      result << "    [#{step.state.to_s}] #{step.name}\n"
      if detailed or step.state_running? or step.state_children_partial?
        step.command_sets.each do |command_set|
          result << "      [#{command_set.state.to_s}] #{command_set.name}\n"
          command_set.commands.each do |command|
            result << "        [#{command.state.to_s}] #{command.title}\n"
          end
        end
      end
    end
  end
  return result
end
str_state_color(state, string) click to toggle source
# File lib/dopi/cli/command_show.rb, line 54
def self.str_state_color(state, string)
  attr = case state
  when :ready then Curses.color_pair(3)
  when :done then Curses.color_pair(4)
  when :partial then Curses.color_pair(5)
  when :running, :started then Curses.color_pair(5) | Curses::A_BLINK
  when :failed then Curses.color_pair(6)
  else Curses.color_pair(2)
  end
  Curses.attrset(attr)
  Curses.addstr(string)
  Curses.attrset(Curses.color_pair(2))
end