Class: MotherBrain::Bootstrap::Manager

Inherits:
Object
  • Object
show all
Includes:
Celluloid, MB::Mixin::AttributeSetting, MB::Mixin::Locks, MB::Mixin::Services, Logging
Defined in:
lib/mb/bootstrap/manager.rb

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Logging

add_argument_header, dev, filename, #log_exception, logger, #logger, reset, set_logger, setup

Constructor Details

#initializeManager

Returns a new instance of Manager.



21
22
23
24
# File 'lib/mb/bootstrap/manager.rb', line 21

def initialize
  log.debug { "Bootstrap Manager starting..." }
  @worker_pool = Bootstrap::Worker.pool(size: 50)
end

Class Method Details

.instanceCelluloid::Actor(Bootstrap::Manager)

Returns:

Raises:

  • (Celluloid::DeadActorError)

    if Bootstrap Manager has not been started



8
9
10
# File 'lib/mb/bootstrap/manager.rb', line 8

def instance
  MB::Application[:bootstrap_manager] or raise Celluloid::DeadActorError, "bootstrap manager not running"
end

Instance Method Details

#async_bootstrap(environment, manifest, plugin, options = {}) ⇒ MB::JobRecord

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

Parameters:

  • environment (String)

    name of the environment to bootstrap nodes to

  • manifest (Bootstrap::Manifest)

    manifest of nodes and what they should become

  • plugin (Plugin)

    a motherbrain plugin with a bootstrap routine to follow

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

    a customizable set of options

Options Hash (options):

  • :component_versions (Hash) — default: Hash.new

    Hash of components and the versions to set them to

  • :cookbook_versions (Hash) — default: Hash.new

    Hash of cookbooks and the versions to set them to

  • :environment_attributes (Hash) — default: Hash.new

    Hash of additional attributes to set on the environment

  • :force (Boolean)

    ignore and bypass any existing locks on an environment

  • :attributes (Hash) — default: Hash.new

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

  • :run_list (Array) — default: Array.new

    an initial run list to bootstrap with

  • :chef_version (String)

    version of Chef to install on the node

  • :hints (Hash) — default: Hash.new

    a hash of Ohai hints to place on the bootstrapped node

  • :sudo (Boolean) — default: true

    bootstrap with sudo

  • :bootstrap_proxy (String) — default: nil

    URL to a proxy server to bootstrap through

Returns:



58
59
60
61
62
63
# 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 = {}) ⇒ Object

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

Parameters:

  • job (MB::Job)

    a job to send progress updates to

  • environment (String)

    name of the environment to bootstrap nodes to

  • manifest (MB::Bootstrap::Manifest)

    manifest of nodes and what they should become

  • plugin (MB::Plugin)

    a motherbrain plugin with a bootstrap routine to follow

See Also:

  • for options


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
104
105
106
107
108
109
110
111
112
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
148
149
150
151
152
153
154
# 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 = {}) ⇒ Hash

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

Examples:

{
  "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
    }
  }
}

Parameters:

  • job (MB::Job)

    a job to send progress updates to

  • manifest (Bootstrap::Manifest)

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

  • instructions (Hash)

    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.

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

    a customizable set of options

Options Hash (options):

  • :attributes (Hash) — default: Hash.new

    a hash of attributes to use in the first Chef run

  • :run_list (Array) — default: Array.new

    an initial run list to bootstrap with

  • :chef_version (String)

    version of Chef to install on the node

  • :hints (Hash) — default: Hash.new

    a hash of Ohai hints to place on the bootstrapped node

  • :sudo (Boolean) — default: true

    bootstrap with sudo

  • :bootstrap_proxy (String) — default: nil

    URL to a proxy server to bootstrap through

Returns:

  • (Hash)

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



212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
# 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