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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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: