summaryrefslogtreecommitdiff
path: root/lib/chef/dsl/declare_resource.rb
diff options
context:
space:
mode:
authorLamont Granquist <lamont@scriptkiddie.org>2016-04-15 11:49:18 -0700
committerLamont Granquist <lamont@scriptkiddie.org>2016-04-15 11:50:01 -0700
commit544a9127cf3ed738d642b2490ed3063f1623c36c (patch)
tree9faf191b88bab71583c257d51298cdc7360b5107 /lib/chef/dsl/declare_resource.rb
parentf99b3362694d9cd9f70aa808b96a3fe3420650e1 (diff)
downloadchef-544a9127cf3ed738d642b2490ed3063f1623c36c.tar.gz
add better resource manipulation API
deprecates chef_rewind functionality completely and adds a few more features
Diffstat (limited to 'lib/chef/dsl/declare_resource.rb')
-rw-r--r--lib/chef/dsl/declare_resource.rb189
1 files changed, 182 insertions, 7 deletions
diff --git a/lib/chef/dsl/declare_resource.rb b/lib/chef/dsl/declare_resource.rb
index e57bc0f4c4..454afdc2b8 100644
--- a/lib/chef/dsl/declare_resource.rb
+++ b/lib/chef/dsl/declare_resource.rb
@@ -1,6 +1,6 @@
#--
# Author:: Adam Jacob (<adam@chef.io>)
-# Author:: Christopher Walters (<cw@chef.io>)
+# Author:: Christopher Walters
# Copyright:: Copyright 2008-2016, 2009-2015 Chef Software, Inc.
# License:: Apache License, Version 2.0
#
@@ -23,7 +23,180 @@ class Chef
module DSL
module DeclareResource
+ # Helper for switching run_contexts. Allows for using :parent or :root in place of
+ # passing the run_context. Executes the block in the run_context. Returns the return
+ # value of the passed block.
#
+ # @param rc [Chef::RunContext,Symbol] Either :root, :parent or a Chef::RunContext
+ #
+ # @return return value of the block
+ #
+ # @example
+ # # creates/returns a 'service[foo]' resource in the root run_context
+ # resource = with_run_context(:root)
+ # edit_resource(:service, "foo") do
+ # action :nothing
+ # end
+ # end
+ #
+ def with_run_context(rc, &block)
+ raise ArgumentError, "with_run_context is useless without a block" unless block_given?
+ @old_run_context = @run_context
+ @run_context =
+ case rc
+ when Chef::RunContext
+ rc
+ when :root
+ Chef.run_context
+ when :parent
+ run_context.parent_run_context
+ else
+ raise "bad argument to run_context helper, must be :root, :parent, or a Chef::RunContext"
+ end
+ ret = yield
+ @run_context = @old_run_context
+ ret
+ end
+
+ # Lookup a resource in the resource collection by name and delete it. This
+ # will raise Chef::Exceptions::ResourceNotFound if the resource is not found.
+ #
+ # @param type [Symbol] The type of resource (e.g. `:file` or `:package`)
+ # @param name [String] The name of the resource (e.g. '/x/y.txt' or 'apache2')
+ # @param run_context [Chef::RunContext] the run_context of the resource collection to operate on
+ #
+ # @return [Chef::Resource] The resource
+ #
+ # @example
+ # delete_resource(:template, '/x/y.txy')
+ #
+ def delete_resource!(type, name, run_context: self.run_context)
+ run_context.resource_collection.delete("#{type}[#{name}]")
+ end
+
+ # Lookup a resource in the resource collection by name and delete it. Returns
+ # nil if the resource is not found and should not fail.
+ #
+ # @param type [Symbol] The type of resource (e.g. `:file` or `:package`)
+ # @param name [String] The name of the resource (e.g. '/x/y.txt' or 'apache2')
+ # @param run_context [Chef::RunContext] the run_context of the resource collection to operate on
+ #
+ # @return [Chef::Resource] The resource
+ #
+ # @example
+ # delete_resource(:template, '/x/y.txy')
+ #
+ def delete_resource(type, name, run_context: self.run_context)
+ delete_resource!(type, name, run_context: run_context)
+ rescue Chef::Exceptions::ResourceNotFound
+ nil
+ end
+
+ # Lookup a resource in the resource collection by name and edit the resource. If the resource is not
+ # found this will raise Chef::Exceptions::ResourceNotFound. This is the correct API to use for
+ # "chef_rewind" functionality.
+ #
+ # @param type [Symbol] The type of resource (e.g. `:file` or `:package`)
+ # @param name [String] The name of the resource (e.g. '/x/y.txt' or 'apache2')
+ # @param run_context [Chef::RunContext] the run_context of the resource collection to operate on
+ # @param resource_attrs_block A block that lets you set attributes of the
+ # resource (it is instance_eval'd on the resource instance).
+ #
+ # @return [Chef::Resource] The updated resource
+ #
+ # @example
+ # edit_resource!(:template, '/x/y.txy') do
+ # cookbook_name: cookbook_name
+ # end
+ #
+ def edit_resource!(type, name, created_at = nil, run_context: self.run_context, &resource_attrs_block)
+ resource = find_resource!(type, name, run_context: run_context)
+ resource.instance_eval(&resource_attrs_block) if block_given?
+ resource
+ end
+
+ # Lookup a resource in the resource collection by name. If it exists,
+ # return it. If it does not exist, create it. This is a useful function
+ # for accumulator patterns. In CRUD terminology this is an "upsert" operation and is
+ # used to assert that the resource must exist with the specified properties.
+ #
+ # @param type [Symbol] The type of resource (e.g. `:file` or `:package`)
+ # @param name [String] The name of the resource (e.g. '/x/y.txt' or 'apache2')
+ # @param created_at [String] The caller of the resource. Use `caller[0]`
+ # to get the caller of your function. Defaults to the caller of this
+ # function.
+ # @param run_context [Chef::RunContext] the run_context of the resource collection to operate on
+ # @param resource_attrs_block A block that lets you set attributes of the
+ # resource (it is instance_eval'd on the resource instance).
+ #
+ # @return [Chef::Resource] The updated or created resource
+ #
+ # @example
+ # resource = edit_resource(:template, '/x/y.txy') do
+ # source "y.txy.erb"
+ # variables {}
+ # end
+ # resource.variables.merge!({ home: "/home/klowns" })
+ #
+ def edit_resource(type, name, created_at = nil, run_context: self.run_context, &resource_attrs_block)
+ edit_resource!(type, name, created_at, run_context: run_context, &resource_attrs_block)
+ rescue Chef::Exceptions::ResourceNotFound
+ declare_resource(type, name, created_at, run_context: run_context, &resource_attrs_block)
+ end
+
+ # Lookup a resource in the resource collection by name. If the resource is not
+ # found this will raise Chef::Exceptions::ResourceNotFound. This API is identical to the
+ # resources() call and while it is a synonym it is not intended to deprecate that call.
+ #
+ # @param type [Symbol] The type of resource (e.g. `:file` or `:package`)
+ # @param name [String] The name of the resource (e.g. '/x/y.txt' or 'apache2')
+ # @param run_context [Chef::RunContext] the run_context of the resource collection to operate on
+ #
+ # @return [Chef::Resource] The updated resource
+ #
+ # @example
+ # resource = find_resource!(:template, '/x/y.txy')
+ #
+ def find_resource!(type, name, run_context: self.run_context)
+ raise ArgumentError, "find_resource! does not take a block" if block_given?
+ run_context.resource_collection.find(type => name)
+ end
+
+ # Lookup a resource in the resource collection by name. If the resource is not found
+ # the will be no exception raised and the call will return nil. If a block is given and
+ # no resource is found it will create the resource using the block, if the resource is
+ # found then the block will not be applied. The block version is similar to create_if_missing
+ #
+ # @param type [Symbol] The type of resource (e.g. `:file` or `:package`)
+ # @param name [String] The name of the resource (e.g. '/x/y.txt' or 'apache2')
+ # @param run_context [Chef::RunContext] the run_context of the resource collection to operate on
+ #
+ # @return [Chef::Resource] The updated resource
+ #
+ # @example
+ # if ( find_resource(:template, '/x/y.txy') )
+ # # do something
+ # else
+ # # don't worry about the error
+ # end
+ #
+ # @example
+ # # this API can be used to return a resource from an outer run context, and will only create
+ # # an action :nothing service if one does not already exist.
+ # resource = with_run_context(:root) do
+ # find_resource(:service, 'whatever') do
+ # action :nothing
+ # end
+ # end
+ #
+ def find_resource(type, name, created_at: nil, run_context: self.run_context, &resource_attrs_block)
+ find_resource!(type, name, run_context: run_context)
+ rescue Chef::Exceptions::ResourceNotFound
+ if block_given?
+ declare_resource(type, name, created_at, run_context: run_context, &resource_attrs_block)
+ end # returns nil otherwise
+ end
+
# Instantiates a resource (via #build_resource), then adds it to the
# resource collection. Note that resource classes are looked up directly,
# so this will create the resource you intended even if the method name
@@ -34,6 +207,7 @@ class Chef
# @param created_at [String] The caller of the resource. Use `caller[0]`
# to get the caller of your function. Defaults to the caller of this
# function.
+ # @param run_context [Chef::RunContext] the run_context of the resource collection to operate on
# @param resource_attrs_block A block that lets you set attributes of the
# resource (it is instance_eval'd on the resource instance).
#
@@ -52,11 +226,9 @@ class Chef
created_at ||= caller[0]
if create_if_missing
- begin
- resource = run_context.resource_collection.find(type => name)
- return resource
- rescue Chef::Exceptions::ResourceNotFound
- end
+ Chef::Log.deprecation "build_resource with a create_if_missing flag is deprecated, use edit_resource instead"
+ # midly goofy since we call edit_resoruce only to re-call ourselves, but that's why its deprecated...
+ return edit_resource(type, name, created_at, run_context: run_context, &resource_attrs_block)
end
resource = build_resource(type, name, created_at, &resource_attrs_block)
@@ -65,7 +237,6 @@ class Chef
resource
end
- #
# Instantiate a resource of the given +type+ with the given +name+ and
# attributes as given in the +resource_attrs_block+.
#
@@ -76,6 +247,7 @@ class Chef
# @param created_at [String] The caller of the resource. Use `caller[0]`
# to get the caller of your function. Defaults to the caller of this
# function.
+ # @param run_context [Chef::RunContext] the run_context of the resource collection to operate on
# @param resource_attrs_block A block that lets you set attributes of the
# resource (it is instance_eval'd on the resource instance).
#
@@ -88,6 +260,9 @@ class Chef
#
def build_resource(type, name, created_at = nil, run_context: self.run_context, &resource_attrs_block)
created_at ||= caller[0]
+
+ # this needs to be lazy in order to avoid circular dependencies since ResourceBuilder
+ # will requires the entire provider+resolver universe
require "chef/resource_builder" unless defined?(Chef::ResourceBuilder)
Chef::ResourceBuilder.new(