summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Keiser <john@johnkeiser.com>2015-05-18 18:00:47 -0700
committerJohn Keiser <john@johnkeiser.com>2015-05-18 18:01:09 -0700
commitc306b1a90a51065877b536eb3d1c00911abac570 (patch)
tree00c7e3922a09933fc5e9c57762271c5ca8590d85
parent080daefa288c3828bff098cf1d632afcf6ce44bc (diff)
downloadchef-jk/client_madness.tar.gz
Non-working spike on breaking up RunContext and Client into manageable piecesjk/client_madness
-rw-r--r--lib/chef/client.rb332
1 files changed, 332 insertions, 0 deletions
diff --git a/lib/chef/client.rb b/lib/chef/client.rb
index 2c8c19c01e..2f07cfd0ae 100644
--- a/lib/chef/client.rb
+++ b/lib/chef/client.rb
@@ -55,6 +55,338 @@ require 'ohai'
require 'rbconfig'
class Chef
+ module CookbookState
+ #
+ # The cookbook version that was loaded.
+ #
+ # @return [CookbookVersion]
+ #
+ attr_reader :cookbook_version
+
+ #
+ # Libraries loaded by this cookbook.
+ #
+ # In-progress and failed library loads will show up in this list;
+ # library files that have not yet been loaded will *not*.
+ #
+ # Paths are relative to the cookbook root and include `.rb` (e.g.
+ # `libraries/default.rb`).
+ #
+ # If attributes have not yet started to load, this will be `nil`.
+ #
+ # @return [Set<String>] A list of relative library paths that were loaded,
+ # in the order they were loaded; ; or `nil` if we have not tried to load libraries.
+ #
+ attr_reader :loaded_libraries
+
+ #
+ # Attribute files loaded by this cookbook.
+ #
+ # In-progress and failed attribute loads will show up in this list;
+ # attribute files that have not yet been loaded will *not*.
+ #
+ # Paths are relative to the cookbook root and include `.rb` (e.g.
+ # `attributes/default.rb`).
+ #
+ # If attributes have not yet started to load, this will be `nil`.
+ #
+ # @return [Enumerable<String>] A list of relative attribute paths that were loaded,
+ # in the order they were loaded; or `nil` if we have not tried to load attributes.
+ #
+ attr_reader :loaded_attributes
+
+ #
+ # LWRP resource classes loaded by this cookbook.
+ #
+ # In-progress resource loads will show up in this list as `nil` if not yet
+ # loaded, and the class will show up even if it is only partially loaded.
+ # Failed resource loads will show up `nil`. Use `has_key?` to determine if
+ # the LWRP attempted to load.
+ #
+ # Paths are relative to the cookbook root and include `.rb` (e.g.
+ # `resources/my_resource.rb`).
+ #
+ # If resources have not yet started to load, this will be `nil`.
+ #
+ # @return [Hash<String, Class>] A hash of LWRP classes, from name to
+ # loaded class; or `nil` if we have not tried to load LWRPs.
+ #
+ attr_reader :loaded_lwrp_resources
+
+ #
+ # LWRP provider classes loaded by this cookbook.
+ #
+ # In-progress provider loads will show up in this list as `nil` if not yet
+ # loaded, and the class will show up even if it is only partially loaded.
+ # Failed provider loads will show up `nil`. Use `has_key?` to determine if
+ # the LWRP attempted to load.
+ #
+ # Paths are relative to the cookbook root and include `.rb` (e.g.
+ # `providers/my_resource.rb`).
+ #
+ # If providers have not yet started to load, this will be `nil`.
+ #
+ # @return [Hash<String, Class>] A hash of LWRP classes, from name to
+ # loaded class; or `nil` if we have not tried to load LWRPs.
+ #
+ attr_reader :loaded_lwrp_providers
+
+ #
+ # Definitions loaded by this cookbook.
+ #
+ # In-progress provider loads will show up in this list as `nil` if not yet
+ # loaded, and the class will show up even if it is only partially loaded.
+ # Failed provider loads will show up `nil`. Use `has_key?` to determine if
+ # the LWRP attempted to load.
+ #
+ # Paths are relative to the cookbook root and include `.rb` (e.g.
+ # `providers/my_resource.rb`).
+ #
+ # @return [Hash<String, Class>] A hash of LWRP classes, from name to
+ # loaded class; or `nil` if we have not tried to load definitions.
+ # If definitions have not yet started to load, this will be `nil`.
+ #
+ attr_reader :loaded_definitions
+ end
+
+ #
+ # Represents the state of a Chef run: ohai data, loaded cookbooks, etc.
+ #
+ # @see Chef#run_status
+ #
+ class RunStatus
+ #
+ # The Chef run ID.
+ #
+ # @return [String]
+ #
+ attr_reader :run_id
+
+ #
+ # Configuration.
+ #
+ # @return [Chef::Config]
+ #
+ attr_reader :config
+
+ #
+ # Ohai data.
+ #
+ # @return [Ohai::System]
+ #
+ attr_reader :ohai
+
+ #
+ # The node we are running against, or `nil` if it is not yet set / loaded.
+ #
+ # @return [Chef::Node]
+ #
+ attr_reader :node
+
+ #
+ # List of loaded cookbooks and their state.
+ #
+ # @return [Hash<String, CookbookState>] A hash from cookbook name -> loaded
+ # cookbook.
+ #
+ attr_reader :loaded_cookbooks
+
+ #
+ # Resource classes registered for each DSL method.
+ #
+ # @return [ResourcePriorityMap]
+ #
+ attr_reader :resource_dsl_providers
+
+ #
+ # Provider classes registered for each DSL method.
+ #
+ # @return [ProviderPriorityMap]
+ #
+ attr_reader :provider_providers
+
+ #
+ # Full list of definitions.
+ #
+ # @return [Hash<String, ResourceDefinition>]
+ attr_reader :definitions
+
+ #
+ # The root converger.
+ #
+ attr_reader :converger
+ end
+
+ #
+ # The Chef run. This includes its state as well as methods to affect it.
+ #
+ # Only one Chef run may exist at a time, and it is global. This is because
+ # the things inside can only happen once even if there were multiple runs:
+ # cookbook libraries, for example, often create named classes.
+ #
+ class Run < RunStatus
+ include Singleton
+
+ #
+ # Run the given ohai plugins.
+ #
+ # @param plugin_names [Array<String>] The list of plugins to run. If none
+ # are specified, all plugins will be run.
+ #
+ def run_ohai(*plugin_names)
+ end
+
+ #
+ # Load the given cookbooks, in the given order.
+ #
+ # Cookbooks will be loaded in the specified order. This will *not* run any
+ # recipes.
+ #
+ # @param cookbooks [Array<CookbookVersion>] The list of cookbooks, in the
+ # order they need to be loaded.
+ #
+ def load_cookbooks(*cookbooks)
+ end
+
+ def config
+ Chef::Config
+ end
+
+ private
+
+ def initialize
+ @run_id = Chef::RequestID.instance.request_id
+ @ohai = Ohai::System.new
+ end
+ end
+
+ class RunContext
+ #
+ # The parent RunContext (for notifications).
+ #
+ # @return [Chef::RunContext] The parent RunContext, or `nil` if this is the
+ # root RunContext.
+ #
+ attr_reader :parent
+
+ #
+ # The top-level Chef run we are a part of.
+ #
+ # @return [Chef::Run]
+ #
+ def chef_run
+ Chef
+ end
+
+ #
+ # The resource collection containing our resources.
+ #
+ # @return [Chef::ResourceCollection]
+ #
+ attr_reader :resource_collection
+
+ #
+ # Create a new RunContext.
+ #
+ # @param parent [Chef::RunContext] The parent run_context
+ #
+ # @api private
+ #
+ def initialize(parent: nil)
+ @parent = parent
+
+ parent_resource_collection = parent.resource_collection if parent
+ @resource_collection = Chef::ResourceCollection.new(parent: parent_resource_collection)
+ end
+
+ def compile(run_list: nil, recipe_files: nil, &recipe_block)
+ if run_list
+ end
+ if recipe_files
+ end
+ if recipe_block
+ recipe_dsl.instance_eval(&recipe_block)
+ end
+ resolve_notifications
+ end
+
+ def converge(run_list: nil, recipe_files: nil, &recipe_block)
+ if run_list || recipe_files || recipe_block
+ compile(run_list: run_list, recipe_files: recipe_files, &recipe_block)
+ end
+
+ while take_next_action
+ end
+ end
+
+ #
+ # Take the next action we're supposed to take.
+ #
+ # @return [Array<Chef::Resource, Symbol>] The resource and action(s)
+ # that were taken, or `nil` if no action was taken. If `Symbol` was `nil`,
+ # the next resource was added to the queue but no action was taken yet.
+ #
+ def take_next_action
+ # TODO this isn't threadsafe on all Rubies (requires atomic increment)
+ @taking_actions += 1
+ begin
+ # Process any immediate actions
+ next_action = immediate_notifications.unshift
+ if next_action
+ next_action.resource.run_action(next_action.action)
+ return
+ end
+
+ # Take the next resource in the queue and add a queue entry for each;
+ # then take the next action.
+ resource = resource_collection.next
+ if resource
+ # TODO seems like it'd be nice to do this in "resource.converge_resource"
+ # or something users could call outside the system.
+ actions = Array(resource.action)
+ actions.each do |action|
+ notify(Notification.new(resource, action), immediately: true)
+ end
+ # Go ahead and take the next action.
+ return take_next_action
+ end
+
+ # Process any delayed actions
+ next_action = delayed_notifications.unshift
+ if next_action
+ next_action.resource.run_action(next_action.action)
+ return [next_action.resource, next_action.action]
+ end
+
+ ensure
+ @taking_actions -= 1
+ end
+ end
+
+ private
+
+ attr_reader :taking_actions
+ end
+
+ # TODO deal with ResourceCollection.insert. People actually use this ...
+ # and in a parallel world it makes much less sense. It makes more sense to
+ # insert resources after whichever resource you are currently converging (and
+ # there may be more than one).
+
+ # @api private
+ class ActionRunner
+ # @api private
+ attr_reader :resource_collection
+ # @api private
+ attr_reader :actions
+
+ protected
+
+ def initialize
+ @run_queue = Queue.new
+ end
+ end
+
# == Chef::Client
# The main object in a Chef run. Preps a Chef::Node and Chef::RunContext,
# syncs cookbooks if necessary, and triggers convergence.