Module: Chef::CookbookVersionSelector
- Defined in:
- lib/chef/cookbook_version_selector.rb
Class Method Summary collapse
-
.constrain(all_cookbooks, recipe_constraints) ⇒ Object
Return a hash mapping cookbook names to a CookbookVersion object.
-
.create_dependency_graph_from_cookbooks(all_cookbooks) ⇒ Object
all_cookbooks - a hash mapping cookbook names to an array of available CookbookVersions.
-
.expand_to_cookbook_versions(run_list, environment, couchdb = nil) ⇒ Object
Expands the run_list, constrained to the environment’s CookbookVersion constraints.
-
.filter_dep_selector_message(message) ⇒ Object
This method replaces verbiage from DepSelector messages with Chef-domain-specific verbiage, such as replacing package with cookbook.
Class Method Details
.constrain(all_cookbooks, recipe_constraints) ⇒ Object
Return a hash mapping cookbook names to a CookbookVersion object. If there is no solution that satisfies the constraints, the first run list item that caused unsatisfiability is returned.
This is the final version-resolved list of cookbooks for the RunList.
all_cookbooks - a hash mapping cookbook names to an array of available CookbookVersions.
recipe_constraints - an array of hashes describing the expanded run list. Each element is a hash containing keys :name and :version_constraint. The :name component is either the fully-qualified recipe name (e.g. “cookbook1::non_default_recipe”) or just a cookbook name, indicating the default recipe is to be run (e.g. “cookbook1”).
84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 |
# File 'lib/chef/cookbook_version_selector.rb', line 84 def self.constrain(all_cookbooks, recipe_constraints) dep_graph = create_dependency_graph_from_cookbooks(all_cookbooks) # extract cookbook names from (possibly) fully-qualified recipe names cookbook_constraints = recipe_constraints.map do |recipe_spec| cookbook_name = (recipe_spec[:name][/^(.+)::/, 1] || recipe_spec[:name]) DepSelector::SolutionConstraint.new(dep_graph.package(cookbook_name), recipe_spec[:version_constraint]) end # Pass in the list of all available cookbooks (packages) so that # DepSelector can distinguish between "no version available for # cookbook X" and "no such cookbook X" when an environment # filters out all versions for a given cookbook. all_packages = all_cookbooks.inject([]) do |acc, (cookbook_name, cookbook_versions)| acc << dep_graph.package(cookbook_name) acc end # find a valid assignment of CoookbookVersions. If no valid # assignment exists, indicate which run_list_item causes the # unsatisfiability and try to hint at what might be wrong. soln = begin DepSelector::Selector.new(dep_graph).find_solution(cookbook_constraints, all_packages) rescue DepSelector::Exceptions::InvalidSolutionConstraints => e non_existent_cookbooks = e.non_existent_packages.map {|constraint| constraint.package.name} cookbooks_with_no_matching_versions = e.constrained_to_no_versions.map {|constraint| constraint.package.name} # Spend a whole lot of effort for pluralizing and # prettifying the message. = "" if non_existent_cookbooks.length > 0 += "no such " + (non_existent_cookbooks.length > 1 ? "cookbooks" : "cookbook") += " #{non_existent_cookbooks.join(", ")}" end if cookbooks_with_no_matching_versions.length > 0 if .length > 0 += "; " end += "no versions match the constraints on " + (cookbooks_with_no_matching_versions.length > 1 ? "cookbooks" : "cookbook") += " #{cookbooks_with_no_matching_versions.join(", ")}" end = "Run list contains invalid items: #{}." raise Chef::Exceptions::CookbookVersionSelection::InvalidRunListItems.new(, non_existent_cookbooks, cookbooks_with_no_matching_versions) rescue DepSelector::Exceptions::NoSolutionExists => e raise Chef::Exceptions::CookbookVersionSelection::UnsatisfiableRunListItem.new((e.), e.unsatisfiable_solution_constraint, e.disabled_non_existent_packages, e.disabled_most_constrained_packages) end # map assignment back to CookbookVersion objects selected_cookbooks = {} soln.each_pair do |cb_name, cb_version| # TODO [cw, 2011/2/10]: related to the TODO in # create_dependency_graph_from_cookbooks, cbv.version # currently returns a String, so we must compare to # cb_version.to_s, since it's a for-real Version object. selected_cookbooks[cb_name] = all_cookbooks[cb_name].find{|cbv| cbv.version == cb_version.to_s} end selected_cookbooks end |
.create_dependency_graph_from_cookbooks(all_cookbooks) ⇒ Object
all_cookbooks - a hash mapping cookbook names to an array of available CookbookVersions.
Creates a DependencyGraph from CookbookVersion objects
41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 |
# File 'lib/chef/cookbook_version_selector.rb', line 41 def self.create_dependency_graph_from_cookbooks(all_cookbooks) dep_graph = DepSelector::DependencyGraph.new all_cookbooks.each do |cb_name, cb_versions| cb_versions.each do |cb_version| cb_version_deps = cb_version..dependencies # TODO [cw. 2011/2/10]: CookbookVersion#version returns a # String even though we're storing as a DepSelector::Version # object underneath. This should be changed so that we # return the object and handle proper serialization and # de-serialization. For now, I'm just going to create a # Version object from the String representation. pv = dep_graph.package(cb_name).add_version(Chef::Version.new(cb_version.version)) cb_version_deps.each_pair do |dep_name, constraint_str| # if the dependency is specified as cookbook::recipe, # extract the cookbook component dep_cb_name = dep_name.split("::").first constraint = Chef::VersionConstraint.new(constraint_str) pv.dependencies << DepSelector::Dependency.new(dep_graph.package(dep_cb_name), constraint) end end end dep_graph end |
.expand_to_cookbook_versions(run_list, environment, couchdb = nil) ⇒ Object
Expands the run_list, constrained to the environment’s CookbookVersion constraints.
Returns:
Hash of: name to CookbookVersion
155 156 157 158 159 160 161 162 163 164 165 166 |
# File 'lib/chef/cookbook_version_selector.rb', line 155 def self.(run_list, environment, couchdb=nil) # expand any roles in this run_list. = run_list.(environment, 'couchdb', :couchdb => couchdb).recipes.with_version_constraints cookbooks_for_environment = Chef::Environment.cdb_minimal_filtered_versions(environment, couchdb) cookbook_collection = constrain(cookbooks_for_environment, ) full_cookbooks = Chef::MinimalCookbookVersion.load_full_versions_of(cookbook_collection.values, couchdb) full_cookbooks.inject({}) do |cb_map, cookbook_version| cb_map[cookbook_version.name] = cookbook_version cb_map end end |
.filter_dep_selector_message(message) ⇒ Object
This method replaces verbiage from DepSelector messages with Chef-domain-specific verbiage, such as replacing package with cookbook.
TODO [cw, 2011/2/25]: this is a near-term hack. In the long run, we’ll do this better.
28 29 30 31 32 33 34 35 |
# File 'lib/chef/cookbook_version_selector.rb', line 28 def self.() m = m.gsub!("Package", "Cookbook") m.gsub!("package", "cookbook") m.gsub!("Solution constraint", "Run list item") m.gsub!("solution constraint", "run list item") m end |