Class: MotherBrain::CliGateway

Inherits:
MotherBrain::Cli::Base show all
Defined in:
lib/mb/cli_gateway.rb,
lib/mb/cli_gateway/sub_commands/plugin.rb,
lib/mb/cli_gateway/sub_commands/environment.rb

Defined Under Namespace

Modules: SubCommand

Constant Summary collapse

SKIP_CONFIG_TASKS =
[
  "configure",
  "help",
  "init",
  "version",
  "ver"
].freeze
SKIP_ENVIRONMENT_TASKS =
[
  "environment",
  "plugin",
  "template",
  "purge",
  "disable",
  "enable",
  "upgrade_omnibus"
].freeze
CREATE_ENVIRONMENT_TASKS =
[
  "bootstrap",
  "provision"
].freeze

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from MotherBrain::Cli::Base

register_subcommand, ui

Constructor Details

#initialize(args = [], options = {}, config = {}) ⇒ CliGateway

Returns a new instance of CliGateway.



246
247
248
249
250
251
252
253
254
255
# 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

Class Method Details

.configure(options) ⇒ MB::Config

Parameters:

  • options (Hash)

Returns:



11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
# 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 = {}) ⇒ MB::Plugin

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.

Parameters:

  • options (Hash) (defaults to: {})

    a customizable set of options

Options Hash (options):

  • :environment (String)
  • :plugin_version (String)

Returns:



59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
# 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_optsObject



4
5
6
# File 'lib/mb/cli_gateway.rb', line 4

def invoked_opts
  @invoked_opts ||= Hashie::Mash.new
end

.local_plugin?Boolean

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

Returns:

  • (Boolean)


108
109
110
# File 'lib/mb/cli_gateway.rb', line 108

def local_plugin?
  Dir.has_mb_plugin?(Dir.pwd)
end

.plugin_task?(name) ⇒ Boolean

Did the user call a plugin task?

Parameters:

  • name (String)

Returns:

  • (Boolean)


179
180
181
182
# 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) ⇒ MB::Cli::SubCommand

Create and register a sub command for the given plugin

Parameters:

Returns:

  • (MB::Cli::SubCommand)

    the sub command generated and registered



190
191
192
193
194
# 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) ⇒ Boolean

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

Parameters:

  • args (Array<String>)

    the CLI arguments

Returns:

  • (Boolean)


154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
# 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 = {}) ⇒ Object

See Also:

  • {{#Thor}


113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
# 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) ⇒ Boolean

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.

Parameters:

  • args (Array)

Returns:

  • (Boolean)


203
204
205
# File 'lib/mb/cli_gateway.rb', line 203

def start_mb_application?(args)
  args.any? && !SKIP_CONFIG_TASKS.include?(args.first)
end

Instance Method Details

#configure(path = MB::Config.default_path) ⇒ Object



303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
# 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

#consoleObject



323
324
325
326
# File 'lib/mb/cli_gateway.rb', line 323

def console
  require 'mb/console'
  MB::Console.start
end

#disable(hostname) ⇒ Object



383
384
385
386
# 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) ⇒ Object



372
373
374
375
# 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) ⇒ Object



333
334
335
336
# 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) ⇒ Object



396
397
398
399
# 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) ⇒ Object



349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
# 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

#versionObject



389
390
391
392
393
# File 'lib/mb/cli_gateway.rb', line 389

def version
  ui.say version_header
  ui.say "\n"
  ui.say license
end