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

events[R]
run_list_expansion[R]

Public Class Methods

new(run_context, run_list_expansion, events) click to toggle source
# 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

compile() click to toggle source

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
compile_attributes() click to toggle source

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
compile_libraries() click to toggle source

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
compile_lwrps() click to toggle source

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
compile_recipes() click to toggle source

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
compile_resource_definitions() click to toggle source

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
cookbook_collection() click to toggle source

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
cookbook_order() click to toggle source

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
definitions() click to toggle source

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
node() click to toggle source

Chef::Node object for the current run.

# File lib/chef/run_context/cookbook_compiler.rb, line 43
def node
  @run_context.node
end
reachable_cookbooks() click to toggle source

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
unreachable_cookbook?(cookbook_name) click to toggle source

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

add_cookbook_with_deps(ordered_cookbooks, seen_cookbooks, cookbook) click to toggle source

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
count_files_by_segment(segment) click to toggle source
# 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
each_cookbook_dep(cookbook_name, &block) click to toggle source

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
files_in_cookbook_by_segment(cookbook, segment) click to toggle source

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
load_attribute_file(cookbook_name, filename) click to toggle source
# 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
load_attributes_from_cookbook(cookbook_name) click to toggle source
# 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
load_libraries_from_cookbook(cookbook_name) click to toggle source
# 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
load_lwrp_provider(cookbook_name, filename) click to toggle source
# 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
load_lwrp_resource(cookbook_name, filename) click to toggle source
# 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
load_lwrps_from_cookbook(cookbook_name) click to toggle source
# 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
load_resource_definitions_from_cookbook(cookbook_name) click to toggle source
# 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
resolve_recipe(recipe_name) click to toggle source

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