diff options
author | Tim Hinderliter <tim@opscode.com> | 2011-03-07 09:27:49 -0800 |
---|---|---|
committer | Tim Hinderliter <tim@opscode.com> | 2011-03-17 16:58:04 -0700 |
commit | 6a39638c07e215f13f6a9a064fba8a0bedda5180 (patch) | |
tree | 0b1b2b1e2ac6613e6ba5716cb730133ea4a14e6f | |
parent | 65ae97fab4193e7eb94473650585b1431a0cc5e7 (diff) | |
download | chef-6a39638c07e215f13f6a9a064fba8a0bedda5180.tar.gz |
added /environments/:env_id/cookbook_versions endpoint
* pass in a run_list and environment and get back the
cookbook versions after applying the environment's
version constraints
* RunList#expand_to_cookbook_versions is method used
to implement this
refactored RunList#expand and friends to require environment
argument instead of making it optional with default of '_default'
added RunList#
-rw-r--r-- | chef-server-api/app/controllers/environments.rb | 68 | ||||
-rw-r--r-- | chef-server-api/config/router.rb | 1 | ||||
-rw-r--r-- | chef-server-webui/app/controllers/roles.rb | 2 | ||||
-rw-r--r-- | chef/lib/chef/environment.rb | 2 | ||||
-rw-r--r-- | chef/lib/chef/node.rb | 4 | ||||
-rw-r--r-- | chef/lib/chef/run_list.rb | 18 | ||||
-rw-r--r-- | chef/lib/chef/run_list/run_list_expansion.rb | 2 | ||||
-rw-r--r-- | chef/spec/unit/run_list/run_list_expansion_spec.rb | 4 | ||||
-rw-r--r-- | chef/spec/unit/run_list_spec.rb | 24 |
9 files changed, 102 insertions, 23 deletions
diff --git a/chef-server-api/app/controllers/environments.rb b/chef-server-api/app/controllers/environments.rb index d3d8a7da4d..baa7a74276 100644 --- a/chef-server-api/app/controllers/environments.rb +++ b/chef-server-api/app/controllers/environments.rb @@ -1,6 +1,7 @@ # # Author:: Stephen Delano (<stephen@opscode.com>) -# Copyright:: Copyright (c) 2010 Opscode, Inc. +# Author:: Tim Hinderliter (<tim@opscode.com>) +# Copyright:: Copyright (c) 2010, 2011 Opscode, Inc. # License:: Apache License, Version 2.0 # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -109,6 +110,71 @@ class Environments < Application }) end + # POST /environment/:environment_id/cookbook_versions + # + # Take the given run_list and return the versions of cookbooks that would + # be used after applying the constraints of the given environment. + # + # INPUT: + # :run_list = an Array of String's, e.g., + # ["recipe[apache2]", "recipe[runit]"] + # + # OUT: + # Hash of cookbook names to version/url hash, e.g., + # { + # "apache2": { + # "version": "1.2.3", + # "url" => "http://.../cookbooks/apache2/1.2.3" + # }, + # "runit": { + # "version": "2.3.4", + # "url" => "http://.../cookbooks/runit/2.3.4" + # } + # } + # + # NOTE: This method is a POST, not because it's a mutator (it's idempotent), + # but the run_list can likely exceed Merb's query string limit for GET + # of 1024 characters. + def cookbook_versions_for_run_list + begin + # not possible to be nil due to the route to get us to this API + # endpoint + environment_input = params[:environment_id] + + run_list_input = params[:run_list] + raise BadRequest, "Missing param: run_list" unless run_list_input + raise BadRequest, "Param run_list is not an Array: #{run_list_input.class}" unless run_list_input.is_a?(Array) + + # Convert the input array of strings to a RunList containing + # RunListItem's. + run_list = Chef::RunList.new + run_list_input.each do |run_list_item_string| + run_list << run_list_item_string + end + + # Expand the run list in the scope of the specified environment. + names_to_cookbook_version = run_list.expand_to_cookbook_versions(environment_input, 'couchdb') + rescue Chef::Exceptions::CouchDBNotFound + raise NotFound, "Cannot load environment #{params[:environment_id]}" + end + + # convert the hash which is + # name => CookbookVersion + # to + # name => {:version => version, :url => url} + names_to_url_and_version = names_to_cookbook_version.values.inject({}) do |res, cb_version| + name = cb_version.name + res[name] = { + :version => cb_version.version, + :url => absolute_url(:cookbook_version, :cookbook_name => name, :cookbook_version => cb_version.version) + } + res + end + + display(names_to_url_and_version) + end + + # GET /environments/:environment_id/cookbooks/:cookbook_id # returns data in the format of: # {"apache2" => { diff --git a/chef-server-api/config/router.rb b/chef-server-api/config/router.rb index 7f9e701b87..2a128b3652 100644 --- a/chef-server-api/config/router.rb +++ b/chef-server-api/config/router.rb @@ -39,6 +39,7 @@ Merb::Router.prepare do e.match("/recipes", :method => "get").to(:controller=>"environments", :action=>"list_recipes") e.match("/nodes", :method => "get").to(:controller=>"environments", :action=>"list_nodes") e.match("/roles/:role_id", :method => "get").to(:controller=>"environments", :action => "role") + e.match("/cookbook_versions", :method => "post").to(:controller=>"environments", :action=>"cookbook_versions_for_run_list") end # Status diff --git a/chef-server-webui/app/controllers/roles.rb b/chef-server-webui/app/controllers/roles.rb index f4e192818c..9d85ea7686 100644 --- a/chef-server-webui/app/controllers/roles.rb +++ b/chef-server-webui/app/controllers/roles.rb @@ -50,7 +50,7 @@ class Roles < Application @current_env = session[:environment] || "_default" @env_run_list_exists = @role.env_run_lists.has_key?(@current_env) @run_list = @role.run_list_for(@current_env) - @recipes = @run_list.expand('server').recipes + @recipes = @run_list.expand(@current_env, 'server').recipes render end diff --git a/chef/lib/chef/environment.rb b/chef/lib/chef/environment.rb index d38f7d4972..a38987e72b 100644 --- a/chef/lib/chef/environment.rb +++ b/chef/lib/chef/environment.rb @@ -302,7 +302,7 @@ class Chef # Hash # i.e. # { - # "coobook_name" => [ Chef::CookbookVersion ... ] ## the array of CookbookVersions is sorted highest to lowest + # "cookbook_name" => [ Chef::CookbookVersion ... ] ## the array of CookbookVersions is sorted highest to lowest # } # # There will be a key for every cookbook. If no CookbookVersions diff --git a/chef/lib/chef/node.rb b/chef/lib/chef/node.rb index 3e8e4918a5..0f7bc5f905 100644 --- a/chef/lib/chef/node.rb +++ b/chef/lib/chef/node.rb @@ -426,7 +426,7 @@ class Chef # invalidated only when run_list is mutated? def expand! # This call should only be called on a chef-client run if you're going to save it later - expansion = run_list.expand('server', :environment => chef_environment) + expansion = run_list.expand(chef_environment, 'server') raise Chef::Exceptions::MissingRole if expansion.errors? self[:tags] = Array.new unless attribute?(:tags) @@ -441,7 +441,7 @@ class Chef end def constrain_cookbooks(all_cookbooks, source) - cookbook_constraints = run_list.expand(source).recipes.with_version_constraints + cookbook_constraints = run_list.expand(chef_environment, source).recipes.with_version_constraints run_list.constrain(all_cookbooks, cookbook_constraints) end diff --git a/chef/lib/chef/run_list.rb b/chef/lib/chef/run_list.rb index 7b152cd781..a5c3f95a91 100644 --- a/chef/lib/chef/run_list.rb +++ b/chef/lib/chef/run_list.rb @@ -131,13 +131,25 @@ class Chef end alias :delete :remove - - def expand(data_source='server', expansion_opts={}) + def expand(environment, data_source='server', expansion_opts={}) expansion = expansion_for_data_source(data_source, expansion_opts) - expansion.expand(expansion_opts[:environment]) + expansion.expand(environment) expansion end + # Expands this run_list, constrained to the environment's CookbookVersion + # constraints. + # + # Returns: + # Hash of: name to CookbookVersion + def expand_to_cookbook_versions(environment, data_source='server', expansion_opts={}) + # expand any roles in this run_list. + expanded_run_list = expand(environment, data_source, expansion_opts).recipes.with_version_constraints + + cookbooks_for_environment = Chef::Environment.cdb_load_filtered_cookbook_versions(environment) + constrain(cookbooks_for_environment, expanded_run_list) + end + # Converts a string run list entry to a RunListItem object. def parse_entry(entry) RunListItem.new(entry) diff --git a/chef/lib/chef/run_list/run_list_expansion.rb b/chef/lib/chef/run_list/run_list_expansion.rb index 7323dba7be..fac5fa596f 100644 --- a/chef/lib/chef/run_list/run_list_expansion.rb +++ b/chef/lib/chef/run_list/run_list_expansion.rb @@ -67,7 +67,7 @@ class Chef # Iterates over the run list items, expanding roles. After this, # +recipes+ will contain the fully expanded recipe list - def expand(environment='_default') + def expand(environment) @run_list_items.each_with_index do |entry, index| case entry.type when :recipe diff --git a/chef/spec/unit/run_list/run_list_expansion_spec.rb b/chef/spec/unit/run_list/run_list_expansion_spec.rb index 52a7665167..f2829c8041 100644 --- a/chef/spec/unit/run_list/run_list_expansion_spec.rb +++ b/chef/spec/unit/run_list/run_list_expansion_spec.rb @@ -68,7 +68,7 @@ describe Chef::RunList::RunListExpansion do @inflated_role.default_attributes({'foo' => 'bar'}) @inflated_role.override_attributes({'baz' => 'qux'}) @expansion.stub!(:fetch_role).and_return(@inflated_role) - @expansion.expand + @expansion.expand("_default") end it "has the ordered list of recipes" do @@ -89,7 +89,7 @@ describe Chef::RunList::RunListExpansion do describe "after expanding a run list with a non existant role" do before do @expansion.stub!(:fetch_role) { @expansion.role_not_found('crabrevenge') } - @expansion.expand + @expansion.expand("_default") end it "is invalid" do diff --git a/chef/spec/unit/run_list_spec.rb b/chef/spec/unit/run_list_spec.rb index b9e4fbebe1..695387f9c9 100644 --- a/chef/spec/unit/run_list_spec.rb +++ b/chef/spec/unit/run_list_spec.rb @@ -172,26 +172,26 @@ describe Chef::RunList do describe "from disk" do it "should load the role from disk" do Chef::Role.should_receive(:from_disk).with("stubby") - @run_list.expand("disk") + @run_list.expand("_default", "disk") end it "should log a helpful error if the role is not available" do Chef::Role.stub!(:from_disk).and_raise(Chef::Exceptions::RoleNotFound) Chef::Log.should_receive(:error).with("Role stubby is in the runlist but does not exist. Skipping expand.") - @run_list.expand("disk") + @run_list.expand("_default", "disk") end end describe "from the chef server" do it "should load the role from the chef server" do #@rest.should_receive(:get_rest).with("roles/stubby") - expansion = @run_list.expand("server") + expansion = @run_list.expand("_default", "server") expansion.recipes.should == ['one', 'two', 'kitty'] end it "should default to expanding from the server" do @rest.should_receive(:get_rest).with("roles/stubby") - @run_list.expand + @run_list.expand("_default") end describe "with an environment set" do @@ -200,7 +200,7 @@ describe Chef::RunList do end it "expands the run list using the environment specific run list" do - expansion = @run_list.expand("server", :environment => "production") + expansion = @run_list.expand("production", "server") expansion.recipes.should == %w{one two five kitty} end @@ -226,7 +226,7 @@ describe Chef::RunList do @multiple_rest_requests.should_receive(:get_rest).with("roles/prod-base").and_return(@role_prod_base) @multiple_rest_requests.should_receive(:get_rest).with("roles/nested-deeper").and_return(@role_nested_deeper) - expansion = @run_list.expand("server", :environment => "production") + expansion = @run_list.expand("production", "server") expansion.recipes.should == %w{one two five prod-secret-sauce kitty} end @@ -239,23 +239,23 @@ describe Chef::RunList do describe "from couchdb" do it "should load the role from couchdb" do Chef::Role.should_receive(:cdb_load).and_return(@role) - @run_list.expand("couchdb") + @run_list.expand("_default", "couchdb") end end it "should return the list of expanded recipes" do - expansion = @run_list.expand + expansion = @run_list.expand("_default") expansion.recipes[0].should == "one" expansion.recipes[1].should == "two" end it "should return the list of default attributes" do - expansion = @run_list.expand + expansion = @run_list.expand("_default") expansion.default_attrs[:one].should == :two end it "should return the list of override attributes" do - expansion = @run_list.expand + expansion = @run_list.expand("_default") expansion.override_attrs[:three].should == :four end @@ -268,7 +268,7 @@ describe Chef::RunList do Chef::Role.stub!(:from_disk).with("stubby").and_return(@role) Chef::Role.stub!(:from_disk).with("dog").and_return(dog) - expansion = @run_list.expand('disk') + expansion = @run_list.expand("_default", 'disk') expansion.recipes[2].should == "three" expansion.default_attrs[:seven].should == :nine end @@ -282,7 +282,7 @@ describe Chef::RunList do Chef::Role.stub!(:from_disk).with("stubby").and_return(@role) Chef::Role.should_receive(:from_disk).with("dog").once.and_return(dog) - expansion = @run_list.expand('disk') + expansion = @run_list.expand("_default", 'disk') expansion.recipes[2].should == "three" expansion.recipes[3].should == "kitty" expansion.default_attrs[:seven].should == :nine |