Class: Chef::PolicyBuilder::Policyfile
- Inherits:
-
Object
- Object
- Chef::PolicyBuilder::Policyfile
- Defined in:
- lib/chef/policy_builder/policyfile.rb
Overview
Policyfile is a policy builder implementation that gets run list and cookbook version information from a single document.
Unsupported Options:
- override_runlist
-
This could potentially be integrated into the
policyfile, or replaced with a similar feature that has different semantics.
- specific_recipes
-
put more design thought into this use case.
- run_list in json_attribs
-
would be ignored anyway, so it raises an error.
- chef-solo
-
not currently supported. Need more design thought around
how this should work.
Defined Under Namespace
Classes: ConfigurationError, PolicyfileError, RunListExpansionIsh, UnsupportedFeature
Instance Attribute Summary collapse
-
#events ⇒ Object
readonly
Returns the value of attribute events.
-
#json_attribs ⇒ Object
readonly
Returns the value of attribute json_attribs.
-
#node ⇒ Object
readonly
Returns the value of attribute node.
-
#node_name ⇒ Object
readonly
Returns the value of attribute node_name.
-
#ohai_data ⇒ Object
readonly
Returns the value of attribute ohai_data.
-
#run_context ⇒ Object
readonly
Returns the value of attribute run_context.
Instance Method Summary collapse
- #api_service ⇒ Object private
-
#apply_policyfile_attributes ⇒ Object
private
Sets attributes from the policyfile on the node, using the role priority.
-
#build_node ⇒ Object
Applies environment, external JSON attributes, and override run list to the node, Then expands the run_list.
- #config ⇒ Object private
- #cookbook_lock_for(cookbook_name) ⇒ Object private
- #cookbook_locks ⇒ Object private
-
#cookbooks_to_sync ⇒ Object
private
Builds a ‘cookbook_hash’ map of the form “COOKBOOK_NAME” => “IDENTIFIER”.
- #deployment_group ⇒ Object private
-
#expand_run_list ⇒ RunListExpansionIsh
Sets ‘run_list` on the node from the policy, sets `roles` and `recipes` attributes on the node accordingly.
-
#finish_load_node(node) ⇒ Object
PolicyBuilder API ##.
-
#hoist_policyfile_attributes(policy_group) ⇒ Object
private
Hoists attributes from role_X up to the equivalent role_X level.
-
#initialize(node_name, ohai_data, json_attribs, override_runlist, events) ⇒ Policyfile
constructor
A new instance of Policyfile.
-
#manifest_for(cookbook_name, lock_data) ⇒ Object
private
Fetches the CookbookVersion object for the given name and identifer specified in the lock_data.
-
#original_runlist ⇒ Object
Override run_list is not supported.
-
#override_runlist ⇒ Object
Override run_list is not supported.
- #parse_recipe_spec(recipe_spec) ⇒ Object private
- #policy ⇒ Object private
- #policy_group ⇒ Object private
- #policy_group_from_config ⇒ Object private
- #policy_group_from_json_attribs ⇒ Object private
- #policy_group_from_node ⇒ Object private
- #policy_name ⇒ Object private
- #policy_name_from_config ⇒ Object private
- #policy_name_from_json_attribs ⇒ Object private
- #policy_name_from_node ⇒ Object private
- #policyfile_location ⇒ Object private
- #revision_id ⇒ Object private
- #run_list ⇒ Object private
-
#run_list_expansion ⇒ Object
Policyfile gives you the run_list already expanded, but users of this class may expect to get a run_list expansion compatible object by calling this method.
-
#run_list_expansion_ish ⇒ Object
private
Sets up a RunListExpansionIsh object so that it can be used in place of a RunListExpansion object, to satisfy the API contract of #expand_run_list.
-
#run_list_with_versions_for_display ⇒ Object
private
Generates an array of strings with recipe names including version and identifier info.
-
#select_policy_name_and_group ⇒ Object
private
Selects the ‘policy_name` and `policy_group` from the following sources in priority order:.
-
#setup_run_context(specific_recipes = nil, run_context = nil) ⇒ Chef::RunContext
Synchronizes cookbooks and initializes the run context object for the run.
-
#sync_cookbooks ⇒ Hash{String => Chef::CookbookManifest}
Synchronizes cookbooks.
-
#temporary_policy? ⇒ false
Whether or not this is a temporary policy.
- #validate_policy_config! ⇒ Object private
-
#validate_policyfile ⇒ Object
Do some mimimal validation of the policyfile we fetched from the server.
- #validate_recipe_spec(recipe_spec) ⇒ Object private
Constructor Details
#initialize(node_name, ohai_data, json_attribs, override_runlist, events) ⇒ Policyfile
Returns a new instance of Policyfile.
85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 |
# File 'lib/chef/policy_builder/policyfile.rb', line 85 def initialize(node_name, ohai_data, json_attribs, override_runlist, events) @node_name = node_name @ohai_data = ohai_data @json_attribs = json_attribs @events = events @node = nil if Chef::Config[:solo_legacy_mode] raise UnsupportedFeature, "Policyfile does not support chef-solo. Use #{Chef::Dist::CLIENT} local mode instead." end if override_runlist raise UnsupportedFeature, "Policyfile does not support override run lists. Use named run_lists instead." end if json_attribs && json_attribs.key?("run_list") raise UnsupportedFeature, "Policyfile does not support setting the run_list in json data." end if Chef::Config[:environment] && !Chef::Config[:environment].chomp.empty? raise UnsupportedFeature, "Policyfile does not work with an Environment configured." end end |
Instance Attribute Details
#events ⇒ Object (readonly)
Returns the value of attribute events.
78 79 80 |
# File 'lib/chef/policy_builder/policyfile.rb', line 78 def events @events end |
#json_attribs ⇒ Object (readonly)
Returns the value of attribute json_attribs.
82 83 84 |
# File 'lib/chef/policy_builder/policyfile.rb', line 82 def json_attribs @json_attribs end |
#node ⇒ Object (readonly)
Returns the value of attribute node.
79 80 81 |
# File 'lib/chef/policy_builder/policyfile.rb', line 79 def node @node end |
#node_name ⇒ Object (readonly)
Returns the value of attribute node_name.
80 81 82 |
# File 'lib/chef/policy_builder/policyfile.rb', line 80 def node_name @node_name end |
#ohai_data ⇒ Object (readonly)
Returns the value of attribute ohai_data.
81 82 83 |
# File 'lib/chef/policy_builder/policyfile.rb', line 81 def ohai_data @ohai_data end |
#run_context ⇒ Object (readonly)
Returns the value of attribute run_context.
83 84 85 |
# File 'lib/chef/policy_builder/policyfile.rb', line 83 def run_context @run_context end |
Instance Method Details
#api_service ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
502 503 504 505 |
# File 'lib/chef/policy_builder/policyfile.rb', line 502 def api_service @api_service ||= Chef::ServerAPI.new(config[:chef_server_url], { version_class: Chef::CookbookManifestVersions }) end |
#apply_policyfile_attributes ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Sets attributes from the policyfile on the node, using the role priority.
273 274 275 276 277 |
# File 'lib/chef/policy_builder/policyfile.rb', line 273 def apply_policyfile_attributes node.attributes.role_default = policy["default_attributes"] node.attributes.role_override = policy["override_attributes"] hoist_policyfile_attributes(node.policy_group) if node.policy_group end |
#build_node ⇒ Object
Applies environment, external JSON attributes, and override run list to the node, Then expands the run_list.
Returns
- node<Chef::Node>
-
The modified node object. node is modified in place.
147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 |
# File 'lib/chef/policy_builder/policyfile.rb', line 147 def build_node # consume_external_attrs may add items to the run_list. Save the # expanded run_list, which we will pass to the server later to # determine which versions of cookbooks to use. node.reset_defaults_and_overrides node.consume_external_attrs(ohai_data, json_attribs) apply_policyfile_attributes Chef::Log.info("Run List is [#{run_list}]") Chef::Log.info("Run List expands to [#{run_list_with_versions_for_display.join(", ")}]") events.node_load_completed(node, run_list_with_versions_for_display, Chef::Config) events.(run_list_expansion_ish) # we must do this after `node.consume_external_attrs` node.automatic_attrs[:policy_name] = node.policy_name node.automatic_attrs[:policy_group] = node.policy_group node.automatic_attrs[:chef_environment] = node.policy_group node rescue Exception => e events.node_load_failed(node_name, e, Chef::Config) raise end |
#config ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
508 509 510 |
# File 'lib/chef/policy_builder/policyfile.rb', line 508 def config Chef::Config end |
#cookbook_lock_for(cookbook_name) ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
299 300 301 |
# File 'lib/chef/policy_builder/policyfile.rb', line 299 def cookbook_lock_for(cookbook_name) cookbook_locks[cookbook_name] end |
#cookbook_locks ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
492 493 494 |
# File 'lib/chef/policy_builder/policyfile.rb', line 492 def cookbook_locks policy["cookbook_locks"] end |
#cookbooks_to_sync ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Builds a ‘cookbook_hash’ map of the form
"COOKBOOK_NAME" => "IDENTIFIER"
This can be passed to a Chef::CookbookSynchronizer object to synchronize the cookbooks.
TODO: Currently this makes N API calls to the server to get the cookbook objects. With server support (bulk API or the like), this should be reduced to a single call.
459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 |
# File 'lib/chef/policy_builder/policyfile.rb', line 459 def cookbooks_to_sync @cookbook_to_sync ||= begin events.cookbook_resolution_start(run_list_with_versions_for_display) cookbook_versions_by_name = cookbook_locks.inject({}) do |cb_map, (name, lock_data)| cb_map[name] = manifest_for(name, lock_data) cb_map end events.cookbook_resolution_complete(cookbook_versions_by_name) cookbook_versions_by_name end rescue Exception => e # TODO: wrap/munge exception to provide helpful error output events.cookbook_resolution_failed(run_list_with_versions_for_display, e) raise end |
#deployment_group ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
369 370 371 |
# File 'lib/chef/policy_builder/policyfile.rb', line 369 def deployment_group Chef::Config[:deployment_group] || raise(ConfigurationError, "Setting `deployment_group` is not configured.") end |
#expand_run_list ⇒ RunListExpansionIsh
Sets ‘run_list` on the node from the policy, sets `roles` and `recipes` attributes on the node accordingly.
208 209 210 211 212 213 214 215 216 |
# File 'lib/chef/policy_builder/policyfile.rb', line 208 def CookbookCacheCleaner.instance.skip_removal = true if named_run_list_requested? node.run_list(run_list) node.automatic_attrs[:policy_revision] = revision_id node.automatic_attrs[:roles] = [] node.automatic_attrs[:recipes] = run_list_expansion_ish.recipes run_list_expansion_ish end |
#finish_load_node(node) ⇒ Object
PolicyBuilder API ##
135 136 137 138 139 140 |
# File 'lib/chef/policy_builder/policyfile.rb', line 135 def finish_load_node(node) @node = node select_policy_name_and_group validate_policyfile events.policyfile_loaded(policy) end |
#hoist_policyfile_attributes(policy_group) ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Hoists attributes from role_X up to the equivalent role_X level
282 283 284 285 286 |
# File 'lib/chef/policy_builder/policyfile.rb', line 282 def hoist_policyfile_attributes(policy_group) Chef::Log.trace("Running attribute Hoist for group #{policy_group}") Chef::Mixin::DeepMerge.hash_only_merge!(node.role_default, node.role_default[policy_group]) if node.role_default.include?(policy_group) Chef::Mixin::DeepMerge.hash_only_merge!(node.role_override, node.role_override[policy_group]) if node.role_override.include?(policy_group) end |
#manifest_for(cookbook_name, lock_data) ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Fetches the CookbookVersion object for the given name and identifer specified in the lock_data. TODO: This only implements Chef 11 compatibility mode, which means that cookbooks are fetched by the “dotted_decimal_identifier”: a representation of a SHA1 in the traditional x.y.z version format.
483 484 485 486 487 488 489 |
# File 'lib/chef/policy_builder/policyfile.rb', line 483 def manifest_for(cookbook_name, lock_data) if Chef::Config[:policy_document_native_api] artifact_manifest_for(cookbook_name, lock_data) else compat_mode_manifest_for(cookbook_name, lock_data) end end |
#original_runlist ⇒ Object
Override run_list is not supported.
114 115 116 |
# File 'lib/chef/policy_builder/policyfile.rb', line 114 def original_runlist nil end |
#override_runlist ⇒ Object
Override run_list is not supported.
119 120 121 |
# File 'lib/chef/policy_builder/policyfile.rb', line 119 def override_runlist nil end |
#parse_recipe_spec(recipe_spec) ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
289 290 291 292 293 294 295 296 |
# File 'lib/chef/policy_builder/policyfile.rb', line 289 def parse_recipe_spec(recipe_spec) rmatch = recipe_spec.match(/recipe\[([^:]+)::([^:]+)\]/) if rmatch.nil? raise PolicyfileError, "invalid recipe specification #{recipe_spec} in Policyfile from #{policyfile_location}" else [rmatch[1], rmatch[2]] end end |
#policy ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
315 316 317 318 319 |
# File 'lib/chef/policy_builder/policyfile.rb', line 315 def policy @policy ||= api_service.get(policyfile_location) rescue Net::HTTPClientException => e raise ConfigurationError, "Error loading policyfile from `#{policyfile_location}': #{e.class} - #{e.}" end |
#policy_group ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
381 382 383 |
# File 'lib/chef/policy_builder/policyfile.rb', line 381 def policy_group Chef::Config[:policy_group] end |
#policy_group_from_config ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
430 431 432 |
# File 'lib/chef/policy_builder/policyfile.rb', line 430 def policy_group_from_config Chef::Config[:policy_group] end |
#policy_group_from_json_attribs ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
420 421 422 |
# File 'lib/chef/policy_builder/policyfile.rb', line 420 def policy_group_from_json_attribs json_attribs["policy_group"] end |
#policy_group_from_node ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
440 441 442 |
# File 'lib/chef/policy_builder/policyfile.rb', line 440 def policy_group_from_node node.policy_group end |
#policy_name ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
386 387 388 |
# File 'lib/chef/policy_builder/policyfile.rb', line 386 def policy_name Chef::Config[:policy_name] end |
#policy_name_from_config ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
435 436 437 |
# File 'lib/chef/policy_builder/policyfile.rb', line 435 def policy_name_from_config Chef::Config[:policy_name] end |
#policy_name_from_json_attribs ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
425 426 427 |
# File 'lib/chef/policy_builder/policyfile.rb', line 425 def policy_name_from_json_attribs json_attribs["policy_name"] end |
#policy_name_from_node ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
445 446 447 |
# File 'lib/chef/policy_builder/policyfile.rb', line 445 def policy_name_from_node node.policy_name end |
#policyfile_location ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
322 323 324 325 326 327 328 329 |
# File 'lib/chef/policy_builder/policyfile.rb', line 322 def policyfile_location if Chef::Config[:policy_document_native_api] validate_policy_config! "policy_groups/#{policy_group}/policies/#{policy_name}" else "data/policyfiles/#{deployment_group}" end end |
#revision_id ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
497 498 499 |
# File 'lib/chef/policy_builder/policyfile.rb', line 497 def revision_id policy["revision_id"] end |
#run_list ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
304 305 306 307 308 309 310 311 312 |
# File 'lib/chef/policy_builder/policyfile.rb', line 304 def run_list if named_run_list_requested? named_run_list || raise(ConfigurationError, "Policy '#{retrieved_policy_name}' revision '#{revision_id}' does not have named_run_list '#{named_run_list_name}'" + "(available named_run_lists: [#{available_named_run_lists.join(", ")}])") else policy["run_list"] end end |
#run_list_expansion ⇒ Object
Policyfile gives you the run_list already expanded, but users of this class may expect to get a run_list expansion compatible object by calling this method.
Returns
- RunListExpansionIsh
-
A RunListExpansion duck type
129 130 131 |
# File 'lib/chef/policy_builder/policyfile.rb', line 129 def run_list_expansion run_list_expansion_ish end |
#run_list_expansion_ish ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Sets up a RunListExpansionIsh object so that it can be used in place of a RunListExpansion object, to satisfy the API contract of #expand_run_list
262 263 264 265 266 267 268 |
# File 'lib/chef/policy_builder/policyfile.rb', line 262 def run_list_expansion_ish recipes = run_list.map do |recipe_spec| cookbook, recipe = parse_recipe_spec(recipe_spec) "#{cookbook}::#{recipe}" end RunListExpansionIsh.new(recipes, []) end |
#run_list_with_versions_for_display ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Generates an array of strings with recipe names including version and identifier info.
248 249 250 251 252 253 254 255 |
# File 'lib/chef/policy_builder/policyfile.rb', line 248 def run_list_with_versions_for_display run_list.map do |recipe_spec| cookbook, recipe = parse_recipe_spec(recipe_spec) lock_data = cookbook_lock_for(cookbook) display = "#{cookbook}::#{recipe}@#{lock_data["version"]} (#{lock_data["identifier"][0...7]})" display end end |
#select_policy_name_and_group ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Selects the ‘policy_name` and `policy_group` from the following sources in priority order:
-
JSON attribs (i.e., ‘-j JSON_FILE`)
-
‘Chef::Config`
-
The node object
The selected values are then copied to ‘Chef::Config` and the node.
400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 |
# File 'lib/chef/policy_builder/policyfile.rb', line 400 def select_policy_name_and_group policy_name_to_set = policy_name_from_json_attribs || policy_name_from_config || policy_name_from_node policy_group_to_set = policy_group_from_json_attribs || policy_group_from_config || policy_group_from_node node.policy_name = policy_name_to_set node.policy_group = policy_group_to_set node.chef_environment = policy_group_to_set Chef::Config[:policy_name] = policy_name_to_set Chef::Config[:policy_group] = policy_group_to_set end |
#setup_run_context(specific_recipes = nil, run_context = nil) ⇒ Chef::RunContext
Synchronizes cookbooks and initializes the run context object for the run.
179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 |
# File 'lib/chef/policy_builder/policyfile.rb', line 179 def setup_run_context(specific_recipes = nil, run_context = nil) run_context ||= Chef::RunContext.new run_context.node = node run_context.events = events Chef::Cookbook::FileVendor.fetch_from_remote(api_service) sync_cookbooks cookbook_collection = Chef::CookbookCollection.new(cookbooks_to_sync) cookbook_collection.validate! cookbook_collection.install_gems(events) run_context.cookbook_collection = cookbook_collection setup_chef_class(run_context) events.cookbook_compilation_start(run_context) run_context.load(run_list_expansion_ish) events.cookbook_compilation_complete(run_context) setup_chef_class(run_context) run_context end |
#sync_cookbooks ⇒ Hash{String => Chef::CookbookManifest}
Synchronizes cookbooks. In a normal chef-client run, this is handled by #setup_run_context, but may be called directly in some circumstances.
223 224 225 226 227 228 229 230 231 232 |
# File 'lib/chef/policy_builder/policyfile.rb', line 223 def sync_cookbooks Chef::Log.trace("Synchronizing cookbooks") synchronizer = Chef::CookbookSynchronizer.new(cookbooks_to_sync, events) synchronizer.sync_cookbooks # register the file cache path in the cookbook path so that CookbookLoader actually picks up the synced cookbooks Chef::Config[:cookbook_path] = File.join(Chef::Config[:file_cache_path], "cookbooks") cookbooks_to_sync end |
#temporary_policy? ⇒ false
Whether or not this is a temporary policy. Since PolicyBuilder doesn’t support override_runlist, this is always false.
238 239 240 |
# File 'lib/chef/policy_builder/policyfile.rb', line 238 def temporary_policy? false end |
#validate_policy_config! ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
374 375 376 377 378 |
# File 'lib/chef/policy_builder/policyfile.rb', line 374 def validate_policy_config! raise ConfigurationError, "Setting `policy_group` is not configured." unless policy_group raise ConfigurationError, "Setting `policy_name` is not configured." unless policy_name end |
#validate_policyfile ⇒ Object
Do some mimimal validation of the policyfile we fetched from the server. Compatibility mode relies on using data bags to store policy files; therefore no real validation will be performed server-side and we need to make additional checks to ensure the data will be formatted correctly.
336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 |
# File 'lib/chef/policy_builder/policyfile.rb', line 336 def validate_policyfile errors = [] unless run_list errors << "Policyfile is missing run_list element" end unless policy.key?("cookbook_locks") errors << "Policyfile is missing cookbook_locks element" end if run_list.is_a?(Array) run_list_errors = run_list.select do |maybe_recipe_spec| validate_recipe_spec(maybe_recipe_spec) end errors += run_list_errors else errors << "Policyfile run_list is malformed, must be an array of `recipe[cb_name::recipe_name]` items: #{policy["run_list"]}" end unless errors.empty? raise PolicyfileError, "Policyfile fetched from #{policyfile_location} was invalid:\n#{errors.join("\n")}" end end |
#validate_recipe_spec(recipe_spec) ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
359 360 361 362 363 364 |
# File 'lib/chef/policy_builder/policyfile.rb', line 359 def validate_recipe_spec(recipe_spec) parse_recipe_spec(recipe_spec) nil rescue PolicyfileError => e e. end |