diff options
author | chris <chris@opscodes-macbook-pro-2.local> | 2009-09-23 22:08:41 +0000 |
---|---|---|
committer | chris <chris@opscodes-macbook-pro-2.local> | 2009-09-23 22:11:01 +0000 |
commit | 480938b0faf62ea264b33d4140ca11561a8235b1 (patch) | |
tree | 2c50a349f117f2dbdd3d968ec876b19670331721 | |
parent | 8ae8a64b8564d19123600434dafc3bf4adfeb9ff (diff) | |
download | chef-480938b0faf62ea264b33d4140ca11561a8235b1.tar.gz |
Adding embedded resources inside providers and some re-factoring in the core. There are cucumber tests for the new functionality, but unit tests are not included in this commit.
29 files changed, 271 insertions, 152 deletions
diff --git a/chef/lib/chef/client.rb b/chef/lib/chef/client.rb index da25a1cbcf..9cce426440 100644 --- a/chef/lib/chef/client.rb +++ b/chef/lib/chef/client.rb @@ -401,15 +401,9 @@ class Chef Chef::Config[:cookbook_path] = File.join(Chef::Config[:file_cache_path], "cookbooks") end compile = Chef::Compile.new(@node) - compile.load_libraries - compile.load_providers - compile.load_resources - compile.load_attributes - compile.load_definitions - compile.load_recipes - + Chef::Log.debug("Converging node #{@safe_name}") - cr = Chef::Runner.new(@node, compile.collection) + cr = Chef::Runner.new(@node, compile.collection, compile.definitions, compile.cookbook_loader) cr.converge true end diff --git a/chef/lib/chef/compile.rb b/chef/lib/chef/compile.rb index 44cc63c92a..b6eaf77e8f 100644 --- a/chef/lib/chef/compile.rb +++ b/chef/lib/chef/compile.rb @@ -28,8 +28,8 @@ class Chef attr_accessor :node, :cookbook_loader, :collection, :definitions - # Creates a new Chef::Compile object. This object gets used by the Chef Server to generate - # a fully compiled recipe list for a node. + # Creates a new Chef::Compile object and populates its fields. This object gets + # used by the Chef Server to generate a fully compiled recipe list for a node. # # === Returns # object<Chef::Compile>:: Duh. :) @@ -41,6 +41,13 @@ class Chef @recipes = Array.new @default_attributes = Array.new @override_attributes = Array.new + + load_libraries + load_providers + load_resources + load_attributes + load_definitions + load_recipes end # Looks up the node via the "name" argument, first from CouchDB, then by calling diff --git a/chef/lib/chef/cookbook.rb b/chef/lib/chef/cookbook.rb index 320da397f3..14f567ef2b 100644 --- a/chef/lib/chef/cookbook.rb +++ b/chef/lib/chef/cookbook.rb @@ -101,9 +101,8 @@ class Chef # true:: Always returns true def load_resources @resource_files.each do |file| - class_name = class_name_from_filename(file) - Chef::Log.debug("Loading cookbook #{name}'s resources from #{file} into class Chef::Resource::#{class_name}") - Chef::Resource.const_set(class_name, Chef::Resource.build_from_file(file)) + Chef::Log.debug("Loading cookbook #{name}'s resources from #{file}") + Chef::Resource.build_from_file(name, file) end end @@ -113,9 +112,8 @@ class Chef # true:: Always returns true def load_providers @provider_files.each do |file| - class_name = class_name_from_filename(file) - Chef::Log.debug("Loading cookbook #{name}'s providers from #{file} into class Chef::Provider::#{class_name}") - Chef::Provider.const_set(class_name, Chef::Provider.build_from_file(file)) + Chef::Log.debug("Loading cookbook #{name}'s providers from #{file}") + Chef::Provider.build_from_file(name, file) end end @@ -169,14 +167,5 @@ class Chef recipe end - private - - def class_name_from_filename(filename) - class_name_base = name.to_s - file_base = File.basename(filename, ".rb") - class_name_base += "_#{file_base}" unless file_base == 'default' - convert_to_class_name(class_name_base) - end - end end diff --git a/chef/lib/chef/mixin/convert_to_class_name.rb b/chef/lib/chef/mixin/convert_to_class_name.rb index ce2c75e449..4ed89b527a 100644 --- a/chef/lib/chef/mixin/convert_to_class_name.rb +++ b/chef/lib/chef/mixin/convert_to_class_name.rb @@ -1,7 +1,7 @@ # # Author:: Adam Jacob (<adam@opscode.com>) # Author:: Christopher Walters (<cw@opscode.com>) -# Copyright:: Copyright (c) 2009 Opscode, Inc. +# Copyright:: Copyright (c) 2008, 2009 Opscode, Inc. # License:: Apache License, Version 2.0 # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -27,7 +27,7 @@ class Chef mn = str.match(regexp) if mn - rname = "#{mod ? "#{mod.to_s}::" : ''}#{mn[1].capitalize}" + rname = mn[1].capitalize while mn && mn[3] mn = mn[3].match(regexp) @@ -38,6 +38,11 @@ class Chef rname end + def filename_to_qualified_string(base, filename) + file_base = File.basename(filename, ".rb") + base.to_s + (file_base == 'default' ? '' : "_#{file_base}") + end + end end end diff --git a/chef/lib/chef/mixin/recipe_definition_dsl_core.rb b/chef/lib/chef/mixin/recipe_definition_dsl_core.rb new file mode 100644 index 0000000000..9f80b41903 --- /dev/null +++ b/chef/lib/chef/mixin/recipe_definition_dsl_core.rb @@ -0,0 +1,75 @@ +# +# Author:: Adam Jacob (<adam@opscode.com>) +# 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"); +# 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 'chef/recipe' +require 'chef/resource' +require 'chef/mixin/convert_to_class_name' + +class Chef + module Mixin + module RecipeDefinitionDSLCore + + include Chef::Mixin::ConvertToClassName + + def method_missing(method_symbol, *args, &block) + # If we have a definition that matches, we want to use that instead. This should + # let you do some really crazy over-riding of "native" types, if you really want + # to. + if @definitions.has_key?(method_symbol) + # This dupes the high level object, but we still need to dup the params + new_def = @definitions[method_symbol].dup + new_def.params = new_def.params.dup + new_def.node = @node + # This sets up the parameter overrides + new_def.instance_eval(&block) if block + new_recipe = Chef::Recipe.new(@cookbook_name, @recipe_name, @node, @collection, @definitions, @cookbook_loader) + new_recipe.params = new_def.params + new_recipe.params[:name] = args[0] + new_recipe.instance_eval(&new_def.recipe) + else + # Otherwise, we're rocking the regular resource call route. + method_name = method_symbol.to_s + rname = convert_to_class_name(method_name) + + resource = nil + begin + args << @collection + args << @node + resource = Chef::Resource.const_get(rname).new(*args) + # If we have a resource like this one, we want to steal its state + resource.load_prior_resource + resource.cookbook_name = @cookbook_name + resource.recipe_name = @recipe_name + resource.params = @params + resource.instance_eval(&block) if block + rescue NameError => e + if e.to_s =~ /Chef::Resource/ + raise NameError, "Cannot find #{rname} for #{method_name}\nOriginal: #{e.to_s}" + else + raise e + end + end + @collection.insert(resource) + resource + end + end + + end + end +end diff --git a/chef/lib/chef/provider.rb b/chef/lib/chef/provider.rb index 822ab1e6cd..267a0f41d4 100644 --- a/chef/lib/chef/provider.rb +++ b/chef/lib/chef/provider.rb @@ -1,7 +1,7 @@ # # Author:: Adam Jacob (<adam@opscode.com>) # Author:: Christopher Walters (<cw@opscode.com>) -# Copyright:: Copyright (c) 2008 Opscode, Inc. +# Copyright:: Copyright (c) 2008, 2009 Opscode, Inc. # License:: Apache License, Version 2.0 # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -17,15 +17,24 @@ # limitations under the License. # +require 'chef/mixin/from_file' +require 'chef/mixin/convert_to_class_name' +require 'chef/mixin/recipe_definition_dsl_core' + class Chef class Provider + include Chef::Mixin::RecipeDefinitionDSLCore + attr_accessor :node, :new_resource, :current_resource - def initialize(node, new_resource) + def initialize(node, new_resource, collection=nil, definitions=nil, cookbook_loader=nil) @node = node @new_resource = new_resource @current_resource = nil + @collection = collection + @definitions = definitions + @cookbook_loader = cookbook_loader end def load_current_resource @@ -38,26 +47,39 @@ class Chef end class << self - def build_from_file(filename) - Class.new self do |cls| - + include Chef::Mixin::ConvertToClassName + + def build_from_file(cookbook_name, filename) + pname = filename_to_qualified_string(cookbook_name, filename) + + new_provider_class = Class.new self do |cls| + def load_current_resource # silence Chef::Exceptions::Override exception end - # setup DSL's shortcut methods class << cls include Chef::Mixin::FromFile + # setup DSL's shortcut methods def action(name, &block) - define_method("action_#{name}", block) + define_method("action_#{name.to_s}") do + instance_eval(&block) + end end end # load provider definition from file cls.class_from_file(filename) - end + + # register new class as a Chef::Provider + pname = filename_to_qualified_string(cookbook_name, filename) + class_name = convert_to_class_name(pname) + Chef::Provider.const_set(class_name, new_provider_class) + Chef::Log.debug("Loaded contents of #{filename} into a provider named #{pname} defined in Chef::Provider::#{class_name}") + + new_provider_class end end diff --git a/chef/lib/chef/provider/cron.rb b/chef/lib/chef/provider/cron.rb index 9e633053ce..a39cff4f25 100644 --- a/chef/lib/chef/provider/cron.rb +++ b/chef/lib/chef/provider/cron.rb @@ -25,8 +25,8 @@ class Chef class Cron < Chef::Provider include Chef::Mixin::Command - def initialize(node, new_resource) - super(node, new_resource) + def initialize(node, new_resource, collection=nil, definitions=nil, cookbook_loader=nil) + super(node, new_resource, collection, definitions, cookbook_loader) @cron_exists = false @cron_empty = false end diff --git a/chef/lib/chef/provider/deploy.rb b/chef/lib/chef/provider/deploy.rb index 569fb14ffd..bd3bb25795 100644 --- a/chef/lib/chef/provider/deploy.rb +++ b/chef/lib/chef/provider/deploy.rb @@ -30,8 +30,8 @@ class Chef attr_reader :scm_provider, :release_path - def initialize(node, new_resource) - super(node, new_resource) + def initialize(node, new_resource, collection=nil, definitions=nil, cookbook_loader=nil) + super(node, new_resource, collection, definitions, cookbook_loader) @scm_provider = @new_resource.scm_provider.new(@node, @new_resource) @release_path = @new_resource.deploy_to + "/releases/#{Time.now.utc.strftime("%Y%m%d%H%M%S")}" diff --git a/chef/lib/chef/provider/group.rb b/chef/lib/chef/provider/group.rb index 30bfcb487c..27500d1e2d 100644 --- a/chef/lib/chef/provider/group.rb +++ b/chef/lib/chef/provider/group.rb @@ -27,8 +27,8 @@ class Chef include Chef::Mixin::Command attr_accessor :group_exists - def initialize(node, new_resource) - super(node, new_resource) + def initialize(node, new_resource, collection=nil, definitions=nil, cookbook_loader=nil) + super(node, new_resource, collection, definitions, cookbook_loader) @group_exists = true end diff --git a/chef/lib/chef/provider/mount.rb b/chef/lib/chef/provider/mount.rb index a12c298034..404677e6fc 100644 --- a/chef/lib/chef/provider/mount.rb +++ b/chef/lib/chef/provider/mount.rb @@ -26,10 +26,6 @@ class Chef include Chef::Mixin::Command - def initialize(node, new_resource) - super(node, new_resource) - end - def action_mount unless @current_resource.mounted Chef::Log.debug("#{@new_resource}: attempting to mount") diff --git a/chef/lib/chef/provider/mount/mount.rb b/chef/lib/chef/provider/mount/mount.rb index 4de2b54fc6..2012401a17 100644 --- a/chef/lib/chef/provider/mount/mount.rb +++ b/chef/lib/chef/provider/mount/mount.rb @@ -27,8 +27,8 @@ class Chef include Chef::Mixin::Command - def initialize(node, new_resource) - super(node, new_resource) + def initialize(node, new_resource, collection=nil, definitions=nil, cookbook_loader=nil) + super(node, new_resource, collection, definitions, cookbook_loader) @real_device = nil end attr_accessor :real_device diff --git a/chef/lib/chef/provider/package.rb b/chef/lib/chef/provider/package.rb index 41390832a6..3b40135c61 100644 --- a/chef/lib/chef/provider/package.rb +++ b/chef/lib/chef/provider/package.rb @@ -30,8 +30,8 @@ class Chef attr_accessor :candidate_version - def initialize(node, new_resource) - super(node, new_resource) + def initialize(node, new_resource, collection=nil, definitions=nil, cookbook_loader=nil) + super(node, new_resource, collection, definitions, cookbook_loader) @candidate_version = nil end diff --git a/chef/lib/chef/provider/package/yum.rb b/chef/lib/chef/provider/package/yum.rb index efd6fee0ad..d4bfac3e87 100644 --- a/chef/lib/chef/provider/package/yum.rb +++ b/chef/lib/chef/provider/package/yum.rb @@ -106,9 +106,9 @@ class Chef end end - def initialize(node, new_resource) + def initialize(node, new_resource, collection=nil, definitions=nil, cookbook_loader=nil) @yum = YumCache.instance - super(node, new_resource) + super(node, new_resource, collection, definitions, cookbook_loader) end def load_current_resource diff --git a/chef/lib/chef/provider/service.rb b/chef/lib/chef/provider/service.rb index f35c424174..d9c3e86401 100644 --- a/chef/lib/chef/provider/service.rb +++ b/chef/lib/chef/provider/service.rb @@ -25,8 +25,8 @@ class Chef include Chef::Mixin::Command - def initialize(node, new_resource) - super(node, new_resource) + def initialize(node, new_resource, collection=nil, definitions=nil, cookbook_loader=nil) + super(node, new_resource, collection, definitions, cookbook_loader) @enabled = nil end diff --git a/chef/lib/chef/provider/service/init.rb b/chef/lib/chef/provider/service/init.rb index 39f3a63ee7..95709626dd 100644 --- a/chef/lib/chef/provider/service/init.rb +++ b/chef/lib/chef/provider/service/init.rb @@ -25,8 +25,8 @@ class Chef class Service class Init < Chef::Provider::Service::Simple - def initialize(node, new_resource) - super(node, new_resource) + def initialize(node, new_resource, collection=nil, definitions=nil, cookbook_loader=nil) + super(node, new_resource, collection, definitions, cookbook_loader) @init_command = "/etc/init.d/#{@new_resource.service_name}" end diff --git a/chef/lib/chef/provider/service/redhat.rb b/chef/lib/chef/provider/service/redhat.rb index 64bfdc4076..ab52762a39 100644 --- a/chef/lib/chef/provider/service/redhat.rb +++ b/chef/lib/chef/provider/service/redhat.rb @@ -25,8 +25,8 @@ class Chef class Service class Redhat < Chef::Provider::Service::Init - def initialize(node, new_resource) - super(node, new_resource) + def initialize(node, new_resource, collection=nil, definitions=nil, cookbook_loader=nil) + super(node, new_resource, collection, definitions, cookbook_loader) @init_command = "/sbin/service #{@new_resource.service_name}" end diff --git a/chef/lib/chef/provider/user.rb b/chef/lib/chef/provider/user.rb index 3f76f8ad4b..5bff74d49b 100644 --- a/chef/lib/chef/provider/user.rb +++ b/chef/lib/chef/provider/user.rb @@ -29,8 +29,8 @@ class Chef attr_accessor :user_exists, :locked - def initialize(node, new_resource) - super(node, new_resource) + def initialize(node, new_resource, collection=nil, definitions=nil, cookbook_loader=nil) + super(node, new_resource, collection, definitions, cookbook_loader) @user_exists = true @locked = nil end diff --git a/chef/lib/chef/recipe.rb b/chef/lib/chef/recipe.rb index a5c5dcb4a2..fdcdfc9e98 100644 --- a/chef/lib/chef/recipe.rb +++ b/chef/lib/chef/recipe.rb @@ -1,6 +1,7 @@ # # Author:: Adam Jacob (<adam@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"); @@ -20,7 +21,7 @@ require 'chef/resource' Dir[File.join(File.dirname(__FILE__), 'resource/**/*.rb')].sort.each { |lib| require lib } require 'chef/mixin/from_file' require 'chef/mixin/language' -require 'chef/mixin/convert_to_class_name' +require 'chef/mixin/recipe_definition_dsl_core' require 'chef/resource_collection' require 'chef/cookbook_loader' require 'chef/rest' @@ -31,8 +32,8 @@ class Chef include Chef::Mixin::FromFile include Chef::Mixin::Language - include Chef::Mixin::ConvertToClassName - + include Chef::Mixin::RecipeDefinitionDSLCore + attr_accessor :cookbook_name, :recipe_name, :recipe, :node, :collection, :definitions, :params, :cookbook_loader @@ -40,25 +41,9 @@ class Chef @cookbook_name = cookbook_name @recipe_name = recipe_name @node = node - - if collection - @collection = collection - else - @collection = Chef::ResourceCollection.new() - end - - if definitions - @definitions = definitions - else - @definitions = Hash.new - end - - if cookbook_loader - @cookbook_loader = cookbook_loader - else - @cookbook_loader = Chef::CookbookLoader.new() - end - + @collection = collection || Chef::ResourceCollection.new + @definitions = definitions || Hash.new + @cookbook_loader = cookbook_loader || Chef::CookbookLoader.new @params = Hash.new end @@ -155,47 +140,5 @@ class Chef end end - def method_missing(method_symbol, *args, &block) - resource = nil - # If we have a definition that matches, we want to use that instead. This should - # let you do some really crazy over-riding of "native" types, if you really want - # to. - if @definitions.has_key?(method_symbol) - # This dupes the high level object, but we still need to dup the params - new_def = @definitions[method_symbol].dup - new_def.params = new_def.params.dup - new_def.node = @node - # This sets up the parameter overrides - new_def.instance_eval(&block) if block - new_recipe = Chef::Recipe.new(@cookbook_name, @recipe_name, @node, @collection, @definitions, @cookbook_loader) - new_recipe.params = new_def.params - new_recipe.params[:name] = args[0] - new_recipe.instance_eval(&new_def.recipe) - else - method_name = method_symbol.to_s - # Otherwise, we're rocking the regular resource call route. - rname = convert_to_class_name(method_name, Chef::Resource) - - begin - args << @collection - args << @node - resource = eval(rname).new(*args) - # If we have a resource like this one, we want to steal it's state - resource.load_prior_resource - resource.cookbook_name = @cookbook_name - resource.recipe_name = @recipe_name - resource.params = @params - resource.instance_eval(&block) if block - rescue Exception => e - if e.kind_of?(NameError) && e.to_s =~ /Chef::Resource/ - raise NameError, "Cannot find #{rname} for #{method_name}\nOriginal: #{e.to_s}" - else - raise e - end - end - @collection << resource - resource - end - end end end diff --git a/chef/lib/chef/resource.rb b/chef/lib/chef/resource.rb index 3e5157304b..77fa606554 100644 --- a/chef/lib/chef/resource.rb +++ b/chef/lib/chef/resource.rb @@ -90,7 +90,11 @@ class Chef begin Chef::Provider.const_get(convert_to_class_name(arg.to_s)) rescue NameError => e - raise ArgumentError, "Undefined provider for #{arg}" + if e.to_s =~ /Chef::Provider/ + raise ArgumentError, "No provider found to match '#{arg}'" + else + raise e + end end else arg @@ -245,8 +249,18 @@ class Chef resource end - def build_from_file(filename) - Class.new self do |cls| + include Chef::Mixin::ConvertToClassName + + def attribute(attr_name, validation_opts={}) + define_method(attr_name.to_sym) do |arg| + set_or_return(attr_name.to_sym, arg, validation_opts) + end + end + + def build_from_file(cookbook_name, filename) + rname = filename_to_qualified_string(cookbook_name, filename) + + new_resource_class = Class.new self do |cls| # default initialize method that ensures that when initialize is finally # wrapped (see below), super is called in the event that the resource @@ -264,19 +278,9 @@ class Chef @actions_to_create end - def actions_to_create=(val) - @actions_to_create = val - end - define_method(:actions) do |*action_names| actions_to_create.push(*action_names) end - - def attribute(attr_name, validation_opts={}) - define_method(attr_name.to_sym) do |arg| - set_or_return(attr_name.to_sym, arg, validation_opts) - end - end end # load resource definition from file @@ -285,15 +289,22 @@ class Chef # create a new constructor that wraps the old one and adds the actions # specified in the DSL old_init = instance_method(:initialize) - + define_method(:initialize) do |name, *optional_args| collection = optional_args.shift node = optional_args.shift + @resource_name = rname.to_sym old_init.bind(self).call(name, collection, node) allowed_actions.push(self.class.actions_to_create).flatten! end - end + + # register new class as a Chef::Resource + class_name = convert_to_class_name(rname) + Chef::Resource.const_set(class_name, new_resource_class) + Chef::Log.debug("Loaded contents of #{filename} into a resource named #{rname} defined in Chef::Resource::#{class_name}") + + new_resource_class end end diff --git a/chef/lib/chef/resource_collection.rb b/chef/lib/chef/resource_collection.rb index 8a6655b704..7e219024c1 100644 --- a/chef/lib/chef/resource_collection.rb +++ b/chef/lib/chef/resource_collection.rb @@ -1,6 +1,7 @@ # # Author:: Adam Jacob (<adam@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"); @@ -21,10 +22,11 @@ require 'chef/resource' class Chef class ResourceCollection include Enumerable - + def initialize @resources = Array.new @resources_by_name = Hash.new + @currently_executing_resource_idx = nil end def [](index) @@ -36,7 +38,7 @@ class Chef @resources[index] = arg @resources_by_name[arg.to_s] = index end - + def <<(*args) args.flatten.each do |a| is_chef_resource(a) @@ -44,6 +46,23 @@ class Chef @resources_by_name[a.to_s] = @resources.length - 1 end end + + def insert(resource) + is_chef_resource(resource) + if @currently_executing_resource_idx + # in the middle of executing a run, so any resources inserted now should + # be placed after the currently executing resource + @resources.insert(@currently_executing_resource_idx + 1, resource) + # update name -> location mappings and register new resource + @resources_by_name.each_key do |key| + @resources_by_name[key] += 1 if @resources_by_name[key] > @currently_executing_resource_idx + end + @resources_by_name[resource.to_s] = @currently_executing_resource_idx + 1 + else + @resources << resource + @resources_by_name[resource.to_s] = @resources.length - 1 + end + end def push(*args) args.flatten.each do |a| @@ -58,6 +77,13 @@ class Chef yield r end end + + def execute_each_resource + @resources.each_with_index do |r, idx| + @currently_executing_resource_idx = idx + yield r + end + end def each_index @resources.each_index do |i| @@ -173,4 +199,4 @@ class Chef true end end -end
\ No newline at end of file +end diff --git a/chef/lib/chef/runner.rb b/chef/lib/chef/runner.rb index f1742dd991..2950908f69 100644 --- a/chef/lib/chef/runner.rb +++ b/chef/lib/chef/runner.rb @@ -26,7 +26,7 @@ class Chef include Chef::Mixin::ParamsValidate - def initialize(node, collection) + def initialize(node, collection, definitions=nil, cookbook_loader=nil) validate( { :node => node, @@ -43,13 +43,15 @@ class Chef ) @node = node @collection = collection + @definitions = definitions + @cookbook_loader = cookbook_loader end def build_provider(resource) provider_klass = resource.provider provider_klass ||= Chef::Platform.find_provider_for_node(@node, resource) Chef::Log.debug("#{resource} using #{provider_klass.to_s}") - provider = provider_klass.new(@node, resource) + provider = provider_klass.new(@node, resource, @collection, @definitions, @cookbook_loader) provider.load_current_resource provider end @@ -58,7 +60,7 @@ class Chef delayed_actions = Hash.new - @collection.each do |resource| + @collection.execute_each_resource do |resource| begin Chef::Log.debug("Processing #{resource}") diff --git a/chef/spec/unit/client_spec.rb b/chef/spec/unit/client_spec.rb index 303306a659..8fd1242da8 100644 --- a/chef/spec/unit/client_spec.rb +++ b/chef/spec/unit/client_spec.rb @@ -32,6 +32,8 @@ describe Chef::Client, "run" do :register, :authenticate, :sync_library_files, + :sync_provider_files, + :sync_resource_files, :sync_attribute_files, :sync_definitions, :sync_recipes, @@ -88,6 +90,16 @@ describe Chef::Client, "run" do @client.run end + it "should synchronize providers from the server" do + @client.should_receive(:sync_provider_files).and_return(true) + @client.run + end + + it "should synchronize resources from the server" do + @client.should_receive(:sync_resource_files).and_return(true) + @client.run + end + it "should save the nodes state on the server (twice!)" do @client.should_receive(:save_node).exactly(3).times.and_return(true) @client.run diff --git a/chef/spec/unit/compile_spec.rb b/chef/spec/unit/compile_spec.rb index beda2a0e95..79ca3c5d06 100644 --- a/chef/spec/unit/compile_spec.rb +++ b/chef/spec/unit/compile_spec.rb @@ -22,7 +22,15 @@ describe Chef::Compile do before(:each) do Chef::Config.node_path(File.join(File.dirname(__FILE__), "..", "data", "compile", "nodes")) Chef::Config.cookbook_path(File.join(File.dirname(__FILE__), "..", "data", "compile", "cookbooks")) - @compile = Chef::Compile.new + node = Chef::Node.new + node.stub!(:determine_node_name).and_return(true) + node.stub!(:load_libraries).and_return(true) + node.stub!(:load_providers).and_return(true) + node.stub!(:load_resources).and_return(true) + node.stub!(:load_attributes).and_return(true) + node.stub!(:load_definitions).and_return(true) + node.stub!(:load_recipes).and_return(true) + @compile = Chef::Compile.new(node) end it "should create a new Chef::Compile" do diff --git a/chef/spec/unit/runner_spec.rb b/chef/spec/unit/runner_spec.rb index fca8af4542..5eef9f0e6f 100644 --- a/chef/spec/unit/runner_spec.rb +++ b/chef/spec/unit/runner_spec.rb @@ -55,7 +55,7 @@ describe Chef::Runner do end it "should pass each resource in the collection to a provider" do - @collection.should_receive(:each).once + @collection.should_receive(:execute_each_resource).once @runner.converge end @@ -153,4 +153,4 @@ describe Chef::Runner do @runner.converge end -end
\ No newline at end of file +end diff --git a/features/cookbooks/lightweight_resources_and_providers.feature b/features/cookbooks/lightweight_resources_and_providers.feature index 908d7a129a..1c567906fd 100644 --- a/features/cookbooks/lightweight_resources_and_providers.feature +++ b/features/cookbooks/lightweight_resources_and_providers.feature @@ -19,8 +19,15 @@ Feature: Light-weight resources and providers | provider_is_a_symbol | Provider is a symbol | | provider_is_a_class | Provider is a class | + @solo + Scenario: Chef solo properly handles providers that invoke resources in their action definitions + Given a local cookbook repository + When I run chef-solo with the 'lwrp::provider_invokes_resource' recipe + Then the run should exit '0' + And a file named 'lwrp_touch_file.txt' should exist + @client @api - Scenario Outline: Chef client handles light-weight resources and providers + Scenario Outline: Chef-client handles light-weight resources and providers Given a validated node And it includes the recipe 'lwrp::<recipe>' When I run the chef-client @@ -37,3 +44,12 @@ Feature: Light-weight resources and providers | provider_is_a_string | Provider is a string | | provider_is_a_symbol | Provider is a symbol | | provider_is_a_class | Provider is a class | + + @client @api + Scenario: Chef-client properly handles providers that invoke resources in their action definitions + Given a validated node + And it includes the recipe 'lwrp::provider_invokes_resource' + When I run the chef-client + Then the run should exit '0' + And a file named 'lwrp_touch_file.txt' should exist + diff --git a/features/data/cookbooks/lwrp/providers/default.rb b/features/data/cookbooks/lwrp/providers/default.rb index f51dcae369..f66e2914f6 100644 --- a/features/data/cookbooks/lwrp/providers/default.rb +++ b/features/data/cookbooks/lwrp/providers/default.rb @@ -1,3 +1,9 @@ action :print_message do puts new_resource.message end + +action :touch_file do + file "#{node[:tmpdir]}/#{new_resource.filename}" do + action :create + end +end diff --git a/features/data/cookbooks/lwrp/recipes/non_default_provider.rb b/features/data/cookbooks/lwrp/recipes/non_default_provider.rb index c37a7b1949..019f3aa9ab 100644 --- a/features/data/cookbooks/lwrp/recipes/non_default_provider.rb +++ b/features/data/cookbooks/lwrp/recipes/non_default_provider.rb @@ -2,5 +2,5 @@ lwrp :non_default_provider do message "Non-default provider" action :print_message - provider Chef::Provider::LwrpLwpNonDefault + provider :lwrp_lwp_non_default end diff --git a/features/data/cookbooks/lwrp/recipes/provider_invokes_resource.rb b/features/data/cookbooks/lwrp/recipes/provider_invokes_resource.rb new file mode 100644 index 0000000000..c2e94aa064 --- /dev/null +++ b/features/data/cookbooks/lwrp/recipes/provider_invokes_resource.rb @@ -0,0 +1,6 @@ +lwrp :lwrp_provider_invokes_resource do + filename "lwrp_touch_file.txt" + action :touch_file + + provider :lwrp +end diff --git a/features/data/cookbooks/lwrp/resources/default.rb b/features/data/cookbooks/lwrp/resources/default.rb index c29654eba3..00be531184 100644 --- a/features/data/cookbooks/lwrp/resources/default.rb +++ b/features/data/cookbooks/lwrp/resources/default.rb @@ -1,3 +1,4 @@ -actions :print_message +actions :print_message, :touch_file attribute :message, :kind_of => String +attribute :filename, :kind_of => String |