summaryrefslogtreecommitdiff
path: root/lib/chef/run_context.rb
diff options
context:
space:
mode:
authordanielsdeleo <dan@opscode.com>2012-11-29 15:45:55 -0800
committerdanielsdeleo <dan@opscode.com>2012-11-30 14:51:47 -0800
commit20fd1383020261c3756b54c26f4c2ea9e652d43c (patch)
treebd00bd9fa4a0e0e18b81a27ca337afc64f1fc287 /lib/chef/run_context.rb
parentb213ae8e8c7aac472332298f0f455d36d122a7b5 (diff)
downloadchef-20fd1383020261c3756b54c26f4c2ea9e652d43c.tar.gz
[CHEF-3376] give CookbookCompiler its own file
Diffstat (limited to 'lib/chef/run_context.rb')
-rw-r--r--lib/chef/run_context.rb227
1 files changed, 3 insertions, 224 deletions
diff --git a/lib/chef/run_context.rb b/lib/chef/run_context.rb
index 6d5f001aac..e41b6603fb 100644
--- a/lib/chef/run_context.rb
+++ b/lib/chef/run_context.rb
@@ -22,236 +22,15 @@ require 'chef/cookbook_version'
require 'chef/node'
require 'chef/role'
require 'chef/log'
+require 'chef/recipe'
+require 'chef/run_context/cookbook_compiler'
class Chef
+
# == Chef::RunContext
# Value object that loads and tracks the context of a Chef run
class RunContext
- # Implements the compile phase of the chef run by loading/eval-ing files
- # from cookbooks in the correct order and in the correct context.
- class CookbookCompiler
- attr_reader :node
- attr_reader :events
- attr_reader :run_list_expansion
- attr_reader :cookbook_collection
-
- # Resource Definitions from the compiled cookbooks. This is populated by
- # calling #compile_resource_definitions (which is called by #compile)
- attr_reader :definitions
-
- def initialize(node, cookbook_collection, run_list_expansion, events)
- @node = node
- @events = events
- @run_list_expansion = run_list_expansion
- @cookbook_collection = cookbook_collection
-
- # @resource_collection = Chef::ResourceCollection.new
- # @immediate_notification_collection = Hash.new {|h,k| h[k] = []}
- # @delayed_notification_collection = Hash.new {|h,k| h[k] = []}
- # @loaded_recipes = {}
- # @loaded_attributes = {}
- #
-
- @definitions = Hash.new
- @cookbook_order = nil
- end
-
- # Run the compile phase of the chef run. Loads files in the following order:
- # * Libraries
- # * Attributes
- # * LWRPs
- # * Resource Definitions
- # * Recipes
- #
- # Recipes are loaded in precisely the order specified by the expanded run_list.
- #
- # Other files are loaded in an order derived from the expanded run_list
- # and the dependencies declared by cookbooks' metadata. See
- # #cookbook_order for more information.
- def compile
- compile_libraries
- compile_attributes
- compile_lwrps
- compile_resource_definitions
- #compile_recipes
- end
-
- # Extracts the cookbook names from the expanded run list, then iterates
- # over the list, recursing through dependencies to give a run_list
- # ordered array of cookbook names with no duplicates. Dependencies appear
- # before the cookbook they depend on.
- def cookbook_order
- @cookbook_order ||= begin
- ordered_cookbooks = []
- seen_cookbooks = {}
- run_list_expansion.recipes.each do |recipe|
- cookbook = Chef::Recipe.parse_recipe_name(recipe).first
- add_cookbook_with_deps(ordered_cookbooks, seen_cookbooks, cookbook)
- end
- ordered_cookbooks
- end
- end
-
- # Loads library files from cookbooks according to #cookbook_order.
- def compile_libraries
- @events.library_load_start(count_files_by_segment(:libraries))
- cookbook_order.each do |cookbook|
- load_libraries_from_cookbook(cookbook)
- end
- @events.library_load_complete
- end
-
- # Loads attributes files from cookbooks. Attributes files are loaded
- # according to #cookbook_order; within a cookbook, +default.rb+ is loaded
- # first, then the remaining attributes files in lexical sort order.
- def compile_attributes
- @events.attribute_load_start(count_files_by_segment(:attributes))
- cookbook_order.each do |cookbook|
- load_attributes_from_cookbook(cookbook)
- end
- @events.attribute_load_complete
- end
-
- # Loads LWRPs according to #cookbook_order. Providers are loaded before
- # resources on a cookbook-wise basis.
- def compile_lwrps
- lwrp_file_count = count_files_by_segment(:providers) + count_files_by_segment(:resources)
- @events.lwrp_load_start(lwrp_file_count)
- cookbook_order.each do |cookbook|
- load_lwrps_from_cookbook(cookbook)
- end
- @events.lwrp_load_complete
- end
-
- def compile_resource_definitions
- @events.definition_load_start(count_files_by_segment(:definitions))
- cookbook_order.each do |cookbook|
- load_resource_definitions_from_cookbook(cookbook)
- end
- @events.definition_load_complete
- end
-
-
- private
-
- def load_attributes_from_cookbook(cookbook_name)
- list_of_attr_files = files_in_cookbook_by_segment(cookbook_name, :attributes).dup
- if default_file = list_of_attr_files.find {|path| File.basename(path) == "default.rb" }
- list_of_attr_files.delete(default_file)
- load_attribute_file(cookbook_name.to_s, default_file)
- end
-
- list_of_attr_files.each do |filename|
- load_attribute_file(cookbook_name.to_s, filename)
- end
- end
-
- def load_attribute_file(cookbook_name, filename)
- Chef::Log.debug("Node #{@node.name} loading cookbook #{cookbook_name}'s attribute file #{filename}")
- attr_file_basename = ::File.basename(filename, ".rb")
- @node.include_attribute("#{cookbook_name}::#{attr_file_basename}")
- rescue Exception => e
- @events.attribute_file_load_failed(filename, e)
- raise
- end
-
- def load_libraries_from_cookbook(cookbook_name)
- files_in_cookbook_by_segment(cookbook_name, :libraries).each do |filename|
- begin
- Chef::Log.debug("Loading cookbook #{cookbook_name}'s library file: #{filename}")
- Kernel.load(filename)
- @events.library_file_loaded(filename)
- rescue Exception => e
- @events.library_file_load_failed(filename, e)
- raise
- end
- end
- end
-
- def load_lwrps_from_cookbook(cookbook_name)
- files_in_cookbook_by_segment(cookbook_name, :providers).each do |filename|
- load_lwrp_provider(cookbook_name, filename)
- end
- files_in_cookbook_by_segment(cookbook_name, :resources).each do |filename|
- load_lwrp_resource(cookbook_name, filename)
- end
- end
-
- def load_lwrp_provider(cookbook_name, filename)
- Chef::Log.debug("Loading cookbook #{cookbook_name}'s providers from #{filename}")
- Chef::Provider.build_from_file(cookbook_name, filename, self)
- @events.lwrp_file_loaded(filename)
- rescue Exception => e
- @events.lwrp_file_load_failed(filename, e)
- raise
- end
-
- def load_lwrp_resource(cookbook_name, filename)
- Chef::Log.debug("Loading cookbook #{cookbook_name}'s resources from #{filename}")
- Chef::Resource.build_from_file(cookbook_name, filename, self)
- @events.lwrp_file_loaded(filename)
- rescue Exception => e
- @events.lwrp_file_load_failed(filename, e)
- raise
- end
-
-
- def load_resource_definitions_from_cookbook(cookbook_name)
- files_in_cookbook_by_segment(cookbook_name, :definitions).each do |filename|
- begin
- Chef::Log.debug("Loading cookbook #{cookbook_name}'s definitions from #{filename}")
- resourcelist = Chef::ResourceDefinitionList.new
- resourcelist.from_file(filename)
- definitions.merge!(resourcelist.defines) do |key, oldval, newval|
- Chef::Log.info("Overriding duplicate definition #{key}, new definition found in #{filename}")
- newval
- end
- @events.definition_file_loaded(filename)
- rescue Exception => e
- @events.definition_file_load_failed(filename, e)
- raise
- end
- end
- end
-
- # Builds up the list of +ordered_cookbooks+ by first recursing through the
- # dependencies of +cookbook+, and then adding +cookbook+ to the list of
- # +ordered_cookbooks+. A cookbook is skipped if it appears in
- # +seen_cookbooks+, otherwise it is added to the set of +seen_cookbooks+
- # before its dependencies are processed.
- def add_cookbook_with_deps(ordered_cookbooks, seen_cookbooks, cookbook)
- return false if seen_cookbooks.key?(cookbook)
-
- seen_cookbooks[cookbook] = true
- each_cookbook_dep(cookbook) do |dependency|
- add_cookbook_with_deps(ordered_cookbooks, seen_cookbooks, dependency)
- end
- ordered_cookbooks << cookbook
- end
-
-
- def count_files_by_segment(segment)
- cookbook_collection.inject(0) do |count, ( cookbook_name, cookbook )|
- count + cookbook.segment_filenames(segment).size
- end
- end
-
- # Lists the local paths to files in +cookbook+ of type +segment+
- # (attribute, recipe, etc.), sorted lexically.
- def files_in_cookbook_by_segment(cookbook, segment)
- cookbook_collection[cookbook].segment_filenames(segment).sort
- end
-
- # Yields the name of each cookbook depended on by +cookbook_name+ in
- # lexical sort order.
- def each_cookbook_dep(cookbook_name, &block)
- cookbook = cookbook_collection[cookbook_name]
- cookbook.metadata.dependencies.keys.sort.each(&block)
- end
-
- end
-
attr_reader :node, :cookbook_collection, :definitions
# Needs to be settable so deploy can run a resource_collection independent