diff options
author | Jay Mundrawala <jdmundrawala@gmail.com> | 2015-06-26 09:37:31 -0700 |
---|---|---|
committer | Jay Mundrawala <jdmundrawala@gmail.com> | 2015-06-30 07:12:11 -0700 |
commit | bcbe1fc82f5afdad1c8b6a855a4108443d1cb729 (patch) | |
tree | a6ac3c8a8e2fd594f512008c8fb31e7a1431585c | |
parent | 3501ba4020dc21377bc999e57e25eadb315ec783 (diff) | |
download | chef-bcbe1fc82f5afdad1c8b6a855a4108443d1cb729.tar.gz |
Fix ability to monkey match LWRP through Chef::Resource::MyLwrp
Repro
=====
The following cookbook would repro the issue
cookbooks/lwrptest/resources/my_lwrp.rb
---------------------------------------
```ruby
```
cookbooks/lwrptest/providers/my_lwrp.rb
---------------------------------------
```ruby
```
cookbooks/lwrptest/recipes/default.rb
-------------------------------------
```ruby
module Something
def something
puts 'something here'
end
end
::Chef::Resource::LwrptestMyLwrp.send(:include, Something)
lwrptest_my_lwrp 'blah' do
something
end
```
Why it does not work
====================
Running this in 12.4.0 produces the error
```
NoMethodError
-------------
undefined method `something' for LWRP resource lwrptest_my_lwrp from cookbook lwrptest
```
The problem is that LWRP usage through `Chef::Resource::MyLwrp` and
`Chef::Provider::MyLwrp` is depreacted. In order to participate in
the deprecation, `Chef::Resource::MyLwrp` is a subclass of the actual
`MyLwrp` class with `initialize` overriden to do a Chef::Log.deprecation.
In the example above, the intention is to add a method to the resource
so that it can be used from the dsl. The reason this does not work is
because including the method on `Chef::Resource::MyLwrp` adds the method
to the subclass, and the resource that is looked up when running the
recipe is the actual resource.
-rw-r--r-- | lib/chef/resource.rb | 53 | ||||
-rw-r--r-- | lib/chef/resource/lwrp_base.rb | 42 |
2 files changed, 34 insertions, 61 deletions
diff --git a/lib/chef/resource.rb b/lib/chef/resource.rb index 12d4f007ba..c7ec43d974 100644 --- a/lib/chef/resource.rb +++ b/lib/chef/resource.rb @@ -1499,56 +1499,9 @@ class Chef Chef::Resource.send(:remove_const, class_name) end - # In order to generate deprecation warnings when you use Chef::Resource::MyLwrp, - # we make a special subclass (identical in nearly all respects) of the - # actual LWRP. When you say any of these, a deprecation warning will be - # generated: - # - # - Chef::Resource::MyLwrp.new(...) - # - resource.is_a?(Chef::Resource::MyLwrp) - # - resource.kind_of?(Chef::Resource::MyLwrp) - # - case resource - # when Chef::Resource::MyLwrp - # end - # - resource_subclass = Class.new(resource_class) do - resource_name nil # we do not actually provide anything - def initialize(*args, &block) - Chef::Log.deprecation("Using an LWRP by its name (#{self.class.name}) directly is no longer supported in Chef 13 and will be removed. Use Chef::Resource.resource_for_node(node, name) instead.") - super - end - def self.resource_name(*args) - if args.empty? - @resource_name ||= superclass.resource_name - else - super - end - end - self - end - eval("Chef::Resource::#{class_name} = resource_subclass") - # Make case, is_a and kind_of work with the new subclass, for backcompat. - # Any subclass of Chef::Resource::ResourceClass is already a subclass of resource_class - # Any subclass of resource_class is considered a subclass of Chef::Resource::ResourceClass - resource_class.class_eval do - define_method(:is_a?) do |other| - other.is_a?(Module) && other === self - end - define_method(:kind_of?) do |other| - other.is_a?(Module) && other === self - end - end - resource_subclass.class_eval do - define_singleton_method(:===) do |other| - Chef::Log.deprecation("Using an LWRP by its name (#{class_name}) directly is no longer supported in Chef 13 and will be removed. Use Chef::Resource.resource_for_node(node, name) instead.") - # resource_subclass is a superclass of all resource_class descendants. - if self == resource_subclass && other.class <= resource_class - return true - end - super(other) - end - end - deprecated_constants[class_name.to_sym] = resource_subclass + eval("Chef::Resource::#{class_name} = resource_class") + + deprecated_constants[class_name.to_sym] = resource_class end def self.deprecated_constants diff --git a/lib/chef/resource/lwrp_base.rb b/lib/chef/resource/lwrp_base.rb index 443e0ed819..0a1cb6aa72 100644 --- a/lib/chef/resource/lwrp_base.rb +++ b/lib/chef/resource/lwrp_base.rb @@ -52,17 +52,37 @@ class Chef resource_name = filename_to_qualified_string(cookbook_name, filename) # We load the class first to give it a chance to set its own name - resource_class = Class.new(self) - resource_class.resource_name resource_name.to_sym - resource_class.run_context = run_context - resource_class.class_from_file(filename) - - # Make a useful string for the class (rather than <Class:312894723894>) - resource_class.instance_eval do - define_singleton_method(:to_s) do - "LWRP resource #{resource_name} from cookbook #{cookbook_name}" + deprecated_resource_class = Class.new(self).tap do |resource_class| + resource_class.resource_name(nil) + resource_class.run_context = run_context + resource_class.instance_eval do + define_method(:initialize) do |*args, &block| + Chef::Log::deprecation("Deprecated Thing") if chef_deprecated_access + super(*args, &block) + end + define_method(:chef_deprecated_access) do + true + end + end + + resource_class.class_from_file(filename) + + # Make a useful string for the class (rather than <Class:312894723894>) + resource_class.instance_eval do + define_singleton_method(:to_s) do + "LWRP resource #{resource_name} from cookbook #{cookbook_name}" + end + define_singleton_method(:inspect) { to_s } + end + end + + resource_class = Class.new(deprecated_resource_class).tap do |resource_class| + resource_class.resource_name(resource_name.to_sym) + resource_class.instance_eval do + define_method(:chef_deprecated_access) do + false + end end - define_singleton_method(:inspect) { to_s } end Chef::Log.debug("Loaded contents of #{filename} into resource #{resource_name} (#{resource_class})") @@ -70,7 +90,7 @@ class Chef LWRPBase.loaded_lwrps[filename] = true # Create the deprecated Chef::Resource::LwrpFoo class - Chef::Resource.register_deprecated_lwrp_class(resource_class, convert_to_class_name(resource_name)) + Chef::Resource.register_deprecated_lwrp_class(deprecated_resource_class, convert_to_class_name(resource_name)) resource_class end |