class MotherBrain::Bootstrap::Worker

@api private

Public Instance Methods

full_bootstrap(host, options = {}) click to toggle source

Perform a bootstrap on a group of nodes which have not yet been registered with the Chef server and may not have Ruby, Chef, or other requirements installed.

@example

host = Host.new("cloud-1.riotgames.com")

worker.full_bootstrap(host) #=> {
  node_name: "cloud-1",
  hostname: "cloud-1.riotgames.com",
  status: :ok
  message: "",
  bootstrap_type: :full
}

@param [Worker::Host] host

a host to bootstrap

@option options [String] :environment

environment to join the node to (default: '_default')

@option options [String] :chef_version

version of Chef to install on the node

@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 [Hash] :hints (Hash.new)

a hash of Ohai hints to place on the bootstrapped node

@option options [Boolean] :sudo (true)

bootstrap with sudo

@return [Hash]

# File lib/mb/bootstrap/worker.rb, line 134
def full_bootstrap(host, options = {})
  options = options.reverse_merge(
    run_list: Array.new,
    attributes: Hash.new,
    hints: Hash.new,
    sudo: true
  )

  begin
    options[:template] = MB::Bootstrap::Template.find(options[:template])
  rescue MB::BootstrapTemplateNotFound => e
    abort e
  end
  options.delete(:template) if options[:template].nil?

  ssh_response = chef_connection.node.bootstrap(host.hostname, options)

  {}.tap do |response|
    response[:node_name]      = nil
    response[:hostname]       = ssh_response.host
    response[:bootstrap_type] = :full
    response[:message]        = ""
    response[:status]         = :ok

    if ssh_response.error?
      response[:status]  = :error
      response[:message] = ssh_response.stderr.chomp
    end
  end
end
partial_bootstrap(host, options = {}) click to toggle source

Perform a bootstrap on a group of nodes which have already been registered with the Chef server.

Partial bootstrap steps:

1. The given values given for the run_list and attributes options will be merged with the existing
   node data
2. Your organization's secret key will be placed on the node
3. Perform a chef client run on the target node

@example

host = Host.new("cloud-1.riotgames.com")
worker.partial_bootstrap(host) #=> {
  node_name: "cloud-1",
  hostname: "cloud-1.riotgames.com",
  status: :ok
  message: "",
  bootstrap_type: :partial
}

@param [Worker::Host] host

a host to bootstrap

@option options [Array] :run_list

a chef run list

@option options [Hash] :attributes

attributes to set on the node at normal precedence

@return [Hash]

# File lib/mb/bootstrap/worker.rb, line 192
def partial_bootstrap(host, options = {})
  log.info "#{host} is already registered with Chef. Performing a partial bootstrap."

  {}.tap do |response|
    response[:node_name]      = host.node_name
    response[:hostname]       = host.hostname
    response[:bootstrap_type] = :partial
    response[:message]        = ""
    response[:status]         = :ok

    begin
      chef_connection.node.merge_data(host.node_name, options.slice(:run_list, :attributes))
      node_querier.put_secret(host.hostname)
      node_querier.chef_run(host.hostname)
    rescue Ridley::Errors::ResourceNotFound => ex
      response[:status]  = :error
      response[:message] = "Host #{host} has a client on the node and a matching client on the Chef server, " +
        "but there is no matching node object on the Chef server for the client. This should not happen. " +
        "Run `mb purge #{host}` or manually destroy the client on the node itself and the node object on " +
        "the Chef server and re-run your bootstrap."
      # JW TODO: We can recover here by creating the node object. However, we can't do this right
      # now because OHC/OPC have ACLs associated with the node object. When we create the object the
      # API user that we are acting as will be the only user with full permissions to the node
      # object resulting in a 403 error when the node attempts to save itself back to the Chef server.
      #
      # TLDR; The undocumented ACL endpoints need to be implemented in Ridley to support graceful
      # recovery. https://github.com/RiotGames/ridley/issues/147
    rescue Exception => ex
      response[:status]  = :error
      response[:message] = ex.to_s
    end
  end
end
run(address, options = {}) click to toggle source

Run a bootstrap on each of the hosts given to this instance of {Worker}. There are two different kinds of bootstrap processes which may be run on a node; a partial bootstrap and a full bootstrap.

Partial Bootstrap: a node will be partially bootstrapped if it has

1. Chef installed by omnibus
2. Ruby installed by omnibus
3. A Chef client registered with the Chef server.
   note: the name of the client is the "node_name" of the node. This obtained by running the
         ruby node name script "script/node_name.rb" on the node.

Full Bootstrap: a node will be fully bootstrapped if it does not satisfy all of the criteria for a

partial bootstrap.

@example

worker = Worker.new
worker.run("cloud-1.riotgames.com") #=> {
  node: "cloud-1.riotgames.com",
  status: :ok,
  message: "",
  bootstrap_type: :full
}

@param [String] address

a hostname or ipaddress to bootstrap

@option options [String] :environment

environment to join the node to (default: '_default')

@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]

# File lib/mb/bootstrap/worker.rb, line 94
def run(address, options = {})
  host = Host.new(address)
  if host.full_bootstrap?
    full_bootstrap(host, options)
  else
    partial_bootstrap(host, options.slice(:attributes, :run_list))
  end
end