class MotherBrain::Bootstrap::Manager
Attributes
Public Class Methods
@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
# 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
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
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
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
# 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
# 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