chef-server-api 0.8.16 → 0.9.0.a3
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/Rakefile +13 -9
- data/app/controllers/application.rb +19 -202
- data/app/controllers/clients.rb +5 -5
- data/app/controllers/cookbooks.rb +79 -155
- data/app/controllers/{data.rb → data_bags.rb} +4 -4
- data/app/controllers/data_item.rb +1 -1
- data/app/controllers/exceptions.rb +1 -1
- data/app/controllers/main.rb +6 -6
- data/app/controllers/nodes.rb +72 -10
- data/app/controllers/roles.rb +3 -3
- data/app/controllers/sandboxes.rb +179 -0
- data/app/controllers/search.rb +8 -8
- data/app/controllers/users.rb +17 -17
- data/app/helpers/tarball_helper.rb +84 -54
- data/app/views/layout/chef_server_api.html.haml +1 -1
- data/bin/chef-server +75 -0
- data/config/environments/development.rb +6 -0
- data/config/init.rb +55 -12
- data/config/rack.rb +5 -0
- data/config/router.rb +81 -5
- data/lib/chef-server-api.rb +2 -158
- data/lib/chef-server-api/version.rb +3 -0
- metadata +56 -43
- data/app/helpers/application_helper.rb +0 -163
- data/app/helpers/exceptions_helper.rb +0 -6
- data/app/helpers/global_helpers.rb +0 -25
- data/app/helpers/nodes_helper.rb +0 -26
- data/app/helpers/roles_helper.rb +0 -5
- data/lib/chef-server-api/merbtasks.rb +0 -103
- data/lib/chef-server-api/slicetasks.rb +0 -20
- data/lib/chef-server-api/spectasks.rb +0 -53
- data/stubs/app/controllers/application.rb +0 -2
- data/stubs/app/controllers/main.rb +0 -2
@@ -19,7 +19,7 @@
|
|
19
19
|
|
20
20
|
require 'chef/data_bag'
|
21
21
|
|
22
|
-
class
|
22
|
+
class DataBags < Application
|
23
23
|
|
24
24
|
provides :json
|
25
25
|
|
@@ -28,7 +28,7 @@ class ChefServerApi::Data < ChefServerApi::Application
|
|
28
28
|
|
29
29
|
def index
|
30
30
|
@bag_list = Chef::DataBag.cdb_list(false)
|
31
|
-
display(@bag_list.inject({}) { |r,b| r[b] =
|
31
|
+
display(@bag_list.inject({}) { |r,b| r[b] = absolute_url(:datum, :id => b); r })
|
32
32
|
|
33
33
|
end
|
34
34
|
|
@@ -38,7 +38,7 @@ class ChefServerApi::Data < ChefServerApi::Application
|
|
38
38
|
rescue Chef::Exceptions::CouchDBNotFound => e
|
39
39
|
raise NotFound, "Cannot load data bag #{params[:id]}"
|
40
40
|
end
|
41
|
-
display(@data_bag.list.inject({}) { |res, i| res[i] =
|
41
|
+
display(@data_bag.list.inject({}) { |res, i| res[i] = absolute_url(:data_bag_item, :data_bag_id => @data_bag.name, :id => i); res })
|
42
42
|
end
|
43
43
|
|
44
44
|
def create
|
@@ -58,7 +58,7 @@ class ChefServerApi::Data < ChefServerApi::Application
|
|
58
58
|
raise Conflict, "Data bag already exists" if exists
|
59
59
|
self.status = 201
|
60
60
|
@data_bag.cdb_save
|
61
|
-
display({ :uri =>
|
61
|
+
display({ :uri => absolute_url(:datum, :id => @data_bag.name) })
|
62
62
|
end
|
63
63
|
|
64
64
|
def destroy
|
data/app/controllers/main.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
class
|
1
|
+
class Main < Application
|
2
2
|
|
3
3
|
before :authenticate_every
|
4
4
|
provides :html, :json
|
@@ -6,11 +6,11 @@ class ChefServerApi::Main < ChefServerApi::Application
|
|
6
6
|
def index
|
7
7
|
display(
|
8
8
|
{
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
9
|
+
absolute_url(:nodes) => "Manage Nodes",
|
10
|
+
absolute_url(:roles) => "Manage Roles",
|
11
|
+
absolute_url(:cookbooks) => "Manage Cookbooks",
|
12
|
+
absolute_url(:data) => "Manage Data Bags",
|
13
|
+
absolute_url(:search) => "Search"
|
14
14
|
}
|
15
15
|
)
|
16
16
|
end
|
data/app/controllers/nodes.rb
CHANGED
@@ -19,17 +19,17 @@
|
|
19
19
|
|
20
20
|
require 'chef' / 'node'
|
21
21
|
|
22
|
-
class
|
22
|
+
class Nodes < Application
|
23
23
|
|
24
24
|
provides :json
|
25
25
|
|
26
26
|
before :authenticate_every
|
27
|
-
before :
|
27
|
+
before :admin_or_requesting_node, :only => [ :update, :destroy, :cookbooks ]
|
28
28
|
|
29
29
|
def index
|
30
30
|
@node_list = Chef::Node.cdb_list
|
31
31
|
display(@node_list.inject({}) do |r,n|
|
32
|
-
r[n] =
|
32
|
+
r[n] = absolute_url(:node, n); r
|
33
33
|
end)
|
34
34
|
end
|
35
35
|
|
@@ -40,9 +40,6 @@ class ChefServerApi::Nodes < ChefServerApi::Application
|
|
40
40
|
raise NotFound, "Cannot load node #{params[:id]}"
|
41
41
|
end
|
42
42
|
@node.couchdb_rev = nil
|
43
|
-
recipes, default, override = @node.run_list.expand("couchdb")
|
44
|
-
@node.default_attrs = default
|
45
|
-
@node.override_attrs = override
|
46
43
|
display @node
|
47
44
|
end
|
48
45
|
|
@@ -55,7 +52,7 @@ class ChefServerApi::Nodes < ChefServerApi::Application
|
|
55
52
|
end
|
56
53
|
self.status = 201
|
57
54
|
@node.cdb_save
|
58
|
-
display({ :uri =>
|
55
|
+
display({ :uri => absolute_url(:node, @node.name) })
|
59
56
|
end
|
60
57
|
|
61
58
|
def update
|
@@ -67,7 +64,8 @@ class ChefServerApi::Nodes < ChefServerApi::Application
|
|
67
64
|
|
68
65
|
updated = params['inflated_object']
|
69
66
|
@node.run_list.reset!(updated.run_list)
|
70
|
-
@node.
|
67
|
+
@node.automatic_attrs = updated.automatic_attrs
|
68
|
+
@node.normal_attrs = updated.normal_attrs
|
71
69
|
@node.override_attrs = updated.override_attrs
|
72
70
|
@node.default_attrs = updated.default_attrs
|
73
71
|
@node.cdb_save
|
@@ -92,9 +90,73 @@ class ChefServerApi::Nodes < ChefServerApi::Application
|
|
92
90
|
rescue Chef::Exceptions::CouchDBNotFound => e
|
93
91
|
raise NotFound, "Cannot load node #{params[:id]}"
|
94
92
|
end
|
95
|
-
|
93
|
+
|
96
94
|
display(load_all_files(params[:id]))
|
97
95
|
end
|
98
|
-
|
96
|
+
|
97
|
+
private
|
98
|
+
|
99
|
+
def load_all_files(node_name)
|
100
|
+
all_cookbooks = Chef::CookbookVersion.cdb_list(true).inject({}) {|hsh,record| hsh[record.name] = record ; hsh}
|
101
|
+
|
102
|
+
included_cookbooks = cookbooks_for_node(node_name, all_cookbooks)
|
103
|
+
nodes_cookbooks = Hash.new
|
104
|
+
included_cookbooks.each do |cookbook_name, cookbook|
|
105
|
+
next unless cookbook
|
106
|
+
|
107
|
+
nodes_cookbooks[cookbook_name.to_s] = cookbook.generate_manifest_with_urls{|opts| absolute_url(:cookbook_file, opts) }
|
108
|
+
end
|
109
|
+
|
110
|
+
nodes_cookbooks
|
111
|
+
end
|
112
|
+
|
113
|
+
# returns name -> CookbookVersion for all cookbooks included on the given node.
|
114
|
+
def cookbooks_for_node(node_name, all_cookbooks)
|
115
|
+
# get node's explicit dependencies
|
116
|
+
node = Chef::Node.cdb_load(node_name)
|
117
|
+
run_list_items, default_attrs, override_attrs = node.run_list.expand('couchdb')
|
118
|
+
|
119
|
+
# walk run list and accumulate included dependencies
|
120
|
+
run_list_items.inject({}) do |included_cookbooks, run_list_item|
|
121
|
+
expand_cookbook_deps(included_cookbooks, all_cookbooks, run_list_item)
|
122
|
+
included_cookbooks
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
# Accumulates transitive cookbook dependencies no more than once in included_cookbooks
|
127
|
+
# included_cookbooks == hash of name -> CookbookVersion, which is used for returning
|
128
|
+
# result as well as for tracking which cookbooks we've already
|
129
|
+
# recursed into
|
130
|
+
# all_cookbooks == hash of name -> CookbookVersion, all cookbooks available
|
131
|
+
# run_list_items == name of cookbook to include
|
132
|
+
def expand_cookbook_deps(included_cookbooks, all_cookbooks, run_list_item)
|
133
|
+
# determine the run list item's parent cookbook, which might be run_list_item in the default case
|
134
|
+
cookbook_name = (run_list_item[/^(.+)::/, 1] || run_list_item.to_s)
|
135
|
+
Chef::Log.debug("Node requires #{cookbook_name}")
|
136
|
+
|
137
|
+
# include its dependencies
|
138
|
+
included_cookbooks[cookbook_name] = all_cookbooks[cookbook_name]
|
139
|
+
if !all_cookbooks[cookbook_name]
|
140
|
+
return false
|
141
|
+
# NOTE [dan/cw] We don't think changing this to an exception breaks stuff.
|
142
|
+
# Chef::Log.warn "#{__FILE__}:#{__LINE__}: in expand_cookbook_deps, cookbook/role #{cookbook_name} could not be found, ignoring it in cookbook expansion"
|
143
|
+
# return included_cookbooks
|
144
|
+
end
|
145
|
+
|
146
|
+
# TODO: 5/27/2010 cw: implement dep_version_constraints according to
|
147
|
+
# http://wiki.opscode.com/display/chef/Metadata#Metadata-depends,
|
148
|
+
all_cookbooks[cookbook_name].metadata.dependencies.each do |depname, dep_version_constraints|
|
149
|
+
# recursively expand dependencies into included_cookbooks unless
|
150
|
+
# we've already done it
|
151
|
+
unless included_cookbooks[depname]
|
152
|
+
unless expand_cookbook_deps(included_cookbooks, all_cookbooks, depname)
|
153
|
+
raise PreconditionFailed, "cookbook #{cookbook_name} depends on cookbook #{depname}, but #{depname} does not exist"
|
154
|
+
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|
158
|
+
true
|
159
|
+
end
|
160
|
+
|
99
161
|
end
|
100
162
|
|
data/app/controllers/roles.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
require 'chef/role'
|
2
2
|
|
3
|
-
class
|
3
|
+
class Roles < Application
|
4
4
|
provides :json
|
5
5
|
|
6
6
|
before :authenticate_every
|
@@ -9,7 +9,7 @@ class ChefServerApi::Roles < ChefServerApi::Application
|
|
9
9
|
# GET /roles
|
10
10
|
def index
|
11
11
|
@role_list = Chef::Role.cdb_list(true)
|
12
|
-
display(@role_list.inject({}) { |r,role| r[role.name] =
|
12
|
+
display(@role_list.inject({}) { |r,role| r[role.name] = absolute_url(:role, role.name); r })
|
13
13
|
end
|
14
14
|
|
15
15
|
# GET /roles/:id
|
@@ -37,7 +37,7 @@ class ChefServerApi::Roles < ChefServerApi::Application
|
|
37
37
|
@role.cdb_save
|
38
38
|
|
39
39
|
self.status = 201
|
40
|
-
display({ :uri =>
|
40
|
+
display({ :uri => absolute_url(:role, :id => @role.name) })
|
41
41
|
end
|
42
42
|
|
43
43
|
# PUT /roles/:id
|
@@ -0,0 +1,179 @@
|
|
1
|
+
#
|
2
|
+
# Author:: Tim Hinderliter (<tim@opscode.com>)
|
3
|
+
# Copyright:: Copyright (c) 2010 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 'chef/sandbox'
|
20
|
+
require 'chef/checksum'
|
21
|
+
|
22
|
+
# Sandboxes are used to upload files to the server (e.g., cookbook upload).
|
23
|
+
class Sandboxes < Application
|
24
|
+
|
25
|
+
provides :json
|
26
|
+
|
27
|
+
before :authenticate_every
|
28
|
+
|
29
|
+
include Chef::Mixin::Checksum
|
30
|
+
include Merb::TarballHelper
|
31
|
+
|
32
|
+
def index
|
33
|
+
couch_sandbox_list = Chef::Sandbox::cdb_list(true)
|
34
|
+
|
35
|
+
sandbox_list = Hash.new
|
36
|
+
couch_sandbox_list.each do |sandbox|
|
37
|
+
sandbox_list[sandbox.guid] = absolute_url(:sandbox, :sandbox_id => sandbox.guid)
|
38
|
+
end
|
39
|
+
display sandbox_list
|
40
|
+
end
|
41
|
+
|
42
|
+
def show
|
43
|
+
begin
|
44
|
+
sandbox = Chef::Sandbox.cdb_load(params[:sandbox_id])
|
45
|
+
rescue Chef::Exceptions::CouchDBNotFound => e
|
46
|
+
raise NotFound, "Cannot find a sandbox named #{params[:sandbox_id]}"
|
47
|
+
end
|
48
|
+
|
49
|
+
display sandbox
|
50
|
+
end
|
51
|
+
|
52
|
+
def create
|
53
|
+
checksums = params[:checksums]
|
54
|
+
|
55
|
+
raise BadRequest, "missing required parameter: checksums" unless checksums
|
56
|
+
raise BadRequest, "required parameter checksums is not a hash: #{checksums.class.name}" unless checksums.is_a?(Hash)
|
57
|
+
|
58
|
+
new_sandbox = Chef::Sandbox.new
|
59
|
+
result_checksums = Hash.new
|
60
|
+
|
61
|
+
all_existing_checksums = Chef::Checksum.cdb_all_checksums
|
62
|
+
checksums.keys.each do |checksum|
|
63
|
+
if all_existing_checksums[checksum]
|
64
|
+
result_checksums[checksum] = {
|
65
|
+
:needs_upload => false
|
66
|
+
}
|
67
|
+
else
|
68
|
+
result_checksums[checksum] = {
|
69
|
+
:url => absolute_url(:sandbox_checksum, :sandbox_id => new_sandbox.guid, :checksum => checksum),
|
70
|
+
:needs_upload => true
|
71
|
+
}
|
72
|
+
new_sandbox.checksums << checksum
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
FileUtils.mkdir_p(sandbox_location(new_sandbox.guid))
|
77
|
+
|
78
|
+
new_sandbox.cdb_save
|
79
|
+
|
80
|
+
# construct successful response
|
81
|
+
self.status = 201
|
82
|
+
location = absolute_url(:sandbox, :sandbox_id => new_sandbox.guid)
|
83
|
+
headers['Location'] = location
|
84
|
+
result = { 'uri' => location, 'checksums' => result_checksums, 'sandbox_id' => new_sandbox.guid }
|
85
|
+
#result = { 'uri' => location }
|
86
|
+
|
87
|
+
display result
|
88
|
+
end
|
89
|
+
|
90
|
+
def upload_checksum
|
91
|
+
sandbox_guid = params[:sandbox_id]
|
92
|
+
checksum = params[:checksum]
|
93
|
+
|
94
|
+
existing_sandbox = Chef::Sandbox.cdb_load(sandbox_guid)
|
95
|
+
raise NotFound, "cannot find sandbox with guid #{sandbox_guid}" unless existing_sandbox
|
96
|
+
raise NotFound, "checksum #{checksum} isn't a part of sandbox #{sandbox_guid}" unless existing_sandbox.checksums.member?(checksum)
|
97
|
+
|
98
|
+
Tempfile.open("sandbox") do |src|
|
99
|
+
src.write(self.request.env["rack.input"].string)
|
100
|
+
src.close
|
101
|
+
|
102
|
+
observed_checksum = Chef::Cache::Checksum.generate_md5_checksum_for_file(src.path)
|
103
|
+
|
104
|
+
raise BadRequest, "Checksum did not match: expected #{checksum}, observed #{observed_checksum}" unless observed_checksum == checksum
|
105
|
+
|
106
|
+
dest = sandbox_checksum_location(sandbox_guid, checksum)
|
107
|
+
Chef::Log.info("upload_checksum: move #{src} to #{dest}")
|
108
|
+
FileUtils.mv(src.path, dest)
|
109
|
+
end
|
110
|
+
|
111
|
+
url = absolute_url(:sandbox_checksum, :sandbox_id => sandbox_guid, :checksum => checksum)
|
112
|
+
result = { 'uri' => url }
|
113
|
+
display result
|
114
|
+
end
|
115
|
+
|
116
|
+
def update
|
117
|
+
# look up the sandbox by its guid
|
118
|
+
existing_sandbox = Chef::Sandbox.cdb_load(params[:sandbox_id])
|
119
|
+
raise NotFound, "cannot find sandbox with guid #{sandbox_id}" unless existing_sandbox
|
120
|
+
|
121
|
+
raise BadRequest, "cannot update sandbox #{sandbox_id}: already complete" if existing_sandbox.is_completed
|
122
|
+
|
123
|
+
if params[:is_completed]
|
124
|
+
existing_sandbox.is_completed = (params[:is_completed] == true)
|
125
|
+
|
126
|
+
if existing_sandbox.is_completed
|
127
|
+
# Check if files were uploaded to sandbox directory before we
|
128
|
+
# commit the sandbox. Fail if any weren't.
|
129
|
+
existing_sandbox.checksums.each do |checksum|
|
130
|
+
checksum_filename = sandbox_checksum_location(existing_sandbox.guid, checksum)
|
131
|
+
if !File.exists?(checksum_filename)
|
132
|
+
raise BadRequest, "cannot update sandbox #{params[:sandbox_id]}: checksum #{checksum} was not uploaded"
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
# If we've gotten here all the files have been uploaded.
|
137
|
+
# Track the steps to undo everything we've done. If any steps fail,
|
138
|
+
# we will undo the successful steps that came before it
|
139
|
+
begin
|
140
|
+
undo_steps = Array.new
|
141
|
+
existing_sandbox.checksums.each do |checksum|
|
142
|
+
checksum_filename_in_sandbox = sandbox_checksum_location(existing_sandbox.guid, checksum)
|
143
|
+
checksum_filename_final = checksum_location(checksum)
|
144
|
+
FileUtils.mkdir_p File.dirname(checksum_filename_final)
|
145
|
+
|
146
|
+
Chef::Log.info("sandbox finalization: move #{checksum_filename_in_sandbox} to #{checksum_filename_final}")
|
147
|
+
File.rename(checksum_filename_in_sandbox, checksum_filename_final)
|
148
|
+
|
149
|
+
# mark the checksum as successfully updated
|
150
|
+
Chef::Checksum.new(checksum).cdb_save
|
151
|
+
|
152
|
+
undo_steps << proc {
|
153
|
+
Chef::Log.warn("sandbox finalization undo: moving #{checksum_filename_final} back to #{checksum_filename_in_sandbox}")
|
154
|
+
File.rename(checksum_filename_final, checksum_filename_in_sandbox)
|
155
|
+
}
|
156
|
+
end
|
157
|
+
rescue
|
158
|
+
# undo the successful moves we did before
|
159
|
+
Chef::Log.error("sandbox finalization: got exception moving files, undoing previous changes: #{$!} -- #{$!.backtrace.join("\n")}")
|
160
|
+
undo_steps.each do |undo_step|
|
161
|
+
undo_step.call
|
162
|
+
end
|
163
|
+
raise
|
164
|
+
end
|
165
|
+
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
existing_sandbox.cdb_save
|
170
|
+
|
171
|
+
display existing_sandbox
|
172
|
+
end
|
173
|
+
|
174
|
+
def destroy
|
175
|
+
raise NotFound, "Destroy not implemented"
|
176
|
+
end
|
177
|
+
|
178
|
+
end
|
179
|
+
|
data/app/controllers/search.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.
|
@@ -19,15 +19,15 @@
|
|
19
19
|
|
20
20
|
require 'chef/solr/query'
|
21
21
|
|
22
|
-
class
|
22
|
+
class Search < Application
|
23
23
|
provides :json
|
24
|
-
|
24
|
+
|
25
25
|
before :authenticate_every
|
26
26
|
before :is_admin, :only => [:reindex]
|
27
|
-
|
27
|
+
|
28
28
|
def index
|
29
29
|
indexes = valid_indexes
|
30
|
-
display(indexes.inject({}) { |r,i| r[i] =
|
30
|
+
display(indexes.inject({}) { |r,i| r[i] = absolute_url(:search, i); r })
|
31
31
|
end
|
32
32
|
|
33
33
|
def valid_indexes
|
@@ -40,7 +40,7 @@ class ChefServerApi::Search < ChefServerApi::Application
|
|
40
40
|
raise NotFound, "I don't know how to search for #{params[:id]} data objects."
|
41
41
|
end
|
42
42
|
|
43
|
-
query = Chef::Solr::Query.new(Chef::Config[:solr_url]
|
43
|
+
query = Chef::Solr::Query.new(Chef::Config[:solr_url])
|
44
44
|
params[:q] ||= "*:*"
|
45
45
|
params[:sort] ||= nil
|
46
46
|
params[:start] ||= 0
|
@@ -52,7 +52,7 @@ class ChefServerApi::Search < ChefServerApi::Application
|
|
52
52
|
"total" => total
|
53
53
|
})
|
54
54
|
end
|
55
|
-
|
55
|
+
|
56
56
|
def reindex
|
57
57
|
display(Chef::Solr.new.rebuild_index)
|
58
58
|
end
|