class MotherBrain::Bootstrap::Manager

Attributes

worker_pool[R]

Public Class Methods

instance() click to toggle source

@raise [Celluloid::DeadActorError] if Bootstrap Manager has not been started

@return [Celluloid::Actor(Bootstrap::Manager)]

# File lib/mb/bootstrap/manager.rb, line 8
def instance
  MB::Application[:bootstrap_manager] or raise Celluloid::DeadActorError, "bootstrap manager not running"
end
new() click to toggle source
# File lib/mb/bootstrap/manager.rb, line 21
def initialize
  log.debug { "Bootstrap Manager starting..." }
  @worker_pool = Bootstrap::Worker.pool(size: 50)
end

Public Instance Methods

async_bootstrap(environment, manifest, plugin, options = {}) click to toggle source

Asynchronously bootstrap a collection of nodes described in the given manifest in the proper order

@param [String] environment

name of the environment to bootstrap nodes to

@param [Bootstrap::Manifest] manifest

manifest of nodes and what they should become

@param [Plugin] plugin

a motherbrain plugin with a bootstrap routine to follow

@option options [Hash] :component_versions (Hash.new)

Hash of components and the versions to set them to

@option options [Hash] :cookbook_versions (Hash.new)

Hash of cookbooks and the versions to set them to

@option options [Hash] :environment_attributes (Hash.new)

Hash of additional attributes to set on the environment

@option options [Boolean] :force

ignore and bypass any existing locks on an environment

@option options [Hash] :attributes (Hash.new)

a hash of node level attributes to set on the bootstrapped nodes

@option options [Array] :run_list (Array.new)

an initial run list to bootstrap with

@option options [String] :chef_version

version of Chef to install on the node

@option options [Hash] :hints (Hash.new)

a hash of Ohai hints to place on the bootstrapped node

@option options [Boolean] :sudo (true)

bootstrap with sudo

@option options [String] :bootstrap_proxy (nil)

URL to a proxy server to bootstrap through

@return [MB::JobRecord]

a reference to the executing job
# File lib/mb/bootstrap/manager.rb, line 58
def async_bootstrap(environment, manifest, plugin, options = {})
  job = Job.new(:bootstrap)
  async(:bootstrap, job, environment, manifest, plugin, options)

  job.ticket
end
bootstrap(job, environment, manifest, plugin, options = {}) click to toggle source

Bootstrap a collection of nodes described in the given manifest in the proper order

@param [MB::Job] job

a job to send progress updates to

@param [String] environment

name of the environment to bootstrap nodes to

@param [MB::Bootstrap::Manifest] manifest

manifest of nodes and what they should become

@param [MB::Plugin] plugin

a motherbrain plugin with a bootstrap routine to follow

@see {#async_bootstrap} for options

# File lib/mb/bootstrap/manager.rb, line 77
def bootstrap(job, environment, manifest, plugin, options = {})
  options = options.reverse_merge(
    component_versions: Hash.new,
    environment_attributes: Hash.new,
    hints: Hash.new,
    bootstrap_proxy: Application.config[:chef][:bootstrap_proxy],
    sudo: Application.config[:ssh][:sudo],
    force: false
  )
  options[:environment] = environment

  job.report_running

  validate_bootstrap_configuration!(manifest, plugin)

  job.set_status("Searching for environment")
  unless chef_connection.environment.find(environment)
    return job.report_failure("Environment '#{environment}' not found")
  end

  job.set_status("Starting bootstrap of nodes on: #{environment}")
  task_queue = plugin.bootstrap_routine.task_queue.dup

  chef_synchronize(chef_environment: environment, force: options[:force], job: job) do
    if options[:component_versions].any?
      job.set_status("Setting component versions")
      set_component_versions(environment, plugin, options[:component_versions])
    end

    cookbook_versions = options[:cookbook_versions] || plugin.cookbook_versions
    if cookbook_versions.any?
      job.set_status("Setting cookbook versions")
      set_cookbook_versions(environment, cookbook_versions)
    end

    if options[:environment_attributes].any?
      job.set_status("Setting environment attributes")
      set_environment_attributes(environment, options[:environment_attributes])
    end

    unless options[:environment_attributes_file].nil?
      job.set_status("Setting environment attributes from file")
      set_environment_attributes_from_file(environment, options[:environment_attributes_file])
    end

    while tasks = task_queue.shift
      host_errors = Hash.new
      group_names = Array(tasks).collect(&:group_name).join(', ')

      instructions = Bootstrap::Routine.map_instructions(tasks, manifest)
      if instructions.empty?
        log.info "Skipping bootstrap of group(s): #{group_names}. No hosts defined in manifest to bootstrap for " +
        "these groups."
        next
      end

      job.set_status("Bootstrapping group(s): #{group_names}")

      concurrent_bootstrap(job, manifest, instructions, options).each do |host, host_info|
        if host_info[:result][:status] == :error
          host_errors[host] = host_info
        end
      end

      unless host_errors.empty?
        abort GroupBootstrapError.new(host_errors)
      end

      job.set_status("Finished bootstrapping group(s): #{group_names}")
    end
  end

  job.report_success
rescue => ex
  job.report_failure(ex)
ensure
  job.terminate if job && job.alive?
end
concurrent_bootstrap(job, manifest, instructions, options = {}) click to toggle source

Concurrently bootstrap a grouped collection of nodes from a manifest and return their results. This function will block until all nodes have finished bootstrapping.

@param [MB::Job] job

a job to send progress updates to

@param [Bootstrap::Manifest] manifest

a hash where the keys are node group names and the values are arrays of hostnames

@param [Hash] instructions

a hash containing an entry for every host to bootstrap and the groups it belongs to, the
run list it should be bootstrapped with, and the chef attributes to be applied to the node
for it's first run.

@option options [Hash] :attributes (Hash.new)

a hash of attributes to use in the first Chef run

@option options [Array] :run_list (Array.new)

an initial run list to bootstrap with

@option options [String] :chef_version

version of Chef to install on the node

@option options [Hash] :hints (Hash.new)

a hash of Ohai hints to place on the bootstrapped node

@option options [Boolean] :sudo (true)

bootstrap with sudo

@option options [String] :bootstrap_proxy (nil)

URL to a proxy server to bootstrap through

@return [Hash]

a hash where keys are group names and their values are the results of {Bootstrap::Worker#run}

@example

{
  "cloud-1.riotgames.com" => {
    groups: ["proxy_server::default", "app_server::default"],
    result: {
      status: :ok,
      message: "",
      bootstrap_type: :full
    }
  },
  "cloud-2.riotgames.com" => {
    groups: ["database_master::default"],
    result: {
      status: :error,
      message: "client verification error"
      bootstrap_type: :partial
    }
  },
  "cloud-3.riotgames.com" => {
    groups: ["database_slave::default"],
    result: {
      status: :ok
      message: ""
      bootstrap_type: :partial
    }
  }
}
# File lib/mb/bootstrap/manager.rb, line 212
def concurrent_bootstrap(job, manifest, instructions, options = {})
  response     = Hash.new

  instructions.each do |host, host_info|
    boot_options = options.merge(host_info[:options])
    boot_options.merge!(manifest[:options]) if manifest[:options]

    job.set_status("Bootstrapping #{host} with group(s): #{host_info[:groups]}")

    response[host] = {
      groups: host_info[:groups],
      result: worker_pool.future(:run, host, boot_options)
    }
  end

  response.each { |host, host_info| host_info[:result] = host_info[:result].value }
end

Private Instance Methods

finalize_callback() click to toggle source
# File lib/mb/bootstrap/manager.rb, line 234
def finalize_callback
  log.debug { "Bootstrap Manager stopping..." }
  worker_pool.terminate if worker_pool && worker_pool.alive?
end
validate_bootstrap_configuration!(manifest, plugin) click to toggle source
# File lib/mb/bootstrap/manager.rb, line 239
def validate_bootstrap_configuration!(manifest, plugin)
  manifest.validate!(plugin)

  validator_path = File.expand_path(config_manager.config.chef[:validator_path])

  unless File.exists?(validator_path)
    raise ValidatorPemNotFound.new(validator_path)
  end
end