diff options
author | Lamont Granquist <lamont@scriptkiddie.org> | 2017-03-22 14:26:34 -0700 |
---|---|---|
committer | Lamont Granquist <lamont@scriptkiddie.org> | 2017-03-30 11:52:24 -0700 |
commit | d08274d635b046210faf07d7f598fee5b3c3effe (patch) | |
tree | eae7c43c4263749d458c06f609b3c7ef2ef997c2 | |
parent | 2151e4f1563441fdacc07c16eaaa4273bb88931d (diff) | |
download | chef-d08274d635b046210faf07d7f598fee5b3c3effe.tar.gz |
Chef-13: Support nameless resources and remove deprecated multi-arg resources
This makes nameless resources work in the DSL:
```ruby
apt_update
```
It does it by giving it an empty-string name of ""
It also drops support for multi-arg resources, that has been deprecated
for some time:
```ruby
some_resource "foo", "bar", "baz"
```
Note that multipackage package resources do not use multiple args, but a
single argument which is an arry:
```ruby
package [ "lsof", "strace", "tcpdump" ]
```
So this change does not affect that usage. Multi-arg has been
deprecated for some time now and its not clear that it was ever used by
anyone.
Signed-off-by: Lamont Granquist <lamont@scriptkiddie.org>
-rw-r--r-- | lib/chef/dsl/resources.rb | 9 | ||||
-rw-r--r-- | lib/chef/resource_collection/resource_set.rb | 17 | ||||
-rw-r--r-- | spec/integration/recipes/notifies_spec.rb | 31 | ||||
-rw-r--r-- | spec/integration/recipes/recipe_dsl_spec.rb | 16 | ||||
-rw-r--r-- | spec/unit/dsl/resources_spec.rb | 2 | ||||
-rw-r--r-- | spec/unit/recipe_spec.rb | 12 | ||||
-rw-r--r-- | spec/unit/resource_collection/resource_set_spec.rb | 31 | ||||
-rw-r--r-- | spec/unit/resource_spec.rb | 17 |
8 files changed, 107 insertions, 28 deletions
diff --git a/lib/chef/dsl/resources.rb b/lib/chef/dsl/resources.rb index 36ec018500..4baec22f2e 100644 --- a/lib/chef/dsl/resources.rb +++ b/lib/chef/dsl/resources.rb @@ -34,11 +34,10 @@ class Chef def self.add_resource_dsl(dsl_name) module_eval(<<-EOM, __FILE__, __LINE__ + 1) - def #{dsl_name}(*args, &block) - Chef.deprecated(:internal_api, "Cannot create resource #{dsl_name} with more than one argument. All arguments except the name (\#{args[0].inspect}) will be ignored. This will cause an error in Chef 13. Arguments: \#{args}") if args.size > 1 - declare_resource(#{dsl_name.inspect}, args[0], created_at: caller[0], &block) - end - EOM + def #{dsl_name}(arg = "", &block) + declare_resource(#{dsl_name.inspect}, arg, created_at: caller[0], &block) + end + EOM end def self.remove_resource_dsl(dsl_name) diff --git a/lib/chef/resource_collection/resource_set.rb b/lib/chef/resource_collection/resource_set.rb index 2c7c0a0b91..66ccc1ccb3 100644 --- a/lib/chef/resource_collection/resource_set.rb +++ b/lib/chef/resource_collection/resource_set.rb @@ -1,6 +1,6 @@ # # Author:: Tyler Ball (<tball@chef.io>) -# Copyright:: Copyright 2014-2016, Chef Software, Inc. +# Copyright:: Copyright 2014-2017, Chef Software Inc. # License:: Apache License, Version 2.0 # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -30,7 +30,10 @@ class Chef # Matches a single resource lookup specification, # e.g., "service[nginx]" - SINGLE_RESOURCE_MATCH = /^(.+)\[(.+)\]$/ + SINGLE_RESOURCE_MATCH = /^(.+)\[(.*)\]$/ + + # Matches e.g. "apt_update" with no name + NAMELESS_RESOURCE_MATCH = /^([^\[\]\s]+)$/ def initialize @resources_by_key = Hash.new @@ -43,7 +46,7 @@ class Chef def insert_as(resource, resource_type = nil, instance_name = nil) is_chef_resource!(resource) resource_type ||= resource.resource_name - instance_name ||= resource.name + instance_name ||= resource.name || "" key = create_key(resource_type, instance_name) @resources_by_key[key] = resource end @@ -118,7 +121,7 @@ class Chef case query_object when Chef::Resource true - when SINGLE_RESOURCE_MATCH, MULTIPLE_RESOURCE_MATCH + when SINGLE_RESOURCE_MATCH, MULTIPLE_RESOURCE_MATCH, NAMELESS_RESOURCE_MATCH true when Hash true @@ -142,7 +145,7 @@ class Chef private - def create_key(resource_type, instance_name) + def create_key(resource_type, instance_name = "") "#{resource_type}[#{instance_name}]" end @@ -171,6 +174,10 @@ class Chef resource_type = $1 name = $2 results << lookup(create_key(resource_type, name)) + when NAMELESS_RESOURCE_MATCH + resource_type = $1 + name = "" + results << lookup(create_key(resource_type, name)) else raise ArgumentError, "Bad string format #{arg}, you must have a string like resource_type[name]!" end diff --git a/spec/integration/recipes/notifies_spec.rb b/spec/integration/recipes/notifies_spec.rb index 000f5e37bf..6f6a0f06b0 100644 --- a/spec/integration/recipes/notifies_spec.rb +++ b/spec/integration/recipes/notifies_spec.rb @@ -8,6 +8,37 @@ describe "notifications" do let(:chef_dir) { File.expand_path("../../../../bin", __FILE__) } let(:chef_client) { "ruby '#{chef_dir}/chef-client' --minimal-ohai" } + when_the_repository "notifies a nameless resource" do + before do + directory "cookbooks/x" do + file "recipes/default.rb", <<-EOM + apt_update do + action :nothing + end + log "foo" do + notifies :nothing, 'apt_update', :delayed + end + log "bar" do + notifies :nothing, 'apt_update[]', :delayed + end + EOM + end + end + + it "should complete with success" do + file "config/client.rb", <<EOM +local_mode true +cookbook_path "#{path_to('cookbooks')}" +log_level :warn +EOM + + result = shell_out("#{chef_client} -c \"#{path_to('config/client.rb')}\" --no-color -F doc -o 'x::default'", :cwd => chef_dir) + # our delayed notification should run at the end of the parent run_context after the baz resource + expect(result.stdout).to match(/\* apt_update\[\] action nothing \(skipped due to action :nothing\)\s+\* log\[foo\] action write\s+\* log\[bar\] action write\s+\* apt_update\[\] action nothing \(skipped due to action :nothing\)/) + result.error! + end + end + when_the_repository "notifies delayed one" do before do directory "cookbooks/x" do diff --git a/spec/integration/recipes/recipe_dsl_spec.rb b/spec/integration/recipes/recipe_dsl_spec.rb index a408bbb0d7..14cee0e1fd 100644 --- a/spec/integration/recipes/recipe_dsl_spec.rb +++ b/spec/integration/recipes/recipe_dsl_spec.rb @@ -59,20 +59,12 @@ describe "Recipe DSL methods" do expect(BaseThingy.created_resource).to eq BaseThingy end - it "errors out when you call base_thingy do ... end in a recipe" do - expect_converge do - base_thingy { ; } - end.to raise_error(ArgumentError, "You must supply a name when declaring a base_thingy resource") - end - - it "emits a warning when you call base_thingy 'foo', 'bar' do ... end in a recipe" do - Chef::Config[:treat_deprecation_warnings_as_errors] = false + it "does not errors when you call base_thingy do ... end in a recipe" do recipe = converge do - base_thingy "foo", "bar" do - end + base_thingy { ; } end - expect(recipe.logged_warnings).to match(/Cannot create resource base_thingy with more than one argument. All arguments except the name \("foo"\) will be ignored. This will cause an error in Chef 13. Arguments: \["foo", "bar"\]/) - expect(BaseThingy.created_name).to eq "foo" + expect(recipe.logged_warnings).to eq "" + expect(BaseThingy.created_name).to eq "" expect(BaseThingy.created_resource).to eq BaseThingy end diff --git a/spec/unit/dsl/resources_spec.rb b/spec/unit/dsl/resources_spec.rb index dc05f8bcf4..5354505df8 100644 --- a/spec/unit/dsl/resources_spec.rb +++ b/spec/unit/dsl/resources_spec.rb @@ -80,6 +80,6 @@ describe Chef::DSL::Resources do test_resource {} end end - it { is_expected.to eq [[:test_resource, nil]] } + it { is_expected.to eq [[:test_resource, ""]] } end end diff --git a/spec/unit/recipe_spec.rb b/spec/unit/recipe_spec.rb index cb500da34a..8a2719120a 100644 --- a/spec/unit/recipe_spec.rb +++ b/spec/unit/recipe_spec.rb @@ -74,10 +74,14 @@ describe Chef::Recipe do expect { recipe.not_home("not_home_resource") }.to raise_error(NameError) end - it "should require a name argument" do - expect do - recipe.cat - end.to raise_error(ArgumentError) + it "does not require a name argument and looks up with empty brackets" do + recipe.zen_master + expect(run_context.resource_collection.lookup("zen_master[]").name).to eql("") + end + + it "does not require a name argument and looks up with bare word" do + recipe.zen_master + expect(run_context.resource_collection.lookup("zen_master").name).to eql("") end it "should allow regular errors (not NameErrors) to pass unchanged" do diff --git a/spec/unit/resource_collection/resource_set_spec.rb b/spec/unit/resource_collection/resource_set_spec.rb index 20f6f70911..ecf3e2707f 100644 --- a/spec/unit/resource_collection/resource_set_spec.rb +++ b/spec/unit/resource_collection/resource_set_spec.rb @@ -1,6 +1,6 @@ # # Author:: Tyler Ball (<tball@chef.io>) -# Copyright:: Copyright 2014-2016, Chef Software, Inc. +# Copyright:: Copyright 2014-2017, Chef Software Inc. # License:: Apache License, Version 2.0 # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -162,6 +162,35 @@ describe Chef::ResourceCollection::ResourceSet do it "raises an error when attempting to find a resource that does not exist" do expect { collection.find("script[nonesuch]") }.to raise_error(Chef::Exceptions::ResourceNotFound) end + + context "nameless resources" do + let(:zen_master_name) { "" } + + it "looks up nameless resources with find without brackets" do + collection.insert_as(zen_master) + expect(collection.find("zen_master")).to eq(zen_master) + end + + it "looks up nameless resources with find with empty brackets" do + collection.insert_as(zen_master) + expect(collection.find("zen_master[]")).to eq(zen_master) + end + + it "looks up nameless resources with find with empty string hash key" do + collection.insert_as(zen_master) + expect(collection.find(zen_master: "")).to eq(zen_master) + end + + it "looks up nameless resources with lookup with empty brackets" do + collection.insert_as(zen_master) + expect(collection.lookup("zen_master[]")).to eq(zen_master) + end + + it "looks up nameless resources with lookup with the resource" do + collection.insert_as(zen_master) + expect(collection.lookup(zen_master)).to eq(zen_master) + end + end end describe "validate_lookup_spec!" do diff --git a/spec/unit/resource_spec.rb b/spec/unit/resource_spec.rb index a806c5d1d9..6285bad50a 100644 --- a/spec/unit/resource_spec.rb +++ b/spec/unit/resource_spec.rb @@ -284,6 +284,23 @@ describe Chef::Resource do resource.notifies :reload, run_context.resource_collection.find(:zen_master => "coffee, tea") expect(resource.delayed_notifications.detect { |e| e.resource.name == "coffee, tea" && e.action == :reload }).not_to be_nil end + + it "notifies a resource without a name via a string name with brackets" do + run_context.resource_collection << Chef::Resource::ZenMaster.new("") + resource.notifies :reload, "zen_master[]" + end + + it "notifies a resource without a name via a string name without brackets" do + run_context.resource_collection << Chef::Resource::ZenMaster.new("") + resource.notifies :reload, "zen_master" + expect(resource.delayed_notifications.first.resource).to eql("zen_master") + end + + it "notifies a resource without a name via a hash name with an empty string" do + run_context.resource_collection << Chef::Resource::ZenMaster.new("") + resource.notifies :reload, zen_master: "" + expect(resource.delayed_notifications.first.resource).to eql(zen_master: "") + end end describe "subscribes" do |