class MotherBrain::EnvironmentManager

Public Class Methods

instance() click to toggle source

@raise [Celluloid::DeadActorError] if the environment manager has not been started

@return [Celluloid::Actor(EnvironmentManager)]

# File lib/mb/environment_manager.rb, line 7
def instance
  MB::Application[:environment_manager] or raise Celluloid::DeadActorError, "environment manager not running"
end
new() click to toggle source
# File lib/mb/environment_manager.rb, line 19
def initialize
  log.debug { "Environment Manager starting..." }
end

Public Instance Methods

async_configure(id, options = {}) click to toggle source

Asynchronously configure a target environment with the given attributes

@param [String] id

identifier of the environment to configure

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

a hash of attributes to merge with the existing attributes of an environment

@option options [Boolean] :force (false)

force configure even if the environment is locked

@note attributes will be set at the ‘default’ level and will be merged into the

existing attributes of the environment

@return [JobTicket]

# File lib/mb/environment_manager.rb, line 37
def async_configure(id, options = {})
  job = Job.new(:environment_configure)
  async(:configure, job, id, options)

  job.ticket
end
async_examine_nodes(id, options = {}) click to toggle source
# File lib/mb/environment_manager.rb, line 109
def async_examine_nodes(id, options = {})
  job = Job.new(:examine_nodes)
  async(:examine_nodes, job, id, options)

  job.ticket
end
configure(job, id, options = {}) click to toggle source

Configure a target environment with the given attributes

@param [MB::Job] job

a job to update with progress

@param [String] id

identifier of the environment to configure

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

a hash of attributes to merge with the existing attributes of an environment

@option options [Boolean] :force (false)

force configure even if the environment is locked

@option options [String] :node_filter

limit chef-run to certain nodes - NOT RECOMMENDED

@api private

# File lib/mb/environment_manager.rb, line 58
def configure(job, id, options = {})
  options = options.reverse_merge(
    attributes: Hash.new,
    force: false
  )

  node_successes_count = 0
  node_successes = Array.new

  node_failures_count  = 0
  node_failures = Array.new

  environment = find(id)
  job.report_running("Finding environment #{environment.name}")

  chef_synchronize(chef_environment: environment.name, force: options[:force], job: job) do
    job.set_status("Saving updated environment with - #{options[:attributes]}")
    environment.default_attributes.deep_merge!(options[:attributes])
    environment.save

    job.set_status("Searching for nodes in the environment")
    nodes = nodes_for_environment(environment.name)
    nodes = MB::NodeFilter.filter(options[:node_filter], nodes) if options[:node_filter]

    job.set_status("Performing a chef client run on #{nodes.length} nodes")
    nodes.collect do |node|
      node_querier.future(:chef_run, node.public_hostname, connector: node_querier.connector_for_os(node.chef_attributes.os))
    end.each do |future|
      begin
        response = future.value
        node_successes_count += 1
        node_successes << response.host
      rescue RemoteCommandError => error
        node_failures_count += 1
        node_failures << error.host
      end
    end
  end

  if node_failures_count > 0
    job.report_failure("chef client run failed on #{node_failures_count} node(s) - #{node_failures.join(', ')}")
  else
    job.report_success("Finished chef client run on #{node_successes_count} node(s) - #{node_successes.join(', ')}")
  end
rescue => ex
  job.report_failure(ex)
ensure
  job.terminate if job && job.alive?
end
create(name) click to toggle source

Creates an environment

@param [#to_s] name

@return [Ridley::EnvironmentResource]

# File lib/mb/environment_manager.rb, line 160
def create(name)
  ridley.environment.create(name: name)
rescue Ridley::Errors::HTTPConflict
  abort EnvironmentExists.new(name)
rescue => error
  abort error
end
create_from_file(path) click to toggle source

Creates an environment from JSON contained in a file

@param [#to_s] path

@return [Ridley::EnvironmentResource]

# File lib/mb/environment_manager.rb, line 173
def create_from_file(path)
  abort FileNotFound.new(path) unless File.exist? path

  env = ridley.environment.from_file(path)
  ridley.environment.create(env)
rescue Ridley::Errors::HTTPConflict
  abort EnvironmentExists.new(env.name)
end
destroy(name) click to toggle source

Destroys an environment

@param [#to_s] name

@return [Ridley::EnvironmentResource, nil]

# File lib/mb/environment_manager.rb, line 187
def destroy(name)
  ridley.environment.delete(name)
end
examine_nodes(job, id, options = {}) click to toggle source
# File lib/mb/environment_manager.rb, line 116
def examine_nodes(job, id, options = {})
  environment = find(id)
  job.report_running("Finding environment #{environment.name}")
  nodes = nodes_for_environment(environment.name)

  job.set_status("Examining #{nodes.length} nodes")

  nodes.collect do |node|
    log.debug "About to execute on: \"#{node.public_hostname}\""
    node_querier.future(:execute_command, node.public_hostname, "echo %time%")
  end.each do |future|
    begin
      response = future.value
    rescue RemoteCommandError => error
      log.warn "Examine command failed on: \"#{error.host}\""
      log.warn "  " + error.message
    end
  end
  job.report_success("Completed on #{nodes.length} nodes.")
ensure
  job.terminate if job && job.alive?
end
find(id) click to toggle source

Find an environment on the remote Chef server

@param [#to_s] id

identifier for the environment to find

@raise [EnvironmentNotFound] if the given environment does not exist

@return [Ridley::EnvironmentResource]

# File lib/mb/environment_manager.rb, line 147
def find(id)
  unless environment = ridley.environment.find(id)
    abort EnvironmentNotFound.new(id)
  end

  environment
end
list() click to toggle source

Returns a list of environments present on the remote server

@return [Array<Ridley::EnvironmentResource>]

# File lib/mb/environment_manager.rb, line 194
def list
  ridley.environment.all
end
nodes_for_environment(name) click to toggle source

Returns an array of nodes for an environment

@param [String] name

@return [Array(Ridley::NodeObject)]

# File lib/mb/environment_manager.rb, line 218
def nodes_for_environment(name)
  ridley.partial_search(:node, "chef_environment:#{name}", ["fqdn", "cloud.public_hostname", "name", "os"])
end
purge_nodes(name) click to toggle source

Removes all nodes and clients from the Chef server for a given environment

@param [String] name

# File lib/mb/environment_manager.rb, line 201
def purge_nodes(name)
  nodes = nodes_for_environment(name)
  futures = []

  nodes.each do |node|
    futures << ridley.client.future(:delete, node)
    futures << ridley.node.future(:delete, node)
  end

  futures.map(&:value)
end

Private Instance Methods

finalize_callback() click to toggle source
# File lib/mb/environment_manager.rb, line 224
def finalize_callback
  log.debug { "Environment Manager stopping..." }
end