Class: Chef::RunContext

Inherits:
Object show all
Defined in:
lib/chef/run_context.rb,
lib/chef/run_context/cookbook_compiler.rb

Overview

Chef::RunContext

Value object that loads and tracks the context of a Chef run

Defined Under Namespace

Classes: CookbookCompiler

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(node, cookbook_collection, events) ⇒ RunContext

Creates a new Chef::RunContext object and populates its fields. This object gets used by the Chef Server to generate a fully compiled recipe list for a node.

Returns

object<Chef::RunContext>

Duh. :)



68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
# File 'lib/chef/run_context.rb', line 68

def initialize(node, cookbook_collection, events)
  @node = node
  @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] = []}
  @definitions = Hash.new
  @loaded_recipes = {}
  @loaded_attributes = {}
  @events = events

  @node.run_context = self

  @cookbook_compiler = nil
end

Instance Attribute Details

#cookbook_collectionObject (readonly)

Chef::CookbookCollection for this run



38
39
40
# File 'lib/chef/run_context.rb', line 38

def cookbook_collection
  @cookbook_collection
end

#definitionsObject (readonly)

Resource Definitions for this run. Populated when the files in definitions/ are evaluated (this is triggered by #load).



42
43
44
# File 'lib/chef/run_context.rb', line 42

def definitions
  @definitions
end

#delayed_notification_collectionObject

A Hash containing the delayed (end of run) notifications triggered by resources during the converge phase of the chef run.



58
59
60
# File 'lib/chef/run_context.rb', line 58

def delayed_notification_collection
  @delayed_notification_collection
end

#eventsObject (readonly)

Event dispatcher for this run.



61
62
63
# File 'lib/chef/run_context.rb', line 61

def events
  @events
end

#immediate_notification_collectionObject

A Hash containing the immediate notifications triggered by resources during the converge phase of the chef run.



54
55
56
# File 'lib/chef/run_context.rb', line 54

def immediate_notification_collection
  @immediate_notification_collection
end

#nodeObject (readonly)

Chef::Node object for this run



35
36
37
# File 'lib/chef/run_context.rb', line 35

def node
  @node
end

#resource_collectionObject

The Chef::ResourceCollection for this run. Populated by evaluating recipes, which is triggered by #load. (See also: CookbookCompiler)



50
51
52
# File 'lib/chef/run_context.rb', line 50

def resource_collection
  @resource_collection
end

Instance Method Details

#delayed_notifications(resource) ⇒ Object



122
123
124
125
126
127
128
# File 'lib/chef/run_context.rb', line 122

def delayed_notifications(resource)
  if resource.instance_of?(Chef::Resource)
    return @delayed_notification_collection[resource.name]
  else
    return @delayed_notification_collection[resource.to_s]
  end
end

#has_cookbook_file_in_cookbook?(cookbook, cb_file_name) ⇒ Boolean

Returns:

  • (Boolean)


240
241
242
243
# File 'lib/chef/run_context.rb', line 240

def has_cookbook_file_in_cookbook?(cookbook, cb_file_name)
  cookbook = cookbook_collection[cookbook]
  cookbook.has_cookbook_file_for_node?(node, cb_file_name)
end

#has_template_in_cookbook?(cookbook, template_name) ⇒ Boolean

Cookbook File Introspection

Returns:

  • (Boolean)


235
236
237
238
# File 'lib/chef/run_context.rb', line 235

def has_template_in_cookbook?(cookbook, template_name)
  cookbook = cookbook_collection[cookbook]
  cookbook.has_template_for_node?(node, template_name)
end

#immediate_notifications(resource) ⇒ Object



114
115
116
117
118
119
120
# File 'lib/chef/run_context.rb', line 114

def immediate_notifications(resource)
  if resource.instance_of?(Chef::Resource)
    return @immediate_notification_collection[resource.name]
  else
    return @immediate_notification_collection[resource.to_s]
  end
end

#include_recipe(*recipe_names) ⇒ Object

Evaluates the recipes recipe_names. Used by DSL::IncludeRecipe



131
132
133
134
135
136
137
138
139
# File 'lib/chef/run_context.rb', line 131

def include_recipe(*recipe_names)
  result_recipes = Array.new
  recipe_names.flatten.each do |recipe_name|
    if result = load_recipe(recipe_name)
      result_recipes << result
    end
  end
  result_recipes
end

#load(run_list_expansion) ⇒ Object

Triggers the compile phase of the chef run. Implemented by Chef::RunContext::CookbookCompiler



86
87
88
89
# File 'lib/chef/run_context.rb', line 86

def load(run_list_expansion)
  @cookbook_compiler = CookbookCompiler.new(self, run_list_expansion, events)
  @cookbook_compiler.compile
end

#load_recipe(recipe_name) ⇒ Object

Evaluates the recipe recipe_name. Used by DSL::IncludeRecipe



142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
# File 'lib/chef/run_context.rb', line 142

def load_recipe(recipe_name)
  Chef::Log.debug("Loading Recipe #{recipe_name} via include_recipe")

  cookbook_name, recipe_short_name = Chef::Recipe.parse_recipe_name(recipe_name)

  if unreachable_cookbook?(cookbook_name) # CHEF-4367
    Chef::Log.warn("MissingCookbookDependency:\nRecipe `\#{recipe_name}` is not in the run_list, and cookbook '\#{cookbook_name}'\nis not a dependency of any cookbook in the run_list.  To load this recipe,\nfirst add a dependency on cookbook '\#{cookbook_name}' in the cookbook you're\nincluding it from in that cookbook's metadata.\n")
  end


  if loaded_fully_qualified_recipe?(cookbook_name, recipe_short_name)
    Chef::Log.debug("I am not loading #{recipe_name}, because I have already seen it.")
    false
  else
    loaded_recipe(cookbook_name, recipe_short_name)
    node.loaded_recipe(cookbook_name, recipe_short_name)
    cookbook = cookbook_collection[cookbook_name]
    cookbook.load_recipe(recipe_short_name, self)
  end
end

#load_recipe_file(recipe_file) ⇒ Object



169
170
171
172
173
174
175
176
177
178
# File 'lib/chef/run_context.rb', line 169

def load_recipe_file(recipe_file)
  if !File.exist?(recipe_file)
    raise Chef::Exceptions::RecipeNotFound, "could not find recipe file #{recipe_file}"
  end

  Chef::Log.debug("Loading Recipe File #{recipe_file}")
  recipe = Chef::Recipe.new('@recipe_files', recipe_file, self)
  recipe.from_file(recipe_file)
  recipe
end

#loaded_attribute(cookbook, attribute_file) ⇒ Object



228
229
230
# File 'lib/chef/run_context.rb', line 228

def loaded_attribute(cookbook, attribute_file)
  @loaded_attributes["#{cookbook}::#{attribute_file}"] = true
end

#loaded_attributesObject

An Array of all attributes files that have been loaded. Stored internally using a Hash, so order is not preserved on ruby 1.8.

Attribute file names are given in fully qualified form, e.g., “nginx::default” instead of “nginx”.



208
209
210
# File 'lib/chef/run_context.rb', line 208

def loaded_attributes
  @loaded_attributes.keys
end

#loaded_fully_qualified_attribute?(cookbook, attribute_file) ⇒ Boolean

Returns:

  • (Boolean)


224
225
226
# File 'lib/chef/run_context.rb', line 224

def loaded_fully_qualified_attribute?(cookbook, attribute_file)
  @loaded_attributes.has_key?("#{cookbook}::#{attribute_file}")
end

#loaded_fully_qualified_recipe?(cookbook, recipe) ⇒ Boolean

Returns:

  • (Boolean)


212
213
214
# File 'lib/chef/run_context.rb', line 212

def loaded_fully_qualified_recipe?(cookbook, recipe)
  @loaded_recipes.has_key?("#{cookbook}::#{recipe}")
end

#loaded_recipe?(recipe) ⇒ Boolean

Returns true if recipe has been loaded, false otherwise. Default recipe names are expanded, so ‘loaded_recipe?(“nginx”)` and `loaded_recipe?(“nginx::default”)` are valid and give identical results.

Returns:

  • (Boolean)


219
220
221
222
# File 'lib/chef/run_context.rb', line 219

def loaded_recipe?(recipe)
  cookbook, recipe_name = Chef::Recipe.parse_recipe_name(recipe)
  loaded_fully_qualified_recipe?(cookbook, recipe_name)
end

#loaded_recipesObject

An Array of all recipes that have been loaded. This is stored internally as a Hash, so ordering is not preserved when using ruby 1.8.

Recipe names are given in fully qualified form, e.g., the recipe “nginx” will be given as “nginx::default”

To determine if a particular recipe has been loaded, use #loaded_recipe?



199
200
201
# File 'lib/chef/run_context.rb', line 199

def loaded_recipes
  @loaded_recipes.keys
end

#notifies_delayed(notification) ⇒ Object

Adds a delayed notification to the delayed_notification_collection. The notification should be a Chef::Resource::Notification or duck type.



105
106
107
108
109
110
111
112
# File 'lib/chef/run_context.rb', line 105

def notifies_delayed(notification)
  nr = notification.notifying_resource
  if nr.instance_of?(Chef::Resource)
    @delayed_notification_collection[nr.name] << notification
  else
    @delayed_notification_collection[nr.to_s] << notification
  end
end

#notifies_immediately(notification) ⇒ Object

Adds an immediate notification to the immediate_notification_collection. The notification should be a Chef::Resource::Notification or duck type.



94
95
96
97
98
99
100
101
# File 'lib/chef/run_context.rb', line 94

def notifies_immediately(notification)
  nr = notification.notifying_resource
  if nr.instance_of?(Chef::Resource)
    @immediate_notification_collection[nr.name] << notification
  else
    @immediate_notification_collection[nr.to_s] << notification
  end
end

#resolve_attribute(cookbook_name, attr_file_name) ⇒ Object

Looks up an attribute file given the cookbook_name and attr_file_name. Used by DSL::IncludeAttribute



182
183
184
185
186
187
188
189
190
# File 'lib/chef/run_context.rb', line 182

def resolve_attribute(cookbook_name, attr_file_name)
  cookbook = cookbook_collection[cookbook_name]
  raise Chef::Exceptions::CookbookNotFound, "could not find cookbook #{cookbook_name} while loading attribute #{name}" unless cookbook

  attribute_filename = cookbook.attribute_filenames_by_short_filename[attr_file_name]
  raise Chef::Exceptions::AttributeNotFound, "could not find filename for attribute #{attr_file_name} in cookbook #{cookbook_name}" unless attribute_filename

  attribute_filename
end

#unreachable_cookbook?(cookbook_name) ⇒ Boolean

Delegates to CookbookCompiler#unreachable_cookbook? Used to raise an error when attempting to load a recipe belonging to a cookbook that is not in the dependency graph. See also: CHEF-4367

Returns:

  • (Boolean)


248
249
250
# File 'lib/chef/run_context.rb', line 248

def unreachable_cookbook?(cookbook_name)
  @cookbook_compiler.unreachable_cookbook?(cookbook_name)
end