class MotherBrain::CliGateway

Constants

CREATE_ENVIRONMENT_TASKS
SKIP_CONFIG_TASKS
SKIP_ENVIRONMENT_TASKS

Public Class Methods

configure(options) click to toggle source

@param [Hash] options

@return [MB::Config]

# File lib/mb/cli_gateway.rb, line 11
def configure(options)
  file = options[:config] || File.expand_path(MB::Config.default_path)

  begin
    config = MB::Config.from_file(file)
  rescue MB::InvalidConfig => ex
    ui.error ex.to_s
    exit_with(InvalidConfig)
  rescue MB::ConfigNotFound => ex
    ui.error "#{ex.message}"
    ui.error "Create one with `mb configure`"
    exit_with(ConfigNotFound)
  end

  level = Logger::WARN
  level = Logger::INFO if options[:verbose]
  level = Logger::DEBUG if options[:debug]

  if (options[:verbose] || options[:debug]) && options[:logfile].nil?
    options[:logfile] = STDOUT
  end

  MB::Logging.setup(level: level, location: options[:logfile])

  config.rest_gateway.enable = false
  config.plugin_manager.eager_loading = false
  config.plugin_manager.async_loading = false
  config
end
find_plugin(name, options = {}) click to toggle source

Return the best plugin version for the given options.

If no options are given, the latest version of the plugin will be loaded from either your Berkshelf or the remote Chef server. If no plugin is found then the CLI will exit with an error.

Specifying an environment will cause this function to check with the target environment to see what plugin version is best suited be be returned for controlling that environment.

If the specified environment does not exist then the latest plugin on the Chef server will be returned. If no plugin is found then the CLI will exit with an error.

Specifying a plugin_version will cause this function to return only a the plugin matching that name and version. If no plugin is found then the CLI will exit with an error.

@option options [String] :environment @option options [String] :plugin_version

@return [MB::Plugin]

# File lib/mb/cli_gateway.rb, line 59
def find_plugin(name, options = {})
  if options[:plugin_version]
    plugin = plugin_manager.find(name, options[:plugin_version], remote: true)

    unless plugin
      ui.error "The cookbook #{name} (version #{options[:plugin_version]}) did not contain a motherbrain" +
        " plugin or it was not found in your Berkshelf or on the remote."
      exit(1)
    end

    plugin
  elsif local_plugin?
    ui.info "Loading #{name} plugin from: #{Dir.pwd}"
    plugin_manager.load_installed(Dir.pwd, allow_failure: false)
  elsif options[:environment]
    plugin = begin
      ui.info "Determining best version of the #{name} plugin to use with the #{options[:environment]}" +
        " environment. This may take a few seconds..."
      plugin_manager.for_environment(name, options[:environment], remote: true)
    rescue MotherBrain::EnvironmentNotFound => ex
      ui.warn "No environment named #{options[:environment]} was found. Finding the latest version of the" +
        " #{name} plugin instead. This may take a few seconds..."
      plugin_manager.latest(name, remote: true)
    end

    unless plugin
      ui.error "No versions of the #{name} cookbook contained a motherbrain plugin that matched the" +
        " requirements of the #{options[:environment]} environment."
      exit(1)
    end

    plugin
  else
    ui.info "Finding the latest version of the #{name} plugin. This may take a few seconds..."
    plugin = plugin_manager.latest(name, remote: true)

    unless plugin
      ui.error "No versions of the #{name} cookbook in your Berkshelf or on the remote contained a" +
        " motherbrain plugin."
      exit(1)
    end

    plugin
  end
end
invoked_opts() click to toggle source
# File lib/mb/cli_gateway.rb, line 4
def invoked_opts
  @invoked_opts ||= Hashie::Mash.new
end
local_plugin?() click to toggle source

Determines if we’re running inside of a cookbook with a plugin.

@return [Boolean]

# File lib/mb/cli_gateway.rb, line 108
def local_plugin?
  Dir.has_mb_plugin?(Dir.pwd)
end
new(args = [], options = {}, config = {}) click to toggle source
Calls superclass method
# File lib/mb/cli_gateway.rb, line 246
def initialize(args = [], options = {}, config = {})
  super
  opts = self.options.dup

  validate_environment

  unless SKIP_CONFIG_TASKS.include?(config[:current_command].try(:name))
    self.class.configure(opts)
  end
end
plugin_task?(name) click to toggle source

Did the user call a plugin task?

@param [String] name

@return [Boolean]

# File lib/mb/cli_gateway.rb, line 179
def plugin_task?(name)
  non_plugin_tasks = tasks.keys.map(&:to_s)
  !non_plugin_tasks.find { |task| task == name }.present?
end
register_plugin(plugin) click to toggle source

Create and register a sub command for the given plugin

@param [MB::Plugin] plugin

@return [MB::Cli::SubCommand]

the sub command generated and registered
# File lib/mb/cli_gateway.rb, line 190
def register_plugin(plugin)
  sub_command = MB::Cli::SubCommand.new(plugin)
  register_subcommand(sub_command)
  sub_command
end
requires_environment?(args) click to toggle source

Does the given argument array require a named argument for environment?

@param [Array<String>] args the CLI arguments

@return [Boolean]

# File lib/mb/cli_gateway.rb, line 154
def requires_environment?(args)
  return false if args.count.zero?

  if args.include?("help")
    return false
  end

  if SKIP_ENVIRONMENT_TASKS.include?(args.first)
    return false
  end
  
  if args.count == 1
    return false
  end

  # All commands/subcommands require an environment unless specified in
  # the {SKIP_ENVIRONMENT_TASKS} constant array.
  true
end
start(given_args = ARGV, config = {}) click to toggle source

@see {#Thor}

# File lib/mb/cli_gateway.rb, line 113
def start(given_args = ARGV, config = {})
  config[:shell] ||= MB::Cli::Shell.shell.new
  args, opts = parse_args(given_args)
  invoked_opts.merge!(opts)

  if requires_environment?(args)
    unless opts[:environment]
      ui.say "No value provided for required option '--environment'"
      exit 1
    end
  end

  if start_mb_application?(args)
    app_config = configure(opts.dup)
    app_config.validate!

    MB::Application.run!(app_config)
    MB::Logging.add_argument_header

    # If the first argument is the name of a plugin, register that plugin and use it.
    if plugin_task?(args[0])
      name = args[0]

      plugin = find_plugin(name, opts)
      register_plugin(plugin)

      ui.say "using #{plugin}"
      ui.say ""
    end
  end

  dispatch(nil, given_args.dup, nil, config)
ensure
  Celluloid.shutdown
end
start_mb_application?(args) click to toggle source

Check if we should start the motherbrain application stack based on the arguments passed to the CliGateway. The application stack won’t be started if the first argument is a member of {SKIP_CONFIG_TASKS}.

@param [Array] args

@return [Boolean]

# File lib/mb/cli_gateway.rb, line 203
def start_mb_application?(args)
  args.any? && !SKIP_CONFIG_TASKS.include?(args.first)
end

Private Class Methods

parse_args(given_args) click to toggle source

Parse the given arguments into an instance of Thor::Argument and Thor::Options

@param [Array] given_args

@return [Array]

# File lib/mb/cli_gateway.rb, line 214
def parse_args(given_args)
  args, opts = Thor::Options.split(given_args)
  thor_opts = Thor::Options.new(self.class_options)
  parsed_opts = thor_opts.parse(opts)

  [ args, parsed_opts ]
end

Public Instance Methods

configure(path = MB::Config.default_path) click to toggle source
# File lib/mb/cli_gateway.rb, line 303
def configure(path = MB::Config.default_path)
  path = File.expand_path(path)

  if File.exist?(path) && !options[:force]
    raise MB::ConfigExists, "A configuration file already exists. Re-run with the --force flag if you wish to overwrite it."
  end

  config = MB::Config.new(path)

  config.chef.api_url     = ui.ask "Enter a Chef API URL:", default: config.chef.api_url
  config.chef.api_client  = ui.ask "Enter a Chef API Client:", default: config.chef.api_client
  config.chef.api_key     = ui.ask "Enter the path to the client's Chef API Key:", default: config.chef.api_key
  config.ssh.user         = ui.ask "Enter a SSH user:", default: config.ssh.user
  config.ssh.password     = ui.ask "Enter a SSH password:", default: config.ssh.password
  config.save

  ui.say "Config written to: '#{path}'"
end
console() click to toggle source
# File lib/mb/cli_gateway.rb, line 323
def console
  require 'mb/console'
  MB::Console.start
end
disable(hostname) click to toggle source
# File lib/mb/cli_gateway.rb, line 383
def disable(hostname)
  job = node_querier.async_disable(hostname, options.to_hash.symbolize_keys)
  CliClient.new(job).display
end
enable(hostname) click to toggle source
# File lib/mb/cli_gateway.rb, line 372
def enable(hostname)
  job = node_querier.async_enable(hostname, options.to_hash.symbolize_keys)
  CliClient.new(job).display
end
purge(hostname) click to toggle source
# File lib/mb/cli_gateway.rb, line 333
def purge(hostname)
  job = node_querier.async_purge(hostname, options.to_hash.symbolize_keys)
  CliClient.new(job).display
end
template(name, path_or_url) click to toggle source
# File lib/mb/cli_gateway.rb, line 396
def template(name, path_or_url)
  MB::Bootstrap::Template.install(name, path_or_url)
  ui.say "Installed template `#{name}`"
end
upgrade_omnibus(version) click to toggle source
# File lib/mb/cli_gateway.rb, line 349
def upgrade_omnibus(version)
  nodes = nil
  if options["host"]
    host = options["host"]
    node_object = Ridley::NodeObject.new(host, automatic: { fqdn: host })
    nodes = [node_object]
  elsif options["environment"]
    nodes = environment_manager.nodes_for_environment(options["environment"])
  end
  if nodes.nil?
    ui.error "Error - you need to either define a host (--host) or an environment (-e) to operate on."
  else
    job = node_querier.async_upgrade_omnibus(version, nodes, options.to_hash.symbolize_keys)
    CliClient.new(job).display
  end
end
version() click to toggle source
# File lib/mb/cli_gateway.rb, line 389
def version
  ui.say version_header
  ui.say "\n"
  ui.say license
end

Private Instance Methods

create_environment(environment_name) click to toggle source
# File lib/mb/cli_gateway.rb, line 444
def create_environment(environment_name)
  environment_manager.create(environment_name)
end
license() click to toggle source
# File lib/mb/cli_gateway.rb, line 438
def license
  File.read(MB.app_root.join('LICENSE'))
end
prompt_to_create_environment(environment_name) click to toggle source
# File lib/mb/cli_gateway.rb, line 421
def prompt_to_create_environment(environment_name)
  message = "Environment '#{environment_name}' does not exist, would you like to create it?"
  case ask(message, limited_to: %w[y n q], default: 'y')
  when 'y' then create_environment(environment_name)
  when 'n' then ui.warn "Not creating environment"
  when 'q' then quit("Because you said so")
  end
end
quit(why) click to toggle source
# File lib/mb/cli_gateway.rb, line 448
def quit(why)
  ui.say "Quitting: #{why}"
  abort
end
testing?() click to toggle source
# File lib/mb/cli_gateway.rb, line 430
def testing?
  MB.testing?
end
validate_environment() click to toggle source
# File lib/mb/cli_gateway.rb, line 403
def validate_environment
  return if testing?

  environment_name = options[:environment]

  return unless environment_name

  environment_manager.find(environment_name)
rescue EnvironmentNotFound
  raise unless CREATE_ENVIRONMENT_TASKS.include?(args.first)

  case options[:on_environment_missing]
  when 'prompt' then prompt_to_create_environment(environment_name)
  when 'create' then create_environment(environment_name)
  when 'quit' then quit("Environment '#{environment_name}' not found and you told me to quit when that happens")
  end
end
version_header() click to toggle source
# File lib/mb/cli_gateway.rb, line 434
def version_header
  "motherbrain (#{MB::VERSION})"
end