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.
- data/README.rdoc +0 -1
- data/app/controllers/application.rb +1 -1
- data/app/controllers/cookbooks.rb +51 -36
- data/app/controllers/environments.rb +207 -0
- data/app/controllers/main.rb +17 -10
- data/app/controllers/nodes.rb +34 -88
- data/app/controllers/roles.rb +23 -5
- data/app/controllers/search.rb +6 -16
- data/app/helpers/cookbook_version_helper.rb +72 -0
- data/app/views/layout/application.html.erb +49 -0
- data/app/views/main/index.html.erb +0 -0
- data/bin/chef-server +1 -0
- data/config/init.rb +6 -0
- data/config/rack.rb +3 -0
- data/config/router.rb +20 -7
- data/lib/chef-server-api/version.rb +1 -1
- data/spec/spec_helper.rb +82 -5
- data/spec/spec_model_helper.rb +67 -0
- data/spec/unit/environments_controller_spec.rb +139 -0
- data/spec/unit/nodes_controller_environments_spec.rb +132 -0
- data/spec/unit/nodes_controller_spec.rb +81 -0
- metadata +41 -13
- data/app/views/layout/chef_server_api.html.haml +0 -23
- data/app/views/main/index.html.haml +0 -5
data/README.rdoc
CHANGED
@@ -45,7 +45,7 @@ class Application < Merb::Controller
|
|
45
45
|
authenticator.authenticate_request(user_key)
|
46
46
|
rescue Mixlib::Authentication::MissingAuthenticationHeader => e
|
47
47
|
Chef::Log.debug "Authentication failed: #{e.class.name}: #{e.message}\n#{e.backtrace.join("\n")}"
|
48
|
-
raise
|
48
|
+
raise BadRequest, "#{e.class.name}: #{e.message}"
|
49
49
|
rescue StandardError => se
|
50
50
|
Chef::Log.debug "Authentication failed: #{se}, #{se.backtrace.join("\n")}"
|
51
51
|
raise Unauthorized, "Failed to authenticate. Ensure that your client key is valid."
|
@@ -9,9 +9,9 @@
|
|
9
9
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
10
10
|
# you may not use this file except in compliance with the License.
|
11
11
|
# You may obtain a copy of the License at
|
12
|
-
#
|
12
|
+
#
|
13
13
|
# http://www.apache.org/licenses/LICENSE-2.0
|
14
|
-
#
|
14
|
+
#
|
15
15
|
# Unless required by applicable law or agreed to in writing, software
|
16
16
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
17
17
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
@@ -23,15 +23,16 @@ require 'chef/cookbook_loader'
|
|
23
23
|
require 'chef/cookbook/metadata'
|
24
24
|
|
25
25
|
class Cookbooks < Application
|
26
|
-
|
26
|
+
|
27
|
+
include Merb::CookbookVersionHelper
|
28
|
+
|
27
29
|
provides :json
|
28
30
|
|
29
31
|
before :authenticate_every
|
30
32
|
before :params_helper
|
31
|
-
before :is_admin, :only => [ :update, :destroy ]
|
32
33
|
|
33
34
|
attr_accessor :cookbook_name, :cookbook_version
|
34
|
-
|
35
|
+
|
35
36
|
def params_helper
|
36
37
|
self.cookbook_name = params[:cookbook_name]
|
37
38
|
self.cookbook_version = params[:cookbook_version]
|
@@ -39,39 +40,47 @@ class Cookbooks < Application
|
|
39
40
|
|
40
41
|
include Chef::Mixin::Checksum
|
41
42
|
include Merb::TarballHelper
|
42
|
-
|
43
|
-
def index
|
44
|
-
cookbook_list = Chef::CookbookVersion.cdb_list_latest.keys.sort
|
45
|
-
response = Hash.new
|
46
|
-
cookbook_list.map! do |cookbook_name|
|
47
|
-
response[cookbook_name] = absolute_url(:cookbook, :cookbook_name => cookbook_name)
|
48
|
-
end
|
49
|
-
display response
|
50
|
-
end
|
51
43
|
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
44
|
+
# returns data in the format of:
|
45
|
+
# {"apache2" => {
|
46
|
+
# :url => "http://url",
|
47
|
+
# :versions => [{:url => "http://url/1.0.0", :version => "1.0.0"}, {:url => "http://url/0.0.1", :version=>"0.0.1"}]
|
48
|
+
# }
|
49
|
+
# }
|
50
|
+
def index
|
51
|
+
cookbook_list = Chef::CookbookVersion.cdb_list
|
52
|
+
# cookbook_list is in the format of {"apache2" => [0.0.1, 0.0.0]} where the version numbers are DepSelector::Version objects
|
53
|
+
num_versions = num_versions!
|
54
|
+
display(cookbook_list.inject({}) {|res, (cookbook_name, versions)|
|
55
|
+
versions = versions.map{ |x| DepSelector::Version.new(x) }.sort.reverse.map{ |x| x.to_s }
|
56
|
+
res[cookbook_name] = expand_cookbook_urls(cookbook_name, versions, num_versions)
|
56
57
|
res
|
57
|
-
|
58
|
-
display response
|
58
|
+
})
|
59
59
|
end
|
60
60
|
|
61
61
|
def index_recipes
|
62
|
-
|
63
|
-
|
64
|
-
|
62
|
+
recipes_with_versions = Chef::CookbookVersion.cdb_list(true).inject({}) do|memo, f|
|
63
|
+
memo[f.name] ||= {}
|
64
|
+
memo[f.name][f.version] = f.recipe_filenames_by_name.keys
|
65
|
+
memo
|
65
66
|
end
|
66
|
-
|
67
|
-
all_cookbooks.sort!
|
68
|
-
display all_cookbooks
|
67
|
+
display recipes_with_versions
|
69
68
|
end
|
70
69
|
|
70
|
+
# GET /cookbooks/:cookbook_name
|
71
|
+
#
|
72
|
+
# returns data in the format of:
|
73
|
+
# {"apache2" => {
|
74
|
+
# :url => "http://url",
|
75
|
+
# :versions => [{:url => "http://url/1.0.0", :version => "1.0.0"}, {:url => "http://url/0.0.1", :version=>"0.0.1"}]
|
76
|
+
# }
|
77
|
+
# }
|
71
78
|
def show_versions
|
72
79
|
versions = Chef::CookbookVersion.cdb_by_name(cookbook_name)
|
73
80
|
raise NotFound, "Cannot find a cookbook named #{cookbook_name}" unless versions && versions.size > 0
|
74
|
-
|
81
|
+
num_versions = num_versions!("all")
|
82
|
+
cb_versions = versions[cookbook_name].map{ |x| DepSelector::Version.new(x) }.sort.reverse.map{ |x| x.to_s }
|
83
|
+
display({ cookbook_name => expand_cookbook_urls(cookbook_name, cb_versions, num_versions) })
|
75
84
|
end
|
76
85
|
|
77
86
|
def show
|
@@ -81,7 +90,7 @@ class Cookbooks < Application
|
|
81
90
|
|
82
91
|
def show_file
|
83
92
|
cookbook = get_cookbook_version(cookbook_name, cookbook_version)
|
84
|
-
|
93
|
+
|
85
94
|
checksum = params[:checksum]
|
86
95
|
raise NotFound, "Cookbook #{cookbook_name} version #{cookbook_version} does not contain a file with checksum #{checksum}" unless cookbook.checksums.keys.include?(checksum)
|
87
96
|
|
@@ -99,9 +108,9 @@ class Cookbooks < Application
|
|
99
108
|
end
|
100
109
|
|
101
110
|
unless params["inflated_object"].version == cookbook_version
|
102
|
-
raise(BadRequest, "You said the cookbook was version #{params['inflated_object'].version}, but the URL says it should be #{cookbook_version}.")
|
111
|
+
raise(BadRequest, "You said the cookbook was version #{params['inflated_object'].version}, but the URL says it should be #{cookbook_version}.")
|
103
112
|
end
|
104
|
-
|
113
|
+
|
105
114
|
begin
|
106
115
|
cookbook = Chef::CookbookVersion.cdb_load(cookbook_name, cookbook_version)
|
107
116
|
cookbook.manifest = params['inflated_object'].manifest
|
@@ -109,29 +118,35 @@ class Cookbooks < Application
|
|
109
118
|
Chef::Log.debug("Cookbook #{cookbook_name} version #{cookbook_version} does not exist")
|
110
119
|
cookbook = params['inflated_object']
|
111
120
|
end
|
112
|
-
|
121
|
+
|
122
|
+
if cookbook.frozen_version? && params[:force].nil?
|
123
|
+
raise Conflict, "The cookbook #{cookbook.name} at version #{cookbook.version} is frozen. Use the 'force' option to override."
|
124
|
+
end
|
125
|
+
|
126
|
+
cookbook.freeze_version if params["inflated_object"].frozen_version?
|
127
|
+
|
113
128
|
# ensure that all checksums referred to by the manifest have been uploaded.
|
114
129
|
Chef::CookbookVersion::COOKBOOK_SEGMENTS.each do |segment|
|
115
130
|
next unless cookbook.manifest[segment]
|
116
131
|
cookbook.manifest[segment].each do |manifest_record|
|
117
132
|
checksum = manifest_record[:checksum]
|
118
133
|
path = manifest_record[:path]
|
119
|
-
|
134
|
+
|
120
135
|
begin
|
121
136
|
checksum_obj = Chef::Checksum.cdb_load(checksum)
|
122
137
|
rescue Chef::Exceptions::CouchDBNotFound => cdbx
|
123
138
|
checksum_obj = nil
|
124
139
|
end
|
125
|
-
|
140
|
+
|
126
141
|
raise BadRequest, "Manifest has checksum #{checksum} (path #{path}) but it hasn't yet been uploaded" unless checksum_obj
|
127
142
|
end
|
128
143
|
end
|
129
|
-
|
144
|
+
|
130
145
|
raise InternalServerError, "Error saving cookbook" unless cookbook.cdb_save
|
131
146
|
|
132
147
|
display cookbook
|
133
148
|
end
|
134
|
-
|
149
|
+
|
135
150
|
def destroy
|
136
151
|
begin
|
137
152
|
cookbook = get_cookbook_version(cookbook_name, cookbook_version)
|
@@ -159,6 +174,6 @@ class Cookbooks < Application
|
|
159
174
|
raise
|
160
175
|
end
|
161
176
|
end
|
162
|
-
|
177
|
+
|
163
178
|
end
|
164
179
|
|
@@ -0,0 +1,207 @@
|
|
1
|
+
#
|
2
|
+
# Author:: Stephen Delano (<stephen@opscode.com>)
|
3
|
+
# Author:: Tim Hinderliter (<tim@opscode.com>)
|
4
|
+
# Copyright:: Copyright (c) 2010, 2011 Opscode, Inc.
|
5
|
+
# License:: Apache License, Version 2.0
|
6
|
+
#
|
7
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
8
|
+
# you may not use this file except in compliance with the License.
|
9
|
+
# You may obtain a copy of the License at
|
10
|
+
#
|
11
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
12
|
+
#
|
13
|
+
# Unless required by applicable law or agreed to in writing, software
|
14
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
15
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
16
|
+
# See the License for the specific language governing permissions and
|
17
|
+
# limitations under the License.
|
18
|
+
#
|
19
|
+
|
20
|
+
require 'chef/environment'
|
21
|
+
require 'chef/cookbook_version_selector'
|
22
|
+
|
23
|
+
class Environments < Application
|
24
|
+
|
25
|
+
include Merb::CookbookVersionHelper
|
26
|
+
|
27
|
+
provides :json
|
28
|
+
|
29
|
+
before :authenticate_every
|
30
|
+
before :is_admin, :only => [ :create, :update, :destroy ]
|
31
|
+
|
32
|
+
# GET /environments
|
33
|
+
def index
|
34
|
+
environment_list = Chef::Environment.cdb_list(true)
|
35
|
+
display(environment_list.inject({}) { |res, env| res[env.name] = absolute_url(:environment, env.name); res })
|
36
|
+
end
|
37
|
+
|
38
|
+
# GET /environments/:id
|
39
|
+
def show
|
40
|
+
begin
|
41
|
+
environment = Chef::Environment.cdb_load(params[:id])
|
42
|
+
rescue Chef::Exceptions::CouchDBNotFound => e
|
43
|
+
raise NotFound, "Cannot load environment #{params[:id]}"
|
44
|
+
end
|
45
|
+
environment.couchdb_rev = nil
|
46
|
+
display environment
|
47
|
+
end
|
48
|
+
|
49
|
+
# POST /environments
|
50
|
+
def create
|
51
|
+
env = params["inflated_object"]
|
52
|
+
exists = true
|
53
|
+
begin
|
54
|
+
Chef::Environment.cdb_load(env.name)
|
55
|
+
rescue Chef::Exceptions::CouchDBNotFound
|
56
|
+
exists = false
|
57
|
+
end
|
58
|
+
raise Conflict, "Environment already exists" if exists
|
59
|
+
|
60
|
+
env.cdb_save
|
61
|
+
self.status = 201
|
62
|
+
display({:uri => absolute_url(:environment, env.name)})
|
63
|
+
end
|
64
|
+
|
65
|
+
# PUT /environments/:id
|
66
|
+
def update
|
67
|
+
raise MethodNotAllowed if params[:id] == "_default"
|
68
|
+
begin
|
69
|
+
env = Chef::Environment.cdb_load(params[:id])
|
70
|
+
rescue Chef::Exceptions::CouchDBNotFound
|
71
|
+
raise NotFound, "Cannot load environment #{params[:id]}"
|
72
|
+
end
|
73
|
+
|
74
|
+
env.update_from!(params["inflated_object"])
|
75
|
+
env.cdb_save
|
76
|
+
env.couchdb_rev = nil
|
77
|
+
self.status = 200
|
78
|
+
display(env)
|
79
|
+
end
|
80
|
+
|
81
|
+
# DELETE /environments/:id
|
82
|
+
def destroy
|
83
|
+
raise MethodNotAllowed if params[:id] == "_default"
|
84
|
+
begin
|
85
|
+
env = Chef::Environment.cdb_load(params[:id])
|
86
|
+
rescue Chef::Exceptions::CouchDBNotFound
|
87
|
+
raise NotFound, "Cannot load environment #{params[:id]}"
|
88
|
+
end
|
89
|
+
env.cdb_destroy
|
90
|
+
display(env)
|
91
|
+
end
|
92
|
+
|
93
|
+
# GET /environments/:environment_id/cookbooks
|
94
|
+
# returns data in the format of:
|
95
|
+
# {"apache2" => {
|
96
|
+
# :url => "http://url",
|
97
|
+
# :versions => [{:url => "http://url/1.0.0", :version => "1.0.0"}, {:url => "http://url/0.0.1", :version=>"0.0.1"}]
|
98
|
+
# }
|
99
|
+
# }
|
100
|
+
def list_cookbooks
|
101
|
+
begin
|
102
|
+
filtered_cookbooks = Chef::Environment.cdb_load_filtered_cookbook_versions(params[:environment_id])
|
103
|
+
rescue Chef::Exceptions::CouchDBNotFound
|
104
|
+
raise NotFound, "Cannot load environment #{params[:environment_id]}"
|
105
|
+
end
|
106
|
+
num_versions = num_versions!
|
107
|
+
display(filtered_cookbooks.inject({}) {|res, (cookbook_name,versions)|
|
108
|
+
versions.map!{|v| v.version.to_s}
|
109
|
+
res[cookbook_name] = expand_cookbook_urls(cookbook_name, versions, num_versions)
|
110
|
+
res
|
111
|
+
})
|
112
|
+
end
|
113
|
+
|
114
|
+
# GET /environments/:environment_id/cookbooks/:cookbook_id
|
115
|
+
# returns data in the format of:
|
116
|
+
# {"apache2" => {
|
117
|
+
# :url => "http://url",
|
118
|
+
# :versions => [{:url => "http://url/1.0.0", :version => "1.0.0"}, {:url => "http://url/0.0.1", :version=>"0.0.1"}]
|
119
|
+
# }
|
120
|
+
# }
|
121
|
+
def cookbook
|
122
|
+
cookbook_name = params[:cookbook_id]
|
123
|
+
begin
|
124
|
+
filtered_cookbooks = Chef::Environment.cdb_load_filtered_cookbook_versions(params[:environment_id])
|
125
|
+
rescue Chef::Exceptions::CouchDBNotFound
|
126
|
+
raise NotFound, "Cannot load environment #{params[:environment_id]}"
|
127
|
+
end
|
128
|
+
raise NotFound, "Cannot load cookbook #{cookbook_name}" unless filtered_cookbooks.has_key?(cookbook_name)
|
129
|
+
versions = filtered_cookbooks[cookbook_name].map{|v| v.version.to_s}
|
130
|
+
num_versions = num_versions!("all")
|
131
|
+
display({ cookbook_name => expand_cookbook_urls(cookbook_name, versions, num_versions) })
|
132
|
+
end
|
133
|
+
|
134
|
+
# GET /environments/:environment/recipes
|
135
|
+
def list_recipes
|
136
|
+
display(Chef::Environment.cdb_load_filtered_recipe_list(params[:environment_id]))
|
137
|
+
end
|
138
|
+
|
139
|
+
# GET /environments/:environment_id/nodes
|
140
|
+
def list_nodes
|
141
|
+
node_list = Chef::Node.cdb_list_by_environment(params[:environment_id])
|
142
|
+
display(node_list.inject({}) {|r,n| r[n] = absolute_url(:node, n); r})
|
143
|
+
end
|
144
|
+
|
145
|
+
# GET /environments/:environment_id/roles/:role_id
|
146
|
+
def role
|
147
|
+
begin
|
148
|
+
role = Chef::Role.cdb_load(params[:role_id])
|
149
|
+
rescue Chef::Exceptions::CouchDBNotFound
|
150
|
+
raise NotFound, "Cannot load role #{params[:role_id]}"
|
151
|
+
end
|
152
|
+
display("run_list" => role.env_run_lists[params[:environment_id]])
|
153
|
+
end
|
154
|
+
|
155
|
+
# POST /environments/:environment_id/cookbook_versions
|
156
|
+
#
|
157
|
+
# Take the given run_list and return the versions of cookbooks that would
|
158
|
+
# be used after applying the constraints of the given environment.
|
159
|
+
#
|
160
|
+
# INPUT:
|
161
|
+
# :run_list = an Array of String's, e.g.,
|
162
|
+
# ["recipe[apache2]", "recipe[runit]"]
|
163
|
+
#
|
164
|
+
# OUT:
|
165
|
+
# Hash of cookbook names cookbook manifest
|
166
|
+
#
|
167
|
+
# NOTE: This method is a POST, not because it's a mutator (it's idempotent),
|
168
|
+
# but the run_list can likely exceed Merb's query string limit for GET
|
169
|
+
# of 1024 characters.
|
170
|
+
def cookbook_versions_for_run_list
|
171
|
+
begin
|
172
|
+
# not possible to be nil due to the route to get us to this API
|
173
|
+
# endpoint
|
174
|
+
environment_input = params[:environment_id]
|
175
|
+
|
176
|
+
run_list_input = params[:run_list]
|
177
|
+
raise BadRequest, "Missing param: run_list" unless run_list_input
|
178
|
+
raise BadRequest, "Param run_list is not an Array: #{run_list_input.class}" unless run_list_input.is_a?(Array)
|
179
|
+
|
180
|
+
# Convert the input array of strings to a RunList containing
|
181
|
+
# RunListItem's.
|
182
|
+
run_list = Chef::RunList.new
|
183
|
+
run_list_input.each do |run_list_item_string|
|
184
|
+
run_list << run_list_item_string
|
185
|
+
end
|
186
|
+
|
187
|
+
# Expand the run list in the scope of the specified environment.
|
188
|
+
names_to_cookbook_version = Chef::CookbookVersionSelector.expand_to_cookbook_versions(run_list, environment_input)
|
189
|
+
rescue Chef::Exceptions::CouchDBNotFound
|
190
|
+
raise NotFound, "Cannot load environment #{params[:environment_id]}"
|
191
|
+
rescue Chef::Exceptions::CookbookVersionSelection::InvalidRunListItems => e
|
192
|
+
raise PreconditionFailed, e.to_json
|
193
|
+
rescue Chef::Exceptions::CookbookVersionSelection::UnsatisfiableRunListItem => e
|
194
|
+
raise PreconditionFailed, e.to_json
|
195
|
+
end
|
196
|
+
|
197
|
+
# Convert from
|
198
|
+
# name => CookbookVersion
|
199
|
+
# to
|
200
|
+
# name => cookbook manifest
|
201
|
+
# and display.
|
202
|
+
display(names_to_cookbook_version.inject({}) do |res, (cookbook_name, cookbook_version)|
|
203
|
+
res[cookbook_name] = cookbook_version.generate_manifest_with_urls {|opts| absolute_url(:cookbook_file, opts) }
|
204
|
+
res
|
205
|
+
end)
|
206
|
+
end
|
207
|
+
end
|
data/app/controllers/main.rb
CHANGED
@@ -1,18 +1,25 @@
|
|
1
1
|
class Main < Application
|
2
2
|
|
3
|
-
before :authenticate_every
|
4
3
|
provides :html, :json
|
5
4
|
|
6
5
|
def index
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
6
|
+
case content_type
|
7
|
+
when :json
|
8
|
+
display absolute_url(:nodes) => "Manage Nodes",
|
9
|
+
absolute_url(:roles) => "Manage Roles",
|
10
|
+
absolute_url(:cookbooks) => "Manage Cookbooks",
|
11
|
+
absolute_url(:data) => "Manage Data Bags",
|
12
|
+
absolute_url(:search) => "Search"
|
13
|
+
else
|
14
|
+
@webui_url = if Chef::Config[:chef_webui_url]
|
15
|
+
Chef::Config[:chef_webui_url]
|
16
|
+
elsif request.host =~ /(.*):4000/
|
17
|
+
absolute_url(:top, :host => "#{$1}:4040")
|
18
|
+
else
|
19
|
+
nil
|
20
|
+
end
|
21
|
+
render
|
22
|
+
end
|
16
23
|
end
|
17
24
|
|
18
25
|
end
|
data/app/controllers/nodes.rb
CHANGED
@@ -7,9 +7,9 @@
|
|
7
7
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
8
8
|
# you may not use this file except in compliance with the License.
|
9
9
|
# You may obtain a copy of the License at
|
10
|
-
#
|
10
|
+
#
|
11
11
|
# http://www.apache.org/licenses/LICENSE-2.0
|
12
|
-
#
|
12
|
+
#
|
13
13
|
# Unless required by applicable law or agreed to in writing, software
|
14
14
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
15
15
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
@@ -17,17 +17,20 @@
|
|
17
17
|
# limitations under the License.
|
18
18
|
#
|
19
19
|
|
20
|
-
require 'chef
|
20
|
+
require 'chef/node'
|
21
|
+
require 'chef/version_class'
|
22
|
+
require 'chef/version_constraint'
|
23
|
+
require 'chef/cookbook_version_selector'
|
21
24
|
|
22
25
|
class Nodes < Application
|
23
|
-
|
26
|
+
|
24
27
|
provides :json
|
25
|
-
|
26
|
-
before :authenticate_every
|
28
|
+
|
29
|
+
before :authenticate_every
|
27
30
|
before :admin_or_requesting_node, :only => [ :update, :destroy, :cookbooks ]
|
28
|
-
|
31
|
+
|
29
32
|
def index
|
30
|
-
@node_list = Chef::Node.cdb_list
|
33
|
+
@node_list = Chef::Node.cdb_list
|
31
34
|
display(@node_list.inject({}) do |r,n|
|
32
35
|
r[n] = absolute_url(:node, n); r
|
33
36
|
end)
|
@@ -46,7 +49,7 @@ class Nodes < Application
|
|
46
49
|
def create
|
47
50
|
@node = params["inflated_object"]
|
48
51
|
begin
|
49
|
-
Chef::Node.cdb_load(@node.name)
|
52
|
+
Chef::Node.cdb_load(@node.name)
|
50
53
|
raise Conflict, "Node already exists"
|
51
54
|
rescue Chef::Exceptions::CouchDBNotFound
|
52
55
|
end
|
@@ -62,12 +65,7 @@ class Nodes < Application
|
|
62
65
|
raise NotFound, "Cannot load node #{params[:id]}"
|
63
66
|
end
|
64
67
|
|
65
|
-
|
66
|
-
@node.run_list.reset!(updated.run_list)
|
67
|
-
@node.automatic_attrs = updated.automatic_attrs
|
68
|
-
@node.normal_attrs = updated.normal_attrs
|
69
|
-
@node.override_attrs = updated.override_attrs
|
70
|
-
@node.default_attrs = updated.default_attrs
|
68
|
+
@node.update_from!(params['inflated_object'])
|
71
69
|
@node.cdb_save
|
72
70
|
@node.couchdb_rev = nil
|
73
71
|
display(@node)
|
@@ -76,7 +74,7 @@ class Nodes < Application
|
|
76
74
|
def destroy
|
77
75
|
begin
|
78
76
|
@node = Chef::Node.cdb_load(params[:id])
|
79
|
-
rescue Chef::Exceptions::CouchDBNotFound => e
|
77
|
+
rescue Chef::Exceptions::CouchDBNotFound => e
|
80
78
|
raise NotFound, "Cannot load node #{params[:id]}"
|
81
79
|
end
|
82
80
|
@node.cdb_destroy
|
@@ -84,86 +82,34 @@ class Nodes < Application
|
|
84
82
|
display @node
|
85
83
|
end
|
86
84
|
|
85
|
+
# Return a hash, cookbook_name => cookbook manifest, of the cookbooks
|
86
|
+
# appropriate for this node, using its run_list and environment.
|
87
87
|
def cookbooks
|
88
88
|
begin
|
89
89
|
@node = Chef::Node.cdb_load(params[:id])
|
90
|
-
rescue Chef::Exceptions::CouchDBNotFound => e
|
90
|
+
rescue Chef::Exceptions::CouchDBNotFound => e
|
91
91
|
raise NotFound, "Cannot load node #{params[:id]}"
|
92
92
|
end
|
93
93
|
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
newest_version = res.has_key?(cookbook.name) ? version > Gem::Version.new(res[cookbook.name].version) : true
|
103
|
-
res[cookbook.name] = cookbook if newest_version
|
104
|
-
res
|
105
|
-
end
|
106
|
-
|
107
|
-
included_cookbooks = cookbooks_for_node(node_name, all_cookbooks)
|
108
|
-
nodes_cookbooks = Hash.new
|
109
|
-
included_cookbooks.each do |cookbook_name, cookbook|
|
110
|
-
next unless cookbook
|
111
|
-
|
112
|
-
nodes_cookbooks[cookbook_name.to_s] = cookbook.generate_manifest_with_urls{|opts| absolute_url(:cookbook_file, opts) }
|
113
|
-
end
|
114
|
-
|
115
|
-
nodes_cookbooks
|
116
|
-
end
|
117
|
-
|
118
|
-
# returns name -> CookbookVersion for all cookbooks included on the given node.
|
119
|
-
def cookbooks_for_node(node_name, all_cookbooks)
|
120
|
-
# get node's explicit dependencies
|
121
|
-
node = Chef::Node.cdb_load(node_name)
|
122
|
-
|
123
|
-
# expand returns a RunListExpansion which contains recipes, default and override attrs [cb]
|
124
|
-
recipes = node.run_list.expand('couchdb').recipes
|
125
|
-
|
126
|
-
# walk run list and accumulate included dependencies
|
127
|
-
recipes.inject({}) do |included_cookbooks, recipe|
|
128
|
-
expand_cookbook_deps(included_cookbooks, all_cookbooks, recipe)
|
129
|
-
included_cookbooks
|
130
|
-
end
|
131
|
-
end
|
132
|
-
|
133
|
-
# Accumulates transitive cookbook dependencies no more than once in included_cookbooks
|
134
|
-
# included_cookbooks == hash of name -> CookbookVersion, which is used for returning
|
135
|
-
# result as well as for tracking which cookbooks we've already
|
136
|
-
# recursed into
|
137
|
-
# all_cookbooks == hash of name -> CookbookVersion, all cookbooks available
|
138
|
-
# run_list_items == name of cookbook to include
|
139
|
-
def expand_cookbook_deps(included_cookbooks, all_cookbooks, run_list_item)
|
140
|
-
# determine the run list item's parent cookbook, which might be run_list_item in the default case
|
141
|
-
cookbook_name = (run_list_item[/^(.+)::/, 1] || run_list_item.to_s)
|
142
|
-
Chef::Log.debug("Node requires #{cookbook_name}")
|
143
|
-
|
144
|
-
# include its dependencies
|
145
|
-
included_cookbooks[cookbook_name] = all_cookbooks[cookbook_name]
|
146
|
-
if !all_cookbooks[cookbook_name]
|
147
|
-
return false
|
148
|
-
# NOTE [dan/cw] We don't think changing this to an exception breaks stuff.
|
149
|
-
# Chef::Log.warn "#{__FILE__}:#{__LINE__}: in expand_cookbook_deps, cookbook/role #{cookbook_name} could not be found, ignoring it in cookbook expansion"
|
150
|
-
# return included_cookbooks
|
94
|
+
# Get the mapping of cookbook_name => CookbookVersion applicable to
|
95
|
+
# this node's run_list and its environment.
|
96
|
+
begin
|
97
|
+
included_cookbooks = Chef::CookbookVersionSelector.expand_to_cookbook_versions(@node.run_list, @node.chef_environment)
|
98
|
+
rescue Chef::Exceptions::CookbookVersionSelection::InvalidRunListItems => e
|
99
|
+
raise PreconditionFailed, e.to_json
|
100
|
+
rescue Chef::Exceptions::CookbookVersionSelection::UnsatisfiableRunListItem => e
|
101
|
+
raise PreconditionFailed, e.to_json
|
151
102
|
end
|
152
103
|
|
153
|
-
#
|
154
|
-
#
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
end
|
163
|
-
end
|
164
|
-
end
|
165
|
-
true
|
104
|
+
# Convert from
|
105
|
+
# name => CookbookVersion
|
106
|
+
# to
|
107
|
+
# name => cookbook manifest
|
108
|
+
# and display.
|
109
|
+
display(included_cookbooks.inject({}) do |acc, (cookbook_name, cookbook_version)|
|
110
|
+
acc[cookbook_name.to_s] = cookbook_version.generate_manifest_with_urls{|opts| absolute_url(:cookbook_file, opts) }
|
111
|
+
acc
|
112
|
+
end)
|
166
113
|
end
|
167
114
|
|
168
115
|
end
|
169
|
-
|