class Chef::RunContext::CookbookCompiler
Implements the compile phase of the chef run by loading/eval-ing files from cookbooks in the correct order and in the correct context.
Attributes
Public Class Methods
# File lib/chef/run_context/cookbook_compiler.rb, line 35 def initialize(run_context, run_list_expansion, events) @run_context = run_context @events = events @run_list_expansion = run_list_expansion @cookbook_order = nil end
Public Instance Methods
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.
# File lib/chef/run_context/cookbook_compiler.rb, line 70 def compile compile_libraries compile_attributes compile_lwrps compile_resource_definitions compile_recipes 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.
# File lib/chef/run_context/cookbook_compiler.rb, line 107 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 library files from cookbooks according to cookbook_order.
# File lib/chef/run_context/cookbook_compiler.rb, line 96 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 LWRPs according to cookbook_order. Providers are loaded before resources on a cookbook-wise basis.
# File lib/chef/run_context/cookbook_compiler.rb, line 117 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
Iterates over the expanded run_list, loading each recipe in turn.
# File lib/chef/run_context/cookbook_compiler.rb, line 136 def compile_recipes @events.recipe_load_start(run_list_expansion.recipes.size) run_list_expansion.recipes.each do |recipe| begin @run_context.load_recipe(recipe) rescue Chef::Exceptions::RecipeNotFound => e @events.recipe_not_found(e) raise rescue Exception => e path = resolve_recipe(recipe) @events.recipe_file_load_failed(path, e) raise end end @events.recipe_load_complete end
Loads resource definitions according to cookbook_order
# File lib/chef/run_context/cookbook_compiler.rb, line 127 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
Chef::CookbookCollection object for the current run
# File lib/chef/run_context/cookbook_compiler.rb, line 48 def cookbook_collection @run_context.cookbook_collection 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(s) that depend on them.
# File lib/chef/run_context/cookbook_compiler.rb, line 82 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 Chef::Log.debug("Cookbooks to compile: #{ordered_cookbooks.inspect}") ordered_cookbooks end end
Resource Definitions from the compiled cookbooks. This is populated by calling compile_resource_definitions (which is called by compile)
# File lib/chef/run_context/cookbook_compiler.rb, line 54 def definitions @run_context.definitions end
Chef::Node object for the current run.
# File lib/chef/run_context/cookbook_compiler.rb, line 43 def node @run_context.node end
All cookbooks in the dependency graph, returned as a Set.
# File lib/chef/run_context/cookbook_compiler.rb, line 160 def reachable_cookbooks @reachable_cookbooks ||= Set.new(cookbook_order) end
Whether or not a cookbook is reachable from the set of cookbook given by the run_list plus those cookbooks' dependencies.
# File lib/chef/run_context/cookbook_compiler.rb, line 155 def unreachable_cookbook?(cookbook_name) !reachable_cookbooks.include?(cookbook_name) end
Private Instance Methods
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.
# File lib/chef/run_context/cookbook_compiler.rb, line 251 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
# File lib/chef/run_context/cookbook_compiler.rb, line 262 def count_files_by_segment(segment) cookbook_collection.inject(0) do |count, cookbook_by_name| count + cookbook_by_name[1].segment_filenames(segment).size end end
Yields the name, as a symbol, of each cookbook depended on by
cookbook_name
in lexical sort order.
# File lib/chef/run_context/cookbook_compiler.rb, line 276 def each_cookbook_dep(cookbook_name, &block) cookbook = cookbook_collection[cookbook_name] cookbook.metadata.dependencies.keys.sort.map{|x| x.to_sym}.each(&block) end
Lists the local paths to files in cookbook
of type
segment
(attribute, recipe, etc.), sorted lexically.
# File lib/chef/run_context/cookbook_compiler.rb, line 270 def files_in_cookbook_by_segment(cookbook, segment) cookbook_collection[cookbook].segment_filenames(segment).sort end
# File lib/chef/run_context/cookbook_compiler.rb, line 178 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
# File lib/chef/run_context/cookbook_compiler.rb, line 166 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
# File lib/chef/run_context/cookbook_compiler.rb, line 187 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
# File lib/chef/run_context/cookbook_compiler.rb, line 209 def load_lwrp_provider(cookbook_name, filename) Chef::Log.debug("Loading cookbook #{cookbook_name}'s providers from #{filename}") Chef::Provider::LWRPBase.build_from_file(cookbook_name, filename, self) @events.lwrp_file_loaded(filename) rescue Exception => e @events.lwrp_file_load_failed(filename, e) raise end
# File lib/chef/run_context/cookbook_compiler.rb, line 218 def load_lwrp_resource(cookbook_name, filename) Chef::Log.debug("Loading cookbook #{cookbook_name}'s resources from #{filename}") Chef::Resource::LWRPBase.build_from_file(cookbook_name, filename, self) @events.lwrp_file_loaded(filename) rescue Exception => e @events.lwrp_file_load_failed(filename, e) raise end
# File lib/chef/run_context/cookbook_compiler.rb, line 200 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
# File lib/chef/run_context/cookbook_compiler.rb, line 228 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
Given a recipe_name
, finds the file associated with the
recipe.
# File lib/chef/run_context/cookbook_compiler.rb, line 282 def resolve_recipe(recipe_name) cookbook_name, recipe_short_name = Chef::Recipe.parse_recipe_name(recipe_name) cookbook = cookbook_collection[cookbook_name] cookbook.recipe_filenames_by_name[recipe_short_name] end