summaryrefslogtreecommitdiff
path: root/lib/chef
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
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')
-rw-r--r--lib/chef/dsl/declare_resource.rb189
-rw-r--r--lib/chef/provider.rb15
-rw-r--r--lib/chef/recipe.rb3
-rw-r--r--lib/chef/resource_collection.rb5
-rw-r--r--lib/chef/resource_collection/resource_list.rb10
-rw-r--r--lib/chef/resource_collection/resource_set.rb25
6 files changed, 220 insertions, 27 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(
diff --git a/lib/chef/provider.rb b/lib/chef/provider.rb
index ebabb7b9eb..03b546c09d 100644
--- a/lib/chef/provider.rb
+++ b/lib/chef/provider.rb
@@ -32,6 +32,14 @@ class Chef
class Provider
require "chef/mixin/why_run"
require "chef/mixin/provides"
+
+ attr_accessor :new_resource
+ attr_accessor :current_resource
+ attr_accessor :run_context
+
+ attr_reader :recipe_name
+ attr_reader :cookbook_name
+
include Chef::Mixin::WhyRun
extend Chef::Mixin::Provides
@@ -43,13 +51,6 @@ class Chef
true
end
- attr_accessor :new_resource
- attr_accessor :current_resource
- attr_accessor :run_context
-
- attr_reader :recipe_name
- attr_reader :cookbook_name
-
#--
# TODO: this should be a reader, and the action should be passed in the
# constructor; however, many/most subclasses override the constructor so
diff --git a/lib/chef/recipe.rb b/lib/chef/recipe.rb
index 403d393fcd..3cc5634dc8 100644
--- a/lib/chef/recipe.rb
+++ b/lib/chef/recipe.rb
@@ -34,14 +34,13 @@ class Chef
# == Chef::Recipe
# A Recipe object is the context in which Chef recipes are evaluated.
class Recipe
+ attr_accessor :cookbook_name, :recipe_name, :recipe, :params, :run_context
include Chef::DSL::Recipe
include Chef::Mixin::FromFile
include Chef::Mixin::Deprecation
- attr_accessor :cookbook_name, :recipe_name, :recipe, :params, :run_context
-
# Parses a potentially fully-qualified recipe name into its
# cookbook name and recipe short name.
#
diff --git a/lib/chef/resource_collection.rb b/lib/chef/resource_collection.rb
index 1429c25d7f..8eaa2961c4 100644
--- a/lib/chef/resource_collection.rb
+++ b/lib/chef/resource_collection.rb
@@ -59,6 +59,11 @@ class Chef
end
end
+ def delete(key)
+ resource_list.delete(key)
+ resource_set.delete(key)
+ end
+
# @deprecated
def []=(index, resource)
Chef::Log.warn("`[]=` is deprecated, use `insert` (which only inserts at the end)")
diff --git a/lib/chef/resource_collection/resource_list.rb b/lib/chef/resource_collection/resource_list.rb
index 37eb12a107..9fe012d4c3 100644
--- a/lib/chef/resource_collection/resource_list.rb
+++ b/lib/chef/resource_collection/resource_list.rb
@@ -67,6 +67,16 @@ class Chef
end
end
+ def delete(key)
+ raise ArgumentError, "Must pass a Chef::Resource or String to delete" unless key.is_a?(String) || key.is_a?(Chef::Resource)
+ key = key.to_s
+ ret = @resources.reject! { |r| r.to_s == key }
+ if ret.nil?
+ raise Chef::Exceptions::ResourceNotFound, "Cannot find a resource matching #{key} (did you define it first?)"
+ end
+ ret
+ end
+
# @deprecated - can be removed when it is removed from resource_collection.rb
def []=(index, resource)
@resources[index] = resource
diff --git a/lib/chef/resource_collection/resource_set.rb b/lib/chef/resource_collection/resource_set.rb
index 88354de31d..99be025cd5 100644
--- a/lib/chef/resource_collection/resource_set.rb
+++ b/lib/chef/resource_collection/resource_set.rb
@@ -49,18 +49,22 @@ class Chef
end
def lookup(key)
- case
- when key.kind_of?(String)
- lookup_by = key
- when key.kind_of?(Chef::Resource)
- lookup_by = create_key(key.resource_name, key.name)
- else
- raise ArgumentError, "Must pass a Chef::Resource or String to lookup"
+ raise ArgumentError, "Must pass a Chef::Resource or String to lookup" unless key.is_a?(String) || key.is_a?(Chef::Resource)
+ key = key.to_s
+ res = @resources_by_key[key]
+ unless res
+ raise Chef::Exceptions::ResourceNotFound, "Cannot find a resource matching #{key} (did you define it first?)"
end
+ res
+ end
- res = @resources_by_key[lookup_by]
- unless res
- raise Chef::Exceptions::ResourceNotFound, "Cannot find a resource matching #{lookup_by} (did you define it first?)"
+ def delete(key)
+ raise ArgumentError, "Must pass a Chef::Resource or String to delete" unless key.is_a?(String) || key.is_a?(Chef::Resource)
+ key = key.to_s
+ res = @resources_by_key.delete(key)
+
+ if res == @resources_by_key.default
+ raise Chef::Exceptions::ResourceNotFound, "Cannot find a resource matching #{key} (did you define it first?)"
end
res
end
@@ -164,7 +168,6 @@ class Chef
end
return results
end
-
end
end
end