chef-server-api 0.9.0.a4 → 0.9.0.a6
Sign up to get free protection for your applications and to get access to all the features.
- 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
|