summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Keiser <john@johnkeiser.com>2015-05-16 12:48:10 -0700
committerJohn Keiser <john@johnkeiser.com>2015-05-28 13:27:43 -0700
commit2ef63f2228a44ca2b81a231249b7a56b226e10d3 (patch)
tree6c8d991c66d60fcf39faab479c9b424554e7bac1
parenta261c2c6954a6e3c682ff40a4c82d30ed994bdd8 (diff)
downloadchef-2ef63f2228a44ca2b81a231249b7a56b226e10d3.tar.gz
Move public APIs first, private second
-rw-r--r--lib/chef/client.rb475
-rw-r--r--lib/chef/client/notification_registry.rb107
2 files changed, 308 insertions, 274 deletions
diff --git a/lib/chef/client.rb b/lib/chef/client.rb
index 428cf6c8d6..a6321f6cca 100644
--- a/lib/chef/client.rb
+++ b/lib/chef/client.rb
@@ -50,6 +50,7 @@ require 'chef/run_lock'
require 'chef/policy_builder'
require 'chef/request_id'
require 'chef/platform/rebooter'
+require 'chef/client/notification_registry'
require 'ohai'
require 'rbconfig'
@@ -60,135 +61,14 @@ class Chef
class Client
include Chef::Mixin::PathSanity
- #
- # IO stream that will be used as 'STDOUT' for formatters. Formatters are
- # configured during `initialize`, so this provides a convenience for
- # setting alternative IO stream during tests.
- #
- # @api private
- #
- STDOUT_FD = STDOUT
-
- #
- # IO stream that will be used as 'STDERR' for formatters. Formatters are
- # configured during `initialize`, so this provides a convenience for
- # setting alternative IO stream during tests.
- #
- # @api private
- #
- STDERR_FD = STDERR
-
- #
- # Clears all listeners for client run status events.
- #
- # Primarily for testing purposes.
- #
- # @api private
- #
- def self.clear_notifications
- @run_start_notifications = nil
- @run_completed_successfully_notifications = nil
- @run_failed_notifications = nil
- end
-
- #
- # Listeners to be run when the client run starts.
- #
- # @return [Array<Proc>]
- #
- # @api private
- #
- def self.run_start_notifications
- @run_start_notifications ||= []
- end
-
- #
- # Listeners to be run when the client run completes successfully.
- #
- # @return [Array<Proc>]
- #
- # @api private
- #
- def self.run_completed_successfully_notifications
- @run_completed_successfully_notifications ||= []
- end
-
- #
- # Listeners to be run when the client run fails.
- #
- # @return [Array<Proc>]
- #
- # @api private
- #
- def self.run_failed_notifications
- @run_failed_notifications ||= []
- end
-
- #
- # Add a listener for the 'client run started' event.
- #
- # @param notification_block The callback (takes |run_status| parameter).
- # @yieldparam [Chef::RunStatus] run_status The run status.
- #
- def self.when_run_starts(&notification_block)
- run_start_notifications << notification_block
- end
-
- #
- # Add a listener for the 'client run success' event.
- #
- # @param notification_block The callback (takes |run_status| parameter).
- # @yieldparam [Chef::RunStatus] run_status The run status.
- #
- def self.when_run_completes_successfully(&notification_block)
- run_completed_successfully_notifications << notification_block
- end
+ extend NotificationRegistry
#
- # Add a listener for the 'client run failed' event.
- #
- # @param notification_block The callback (takes |run_status| parameter).
- # @yieldparam [Chef::RunStatus] run_status The run status.
- #
- def self.when_run_fails(&notification_block)
- run_failed_notifications << notification_block
- end
-
- #
- # Callback to fire notifications that the Chef run is starting
- #
- # @api private
- #
- def run_started
- self.class.run_start_notifications.each do |notification|
- notification.call(run_status)
- end
- @events.run_started(run_status)
- end
-
- #
- # Callback to fire notifications that the run completed successfully
- #
- # @api private
- #
- def run_completed_successfully
- success_handlers = self.class.run_completed_successfully_notifications
- success_handlers.each do |notification|
- notification.call(run_status)
- end
- end
-
- #
- # Callback to fire notifications that the Chef run failed
+ # The status of the Chef run.
#
- # @api private
+ # @return [Chef::RunStatus]
#
- def run_failed
- failure_handlers = self.class.run_failed_notifications
- failure_handlers.each do |notification|
- notification.call(run_status)
- end
- end
+ attr_reader :run_status
#
# The node represented by this client.
@@ -226,13 +106,6 @@ class Chef
attr_reader :json_attribs
#
- # The status of the Chef run.
- #
- # @return [Chef::RunStatus]
- #
- attr_reader :run_status
-
- #
# The event dispatcher for the Chef run, including any configured output
# formatters and event loggers.
#
@@ -293,6 +166,153 @@ class Chef
end
#
+ # Do a full run for this Chef::Client.
+ #
+ # Locks the run while doing its job.
+ #
+ # Fires run_start before doing anything and fires run_completed or
+ # run_failed when finished. Also notifies client listeners of run_started
+ # at the beginning of Compile, and run_completed_successfully or run_failed
+ # when all is complete.
+ #
+ # Phase 1: Setup
+ # --------------
+ # Gets information about the system and the run we are doing.
+ #
+ # 1. Run ohai to collect system information.
+ # 2. Register / connect to the Chef server (unless in solo mode).
+ # 3. Retrieve the node (or create a new one).
+ # 4. Merge in json_attribs, Chef::Config.environment, and override_run_list.
+ #
+ # Phase 2: Compile
+ # ----------------
+ # Decides *what* we plan to converge by compiling recipes.
+ #
+ # 1. Sync required cookbooks to the local cache.
+ # 2. Load libraries from all cookbooks.
+ # 3. Load attributes from all cookbooks.
+ # 4. Load LWRPs from all cookbooks.
+ # 5. Load resource definitions from all cookbooks.
+ # 6. Load recipes in the run list.
+ # 7. Load recipes from the command line.
+ #
+ # Phase 3: Converge
+ # -----------------
+ # Brings the system up to date.
+ #
+ # 1. Converge the resources built from recipes in Phase 2.
+ # 2. Save the node.
+ # 3. Reboot if we were asked to.
+ #
+ # @raise [Chef::Exceptions::RunFailedWrappingError] If converge or audit failed.
+ #
+ # @see Chef::Config#lockfile
+ # @see Chef::Config#enforce_path_sanity
+ # @see Chef::Config#solo
+ # @see Chef::Config#audit_mode
+ #
+ # @see Chef::RunLock#acquire
+ # @see #run_ohai
+ # @see #load_node
+ # @see #build_node
+ # @see Chef::CookbookCompiler#compile
+ #
+ # @see #setup_run_context Syncs and compiles cookbooks.
+ #
+ # @return Always returns true.
+ #
+ def run
+ run_error = nil
+
+ runlock = RunLock.new(Chef::Config.lockfile)
+ # TODO feels like acquire should have its own block arg for this
+ runlock.acquire
+ # don't add code that may fail before entering this section to be sure to release lock
+ begin
+ runlock.save_pid
+
+ request_id = Chef::RequestID.instance.request_id
+ run_context = nil
+ @events.run_start(Chef::VERSION)
+ Chef::Log.info("*** Chef #{Chef::VERSION} ***")
+ Chef::Log.info "Chef-client pid: #{Process.pid}"
+ Chef::Log.debug("Chef-client request_id: #{request_id}")
+ enforce_path_sanity
+ run_ohai
+
+ register unless Chef::Config[:solo]
+
+ load_node
+
+ build_node
+
+ run_status.run_id = request_id
+ run_status.start_clock
+ Chef::Log.info("Starting Chef Run for #{node.name}")
+ run_started
+
+ do_windows_admin_check
+
+ run_context = setup_run_context
+
+ if Chef::Config[:audit_mode] != :audit_only
+ converge_error = converge_and_save(run_context)
+ end
+
+ if Chef::Config[:why_run] == true
+ # why_run should probably be renamed to why_converge
+ Chef::Log.debug("Not running controls in 'why_run' mode - this mode is used to see potential converge changes")
+ elsif Chef::Config[:audit_mode] != :disabled
+ audit_error = run_audits(run_context)
+ end
+
+ # Raise converge_error so run_failed reporters/events are processed.
+ raise converge_error if converge_error
+
+ run_status.stop_clock
+ Chef::Log.info("Chef Run complete in #{run_status.elapsed_time} seconds")
+ run_completed_successfully
+ @events.run_completed(node)
+
+ # rebooting has to be the last thing we do, no exceptions.
+ Chef::Platform::Rebooter.reboot_if_needed!(node)
+ rescue Exception => run_error
+ # CHEF-3336: Send the error first in case something goes wrong below and we don't know why
+ Chef::Log.debug("Re-raising exception: #{run_error.class} - #{run_error.message}\n#{run_error.backtrace.join("\n ")}")
+ # If we failed really early, we may not have a run_status yet. Too early for these to be of much use.
+ if run_status
+ run_status.stop_clock
+ run_status.exception = run_error
+ run_failed
+ end
+ @events.run_failed(run_error)
+ ensure
+ Chef::RequestID.instance.reset_request_id
+ request_id = nil
+ @run_status = nil
+ run_context = nil
+ runlock.release
+ GC.start
+ end
+
+ # Raise audit, converge, and other errors here so that we exit
+ # with the proper exit status code and everything gets raised
+ # as a RunFailedWrappingError
+ if run_error || converge_error || audit_error
+ error = if run_error == converge_error
+ Chef::Exceptions::RunFailedWrappingError.new(converge_error, audit_error)
+ else
+ Chef::Exceptions::RunFailedWrappingError.new(run_error, converge_error, audit_error)
+ end
+ error.fill_backtrace
+ Chef::Application.debug_stacktrace(error)
+ raise error
+ end
+
+ true
+ end
+
+ #
# Private API
# TODO make this stuff protected or private
#
@@ -358,6 +378,42 @@ class Chef
end
#
+ # Callback to fire notifications that the Chef run is starting
+ #
+ # @api private
+ #
+ def run_started
+ self.class.run_start_notifications.each do |notification|
+ notification.call(run_status)
+ end
+ @events.run_started(run_status)
+ end
+
+ #
+ # Callback to fire notifications that the run completed successfully
+ #
+ # @api private
+ #
+ def run_completed_successfully
+ success_handlers = self.class.run_completed_successfully_notifications
+ success_handlers.each do |notification|
+ notification.call(run_status)
+ end
+ end
+
+ #
+ # Callback to fire notifications that the Chef run failed
+ #
+ # @api private
+ #
+ def run_failed
+ failure_handlers = self.class.run_failed_notifications
+ failure_handlers.each do |notification|
+ notification.call(run_status)
+ end
+ end
+
+ #
# Instantiates a Chef::Node object, possibly loading the node's prior state
# when using chef-client. Sets Chef.node to the new node.
#
@@ -579,7 +635,7 @@ class Chef
@events.converge_start(run_context)
Chef::Log.debug("Converging node #{node_name}")
@runner = Chef::Runner.new(run_context)
- @runner.converge
+ runner.converge
@events.converge_complete
rescue Exception => e
@events.converge_failed(e)
@@ -658,7 +714,7 @@ class Chef
end
rescue Exception => e
Chef::Log.error("Audit phase failed with error message: #{e.message}")
- @events.audit_phase_failed(e)
+ events.audit_phase_failed(e)
audit_exception = e
end
audit_exception
@@ -708,151 +764,23 @@ class Chef
end
#
- # Do a full run for this Chef::Client.
- #
- # Locks the run while doing its job.
- #
- # Fires run_start before doing anything and fires run_completed or
- # run_failed when finished. Also notifies client listeners of run_started
- # at the beginning of Compile, and run_completed_successfully or run_failed
- # when all is complete.
- #
- # Phase 1: Setup
- # --------------
- # Gets information about the system and the run we are doing.
- #
- # 1. Run ohai to collect system information.
- # 2. Register / connect to the Chef server (unless in solo mode).
- # 3. Retrieve the node (or create a new one).
- # 4. Merge in json_attribs, Chef::Config.environment, and override_run_list.
- #
- # Phase 2: Compile
- # ----------------
- # Decides *what* we plan to converge by compiling recipes.
- #
- # 1. Sync required cookbooks to the local cache.
- # 2. Load libraries from all cookbooks.
- # 3. Load attributes from all cookbooks.
- # 4. Load LWRPs from all cookbooks.
- # 5. Load resource definitions from all cookbooks.
- # 6. Load recipes in the run list.
- # 7. Load recipes from the command line.
- #
- # Phase 3: Converge
- # -----------------
- # Brings the system up to date.
- #
- # 1. Converge the resources built from recipes in Phase 2.
- # 2. Save the node.
- # 3. Reboot if we were asked to.
- #
- # @raise [Chef::Exceptions::RunFailedWrappingError] If converge or audit failed.
+ # IO stream that will be used as 'STDOUT' for formatters. Formatters are
+ # configured during `initialize`, so this provides a convenience for
+ # setting alternative IO stream during tests.
#
- # @see Chef::Config#lockfile
- # @see Chef::Config#enforce_path_sanity
- # @see Chef::Config#solo
- # @see Chef::Config#audit_mode
+ # @api private
#
- # @see Chef::RunLock#acquire
- # @see #run_ohai
- # @see #load_node
- # @see #build_node
- # @see Chef::CookbookCompiler#compile
+ STDOUT_FD = STDOUT
+
#
- # @see #setup_run_context Syncs and compiles cookbooks.
+ # IO stream that will be used as 'STDERR' for formatters. Formatters are
+ # configured during `initialize`, so this provides a convenience for
+ # setting alternative IO stream during tests.
#
- # @return Always returns true.
+ # @api private
#
- def run
- run_error = nil
-
- runlock = RunLock.new(Chef::Config.lockfile)
- # TODO feels like acquire should have its own block arg for this
- runlock.acquire
- # don't add code that may fail before entering this section to be sure to release lock
- begin
- runlock.save_pid
-
- request_id = Chef::RequestID.instance.request_id
- run_context = nil
- @events.run_start(Chef::VERSION)
- Chef::Log.info("*** Chef #{Chef::VERSION} ***")
- Chef::Log.info "Chef-client pid: #{Process.pid}"
- Chef::Log.debug("Chef-client request_id: #{request_id}")
- enforce_path_sanity
- run_ohai
-
- register unless Chef::Config[:solo]
-
- load_node
-
- build_node
-
- run_status.run_id = request_id
- run_status.start_clock
- Chef::Log.info("Starting Chef Run for #{node.name}")
- run_started
-
- do_windows_admin_check
-
- run_context = setup_run_context
-
- if Chef::Config[:audit_mode] != :audit_only
- converge_error = converge_and_save(run_context)
- end
-
- if Chef::Config[:why_run] == true
- # why_run should probably be renamed to why_converge
- Chef::Log.debug("Not running controls in 'why_run' mode - this mode is used to see potential converge changes")
- elsif Chef::Config[:audit_mode] != :disabled
- audit_error = run_audits(run_context)
- end
-
- # Raise converge_error so run_failed reporters/events are processed.
- raise converge_error if converge_error
-
- run_status.stop_clock
- Chef::Log.info("Chef Run complete in #{run_status.elapsed_time} seconds")
- run_completed_successfully
- @events.run_completed(node)
-
- # rebooting has to be the last thing we do, no exceptions.
- Chef::Platform::Rebooter.reboot_if_needed!(node)
- rescue Exception => run_error
- # CHEF-3336: Send the error first in case something goes wrong below and we don't know why
- Chef::Log.debug("Re-raising exception: #{run_error.class} - #{run_error.message}\n#{run_error.backtrace.join("\n ")}")
- # If we failed really early, we may not have a run_status yet. Too early for these to be of much use.
- if run_status
- run_status.stop_clock
- run_status.exception = run_error
- run_failed
- end
- @events.run_failed(run_error)
- ensure
- Chef::RequestID.instance.reset_request_id
- request_id = nil
- @run_status = nil
- run_context = nil
- runlock.release
- GC.start
- end
-
- # Raise audit, converge, and other errors here so that we exit
- # with the proper exit status code and everything gets raised
- # as a RunFailedWrappingError
- if run_error || converge_error || audit_error
- error = if run_error == converge_error
- Chef::Exceptions::RunFailedWrappingError.new(converge_error, audit_error)
- else
- Chef::Exceptions::RunFailedWrappingError.new(run_error, converge_error, audit_error)
- end
- error.fill_backtrace
- Chef::Application.debug_stacktrace(error)
- raise error
- end
+ STDERR_FD = STDERR
- true
- end
private
@@ -879,7 +807,6 @@ class Chef
else
Chef::Log.warn("Node #{node_name} has an empty run list.") if run_context.node.run_list.empty?
end
-
end
def has_admin_privileges?
diff --git a/lib/chef/client/notification_registry.rb b/lib/chef/client/notification_registry.rb
new file mode 100644
index 0000000000..e34115c5dd
--- /dev/null
+++ b/lib/chef/client/notification_registry.rb
@@ -0,0 +1,107 @@
+#
+# Author:: Adam Jacob (<adam@opscode.com>)
+# Author:: Christopher Walters (<cw@opscode.com>)
+# Author:: Christopher Brown (<cb@opscode.com>)
+# Author:: Tim Hinderliter (<tim@opscode.com>)
+# Copyright:: Copyright (c) 2008-2011 Opscode, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+require 'chef/client/notification_registry'
+
+class Chef
+ class Client
+ module NotificationRegistry
+ #
+ # Add a listener for the 'client run started' event.
+ #
+ # @param notification_block The callback (takes |run_status| parameter).
+ # @yieldparam [Chef::RunStatus] run_status The run status.
+ #
+ def when_run_starts(&notification_block)
+ run_start_notifications << notification_block
+ end
+
+ #
+ # Add a listener for the 'client run success' event.
+ #
+ # @param notification_block The callback (takes |run_status| parameter).
+ # @yieldparam [Chef::RunStatus] run_status The run status.
+ #
+ def when_run_completes_successfully(&notification_block)
+ run_completed_successfully_notifications << notification_block
+ end
+
+ #
+ # Add a listener for the 'client run failed' event.
+ #
+ # @param notification_block The callback (takes |run_status| parameter).
+ # @yieldparam [Chef::RunStatus] run_status The run status.
+ #
+ def when_run_fails(&notification_block)
+ run_failed_notifications << notification_block
+ end
+
+ #
+ # Clears all listeners for client run status events.
+ #
+ # Primarily for testing purposes.
+ #
+ # @api private
+ #
+ def clear_notifications
+ @run_start_notifications = nil
+ @run_completed_successfully_notifications = nil
+ @run_failed_notifications = nil
+ end
+
+ #
+ # TODO These seem protected to me.
+ #
+
+ #
+ # Listeners to be run when the client run starts.
+ #
+ # @return [Array<Proc>]
+ #
+ # @api private
+ #
+ def run_start_notifications
+ @run_start_notifications ||= []
+ end
+
+ #
+ # Listeners to be run when the client run completes successfully.
+ #
+ # @return [Array<Proc>]
+ #
+ # @api private
+ #
+ def run_completed_successfully_notifications
+ @run_completed_successfully_notifications ||= []
+ end
+
+ #
+ # Listeners to be run when the client run fails.
+ #
+ # @return [Array<Proc>]
+ #
+ # @api private
+ #
+ def run_failed_notifications
+ @run_failed_notifications ||= []
+ end
+ end
+ end
+end