chef-server-api 0.9.0.a4 → 0.9.0.a6
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/app/controllers/cookbooks.rb +27 -7
- data/app/controllers/sandboxes.rb +6 -19
- data/app/models/sandbox_file.rb +117 -0
- data/config/router.rb +2 -0
- data/lib/chef-server-api/version.rb +1 -1
- data/spec/spec.opts +3 -0
- data/spec/spec_helper.rb +6 -0
- data/spec/unit/sandbox_file_spec.rb +135 -0
- metadata +7 -3
@@ -19,8 +19,8 @@
|
|
19
19
|
# limitations under the License.
|
20
20
|
#
|
21
21
|
|
22
|
-
require 'chef
|
23
|
-
require 'chef
|
22
|
+
require 'chef/cookbook_loader'
|
23
|
+
require 'chef/cookbook/metadata'
|
24
24
|
|
25
25
|
class Cookbooks < Application
|
26
26
|
|
@@ -40,13 +40,33 @@ class Cookbooks < Application
|
|
40
40
|
include Merb::TarballHelper
|
41
41
|
|
42
42
|
def index
|
43
|
-
cookbook_list = Chef::CookbookVersion.
|
43
|
+
cookbook_list = Chef::CookbookVersion.cdb_list_latest.keys.sort
|
44
44
|
response = Hash.new
|
45
|
-
cookbook_list.
|
46
|
-
cookbook_name
|
47
|
-
response[$1] = absolute_url(:cookbook, :cookbook_name => $1)
|
45
|
+
cookbook_list.map! do |cookbook_name|
|
46
|
+
response[cookbook_name] = absolute_url(:cookbook, :cookbook_name => cookbook_name)
|
48
47
|
end
|
49
|
-
display response
|
48
|
+
display response
|
49
|
+
end
|
50
|
+
|
51
|
+
#FIXME: this is different from the rest of our API, but in a useful way...
|
52
|
+
def index_latest
|
53
|
+
cookbook_list = Chef::CookbookVersion.cdb_list_latest(true)
|
54
|
+
response = Hash.new
|
55
|
+
cookbook_list.map! do |cookbook_name, cookbook_version|
|
56
|
+
response[cookbook_name]={ :url=>absolute_url(:cookbook, :cookbook_name => cookbook_name, :cookbook_version => cookbook_version),
|
57
|
+
:cookbook_name => cookbook_name, :cookbook_version=>cookbook_version}
|
58
|
+
end
|
59
|
+
display response
|
60
|
+
end
|
61
|
+
|
62
|
+
def index_recipes #FIXME: is this cool to do w/ access control on platform?
|
63
|
+
all_cookbooks = Array(Chef::CookbookVersion.cdb_list_latest(true))
|
64
|
+
all_cookbooks.map! do |cookbook|
|
65
|
+
cookbook.manifest["recipes"].map { |r| "#{cookbook.name}::#{r['name']}" }
|
66
|
+
end
|
67
|
+
all_cookbooks.flatten!
|
68
|
+
all_cookbooks.sort!
|
69
|
+
display all_cookbooks
|
50
70
|
end
|
51
71
|
|
52
72
|
def show_versions
|
@@ -88,27 +88,14 @@ class Sandboxes < Application
|
|
88
88
|
end
|
89
89
|
|
90
90
|
def upload_checksum
|
91
|
-
|
92
|
-
|
91
|
+
sandbox_file = ChefServerApi::SandboxFile.new(self.request.env["rack.input"], params)
|
92
|
+
raise BadRequest, sandbox_file.error if sandbox_file.invalid_params?
|
93
|
+
raise NotFound, sandbox_file.error if sandbox_file.invalid_sandbox?
|
94
|
+
raise BadRequest, sandbox_file.error if sandbox_file.invalid_file?
|
93
95
|
|
94
|
-
|
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
|
96
|
+
sandbox_file.commit_to(sandbox_checksum_location(sandbox_file.sandbox_id, sandbox_file.expected_checksum))
|
110
97
|
|
111
|
-
url = absolute_url(:sandbox_checksum,
|
98
|
+
url = absolute_url(:sandbox_checksum, sandbox_file.resource_params)
|
112
99
|
result = { 'uri' => url }
|
113
100
|
display result
|
114
101
|
end
|
@@ -0,0 +1,117 @@
|
|
1
|
+
#
|
2
|
+
# Author:: Daniel DeLeo (<dan@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/exceptions'
|
21
|
+
require 'chef/cache/checksum'
|
22
|
+
|
23
|
+
module ChefServerApi
|
24
|
+
class SandboxFile
|
25
|
+
attr_reader :sandbox_id
|
26
|
+
attr_reader :expected_checksum
|
27
|
+
attr_reader :error
|
28
|
+
|
29
|
+
def initialize(input, params={})
|
30
|
+
@input = input
|
31
|
+
@sandbox_id = params[:sandbox_id]
|
32
|
+
@expected_checksum = params[:checksum]
|
33
|
+
@sandbox_loaded = false
|
34
|
+
@error = nil
|
35
|
+
end
|
36
|
+
|
37
|
+
def resource_params
|
38
|
+
{:sandbox_id => sandbox_id, :checksum => expected_checksum}
|
39
|
+
end
|
40
|
+
|
41
|
+
def sandbox
|
42
|
+
unless @sandbox_loaded
|
43
|
+
load_sandbox
|
44
|
+
@sandbox_loaded = true
|
45
|
+
end
|
46
|
+
@sandbox
|
47
|
+
end
|
48
|
+
|
49
|
+
def commit_to(destination_file_path)
|
50
|
+
if @input.respond_to?(:path) && @input.path
|
51
|
+
commit_tempfile_to(destination_file_path)
|
52
|
+
else
|
53
|
+
commit_stringio_to(destination_file_path)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def actual_checksum
|
58
|
+
@actual_checksum ||= begin
|
59
|
+
@input.rewind
|
60
|
+
Chef::Cache::Checksum.instance.generate_md5_checksum(@input)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def invalid_file?
|
65
|
+
if expected_checksum != actual_checksum
|
66
|
+
@error = "Uploaded file is invalid: expected a md5 sum '#{expected_checksum}', but it was '#{actual_checksum}'"
|
67
|
+
else
|
68
|
+
false
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def invalid_params?
|
73
|
+
if @sandbox_id.nil?
|
74
|
+
@error = "Cannot upload file with checksum '#{expected_checksum}': you must provide a sandbox_id"
|
75
|
+
elsif @expected_checksum.nil?
|
76
|
+
@error = "Cannot upload file to sandbox '#{sandbox_id}': you must provide the file's checksum"
|
77
|
+
else
|
78
|
+
false
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def invalid_sandbox?
|
83
|
+
if sandbox.nil?
|
84
|
+
@error = "Cannot find sandbox with id '#{sandbox_id}' in the database"
|
85
|
+
elsif !sandbox.member?(@expected_checksum)
|
86
|
+
@error = "Cannot upload file: checksum '#{expected_checksum}' isn't a part of sandbox '#{sandbox_id}'"
|
87
|
+
else
|
88
|
+
false
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
private
|
93
|
+
|
94
|
+
def load_sandbox
|
95
|
+
@sandbox = Chef::Sandbox.cdb_load(@sandbox_id)
|
96
|
+
rescue Chef::Exceptions::CouchDBNotFound
|
97
|
+
@sandbox = nil
|
98
|
+
end
|
99
|
+
|
100
|
+
def commit_stringio_to(destination_file_path)
|
101
|
+
Tempfile.open("sandbox") do |src|
|
102
|
+
src.write(@input.string)
|
103
|
+
src.close
|
104
|
+
Chef::Log.info("upload_checksum: move #{src.path} to #{destination_file_path}")
|
105
|
+
FileUtils.mv(src.path, destination_file_path)
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
def commit_tempfile_to(destination_file_path)
|
110
|
+
Chef::Log.debug("Sandbox file provided as tempfile: #{@input.inspect}")
|
111
|
+
Chef::Log.info("upload_checksum: move #{@input.path} to #{destination_file_path}")
|
112
|
+
FileUtils.mv(@input.path, destination_file_path)
|
113
|
+
end
|
114
|
+
|
115
|
+
end
|
116
|
+
|
117
|
+
end
|
data/config/router.rb
CHANGED
@@ -31,6 +31,8 @@ Merb::Router.prepare do
|
|
31
31
|
:method => 'get'
|
32
32
|
).to(:controller => "cookbooks", :action => "index")
|
33
33
|
|
34
|
+
match("/cookbooks/_recipes", :method=>'get').to(:controller=>'cookbooks',:action=>'index_recipes')
|
35
|
+
|
34
36
|
match("/cookbooks/:cookbook_name/:cookbook_version",
|
35
37
|
:method => 'put',
|
36
38
|
:cookbook_name => /[\w\.]+/,
|
data/spec/spec.opts
ADDED
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,135 @@
|
|
1
|
+
#
|
2
|
+
# Author:: Daniel DeLeo (<dan@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 File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
20
|
+
require 'models/sandbox_file'
|
21
|
+
|
22
|
+
describe ChefServerApi::SandboxFile do
|
23
|
+
before do
|
24
|
+
@input = StringIO.new
|
25
|
+
@params = {:sandbox_id => '1234', :checksum => '2342'}
|
26
|
+
@sandbox_file = ChefServerApi::SandboxFile.new(@input, @params)
|
27
|
+
end
|
28
|
+
|
29
|
+
describe "when first created" do
|
30
|
+
it "gets a sandbox guid from the parameters" do
|
31
|
+
@sandbox_file.sandbox_id.should == '1234'
|
32
|
+
end
|
33
|
+
|
34
|
+
it "gets a checksum from the provided parameters" do
|
35
|
+
@sandbox_file.expected_checksum.should == '2342'
|
36
|
+
end
|
37
|
+
|
38
|
+
it "returns the parameters that idendify the resource in the api" do
|
39
|
+
@sandbox_file.resource_params.should == {:sandbox_id => '1234', :checksum => '2342'}
|
40
|
+
end
|
41
|
+
|
42
|
+
it "loads an existing sandbox from couchdb" do
|
43
|
+
Chef::Sandbox.should_receive(:cdb_load).with('1234').once.and_return(:ohai2u)
|
44
|
+
@sandbox_file.sandbox.should == :ohai2u
|
45
|
+
@sandbox_file.sandbox.should == :ohai2u
|
46
|
+
end
|
47
|
+
|
48
|
+
# BadRequest in the controller
|
49
|
+
it "is invalid if no sandbox_id is given" do
|
50
|
+
@params.delete(:sandbox_id)
|
51
|
+
sandbox_file = ChefServerApi::SandboxFile.new(@input, @params)
|
52
|
+
sandbox_file.invalid_params?.should_not be_false
|
53
|
+
sandbox_file.invalid_params?.should == "Cannot upload file with checksum '2342': you must provide a sandbox_id"
|
54
|
+
end
|
55
|
+
|
56
|
+
# BadRequest in the controller
|
57
|
+
it "is invalid if no expected checksum is given" do
|
58
|
+
@params.delete(:checksum)
|
59
|
+
sandbox_file = ChefServerApi::SandboxFile.new(@input, @params)
|
60
|
+
sandbox_file.invalid_params?.should_not be_false
|
61
|
+
sandbox_file.invalid_params?.should == "Cannot upload file to sandbox '1234': you must provide the file's checksum"
|
62
|
+
end
|
63
|
+
|
64
|
+
it "considers the params valid when both the checksum and sandbox_id are provided" do
|
65
|
+
@sandbox_file.invalid_params?.should be_false
|
66
|
+
end
|
67
|
+
|
68
|
+
# NotFound in the controller
|
69
|
+
it "is invalid if the provided sandbox_id doesn't exist in the database" do
|
70
|
+
err = Chef::Exceptions::CouchDBNotFound.new "Cannot find sandbox 1234 in CouchDB!"
|
71
|
+
Chef::Sandbox.should_receive(:cdb_load).with('1234').once.and_raise(err)
|
72
|
+
@sandbox_file.invalid_sandbox?.should == "Cannot find sandbox with id '1234' in the database"
|
73
|
+
end
|
74
|
+
|
75
|
+
# NotFound in the controller
|
76
|
+
it "is invalid if the sandbox exists, but the given checksum isn't a member of it" do
|
77
|
+
sandbox = Chef::Sandbox.new('1234')
|
78
|
+
sandbox.checksums << 'not-2342'
|
79
|
+
Chef::Sandbox.should_receive(:cdb_load).with('1234').once.and_return(sandbox)
|
80
|
+
@sandbox_file.invalid_sandbox?.should == "Cannot upload file: checksum '2342' isn't a part of sandbox '1234'"
|
81
|
+
end
|
82
|
+
|
83
|
+
it "is valid when the sandbox exists and the checksum is a member of it" do
|
84
|
+
sandbox = Chef::Sandbox.new('1234')
|
85
|
+
sandbox.checksums << '2342'
|
86
|
+
Chef::Sandbox.should_receive(:cdb_load).with('1234').once.and_return(sandbox)
|
87
|
+
@sandbox_file.invalid_sandbox?.should be_false
|
88
|
+
end
|
89
|
+
|
90
|
+
end
|
91
|
+
|
92
|
+
context "when created with valid parameters and a valid sandbox" do
|
93
|
+
before do
|
94
|
+
@sandbox = Chef::Sandbox.new('1234')
|
95
|
+
@sandbox_file.stub!(:sandbox).and_return(@sandbox)
|
96
|
+
@input.string.replace("riseofthemachines\nriseofthechefs\n")
|
97
|
+
end
|
98
|
+
|
99
|
+
it "checksums the uploaded data" do
|
100
|
+
@sandbox_file.actual_checksum.should == '0e157ac1e2dd73191b76067fb6b4bceb'
|
101
|
+
end
|
102
|
+
|
103
|
+
# BadRequest in the controller
|
104
|
+
it "considers the uploaded file invalid if its checksum doesn't match" do
|
105
|
+
message = "Uploaded file is invalid: expected a md5 sum '2342', but it was '0e157ac1e2dd73191b76067fb6b4bceb'"
|
106
|
+
@sandbox_file.invalid_file?.should == message
|
107
|
+
end
|
108
|
+
|
109
|
+
it "is valid if the expected and actual checksums match" do
|
110
|
+
@sandbox_file.expected_checksum.replace('0e157ac1e2dd73191b76067fb6b4bceb')
|
111
|
+
@sandbox_file.invalid_file?.should be_false
|
112
|
+
end
|
113
|
+
|
114
|
+
context "and a string io for input" do
|
115
|
+
it "writes the StringIO's contents to a tempfile, then moves it into place" do
|
116
|
+
@tempfile = StringIO.new
|
117
|
+
@tempfile.stub!(:path).and_return("/tmpfile/source")
|
118
|
+
Tempfile.should_receive(:open).with("sandbox").and_yield(@tempfile)
|
119
|
+
FileUtils.should_receive(:mv).with("/tmpfile/source", "/tmp/final_home")
|
120
|
+
@sandbox_file.commit_to('/tmp/final_home')
|
121
|
+
@tempfile.string.should == "riseofthemachines\nriseofthechefs\n"
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
context "and a tempfile for input" do
|
126
|
+
it "moves the tempfile into place" do
|
127
|
+
@input.stub!(:path).and_return('/existing/tempfile')
|
128
|
+
FileUtils.should_receive(:mv).with("/existing/tempfile", "/tmp/final_home")
|
129
|
+
@sandbox_file.commit_to('/tmp/final_home')
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
end
|
134
|
+
|
135
|
+
end
|
metadata
CHANGED
@@ -6,8 +6,8 @@ version: !ruby/object:Gem::Version
|
|
6
6
|
- 0
|
7
7
|
- 9
|
8
8
|
- 0
|
9
|
-
-
|
10
|
-
version: 0.9.0.
|
9
|
+
- a6
|
10
|
+
version: 0.9.0.a6
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Opscode
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2010-06-
|
18
|
+
date: 2010-06-07 00:00:00 -07:00
|
19
19
|
default_executable:
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|
@@ -155,6 +155,9 @@ files:
|
|
155
155
|
- config/router.rb
|
156
156
|
- lib/chef-server-api/version.rb
|
157
157
|
- lib/chef-server-api.rb
|
158
|
+
- spec/spec.opts
|
159
|
+
- spec/spec_helper.rb
|
160
|
+
- spec/unit/sandbox_file_spec.rb
|
158
161
|
- app/controllers/application.rb
|
159
162
|
- app/controllers/clients.rb
|
160
163
|
- app/controllers/cookbooks.rb
|
@@ -168,6 +171,7 @@ files:
|
|
168
171
|
- app/controllers/search.rb
|
169
172
|
- app/controllers/users.rb
|
170
173
|
- app/helpers/tarball_helper.rb
|
174
|
+
- app/models/sandbox_file.rb
|
171
175
|
- app/views/exceptions/bad_request.json.erb
|
172
176
|
- app/views/exceptions/internal_server_error.html.erb
|
173
177
|
- app/views/exceptions/not_acceptable.html.haml
|