summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTim Hinderliter <tim@opscode.com>2011-03-07 09:27:49 -0800
committerTim Hinderliter <tim@opscode.com>2011-03-17 16:58:04 -0700
commit6a39638c07e215f13f6a9a064fba8a0bedda5180 (patch)
tree0b1b2b1e2ac6613e6ba5716cb730133ea4a14e6f
parent65ae97fab4193e7eb94473650585b1431a0cc5e7 (diff)
downloadchef-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.rb68
-rw-r--r--chef-server-api/config/router.rb1
-rw-r--r--chef-server-webui/app/controllers/roles.rb2
-rw-r--r--chef/lib/chef/environment.rb2
-rw-r--r--chef/lib/chef/node.rb4
-rw-r--r--chef/lib/chef/run_list.rb18
-rw-r--r--chef/lib/chef/run_list/run_list_expansion.rb2
-rw-r--r--chef/spec/unit/run_list/run_list_expansion_spec.rb4
-rw-r--r--chef/spec/unit/run_list_spec.rb24
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