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.
- 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
|
-
|