Skip to content

Commit

Permalink
Merge branch 'master' into whyrun
Browse files Browse the repository at this point in the history
Conflicts:
	chef/lib/chef/cookbook_version.rb
	chef/lib/chef/provider/deploy.rb
	chef/lib/chef/provider/service/freebsd.rb
	chef/spec/unit/provider/service/freebsd_service_spec.rb
  • Loading branch information
marcparadise committed Jun 22, 2012
2 parents 32f6540 + baa9a78 commit b36f636
Show file tree
Hide file tree
Showing 49 changed files with 908 additions and 82 deletions.
2 changes: 1 addition & 1 deletion chef-expander/lib/chef/expander/version.rb
Expand Up @@ -23,7 +23,7 @@
module Chef
module Expander

VERSION = "10.12.0"
VERSION = "10.13.0"

def self.version
@rev ||= begin
Expand Down
4 changes: 2 additions & 2 deletions chef-server-api/app/controllers/clients.rb
Expand Up @@ -23,9 +23,9 @@ class Clients < Application
provides :json

before :authenticate_every
before :is_admin, :only => [ :index, :update, :destroy ]
before :is_admin, :only => [ :index, :update ]
before :is_admin_or_validator, :only => [ :create ]
before :admin_or_requesting_node, :only => [ :show ]
before :admin_or_requesting_node, :only => [ :show, :destroy ]

# GET /clients
def index
Expand Down
2 changes: 1 addition & 1 deletion chef-server-api/lib/chef-server-api/version.rb
@@ -1,3 +1,3 @@
module ChefServerApi
VERSION = '10.12.0'
VERSION = '10.13.0'
end
10 changes: 6 additions & 4 deletions chef-server-api/spec/spec_helper.rb
Expand Up @@ -78,12 +78,14 @@ def request_json(method, path, params, env, &block)
@response_json = Chef::JSONCompat.from_json(@response_raw)
end

def stub_authentication(controller)
def stub_authentication(controller,user=nil)
username = "tester"

user = Chef::ApiClient.new
user.name(username)
user.admin(true)
unless user
user = Chef::ApiClient.new
user.name(username)
user.admin(true)
end

# authenticate_every has a side-effect of setting @auth_user
controller.stub!(:authenticate_every).and_return(true)
Expand Down
7 changes: 7 additions & 0 deletions chef-server-api/spec/spec_model_helper.rb
Expand Up @@ -53,6 +53,13 @@ def make_runlist(*items)
res
end

def make_client(name,admin=false)
res = Chef::ApiClient.new
res.name(name)
res.admin(admin)
res
end

def stub_checksum(checksum, present = true)
Chef::Checksum.should_receive(:new).with(checksum).and_return do
obj = stub(Chef::Checksum)
Expand Down
74 changes: 74 additions & 0 deletions chef-server-api/spec/unit/clients_controller_spec.rb
@@ -0,0 +1,74 @@
#
# Author:: Michael Ivey (<ivey@gweezlebur.com>)
# Copyright:: Copyright (c) 2012 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.
#

require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
require File.expand_path(File.dirname(__FILE__) + '/../spec_model_helper')
require 'pp'

describe "Clients Controller" do
before do
Merb.logger.set_log(StringIO.new)
end

describe "when deleting a client" do
before do
@client = make_client("deleted_client")
@caller = make_client("deleting_client")
end

describe "from an admin client" do
before do
@caller.admin(true)
end

it "should delete the client" do
Chef::ApiClient.stub!(:cdb_load).and_return(@client)
@client.should_receive(:cdb_destroy).and_return(true)
@controller = mock_request("/clients/deleted_client", {}, {'HTTP_ACCEPT' => "application/json", :request_method => "DELETE"}) do |controller|
stub_authentication(controller, @caller)
end
@response_raw = @controller.body
@response_json = Chef::JSONCompat.from_json(@response_raw)
end
end

describe "from a non-admin client" do
it "should not delete the client" do
Chef::ApiClient.stub!(:cdb_load).and_return(@client)
lambda {
@controller = mock_request("/clients/deleted_client", {}, {'HTTP_ACCEPT' => "application/json", :request_method => "DELETE"}) do |controller|
stub_authentication(controller, @caller)
end
}.should raise_error(Merb::ControllerExceptions::Forbidden, /You are not the correct node.*not an API admin/)
end
end

describe "from the same client as it is trying to delete" do
it "should delete the client" do
Chef::ApiClient.stub!(:cdb_load).and_return(@client)
@client.should_receive(:cdb_destroy).and_return(true)
@controller = mock_request("/clients/deleted_client", {}, {'HTTP_ACCEPT' => "application/json", :request_method => "DELETE"}) do |controller|
stub_authentication(controller, @client)
end
@response_raw = @controller.body
@response_json = Chef::JSONCompat.from_json(@response_raw)
end
end

end
end
2 changes: 1 addition & 1 deletion chef-server-webui/lib/chef-server-webui/version.rb
@@ -1,3 +1,3 @@
module ChefServerWebui
VERSION = '10.12.0'
VERSION = '10.13.0'
end
6 changes: 3 additions & 3 deletions chef-server-webui/public/javascripts/chef.js
Expand Up @@ -116,7 +116,7 @@ $(document).ready(function(){
});

// livequery hidden form for link_to ajax magic
$(document.body).delegate('a[method]', 'click', function(event){
$(document.body).delegate('a[method]', 'click', function(e){
var $this = $(this);
var message = $this.attr('confirm'), method = $this.attr('method');

Expand All @@ -125,12 +125,12 @@ $(document).ready(function(){
}

if (message && !confirm(message)) {
event.preventDefault();
e.preventDefault(e);
return;
}

if (method === 'post' || method === 'put' || method === 'delete') {
event.preventDefault();
e.preventDefault(e);
var form = $("<form/>").attr('method', 'post').attr('action', this.href).attr('style', 'display: none');
if (method !== "post") {
form.append($('<input type="hidden" name="_method"/>').attr('value', method));
Expand Down
2 changes: 1 addition & 1 deletion chef-server/lib/chef-server/version.rb
Expand Up @@ -17,5 +17,5 @@
#

module ChefServer
VERSION = '10.12.0'
VERSION = '10.13.0'
end
2 changes: 1 addition & 1 deletion chef-solr/lib/chef/solr/version.rb
@@ -1,6 +1,6 @@
class Chef
class Solr
VERSION = '10.12.0'
VERSION = '10.13.0'

# Solr Schema. Used to detect incompatibilities between installed solr and
# chef-solr versions.
Expand Down
2 changes: 1 addition & 1 deletion chef/chef.gemspec
Expand Up @@ -38,5 +38,5 @@ Gem::Specification.new do |s|
s.bindir = "bin"
s.executables = %w( chef-client chef-solo knife shef )
s.require_path = 'lib'
s.files = %w(LICENSE README.rdoc) + Dir.glob("{distro,lib}/**/*")
s.files = %w(Rakefile LICENSE README.rdoc) + Dir.glob("{distro,lib,tasks,spec}/**/*")
end
3 changes: 3 additions & 0 deletions chef/distro/common/markdown/man1/knife-bootstrap.mkd
Expand Up @@ -31,6 +31,9 @@ __knife__ __bootstrap__ _(options)_
Bootstrap a distro using a template
* `--[no-]host-key-verify`:
Enable host key verification, which is the default behavior.
* `--hint HINT_NAME[=HINT_FILE]`:
Provide the name of a hint (with option JSON file) to set for use by
Ohai plugins.

## DESCRIPTION

Expand Down
3 changes: 3 additions & 0 deletions chef/lib/chef/config.rb
Expand Up @@ -139,6 +139,9 @@ def self.platform_specific_path(path)
cookbook_path [ platform_specific_path("/var/chef/cookbooks"),
platform_specific_path("/var/chef/site-cookbooks") ]

# An array of paths to search for knife exec scripts if they aren't in the current directory
script_path []

# Where files are stored temporarily during uploads
sandbox_path "/var/chef/sandboxes"

Expand Down
120 changes: 120 additions & 0 deletions chef/lib/chef/cookbook_version.rb
Expand Up @@ -288,6 +288,126 @@ def self.cache
Chef::FileCache
end

# Setup a notification to clear the valid_cache_entries when a Chef client
# run starts
Chef::Client.when_run_starts do |run_status|
reset_cache_validity
end

# Synchronizes all the cookbooks from the chef-server.
#
# === Returns
# true:: Always returns true
def self.sync_cookbooks(cookbook_hash)
Chef::Log.info("Loading cookbooks [#{cookbook_hash.keys.sort.join(', ')}]")
Chef::Log.debug("Cookbooks detail: #{cookbook_hash.inspect}")

clear_obsoleted_cookbooks(cookbook_hash)

# Synchronize each of the node's cookbooks, and add to the
# valid_cache_entries hash.
cookbook_hash.values.each do |cookbook|
sync_cookbook_file_cache(cookbook)
end

true
end

# Iterates over cached cookbooks' files, removing files belonging to
# cookbooks that don't appear in +cookbook_hash+
def self.clear_obsoleted_cookbooks(cookbook_hash)
# Remove all cookbooks no longer relevant to this node
cache.find(File.join(%w{cookbooks ** *})).each do |cache_file|
cache_file =~ /^cookbooks\/([^\/]+)\//
unless cookbook_hash.has_key?($1)
Chef::Log.info("Removing #{cache_file} from the cache; its cookbook is no longer needed on this client.")
cache.delete(cache_file)
end
end
end

# Update the file caches for a given cache segment. Takes a segment name
# and a hash that matches one of the cookbooks/_attribute_files style
# remote file listings.
#
# === Parameters
# cookbook<Chef::Cookbook>:: The cookbook to update
# valid_cache_entries<Hash>:: Out-param; Added to this hash are the files that
# were referred to by this cookbook
def self.sync_cookbook_file_cache(cookbook)
Chef::Log.debug("Synchronizing cookbook #{cookbook.name}")

# files and templates are lazily loaded, and will be done later.
eager_segments = COOKBOOK_SEGMENTS.dup

unless Chef::Config[:no_lazy_load] then
eager_segments.delete(:files)
eager_segments.delete(:templates)
end

eager_segments.each do |segment|
segment_filenames = Array.new
cookbook.manifest[segment].each do |manifest_record|
# segment = cookbook segment
# remote_list = list of file hashes
#
# We need the list of known good attribute files, so we can delete any that are
# just laying about.

cache_filename = File.join("cookbooks", cookbook.name, manifest_record['path'])
valid_cache_entries[cache_filename] = true

current_checksum = nil
if cache.has_key?(cache_filename)
current_checksum = checksum_cookbook_file(cache.load(cache_filename, false))
end

# If the checksums are different between on-disk (current) and on-server
# (remote, per manifest), do the update. This will also execute if there
# is no current checksum.
if current_checksum != manifest_record['checksum']
raw_file = chef_server_rest.get_rest(manifest_record[:url], true)

Chef::Log.info("Storing updated #{cache_filename} in the cache.")
cache.move_to(raw_file.path, cache_filename)
else
Chef::Log.debug("Not storing #{cache_filename}, as the cache is up to date.")
end

# make the segment filenames a full path.
full_path_cache_filename = cache.load(cache_filename, false)
segment_filenames << full_path_cache_filename
end

# replace segment filenames with a full-path one.
if segment.to_sym == :recipes
cookbook.recipe_filenames = segment_filenames
elsif segment.to_sym == :attributes
cookbook.attribute_filenames = segment_filenames
else
cookbook.segment_filenames(segment).replace(segment_filenames)
end
end
end

def self.cleanup_file_cache
unless Chef::Config[:solo]
# Delete each file in the cache that we didn't encounter in the
# manifest.
cache.find(File.join(%w{cookbooks ** *})).each do |cache_filename|
unless valid_cache_entries[cache_filename]
Chef::Log.info("Removing #{cache_filename} from the cache; it is no longer needed by chef-client.")
cache.delete(cache_filename)
end
end
end
end

# Register a notification to cleanup unused files from cookbooks
Chef::Client.when_run_completes_successfully do |run_status|
cleanup_file_cache
end

# Creates a new Chef::CookbookVersion object.
#
# === Returns
Expand Down
2 changes: 1 addition & 1 deletion chef/lib/chef/data_bag.rb
Expand Up @@ -159,7 +159,7 @@ def self.load(name)
raise Chef::Exceptions::InvalidDataBagPath, "Data bag path '#{Chef::Config[:data_bag_path]}' is invalid"
end

Dir.glob(File.join(Chef::Config[:data_bag_path], name, "*.json")).inject({}) do |bag, f|
Dir.glob(File.join(Chef::Config[:data_bag_path], "#{name}", "*.json")).inject({}) do |bag, f|
item = JSON.parse(IO.read(f))
bag[item['id']] = item
bag
Expand Down
6 changes: 4 additions & 2 deletions chef/lib/chef/file_cache.rb
Expand Up @@ -33,10 +33,12 @@ class << self
# path<String>:: The path to the file you want to put in the cache - should
# be relative to file_cache_path
# contents<String>:: A string with the contents you want written to the file
# perm<String>:: Sets file permission bits. Permission bits are platform
# dependent; on Unix systems, see open(2) for details.
#
# === Returns
# true
def store(path, contents)
def store(path, contents, perm=0640)
validate(
{
:path => path,
Expand All @@ -51,7 +53,7 @@ def store(path, contents)
file_path_array = File.split(path)
file_name = file_path_array.pop
cache_path = create_cache_path(File.join(file_path_array))
File.open(File.join(cache_path, file_name), "w") do |io|
File.open(File.join(cache_path, file_name), "w", perm) do |io|
io.print(contents)
end
true
Expand Down
2 changes: 1 addition & 1 deletion chef/lib/chef/handler/error_report.rb
Expand Up @@ -24,7 +24,7 @@ class Handler
class ErrorReport < ::Chef::Handler

def report
Chef::FileCache.store("failed-run-data.json", Chef::JSONCompat.to_json_pretty(data))
Chef::FileCache.store("failed-run-data.json", Chef::JSONCompat.to_json_pretty(data), 0640)
Chef::Log.fatal("Saving node information to #{Chef::FileCache.load("failed-run-data.json", false)}")
end

Expand Down

0 comments on commit b36f636

Please sign in to comment.