chef-server-api 0.9.18 → 0.10.0.beta.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,139 @@
1
+ #
2
+ # Author:: Tim Hinderliter (<tim@opscode.com>)
3
+ # Copyright:: Copyright (c) 2011 Opscode, Inc.
4
+ # License:: Apache License, Version 2.0
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+ #
18
+
19
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
20
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_model_helper')
21
+ require 'chef/node'
22
+ require 'pp'
23
+
24
+ describe "Environments controller" do
25
+ before do
26
+ Merb.logger.set_log(StringIO.new)
27
+
28
+ @env1 = make_environment("env1")
29
+
30
+ @filtered_cookbook_list_env1 = make_filtered_cookbook_hash(make_cookbook("cookbook1", "1.0.0"),
31
+ make_cookbook("cookbook2", "1.0.0"))
32
+ @filtered_cookbook_list_env1["cookbook_noversions"] = Array.new
33
+
34
+ @filtered_cookbook_list_env2 = make_filtered_cookbook_hash(make_cookbook("cookbook1", "2.0.0"),
35
+ make_cookbook("cookbook2", "2.0.0"))
36
+
37
+ @filtered_cookbook_list_env_many_versions = make_filtered_cookbook_hash(make_cookbook("cookbook1", "1.0.0"),
38
+ make_cookbook("cookbook1", "2.0.0"),
39
+ make_cookbook("cookbook1", "3.0.0"),
40
+ make_cookbook("cookbook1", "4.0.0"))
41
+
42
+ @cookbook_deps_on_nosuch = make_cookbook("cookbook_deps_on_nosuch", "1.0.0")
43
+ @cookbook_deps_on_nosuch.metadata.depends("cookbook_nosuch")
44
+
45
+ @cookbook_deps_on_badver = make_cookbook("cookbook_deps_on_badver", "1.0.0")
46
+ @cookbook_deps_on_badver.metadata.depends("cookbook1", ">= 3.0.0")
47
+ end
48
+
49
+ describe "when handling Environments API calls" do
50
+ it "should expand the passed-in run_list using the correct environment: one run_list item" do
51
+
52
+ # Env1 pins both versions at 1.0.0. Expect only the one we ask for, cookbook1,
53
+ # back in the result.
54
+ Chef::Environment.should_receive(:cdb_load_filtered_cookbook_versions).with("env1").and_return(@filtered_cookbook_list_env1)
55
+ response = post_json("/environments/env1/cookbook_versions", {"run_list" => ["recipe[cookbook1]"]})
56
+ response.should be_kind_of(Hash)
57
+ response.keys.size.should == 1
58
+ response["cookbook1"].should_not == nil
59
+ response["cookbook1"]['version'].should == "1.0.0"
60
+ end
61
+
62
+ it "should expect the passed-in run_list using the correct environment: two run_list items" do
63
+ # Ask for both cookbook1 and cookbook2 back. Expect version 2.0.0 for
64
+ # each, as those are what's appropriate for the environment.
65
+ Chef::Environment.should_receive(:cdb_load_filtered_cookbook_versions).with("env2").and_return(@filtered_cookbook_list_env2)
66
+ response = post_json("/environments/env2/cookbook_versions", {"run_list" => ["recipe[cookbook2]", "recipe[cookbook1]"]})
67
+ response.should be_kind_of(Hash)
68
+ response.keys.size.should == 2
69
+ response["cookbook1"].should_not == nil
70
+ response["cookbook1"]['version'].should == "2.0.0"
71
+ response["cookbook2"].should_not == nil
72
+ response["cookbook2"]['version'].should == "2.0.0"
73
+ end
74
+
75
+ it "should return the newest version of a cookbook when given multiple versions" do
76
+ Chef::Environment.should_receive(:cdb_load_filtered_cookbook_versions).with("env_many_versions").and_return(@filtered_cookbook_list_env_many_versions)
77
+ response = post_json("/environments/env_many_versions/cookbook_versions", {"run_list" => ["recipe[cookbook1]"]})
78
+
79
+ response.should be_kind_of(Hash)
80
+ response.keys.size.should == 1
81
+ response["cookbook1"].should_not == nil
82
+ response["cookbook1"]['version'].should == "4.0.0"
83
+ end
84
+
85
+ it "should return the asked-for, older version of a cookbook if the version is specified in the run_list" do
86
+ Chef::Environment.should_receive(:cdb_load_filtered_cookbook_versions).with("env_many_versions").and_return(@filtered_cookbook_list_env_many_versions)
87
+ response = post_json("/environments/env_many_versions/cookbook_versions", {"run_list" => ["recipe[cookbook1@1.0.0]"]})
88
+
89
+ response.should be_kind_of(Hash)
90
+ response.keys.size.should == 1
91
+ response["cookbook1"].should_not == nil
92
+ response["cookbook1"]['version'].should == "1.0.0"
93
+ end
94
+
95
+ it "should report no_such_cookbook if given a dependency on a non-existant cookbook" do
96
+ Chef::Environment.should_receive(:cdb_load_filtered_cookbook_versions).with("env1").and_return(@filtered_cookbook_list_env1)
97
+ expected_error = {
98
+ "message" => "Run list contains invalid items: no such cookbook cookbook_nosuch.",
99
+ "non_existent_cookbooks" => ["cookbook_nosuch"],
100
+ "cookbooks_with_no_versions" => []
101
+ }.to_json
102
+
103
+ lambda {
104
+ response = post_json("/environments/env1/cookbook_versions", {"run_list" => ["recipe[cookbook_nosuch]"]})
105
+ }.should raise_error(Merb::ControllerExceptions::PreconditionFailed, expected_error)
106
+ end
107
+
108
+ it "should report no_such_version if given a dependency on a cookbook that doesn't have any valid versions for an environment" do
109
+ Chef::Environment.should_receive(:cdb_load_filtered_cookbook_versions).with("env1").and_return(@filtered_cookbook_list_env1)
110
+ expected_error = {
111
+ "message" => "Run list contains invalid items: no versions match the constraints on cookbook cookbook_noversions.",
112
+ "non_existent_cookbooks" => [],
113
+ "cookbooks_with_no_versions" => ["cookbook_noversions"]
114
+ }.to_json
115
+
116
+ lambda {
117
+ response = post_json("/environments/env1/cookbook_versions", {"run_list" => ["recipe[cookbook_noversions]"]})
118
+ }.should raise_error(Merb::ControllerExceptions::PreconditionFailed, expected_error)
119
+ end
120
+
121
+ # TODO; have top-level cookbooks depend on other, non-existent cookbooks,
122
+ # to get the other kind of exceptions.
123
+ it "should report multiple failures (compound exceptions) if there is more than one error in dependencies" do
124
+ Chef::Environment.should_receive(:cdb_load_filtered_cookbook_versions).with("env1").and_return(@filtered_cookbook_list_env1)
125
+
126
+ expected_error = {
127
+ "message" => "Run list contains invalid items: no such cookbooks cookbook_nosuch_1, cookbook_nosuch_2; no versions match the constraints on cookbook cookbook_noversions.",
128
+ "non_existent_cookbooks" => ["cookbook_nosuch_1", "cookbook_nosuch_2"],
129
+ "cookbooks_with_no_versions" => ["cookbook_noversions"]
130
+ }.to_json
131
+
132
+ lambda {
133
+ response = post_json("/environments/env1/cookbook_versions",
134
+ {"run_list" => ["recipe[cookbook_nosuch_1]", "recipe[cookbook_nosuch_2]", "recipe[cookbook_noversions]"]})
135
+ }.should raise_error(Merb::ControllerExceptions::PreconditionFailed, expected_error)
136
+ end
137
+ end
138
+ end
139
+
@@ -0,0 +1,132 @@
1
+ #
2
+ # Author:: Tim Hinderliter (<tim@opscode.com>)
3
+ # Copyright:: Copyright (c) 2011 Opscode, Inc.
4
+ # License:: Apache License, Version 2.0
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+ #
18
+
19
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
20
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_model_helper')
21
+ require 'chef/node'
22
+ require 'pp'
23
+
24
+ describe "Nodes controller - environments and run_list expansion" do
25
+ before do
26
+ Merb.logger.set_log(StringIO.new)
27
+
28
+ # Node 'node1':
29
+ # contains 'role[role1]'
30
+ #
31
+ # Role 'role1':
32
+ # for env '_default', contains 'recipe[cb_for_default]'
33
+ # for env 'env1', contains 'recipe[cb_for_env1]'
34
+ # for env 'env_fallback', contains nothing (should fall back to _default).
35
+ #
36
+ # Check that the node returns the right expanded run list no matter the
37
+ # environment it's in.
38
+ @node1 = make_node("node1")
39
+ @node1.run_list << "role[role1]"
40
+
41
+ @node_containing_nosuch_cookbook = make_node("node_containing_nosuch_cookbook")
42
+ @node_containing_nosuch_cookbook.run_list << "recipe[cookbook_nosuch]"
43
+
44
+ @node_containing_role_containing_nosuch_cookbook = make_node("node_containing_role_containing_nosuch_cookbook")
45
+ @node_containing_role_containing_nosuch_cookbook.run_list << "role[role_containing_nosuch_cookbook]"
46
+
47
+ @role1 = make_role("role1")
48
+ @role1.env_run_lists({"_default" => make_runlist("recipe[cb_for_default]"), "env1" => make_runlist("recipe[cb_for_env1]")})
49
+
50
+ @role_containing_nosuch_cookbook = make_role("role_containing_nosuch_cookbook")
51
+ @role_containing_nosuch_cookbook.env_run_lists({"_default" => make_runlist("recipe[cookbook_nosuch]")})
52
+
53
+ @all_filtered_cookbook_list =
54
+ make_filtered_cookbook_hash(make_cookbook("cb_for_default", "1.0.0"),
55
+ make_cookbook("cb_for_env1", "1.0.0"))
56
+ end
57
+
58
+ describe "when handling Node API calls" do
59
+ it "should expand role and cookbook dependencies using the _default environment" do
60
+ # Test that node@_default resolves to use cookbook cb_for_default
61
+ Chef::Node.should_receive(:cdb_load).with("node1").and_return(@node1)
62
+ Chef::Role.should_receive(:cdb_load).with("role1", nil).and_return(@role1)
63
+ Chef::Environment.should_receive(:cdb_load_filtered_cookbook_versions).with("_default").and_return(@all_filtered_cookbook_list)
64
+
65
+ response = get_json("/nodes/node1/cookbooks")
66
+ response.should be_kind_of(Hash)
67
+ response["cb_for_default"].should_not == nil
68
+ response["cb_for_env1"].should == nil
69
+ end
70
+
71
+ it "should expand role and cookbook dependencies using the env1 environment" do
72
+ # Test that node@env1 resolves to use cookbook cb_for_env1
73
+ @node1.chef_environment("env1")
74
+ Chef::Node.should_receive(:cdb_load).with("node1").and_return(@node1)
75
+ Chef::Role.should_receive(:cdb_load).with("role1", nil).and_return(@role1)
76
+ Chef::Environment.should_receive(:cdb_load_filtered_cookbook_versions).with("env1").and_return(@all_filtered_cookbook_list)
77
+
78
+ response = get_json("/nodes/node1/cookbooks")
79
+ response.should be_kind_of(Hash)
80
+ response["cb_for_default"].should == nil
81
+ response["cb_for_env1"].should_not == nil
82
+ end
83
+
84
+ it "should expand role and cookbook dependencies using the _default environment, when passed an empty environment" do
85
+ # Test that node@env_fallback resolves to use cookbook cb_for_default
86
+ # because env_fallback falls back to _default
87
+ @node1.chef_environment("env_fallback")
88
+ Chef::Node.should_receive(:cdb_load).with("node1").and_return(@node1)
89
+ Chef::Role.should_receive(:cdb_load).with("role1", nil).and_return(@role1)
90
+ Chef::Environment.should_receive(:cdb_load_filtered_cookbook_versions).with("env_fallback").and_return(@all_filtered_cookbook_list)
91
+
92
+ response = get_json("/nodes/node1/cookbooks")
93
+ response.should be_kind_of(Hash)
94
+ response["cb_for_default"].should_not == nil
95
+ response["cb_for_env1"].should == nil
96
+ end
97
+
98
+ it "should throw the proper exception when a node's run_list contains a non-existent cookbook" do
99
+ expected_error = {
100
+ "message" => "Run list contains invalid items: no such cookbook cookbook_nosuch.",
101
+ "non_existent_cookbooks" => ["cookbook_nosuch"],
102
+ "cookbooks_with_no_versions" => []
103
+ }.to_json
104
+
105
+ Chef::Node.should_receive(:cdb_load).with("node_containing_nosuch_cookbook").and_return(@node_containing_nosuch_cookbook)
106
+ Chef::Environment.should_receive(:cdb_load_filtered_cookbook_versions).with("_default").and_return(@all_filtered_cookbook_list)
107
+
108
+ lambda {
109
+ response = get_json("/nodes/node_containing_nosuch_cookbook/cookbooks")
110
+ }.should raise_error(Merb::ControllerExceptions::PreconditionFailed, expected_error)
111
+ end
112
+
113
+
114
+ it "should throw the proper exception when a node's run_list contains a role that contains a non-existent cookbook" do
115
+ expected_error = {
116
+ "message" => "Run list contains invalid items: no such cookbook cookbook_nosuch.",
117
+ "non_existent_cookbooks" => ["cookbook_nosuch"],
118
+ "cookbooks_with_no_versions" => []
119
+ }.to_json
120
+
121
+ Chef::Node.should_receive(:cdb_load).with("node_containing_role_containing_nosuch_cookbook").and_return(@node_containing_role_containing_nosuch_cookbook)
122
+ Chef::Role.should_receive(:cdb_load).with("role_containing_nosuch_cookbook", nil).and_return(@role_containing_nosuch_cookbook)
123
+ Chef::Environment.should_receive(:cdb_load_filtered_cookbook_versions).with("_default").and_return(@all_filtered_cookbook_list)
124
+
125
+ lambda {
126
+ response = get_json("/nodes/node_containing_role_containing_nosuch_cookbook/cookbooks")
127
+ }.should raise_error(Merb::ControllerExceptions::PreconditionFailed, expected_error)
128
+ end
129
+
130
+ end
131
+ end
132
+
@@ -0,0 +1,81 @@
1
+ #
2
+ # Author:: Tim Hinderliter (<tim@opscode.com>)
3
+ # Copyright:: Copyright (c) 2011 Opscode, Inc.
4
+ # License:: Apache License, Version 2.0
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+ #
18
+
19
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
20
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_model_helper')
21
+ require 'chef/node'
22
+ require 'pp'
23
+
24
+ describe "Nodes controller" do
25
+ before do
26
+ Merb.logger.set_log(StringIO.new)
27
+ end
28
+
29
+ describe "when handling Node API calls" do
30
+ it "returns a list of nodes" do
31
+ returned_node_list = ["node1", "node2"]
32
+ Chef::Node.stub!(:cdb_list).and_return(returned_node_list)
33
+
34
+ res = get_json("/nodes")
35
+
36
+ expected_response = returned_node_list.inject({}) do |res,node_name|
37
+ res[node_name] = "#{root_url}/#{node_name}"
38
+ res
39
+ end
40
+ res.should == expected_response
41
+ end
42
+
43
+ it "returns an existing node" do
44
+ returned_node = make_node("node1")
45
+ Chef::Node.stub!(:cdb_load).and_return(returned_node)
46
+
47
+ response = get_json("/nodes/node1")
48
+ response.name.should == returned_node.name
49
+ end
50
+
51
+ it "returns a 404 when a non-existant node is shown" do
52
+ Chef::Node.should_receive(:cdb_load).with("node1").and_raise(Chef::Exceptions::CouchDBNotFound)
53
+
54
+ lambda {
55
+ get_json("/nodes/node1")
56
+ }.should raise_error(Merb::ControllerExceptions::NotFound)
57
+ end
58
+
59
+ it "creates a node if no same-named node exists" do
60
+ create_node = make_node("node1")
61
+
62
+ Chef::Node.should_receive(:cdb_load).with("node1").and_raise(Chef::Exceptions::CouchDBNotFound)
63
+ create_node.should_receive(:cdb_save)
64
+
65
+ response = post_json("/nodes", create_node)
66
+ response.should == {"uri" => "#{root_url}/nodes/node1"}
67
+ end
68
+
69
+ it "raises a Conflict if you create a node whose name already exists" do
70
+ create_node = make_node("node1")
71
+ existing_node = make_node("node1")
72
+
73
+ Chef::Node.should_receive(:cdb_load).with("node1").and_return(existing_node)
74
+
75
+ lambda {
76
+ post_json("/nodes", create_node)
77
+ }.should raise_error(Merb::ControllerExceptions::Conflict)
78
+ end
79
+ end
80
+ end
81
+
metadata CHANGED
@@ -1,8 +1,8 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: chef-server-api
3
3
  version: !ruby/object:Gem::Version
4
- prerelease:
5
- version: 0.9.18
4
+ prerelease: 7
5
+ version: 0.10.0.beta.0
6
6
  platform: ruby
7
7
  authors:
8
8
  - Opscode
@@ -10,7 +10,7 @@ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
12
 
13
- date: 2011-06-29 00:00:00 -07:00
13
+ date: 2011-03-28 00:00:00 -07:00
14
14
  default_executable:
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
@@ -69,8 +69,19 @@ dependencies:
69
69
  prerelease: false
70
70
  version_requirements: *id005
71
71
  - !ruby/object:Gem::Dependency
72
- name: json
72
+ name: dep_selector
73
73
  requirement: &id006 !ruby/object:Gem::Requirement
74
+ none: false
75
+ requirements:
76
+ - - ">="
77
+ - !ruby/object:Gem::Version
78
+ version: 0.0.3
79
+ type: :runtime
80
+ prerelease: false
81
+ version_requirements: *id006
82
+ - !ruby/object:Gem::Dependency
83
+ name: json
84
+ requirement: &id007 !ruby/object:Gem::Requirement
74
85
  none: false
75
86
  requirements:
76
87
  - - ">="
@@ -81,10 +92,10 @@ dependencies:
81
92
  version: 1.4.6
82
93
  type: :runtime
83
94
  prerelease: false
84
- version_requirements: *id006
95
+ version_requirements: *id007
85
96
  - !ruby/object:Gem::Dependency
86
97
  name: uuidtools
87
- requirement: &id007 !ruby/object:Gem::Requirement
98
+ requirement: &id008 !ruby/object:Gem::Requirement
88
99
  none: false
89
100
  requirements:
90
101
  - - ~>
@@ -92,10 +103,10 @@ dependencies:
92
103
  version: 2.1.1
93
104
  type: :runtime
94
105
  prerelease: false
95
- version_requirements: *id007
106
+ version_requirements: *id008
96
107
  - !ruby/object:Gem::Dependency
97
108
  name: thin
98
- requirement: &id008 !ruby/object:Gem::Requirement
109
+ requirement: &id009 !ruby/object:Gem::Requirement
99
110
  none: false
100
111
  requirements:
101
112
  - - ">="
@@ -103,7 +114,18 @@ dependencies:
103
114
  version: "0"
104
115
  type: :runtime
105
116
  prerelease: false
106
- version_requirements: *id008
117
+ version_requirements: *id009
118
+ - !ruby/object:Gem::Dependency
119
+ name: dep_selector
120
+ requirement: &id010 !ruby/object:Gem::Requirement
121
+ none: false
122
+ requirements:
123
+ - - ">="
124
+ - !ruby/object:Gem::Version
125
+ version: "0"
126
+ type: :runtime
127
+ prerelease: false
128
+ version_requirements: *id010
107
129
  description: A systems integration framework, built to bring the benefits of configuration management to your entire infrastructure.
108
130
  email: chef@opscode.com
109
131
  executables:
@@ -127,12 +149,17 @@ files:
127
149
  - lib/chef-server-api.rb
128
150
  - spec/spec.opts
129
151
  - spec/spec_helper.rb
152
+ - spec/spec_model_helper.rb
153
+ - spec/unit/environments_controller_spec.rb
154
+ - spec/unit/nodes_controller_environments_spec.rb
155
+ - spec/unit/nodes_controller_spec.rb
130
156
  - spec/unit/sandbox_file_spec.rb
131
157
  - app/controllers/application.rb
132
158
  - app/controllers/clients.rb
133
159
  - app/controllers/cookbooks.rb
134
160
  - app/controllers/data_bags.rb
135
161
  - app/controllers/data_item.rb
162
+ - app/controllers/environments.rb
136
163
  - app/controllers/exceptions.rb
137
164
  - app/controllers/main.rb
138
165
  - app/controllers/nodes.rb
@@ -140,6 +167,7 @@ files:
140
167
  - app/controllers/sandboxes.rb
141
168
  - app/controllers/search.rb
142
169
  - app/controllers/users.rb
170
+ - app/helpers/cookbook_version_helper.rb
143
171
  - app/helpers/tarball_helper.rb
144
172
  - app/models/sandbox_file.rb
145
173
  - app/views/exceptions/bad_request.json.erb
@@ -147,8 +175,8 @@ files:
147
175
  - app/views/exceptions/not_acceptable.html.haml
148
176
  - app/views/exceptions/not_found.html.erb
149
177
  - app/views/exceptions/standard_error.html.erb
150
- - app/views/layout/chef_server_api.html.haml
151
- - app/views/main/index.html.haml
178
+ - app/views/layout/application.html.erb
179
+ - app/views/main/index.html.erb
152
180
  - public/images/avatar.png
153
181
  - public/images/indicator.gif
154
182
  - public/images/merb.jpg
@@ -183,9 +211,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
183
211
  required_rubygems_version: !ruby/object:Gem::Requirement
184
212
  none: false
185
213
  requirements:
186
- - - ">="
214
+ - - ">"
187
215
  - !ruby/object:Gem::Version
188
- version: "0"
216
+ version: 1.3.1
189
217
  requirements: []
190
218
 
191
219
  rubyforge_project: