diff options
-rw-r--r-- | lib/chef/provider/lwrp_base.rb | 3 | ||||
-rw-r--r-- | lib/chef/resource.rb | 90 | ||||
-rw-r--r-- | lib/chef/resource/lwrp_base.rb | 125 | ||||
-rw-r--r-- | lib/chef/resources.rb | 1 | ||||
-rw-r--r-- | lib/chef/run_context/cookbook_compiler.rb | 2 | ||||
-rw-r--r-- | spec/unit/lwrp_spec.rb | 14 |
6 files changed, 137 insertions, 98 deletions
diff --git a/lib/chef/provider/lwrp_base.rb b/lib/chef/provider/lwrp_base.rb index 54ba23e728..1ae17e288c 100644 --- a/lib/chef/provider/lwrp_base.rb +++ b/lib/chef/provider/lwrp_base.rb @@ -1,7 +1,8 @@ # # Author:: Adam Jacob (<adam@opscode.com>) # Author:: Christopher Walters (<cw@opscode.com>) -# Copyright:: Copyright (c) 2008, 2009 Opscode, Inc. +# Author:: Daniel DeLeo (<dan@opscode.com>) +# Copyright:: Copyright (c) 2008-2012 Opscode, Inc. # License:: Apache License, Version 2.0 # # Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/lib/chef/resource.rb b/lib/chef/resource.rb index 9a1b983360..c49bb6684e 100644 --- a/lib/chef/resource.rb +++ b/lib/chef/resource.rb @@ -125,6 +125,7 @@ F include Chef::Mixin::ConvertToClassName include Chef::Mixin::Deprecation + extend Chef::Mixin::ConvertToClassName # Set or return the list of "state attributes" implemented by the Resource # subclass. State attributes are attributes that describe the desired state @@ -662,95 +663,6 @@ F nil end - extend Chef::Mixin::ConvertToClassName - - def self.attribute(attr_name, validation_opts={}) - # This atrocity is the only way to support 1.8 and 1.9 at the same time - # When you're ready to drop 1.8 support, do this: - # define_method attr_name.to_sym do |arg=nil| - # etc. - shim_method=<<-SHIM - def #{attr_name}(arg=nil) - _set_or_return_#{attr_name}(arg) - end - SHIM - class_eval(shim_method) - - define_method("_set_or_return_#{attr_name.to_s}".to_sym) do |arg| - set_or_return(attr_name.to_sym, arg, validation_opts) - end - end - - def self.build_from_file(cookbook_name, filename, run_context) - rname = filename_to_qualified_string(cookbook_name, filename) - - # Add log entry if we override an existing light-weight resource. - class_name = convert_to_class_name(rname) - overriding = Chef::Resource.const_defined?(class_name) - Chef::Log.info("#{class_name} light-weight resource already initialized -- overriding!") if overriding - - 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 - # definer does not implement initialize - def initialize(name, run_context) - super(name, run_context) - end - - @actions_to_create = [] - - class << cls - include Chef::Mixin::FromFile - - attr_accessor :run_context - attr_reader :action_to_set_default - - def node - self.run_context.node - end - - def actions_to_create - @actions_to_create - end - - define_method(:default_action) do |action_name| - actions_to_create.push(action_name) - @action_to_set_default = action_name - end - - define_method(:actions) do |*action_names| - actions_to_create.push(*action_names) - end - end - - # set the run context in the class instance variable - cls.run_context = run_context - - # load resource definition from file - cls.class_from_file(filename) - - # 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| - args_run_context = optional_args.shift - @resource_name = rname.to_sym - old_init.bind(self).call(name, args_run_context) - @action = self.class.action_to_set_default || @action - 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 - # Resources that want providers namespaced somewhere other than # Chef::Provider can set the namespace with +provider_base+ # Ex: diff --git a/lib/chef/resource/lwrp_base.rb b/lib/chef/resource/lwrp_base.rb new file mode 100644 index 0000000000..af743b000e --- /dev/null +++ b/lib/chef/resource/lwrp_base.rb @@ -0,0 +1,125 @@ +# +# Author:: Adam Jacob (<adam@opscode.com>) +# Author:: Christopher Walters (<cw@opscode.com>) +# Author:: Daniel DeLeo (<dan@opscode.com>) +# Copyright:: Copyright (c) 2008-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. +# + +class Chef + class Resource + + # == Chef::Resource::LWRPBase + # Base class for LWRP resources. Adds DSL sugar on top of Chef::Resource, + # so attributes, default action, etc. can be defined with pleasing syntax. + class LWRPBase < Resource + + NULL_ARG = Object.new + + extend Chef::Mixin::ConvertToClassName + extend Chef::Mixin::FromFile + + # Evaluates the LWRP resource file and instantiates a new Resource class. + def self.build_from_file(cookbook_name, filename, run_context) + rname = filename_to_qualified_string(cookbook_name, filename) + + # Add log entry if we override an existing light-weight resource. + class_name = convert_to_class_name(rname) + overriding = Chef::Resource.const_defined?(class_name) + Chef::Log.info("#{class_name} light-weight resource already initialized -- overriding!") if overriding + + resource_class = Class.new(self) + + resource_class.resource_name = rname + resource_class.run_context = run_context + resource_class.class_from_file(filename) + + Chef::Resource.const_set(class_name, resource_class) + Chef::Log.debug("Loaded contents of #{filename} into a resource named #{rname} defined in Chef::Resource::#{class_name}") + + resource_class + end + + # Set the resource snake_case name. Should only be called via + # build_from_file Should only be called via build_from_file. + def self.resource_name=(resource_name) + @resource_name = resource_name + end + + # Returns the resource snake_case name + def self.resource_name + @resource_name + end + + # Define an attribute on this resource, including optional validation + # parameters. + def self.attribute(attr_name, validation_opts={}) + # Ruby 1.8 doesn't support default arguments to blocks, but we have to + # use define_method with a block to capture +validation_opts+. + # Workaround this by defining two methods :( + class_eval(<<-SHIM, __FILE__, __LINE__) + def #{attr_name}(arg=nil) + _set_or_return_#{attr_name}(arg) + end + SHIM + + define_method("_set_or_return_#{attr_name.to_s}".to_sym) do |arg| + set_or_return(attr_name.to_sym, arg, validation_opts) + end + end + + # Sets the default action + def self.default_action(action_name=NULL_ARG) + unless action_name.equal?(NULL_ARG) + valid_actions.push(action_name) + @default_action = action_name + end + @default_action + end + + # Adds +action_names+ to the list of valid actions for this resource. + def self.actions(*action_names) + valid_actions.push(*action_names) + end + + def self.valid_actions + @valid_actions ||= [] + end + + # Set the run context on the class. Used to provide access to the node + # during class definition. + def self.run_context=(run_context) + @run_context = run_context + end + + def self.run_context + @run_context + end + + def self.node + run_context.node + end + + # Default initializer. Sets the default action and allowed actions. + def initialize(name, run_context=nil) + super(name, run_context) + @resource_name = self.class.resource_name.to_sym + @action = self.class.default_action + allowed_actions.push(self.class.valid_actions).flatten! + end + + end + end +end diff --git a/lib/chef/resources.rb b/lib/chef/resources.rb index 7fadb17444..f4212f1498 100644 --- a/lib/chef/resources.rb +++ b/lib/chef/resources.rb @@ -65,3 +65,4 @@ require 'chef/resource/template' require 'chef/resource/timestamped_deploy' require 'chef/resource/user' require 'chef/resource/yum_package' +require 'chef/resource/lwrp_base' diff --git a/lib/chef/run_context/cookbook_compiler.rb b/lib/chef/run_context/cookbook_compiler.rb index 784458fdce..0b65569cbe 100644 --- a/lib/chef/run_context/cookbook_compiler.rb +++ b/lib/chef/run_context/cookbook_compiler.rb @@ -205,7 +205,7 @@ class Chef def load_lwrp_resource(cookbook_name, filename) Chef::Log.debug("Loading cookbook #{cookbook_name}'s resources from #{filename}") - Chef::Resource.build_from_file(cookbook_name, filename, self) + Chef::Resource::LWRPBase.build_from_file(cookbook_name, filename, self) @events.lwrp_file_loaded(filename) rescue Exception => e @events.lwrp_file_load_failed(filename, e) diff --git a/spec/unit/lwrp_spec.rb b/spec/unit/lwrp_spec.rb index a399ee0521..b28fd812a2 100644 --- a/spec/unit/lwrp_spec.rb +++ b/spec/unit/lwrp_spec.rb @@ -25,12 +25,12 @@ describe "override logging" do it "should log if attempting to load resource of same name" do Dir[File.expand_path(File.join(File.dirname(__FILE__), "..", "data", "lwrp", "resources", "*"))].each do |file| - Chef::Resource.build_from_file("lwrp", file, nil) + Chef::Resource::LWRPBase.build_from_file("lwrp", file, nil) end Dir[File.expand_path(File.join(File.dirname(__FILE__), "..", "data", "lwrp_override", "resources", "*"))].each do |file| Chef::Log.should_receive(:info).with(/overriding/) - Chef::Resource.build_from_file("lwrp", file, nil) + Chef::Resource::LWRPBase.build_from_file("lwrp", file, nil) end end @@ -61,11 +61,11 @@ describe "LWRP" do before do Dir[File.expand_path(File.join(File.dirname(__FILE__), "..", "data", "lwrp", "resources", "*"))].each do |file| - Chef::Resource.build_from_file("lwrp", file, nil) + Chef::Resource::LWRPBase.build_from_file("lwrp", file, nil) end Dir[File.expand_path(File.join(File.dirname(__FILE__), "..", "data", "lwrp_override", "resources", "*"))].each do |file| - Chef::Resource.build_from_file("lwrp", file, nil) + Chef::Resource::LWRPBase.build_from_file("lwrp", file, nil) end end @@ -99,7 +99,7 @@ describe "LWRP" do run_context = Chef::RunContext.new(node, Chef::CookbookCollection.new, @events) Dir[File.expand_path(File.join(File.dirname(__FILE__), "..", "data", "lwrp", "resources_with_default_attributes", "*"))].each do |file| - Chef::Resource.build_from_file("lwrp", file, run_context) + Chef::Resource::LWRPBase.build_from_file("lwrp", file, run_context) end cls = Chef::Resource.const_get("LwrpNodeattr") @@ -122,11 +122,11 @@ describe "LWRP" do before(:each) do Dir[File.expand_path(File.join(File.dirname(__FILE__), "..", "data", "lwrp", "resources", "*"))].each do |file| - Chef::Resource.build_from_file("lwrp", file, @run_context) + Chef::Resource::LWRPBase.build_from_file("lwrp", file, @run_context) end Dir[File.expand_path(File.join(File.dirname(__FILE__), "..", "data", "lwrp_override", "resources", "*"))].each do |file| - Chef::Resource.build_from_file("lwrp", file, @run_context) + Chef::Resource::LWRPBase.build_from_file("lwrp", file, @run_context) end Dir[File.expand_path(File.join(File.dirname(__FILE__), "..", "data", "lwrp", "providers", "*"))].each do |file| |