Skip to content

Commit 0ece269

Browse files
committed
Merge branch 'CHEF-542-754' of git://github.com/cwalters/chef into cwalters/CHEF-542-754
2 parents b2f2ba7 + 05fd6c3 commit 0ece269

17 files changed

Lines changed: 499 additions & 30 deletions

File tree

Rakefile

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -290,6 +290,10 @@ namespace :features do
290290
Cucumber::Rake::Task.new(:cookbooks) do |t|
291291
t.profile = "api_cookbooks"
292292
end
293+
294+
Cucumber::Rake::Task.new(:cookbook_tarballs) do |t|
295+
t.profile = "api_cookbooks_tarballs"
296+
end
293297
end
294298

295299
namespace :data do

chef-server-api/app/controllers/cookbooks.rb

Lines changed: 66 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
#
22
# Author:: Adam Jacob (<adam@opscode.com>)
33
# Author:: Christopher Brown (<cb@opscode.com>)
4-
# Copyright:: Copyright (c) 2008 Opscode, Inc.
4+
# Author:: Christopher Walters (<cw@opscode.com>)
5+
# Copyright:: Copyright (c) 2008, 2009 Opscode, Inc.
56
# License:: Apache License, Version 2.0
67
#
78
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -27,6 +28,7 @@ class ChefServerApi::Cookbooks < ChefServerApi::Application
2728
before :authenticate_every
2829

2930
include Chef::Mixin::Checksum
31+
include Merb::ChefServerApi::TarballHelper
3032

3133
def index
3234
cl = Chef::CookbookLoader.new
@@ -42,15 +44,15 @@ def show
4244
begin
4345
cookbook = cl[params[:id]]
4446
rescue ArgumentError => e
45-
raise NotFound, "Cannot find a cookbook named #{cookbook.to_s}"
47+
raise NotFound, "Cannot find a cookbook named #{params[:id]}"
4648
end
4749
results = load_cookbook_files(cookbook)
4850
results[:name] = cookbook.name.to_s
4951
results[:metadata] = cl.metadata[cookbook.name.to_sym]
5052
display results
5153
end
5254

53-
def show_segment
55+
def show_segment
5456
cl = Chef::CookbookLoader.new
5557
begin
5658
cookbook = cl[params[:cookbook_id]]
@@ -125,5 +127,66 @@ def serve_segment_file(cookbook, segment, files)
125127
end
126128
end
127129

130+
def create
131+
# validate name and file parameters and throw an error if a cookbook with the same name already exists
132+
raise BadRequest, "missing required parameter: name" unless params[:name]
133+
desired_name = params[:name]
134+
raise BadRequest, "invalid parameter: name must be at least one character long and contain only letters, numbers, periods (.), underscores (_), and hyphens (-)" unless desired_name =~ /\A[\w.-]+\Z/
135+
begin
136+
validate_file_parameter(desired_name, params[:file])
137+
rescue FileParameterException => te
138+
raise BadRequest, te.message
139+
end
140+
141+
begin
142+
Chef::CookbookLoader.new[desired_name]
143+
raise BadRequest, "Cookbook with the name #{desired_name} already exists"
144+
rescue ArgumentError
145+
end
146+
147+
expand_tarball_and_put_in_repository(desired_name, params[:file][:tempfile])
148+
149+
# construct successful response
150+
self.status = 201
151+
location = absolute_slice_url(:cookbook, :id => desired_name)
152+
headers['Location'] = location
153+
result = { 'uri' => location }
154+
display result
155+
end
156+
157+
def get_tarball
158+
cookbook_name = params[:cookbook_id]
159+
expected_location = cookbook_location(cookbook_name)
160+
raise NotFound, "Cannot find cookbook named #{cookbook_name} at #{expected_location}. Note: Tarball generation only applies to cookbooks under the first directory in the server's Chef::Config.cookbook_path variable and does to apply overrides." unless File.directory? expected_location
161+
162+
send_file(get_or_create_cookbook_tarball_location(cookbook_name))
163+
end
164+
165+
def update
166+
cookbook_name = params[:cookbook_id]
167+
cookbook_path = cookbook_location(cookbook_name)
168+
raise NotFound, "Cannot find cookbook named #{cookbook_name}" unless File.directory? cookbook_path
169+
begin
170+
validate_file_parameter(cookbook_name, params[:file])
171+
rescue FileParameterException => te
172+
raise BadRequest, te.message
173+
end
174+
175+
expand_tarball_and_put_in_repository(cookbook_name, params[:file][:tempfile])
176+
177+
display Hash.new
178+
end
179+
180+
def destroy
181+
cookbook_name = params[:id]
182+
cookbook_path = cookbook_location(cookbook_name)
183+
raise NotFound, "Cannot find cookbook named #{cookbook_name}" unless File.directory? cookbook_path
184+
185+
FileUtils.rm_rf(cookbook_path)
186+
FileUtils.rm_f(cookbook_tarball_location(cookbook_name))
187+
188+
display Hash.new
189+
end
190+
128191
end
129192

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
#
2+
# Author:: Christopher Walters (<cw@opscode.com>)
3+
# Copyright:: Copyright (c) 2009 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+
module Merb
20+
module ChefServerApi
21+
module TarballHelper
22+
23+
class FileParameterException < StandardError ; end
24+
25+
def validate_file_parameter(cookbook_name, file_param)
26+
raise FileParameterException, "missing required parameter: file" unless file_param
27+
raise FileParameterException, "invalid parameter: file must be a File" unless file_param.respond_to?(:has_key?) && file_param[:tempfile].respond_to?(:read)
28+
tarball_path = file_param[:tempfile].path
29+
raise FileParameterException, "invalid tarball: (try creating with 'tar czf cookbook.tar.gz cookbook/')" unless system("tar", "tzf", tarball_path)
30+
entry_roots = `tar tzf #{tarball_path}`.split("\n").map{|e|(e.split('/')-['.']).first}.uniq
31+
raise FileParameterException, "invalid tarball: tarball root must contain #{cookbook_name}" unless entry_roots.include?(cookbook_name)
32+
end
33+
34+
def cookbook_base
35+
[Chef::Config.cookbook_path].flatten.first
36+
end
37+
38+
def cookbook_location(cookbook_name)
39+
File.join(cookbook_base, cookbook_name)
40+
end
41+
42+
def cookbook_tarball_location(cookbook_name)
43+
File.join(Chef::Config.cookbook_tarball_path, "#{cookbook_name}.tar.gz")
44+
end
45+
46+
def get_or_create_cookbook_tarball_location(cookbook_name)
47+
tarball_location = cookbook_tarball_location(cookbook_name)
48+
unless File.exists? tarball_location
49+
args = ["tar", "-C", cookbook_base, "-czf", tarball_location, cookbook_name]
50+
Chef::Log.debug("Tarball for #{cookbook_name} not found, so creating at #{tarball_location} with '#{args.join(' ')}'")
51+
FileUtils.mkdir_p(Chef::Config.cookbook_tarball_path)
52+
system(*args)
53+
end
54+
tarball_location
55+
end
56+
57+
def expand_tarball_and_put_in_repository(cookbook_name, file)
58+
# untar cookbook tarball into tempdir
59+
tempdir = File.join("#{file.path}.data")
60+
Chef::Log.debug("Creating #{tempdir} and untarring #{file.path} into it")
61+
FileUtils.mkdir_p(tempdir)
62+
raise "Could not untar file" unless system("tar", "xzf", file.path, "-C", tempdir)
63+
64+
cookbook_path = cookbook_location(cookbook_name)
65+
tarball_path = cookbook_tarball_location(cookbook_name)
66+
67+
# clear any existing cookbook components and move tempdir into the repository
68+
Chef::Log.debug("Moving #{tempdir} to #{cookbook_path}")
69+
FileUtils.rm_rf(cookbook_path)
70+
FileUtils.mkdir_p(cookbook_path)
71+
Dir[File.join(tempdir, cookbook_name, "*")].each{|e| FileUtils.mv(e, cookbook_path)}
72+
73+
# clear the existing tarball (if exists) and move the downloaded tarball to the cache
74+
Chef::Log.debug("Moving #{file.path} to #{tarball_path}")
75+
FileUtils.mkdir_p(Chef::Config.cookbook_tarball_path)
76+
FileUtils.rm_f(tarball_path)
77+
FileUtils.mv(file.path, tarball_path)
78+
end
79+
80+
end
81+
end
82+
end

chef/lib/chef/config.rb

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,8 @@ def self.manage_secret_key
9898

9999
authorized_openid_identifiers nil
100100
authorized_openid_providers nil
101-
cookbook_path [ "/var/chef/site-cookbooks", "/var/chef/cookbooks" ]
101+
cookbook_path [ "/var/chef/cookbooks", "/var/chef/site-cookbooks" ]
102+
cookbook_tarballs_path "/var/chef/cookbook-tarballs"
102103
couchdb_database "chef"
103104
couchdb_url "http://localhost:5984"
104105
couchdb_version nil

chef/lib/chef/cookbook_loader.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ def initialize()
3838

3939
def load_cookbooks
4040
cookbook_settings = Hash.new
41-
[Chef::Config.cookbook_path].flatten.reverse.each do |cb_path|
41+
[Chef::Config.cookbook_path].flatten.each do |cb_path|
4242
Dir[File.join(cb_path, "*")].each do |cookbook|
4343
next unless File.directory?(cookbook)
4444
cookbook_name = File.basename(cookbook).to_sym

chef/lib/chef/rest.rb

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,14 +36,15 @@ class CookieJar < Hash
3636
include Singleton
3737
end
3838

39-
attr_accessor :url, :cookies, :signing_key
39+
attr_accessor :url, :cookies, :client_name, :signing_key, :signing_key_filename
4040

41-
def initialize(url, client_name=Chef::Config[:node_name], signing_key=Chef::Config[:client_key])
41+
def initialize(url, client_name=Chef::Config[:node_name], signing_key_filename=Chef::Config[:client_key])
4242
@url = url
4343
@cookies = CookieJar.instance
4444
@client_name = client_name
45-
if signing_key
46-
@signing_key = load_signing_key(signing_key)
45+
if signing_key_filename
46+
@signing_key_filename = signing_key_filename
47+
@signing_key = load_signing_key(signing_key_filename)
4748
else
4849
@signing_key = nil
4950
end

chef/spec/unit/cookbook_loader_spec.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@
2121
describe Chef::CookbookLoader do
2222
before(:each) do
2323
Chef::Config.cookbook_path [
24-
File.join(File.dirname(__FILE__), "..", "data", "cookbooks"),
25-
File.join(File.dirname(__FILE__), "..", "data", "kitchen")
24+
File.join(File.dirname(__FILE__), "..", "data", "kitchen"),
25+
File.join(File.dirname(__FILE__), "..", "data", "cookbooks")
2626
]
2727
@cl = Chef::CookbookLoader.new()
2828
end

cucumber.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
default: -f pretty features -r features/steps -r features/support
22
api: --tags @api --format pretty -r features/steps -r features/support features
33
api_cookbooks: --tags @api,@cookbooks --format pretty -r features/steps -r features/support features
4+
api_cookbooks_tarballs: --tags @api,@cookbooks,@tarballs --format pretty -r features/steps -r features/support features
45
api_clients: --tags @api_clients --format pretty -r features/steps -r features/support features
56
api_clients_create: --tags clients_create --format pretty -r features/steps -r features/support features
67
api_clients_delete: --tags clients_delete --format pretty -r features/steps -r features/support features

0 commit comments

Comments
 (0)