Skip to content

Commit

Permalink
CHEF-542: cookbook tarball CRUD, which necessitated CHEF-754: reposit…
Browse files Browse the repository at this point in the history
…ories configured in the cookbook_path are no longer overlayed in reverse order.
  • Loading branch information
chris committed Dec 7, 2009
1 parent aa9e71e commit 61062af
Show file tree
Hide file tree
Showing 17 changed files with 499 additions and 30 deletions.
4 changes: 4 additions & 0 deletions Rakefile
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,10 @@ namespace :features do
Cucumber::Rake::Task.new(:cookbooks) do |t|
t.profile = "api_cookbooks"
end

Cucumber::Rake::Task.new(:cookbook_tarballs) do |t|
t.profile = "api_cookbooks_tarballs"
end
end

namespace :data do
Expand Down
69 changes: 66 additions & 3 deletions chef-server-api/app/controllers/cookbooks.rb
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
#
# Author:: Adam Jacob (<adam@opscode.com>)
# Author:: Christopher Brown (<cb@opscode.com>)
# Copyright:: Copyright (c) 2008 Opscode, Inc.
# Author:: Christopher Walters (<cw@opscode.com>)
# Copyright:: Copyright (c) 2008, 2009 Opscode, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
Expand All @@ -27,6 +28,7 @@ class ChefServerApi::Cookbooks < ChefServerApi::Application
before :authenticate_every

include Chef::Mixin::Checksum
include Merb::ChefServerApi::TarballHelper

def index
cl = Chef::CookbookLoader.new
Expand All @@ -42,15 +44,15 @@ def show
begin
cookbook = cl[params[:id]]
rescue ArgumentError => e
raise NotFound, "Cannot find a cookbook named #{cookbook.to_s}"
raise NotFound, "Cannot find a cookbook named #{params[:id]}"
end
results = load_cookbook_files(cookbook)
results[:name] = cookbook.name.to_s
results[:metadata] = cl.metadata[cookbook.name.to_sym]
display results
end

def show_segment
def show_segment
cl = Chef::CookbookLoader.new
begin
cookbook = cl[params[:cookbook_id]]
Expand Down Expand Up @@ -125,5 +127,66 @@ def serve_segment_file(cookbook, segment, files)
end
end

def create
# validate name and file parameters and throw an error if a cookbook with the same name already exists
raise BadRequest, "missing required parameter: name" unless params[:name]
desired_name = params[:name]
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/
begin
validate_file_parameter(desired_name, params[:file])
rescue FileParameterException => te
raise BadRequest, te.message
end

begin
Chef::CookbookLoader.new[desired_name]
raise BadRequest, "Cookbook with the name #{desired_name} already exists"
rescue ArgumentError
end

expand_tarball_and_put_in_repository(desired_name, params[:file][:tempfile])

# construct successful response
self.status = 201
location = absolute_slice_url(:cookbook, :id => desired_name)
headers['Location'] = location
result = { 'uri' => location }
display result
end

def get_tarball
cookbook_name = params[:cookbook_id]
expected_location = cookbook_location(cookbook_name)
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

send_file(get_or_create_cookbook_tarball_location(cookbook_name))
end

def update
cookbook_name = params[:cookbook_id]
cookbook_path = cookbook_location(cookbook_name)
raise NotFound, "Cannot find cookbook named #{cookbook_name}" unless File.directory? cookbook_path
begin
validate_file_parameter(cookbook_name, params[:file])
rescue FileParameterException => te
raise BadRequest, te.message
end

expand_tarball_and_put_in_repository(cookbook_name, params[:file][:tempfile])

display Hash.new
end

def destroy
cookbook_name = params[:id]
cookbook_path = cookbook_location(cookbook_name)
raise NotFound, "Cannot find cookbook named #{cookbook_name}" unless File.directory? cookbook_path

FileUtils.rm_rf(cookbook_path)
FileUtils.rm_f(cookbook_tarball_location(cookbook_name))

display Hash.new
end

end

82 changes: 82 additions & 0 deletions chef-server-api/app/helpers/tarball_helper.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
#
# Author:: Christopher Walters (<cw@opscode.com>)
# Copyright:: Copyright (c) 2009 Opscode, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#

module Merb
module ChefServerApi
module TarballHelper

class FileParameterException < StandardError ; end

def validate_file_parameter(cookbook_name, file_param)
raise FileParameterException, "missing required parameter: file" unless file_param
raise FileParameterException, "invalid parameter: file must be a File" unless file_param.respond_to?(:has_key?) && file_param[:tempfile].respond_to?(:read)
tarball_path = file_param[:tempfile].path
raise FileParameterException, "invalid tarball: (try creating with 'tar czf cookbook.tar.gz cookbook/')" unless system("tar", "tzf", tarball_path)
entry_roots = `tar tzf #{tarball_path}`.split("\n").map{|e|e.split('/').first}.uniq
raise FileParameterException, "invalid tarball: tarball root must contain #{cookbook_name}" unless entry_roots.include?(cookbook_name)
end

def cookbook_base
[Chef::Config.cookbook_path].flatten.first
end

def cookbook_location(cookbook_name)
File.join(cookbook_base, cookbook_name)
end

def cookbook_tarball_location(cookbook_name)
File.join(Chef::Config.cookbook_tarball_path, "#{cookbook_name}.tar.gz")
end

def get_or_create_cookbook_tarball_location(cookbook_name)
tarball_location = cookbook_tarball_location(cookbook_name)
unless File.exists? tarball_location
args = ["tar", "-C", cookbook_base, "-czf", tarball_location, cookbook_name]
Chef::Log.debug("Tarball for #{cookbook_name} not found, so creating at #{tarball_location} with '#{args.join(' ')}'")
FileUtils.mkdir_p(Chef::Config.cookbook_tarball_path)
system(*args)
end
tarball_location
end

def expand_tarball_and_put_in_repository(cookbook_name, file)
# untar cookbook tarball into tempdir
tempdir = File.join("#{file.path}.data")
Chef::Log.debug("Creating #{tempdir} and untarring #{file.path} into it")
FileUtils.mkdir_p(tempdir)
raise "Could not untar file" unless system("tar", "xzf", file.path, "-C", tempdir)

cookbook_path = cookbook_location(cookbook_name)
tarball_path = cookbook_tarball_location(cookbook_name)

# clear any existing cookbook components and move tempdir into the repository
Chef::Log.debug("Moving #{tempdir} to #{cookbook_path}")
FileUtils.rm_rf(cookbook_path)
FileUtils.mkdir_p(cookbook_path)
Dir[File.join(tempdir, cookbook_name, "*")].each{|e| FileUtils.mv(e, cookbook_path)}

# clear the existing tarball (if exists) and move the downloaded tarball to the cache
Chef::Log.debug("Moving #{file.path} to #{tarball_path}")
FileUtils.mkdir_p(Chef::Config.cookbook_tarball_path)
FileUtils.rm_f(tarball_path)
FileUtils.mv(file.path, tarball_path)
end

end
end
end
3 changes: 2 additions & 1 deletion chef/lib/chef/config.rb
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,8 @@ def self.manage_secret_key

authorized_openid_identifiers nil
authorized_openid_providers nil
cookbook_path [ "/var/chef/site-cookbooks", "/var/chef/cookbooks" ]
cookbook_path [ "/var/chef/cookbooks", "/var/chef/site-cookbooks" ]
cookbook_tarballs_path "/var/chef/cookbook-tarballs"
couchdb_database "chef"
couchdb_url "http://localhost:5984"
couchdb_version nil
Expand Down
2 changes: 1 addition & 1 deletion chef/lib/chef/cookbook_loader.rb
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ def initialize()

def load_cookbooks
cookbook_settings = Hash.new
[Chef::Config.cookbook_path].flatten.reverse.each do |cb_path|
[Chef::Config.cookbook_path].flatten.each do |cb_path|
Dir[File.join(cb_path, "*")].each do |cookbook|
next unless File.directory?(cookbook)
cookbook_name = File.basename(cookbook).to_sym
Expand Down
9 changes: 5 additions & 4 deletions chef/lib/chef/rest.rb
Original file line number Diff line number Diff line change
Expand Up @@ -36,14 +36,15 @@ class CookieJar < Hash
include Singleton
end

attr_accessor :url, :cookies, :signing_key
attr_accessor :url, :cookies, :client_name, :signing_key, :signing_key_filename

def initialize(url, client_name=Chef::Config[:node_name], signing_key=Chef::Config[:client_key])
def initialize(url, client_name=Chef::Config[:node_name], signing_key_filename=Chef::Config[:client_key])
@url = url
@cookies = CookieJar.instance
@client_name = client_name
if signing_key
@signing_key = load_signing_key(signing_key)
if signing_key_filename
@signing_key_filename = signing_key_filename
@signing_key = load_signing_key(signing_key_filename)
else
@signing_key = nil
end
Expand Down
4 changes: 2 additions & 2 deletions chef/spec/unit/cookbook_loader_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@
describe Chef::CookbookLoader do
before(:each) do
Chef::Config.cookbook_path [
File.join(File.dirname(__FILE__), "..", "data", "cookbooks"),
File.join(File.dirname(__FILE__), "..", "data", "kitchen")
File.join(File.dirname(__FILE__), "..", "data", "kitchen"),
File.join(File.dirname(__FILE__), "..", "data", "cookbooks")
]
@cl = Chef::CookbookLoader.new()
end
Expand Down
1 change: 1 addition & 0 deletions cucumber.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
default: -f pretty features -r features/steps -r features/support
api: --tags @api --format pretty -r features/steps -r features/support features
api_cookbooks: --tags @api,@cookbooks --format pretty -r features/steps -r features/support features
api_cookbooks_tarballs: --tags @api,@cookbooks,@tarballs --format pretty -r features/steps -r features/support features
api_clients: --tags @api_clients --format pretty -r features/steps -r features/support features
api_clients_create: --tags clients_create --format pretty -r features/steps -r features/support features
api_clients_delete: --tags clients_delete --format pretty -r features/steps -r features/support features
Expand Down
Loading

0 comments on commit 61062af

Please sign in to comment.