Parent

Included Modules

Class/Module Index [+]

Quicksearch

Chef::Client

Chef::Client

The main object in a Chef run. Preps a Chef::Node and Chef::RunContext, syncs cookbooks if necessary, and triggers convergence.

Attributes

json_attribs[R]
node[RW]
ohai[RW]
rest[RW]
run_status[R]
runner[RW]

Public Class Methods

clear_notifications() click to toggle source

Clears all notifications for client run status events. Primarily for testing purposes.

# File lib/chef/client.rb, line 56
def self.clear_notifications
  @run_start_notifications = nil
  @run_completed_successfully_notifications = nil
  @run_failed_notifications = nil
end
new(json_attribs=nil, args={}) click to toggle source

Creates a new Chef::Client.

# File lib/chef/client.rb, line 134
def initialize(json_attribs=nil, args={})
  @json_attribs = json_attribs
  @node = nil
  @run_status = nil
  @runner = nil
  @ohai = Ohai::System.new

  # If we want why-run output and user hasn't explicitly specified a format
  # we need to use a formatter that will render whyrun output. 
  if Chef::Config.why_run
    if Chef::Config.formatter == "null"
      Chef::Log.warn("Forcing formatter of 'doc' to capture whyrun output.")
      Chef::Config[:formatter] = 'doc'
    end
  end
  formatter = Chef::Formatters.new(Chef::Config.formatter, STDOUT, STDERR)
  @events = EventDispatch::Dispatcher.new(formatter)
  @override_runlist = args.delete(:override_runlist)
  runlist_override_sanity_check!
end
run_completed_successfully_notifications() click to toggle source

The list of notifications to be run when the client run completes successfully.

# File lib/chef/client.rb, line 69
def self.run_completed_successfully_notifications
  @run_completed_successfully_notifications ||= []
end
run_failed_notifications() click to toggle source

The list of notifications to be run when the client run fails.

# File lib/chef/client.rb, line 74
def self.run_failed_notifications
  @run_failed_notifications ||= []
end
run_start_notifications() click to toggle source

The list of notifications to be run when the client run starts.

# File lib/chef/client.rb, line 63
def self.run_start_notifications
  @run_start_notifications ||= []
end
when_run_completes_successfully(¬ification_block) click to toggle source

Add a notification for the 'client run success' event. The notification is provided as a block. The current Chef::RunStatus object will be passed to the notification_block when the event is triggered.

# File lib/chef/client.rb, line 88
def self.when_run_completes_successfully(&notification_block)
  run_completed_successfully_notifications << notification_block
end
when_run_fails(¬ification_block) click to toggle source

Add a notification for the 'client run failed' event. The notification is provided as a block. The current Chef::RunStatus is passed to the notification_block when the event is triggered.

# File lib/chef/client.rb, line 95
def self.when_run_fails(&notification_block)
  run_failed_notifications << notification_block
end
when_run_starts(¬ification_block) click to toggle source

Add a notification for the 'client run started' event. The notification is provided as a block. The current Chef::RunStatus object will be passed to the notification_block when the event is triggered.

# File lib/chef/client.rb, line 81
def self.when_run_starts(&notification_block)
  run_start_notifications << notification_block
end

Public Instance Methods

build_node() click to toggle source

Applies environment, external JSON attributes, and override run list to the node, Then expands the run_list.

Returns

node<Chef::Node>

The modified @node object. @node is modified in place.

# File lib/chef/client.rb, line 241
def build_node
  # Allow user to override the environment of a node by specifying
  # a config parameter.
  if Chef::Config[:environment] && !Chef::Config[:environment].chop.empty?
    @node.chef_environment(Chef::Config[:environment])
  end

  # consume_external_attrs may add items to the run_list. Save the
  # expanded run_list, which we will pass to the server later to
  # determine which versions of cookbooks to use.
  @node.reset_defaults_and_overrides
  @node.consume_external_attrs(ohai.data, @json_attribs)

  unless(@override_runlist.empty?)
    @original_runlist = @node.run_list.run_list_items.dup
    runlist_override_sanity_check!
    @node.run_list(*@override_runlist)
    Chef::Log.warn "Run List override has been provided."
    Chef::Log.warn "Original Run List: [#{@original_runlist.join(', ')}]"
    Chef::Log.warn "Overridden Run List: [#{@node.run_list}]"
  end

  @run_list_expansion = expand_run_list

  # @run_list_expansion is a RunListExpansion.
  #
  # Convert @expanded_run_list, which is an
  # Array of Hashes of the form
  #   {:name => NAME, :version_constraint => Chef::VersionConstraint },
  # into @expanded_run_list_with_versions, an
  # Array of Strings of the form
  #   "#{NAME}@#{VERSION}"
  @expanded_run_list_with_versions = @run_list_expansion.recipes.with_version_constraints_strings

  Chef::Log.info("Run List is [#{@node.run_list}]")
  Chef::Log.info("Run List expands to [#{@expanded_run_list_with_versions.join(', ')}]")

  @run_status = Chef::RunStatus.new(@node, @events)

  @events.node_load_completed(node, @expanded_run_list_with_versions, Chef::Config)

  @node
end
converge(run_context) click to toggle source

Converges the node.

Returns

true

Always returns true

# File lib/chef/client.rb, line 374
def converge(run_context)
  @events.converge_start(run_context)
  Chef::Log.debug("Converging node #{node_name}")
  @runner = Chef::Runner.new(run_context)
  runner.converge
  @events.converge_complete
  true
rescue Exception => e
  # TODO: should this be a separate #converge_failed(exception) method?
  @events.converge_complete
  raise
end
expand_run_list() click to toggle source
# File lib/chef/client.rb, line 303
def expand_run_list
  if Chef::Config[:solo]
    @node.expand!('disk')
  else
    @node.expand!('server')
  end
rescue Exception => e
  # TODO: wrap/munge exception with useful error output.
  @events.run_list_expand_failed(node, e)
  raise
end
load_node() click to toggle source

In client-server operation, loads the node state from the server. In chef-solo operation, builds a new node object.

# File lib/chef/client.rb, line 287
def load_node
  @events.node_load_start(node_name, Chef::Config)
  Chef::Log.debug("Building node object for #{node_name}")

  if Chef::Config[:solo]
    @node = Chef::Node.build(node_name)
  else
    @node = Chef::Node.find_or_create(node_name)
  end
rescue Exception => e
  # TODO: wrap this exception so useful error info can be given to the
  # user.
  @events.node_load_failed(node_name, e, Chef::Config)
  raise
end
node_name() click to toggle source
# File lib/chef/client.rb, line 218
def node_name
  name = Chef::Config[:node_name] || ohai[:fqdn] || ohai[:hostname]
  Chef::Config[:node_name] = name

  unless name
    msg = "Unable to determine node name: configure node_name or configure the system's hostname and fqdn"
    raise Chef::Exceptions::CannotDetermineNodeName, msg
  end

  # node names > 90 bytes only work with authentication protocol >= 1.1
  # see discussion in config.rb.
  if name.bytesize > 90
    Chef::Config[:authentication_protocol_version] = "1.1"
  end

  name
end
register(client_name=node_name, config=Chef::Config) click to toggle source

Returns

rest<Chef::REST>

returns Chef::REST connection object

# File lib/chef/client.rb, line 318
def register(client_name=node_name, config=Chef::Config)
  if File.exists?(config[:client_key])
    @events.skipping_registration(client_name, config)
    Chef::Log.debug("Client key #{config[:client_key]} is present - skipping registration")
  else
    @events.registration_start(node_name, config)
    Chef::Log.info("Client key #{config[:client_key]} is not present - registering")
    Chef::REST.new(config[:client_url], config[:validation_client_name], config[:validation_key]).register(client_name, config[:client_key])
    @events.registration_completed
  end
  # We now have the client key, and should use it from now on.
  @rest = Chef::REST.new(config[:chef_server_url], client_name, config[:client_key])
  @resource_reporter = Chef::ResourceReporter.new(@rest)
  @events.register(@resource_reporter)
rescue Exception => e
  # TODO: munge exception so a semantic failure message can be given to the
  # user
  @events.registration_failed(node_name, e, config)
  raise
end
run() click to toggle source

Do a full run for this Chef::Client. Calls:

  • do_run

This provides a wrapper around do_run allowing the run to be optionally forked.

Returns

boolean

Return value from do_run. Should always returns true.

# File lib/chef/client.rb, line 162
def run
  if(Chef::Config[:client_fork] && Process.respond_to?(:fork))
    Chef::Log.info "Forking chef instance to converge..."
    pid = fork do
      Chef::Log.info "Forked instance now converging"
      do_run
      exit
    end
    Chef::Log.info "Fork successful. Waiting for new chef pid: #{pid}"
    result = Process.waitpid2(pid)
    raise "Forked convergence run failed" unless result.last.success?
    Chef::Log.info "Forked child successfully reaped (pid: #{pid})"
    true
  else
    do_run
  end
end
run_completed_successfully() click to toggle source

Callback to fire notifications that the run completed successfully

# File lib/chef/client.rb, line 107
def run_completed_successfully
  success_handlers = self.class.run_completed_successfully_notifications
  success_handlers.each do |notification|
    notification.call(run_status)
  end
end
run_failed() click to toggle source

Callback to fire notifications that the Chef run failed

# File lib/chef/client.rb, line 115
def run_failed
  failure_handlers = self.class.run_failed_notifications
  failure_handlers.each do |notification|
    notification.call(run_status)
  end
end
run_ohai() click to toggle source
# File lib/chef/client.rb, line 214
def run_ohai
  ohai.all_plugins
end
run_started() click to toggle source

Callback to fire notifications that the Chef run is starting

# File lib/chef/client.rb, line 100
def run_started
  self.class.run_start_notifications.each do |notification|
    notification.call(run_status)
  end
end
save_updated_node() click to toggle source
# File lib/chef/client.rb, line 203
def save_updated_node
  unless Chef::Config[:solo]
    Chef::Log.debug("Saving the current state of node #{node_name}")
    if(@original_runlist)
      @node.run_list(*@original_runlist)
      @node[:runlist_override_history] = {Time.now.to_i => @override_runlist.inspect}
    end
    @node.save
  end
end
setup_run_context() click to toggle source
Configures the Chef::Cookbook::FileVendor class to fetch file from the
server or disk as appropriate, creates the run context for this run, and
sanity checks the cookbook collection.

Returns

Chef::RunContext:: the run context for this run.
# File lib/chef/client.rb, line 185
def setup_run_context
  if Chef::Config[:solo]
    Chef::Cookbook::FileVendor.on_create { |manifest| Chef::Cookbook::FileSystemFileVendor.new(manifest, Chef::Config[:cookbook_path]) }
    cookbook_collection = Chef::CookbookCollection.new(Chef::CookbookLoader.new(Chef::Config[:cookbook_path]))
    run_context = Chef::RunContext.new(node, cookbook_collection, @events)
  else
    Chef::Cookbook::FileVendor.on_create { |manifest| Chef::Cookbook::RemoteFileVendor.new(manifest, rest) }
    cookbook_hash = sync_cookbooks
    cookbook_collection = Chef::CookbookCollection.new(cookbook_hash)
    run_context = Chef::RunContext.new(node, cookbook_collection, @events)
  end
  run_status.run_context = run_context

  run_context.load(@run_list_expansion)
  assert_cookbook_path_not_empty(run_context)
  run_context
end
sync_cookbooks() click to toggle source

Sync_cookbooks eagerly loads all files except files and templates. It returns the cookbook_hash -- the return result from /environments/#{node.chef_environment}/cookbook_versions, which we will use for our run_context.

Returns

Hash

The hash of cookbooks with download URLs as given by the server

# File lib/chef/client.rb, line 346
def sync_cookbooks
  Chef::Log.debug("Synchronizing cookbooks")

  begin
    @events.cookbook_resolution_start(@expanded_run_list_with_versions)
    cookbook_hash = rest.post_rest("environments/#{@node.chef_environment}/cookbook_versions",
                                   {:run_list => @expanded_run_list_with_versions})
  rescue Exception => e
    # TODO: wrap/munge exception to provide helpful error output
    @events.cookbook_resolution_failed(@expanded_run_list_with_versions, e)
    raise
  else
    @events.cookbook_resolution_complete(cookbook_hash)
  end

  synchronizer = Chef::CookbookSynchronizer.new(cookbook_hash, @events)
  synchronizer.sync_cookbooks

  # register the file cache path in the cookbook path so that CookbookLoader actually picks up the synced cookbooks
  Chef::Config[:cookbook_path] = File.join(Chef::Config[:file_cache_path], "cookbooks")

  cookbook_hash
end

[Validate]

Generated with the Darkfish Rdoc Generator 2.