summaryrefslogtreecommitdiff
path: root/lib/chef/resource_collection
diff options
context:
space:
mode:
authortyler-ball <tyleraball@gmail.com>2014-10-16 10:32:49 -0500
committertyler-ball <tyleraball@gmail.com>2014-10-16 10:33:02 -0500
commit2cae7f7b39fd5dc34eefd5e0700bdbd693c6cba5 (patch)
tree72509bcdf57aab18b9e60542e412350fab3d032d /lib/chef/resource_collection
parent72dd653d9481848a7489845a46851c66964c5a37 (diff)
downloadchef-2cae7f7b39fd5dc34eefd5e0700bdbd693c6cba5.tar.gz
Moving resource_set and resource_list so they are hidden from consumers more since we don't want to change the resource_collection API yet
Diffstat (limited to 'lib/chef/resource_collection')
-rw-r--r--lib/chef/resource_collection/resource_list.rb100
-rw-r--r--lib/chef/resource_collection/resource_set.rb169
2 files changed, 269 insertions, 0 deletions
diff --git a/lib/chef/resource_collection/resource_list.rb b/lib/chef/resource_collection/resource_list.rb
new file mode 100644
index 0000000000..50b5a41e58
--- /dev/null
+++ b/lib/chef/resource_collection/resource_list.rb
@@ -0,0 +1,100 @@
+#
+# Author:: Tyler Ball (<tball@getchef.com>)
+# Copyright:: Copyright (c) 2014 Chef Software, 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.
+#
+
+require 'chef/resource'
+require 'chef/resource_collection/stepable_iterator'
+require 'chef/resource_collection/resource_collection_serialization'
+
+class Chef
+ class ResourceCollection
+ class ResourceList
+ include ResourceCollection::ResourceCollectionSerialization
+ include Enumerable
+
+ attr_reader :iterator
+
+ def initialize
+ @resources = Array.new
+ @insert_after_idx = nil
+ end
+
+ # TODO the differences between these 2 insert methods is very confusing
+ def insert(resource)
+ if @insert_after_idx
+ # in the middle of executing a run, so any resources inserted now should
+ # be placed after the most recent addition done by the currently executing
+ # resource
+ insert_at(@insert_after_idx += 1, resource)
+ else
+ is_chef_resource!(resource)
+ @resources << resource
+ end
+ end
+
+ # TODO this did not adjust @insert_after_idx in the old class - add test case and ask JohnK
+ def insert_at(index, *resources)
+ resources.each do |resource|
+ is_chef_resource!(resource)
+ end
+ @resources.insert(index, *resources)
+ end
+
+ # @depreciated
+ def []=(index, resource)
+ @resources[index] = resource
+ end
+
+ def all_resources
+ @resources
+ end
+
+ def [](index)
+ @resources[index]
+ end
+
+ def each
+ @resources.each do |resource|
+ yield resource
+ end
+ end
+
+ # TODO I would like to rename this to something that illustrates it sets the @insert_after_idx variable, then alias this old name
+ # TODO or perhaps refactor it to have 2 pointers - 1 for the end of the list and 1 for resources we have processed
+ # so far, and then move that logic up into the ResourceCollection class to simplify this class
+ def execute_each_resource(&resource_exec_block)
+ @iterator = ResourceCollection::StepableIterator.for_collection(@resources)
+ @iterator.each_with_index do |resource, idx|
+ @insert_after_idx = idx
+ yield resource
+ end
+ end
+
+ def each_index
+ @resources.each_index do |i|
+ yield i
+ end
+ end
+
+ def empty?
+ @resources.empty?
+ end
+
+ end
+ end
+end
+
diff --git a/lib/chef/resource_collection/resource_set.rb b/lib/chef/resource_collection/resource_set.rb
new file mode 100644
index 0000000000..65e47972cd
--- /dev/null
+++ b/lib/chef/resource_collection/resource_set.rb
@@ -0,0 +1,169 @@
+#
+# Author:: Tyler Ball (<tball@getchef.com>)
+# Copyright:: Copyright (c) 2014 Chef Software, 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.
+#
+
+require 'chef/resource'
+require 'chef/resource_collection/resource_collection_serialization'
+
+class Chef
+ # TODO move into subfolder until we promote these to top level classes
+ class ResourceCollection
+ class ResourceSet
+ include ResourceCollection::ResourceCollectionSerialization
+
+ # Matches a multiple resource lookup specification,
+ # e.g., "service[nginx,unicorn]"
+ MULTIPLE_RESOURCE_MATCH = /^(.+)\[(.+?),(.+)\]$/
+
+ # Matches a single resource lookup specification,
+ # e.g., "service[nginx]"
+ SINGLE_RESOURCE_MATCH = /^(.+)\[(.+)\]$/
+
+ def initialize
+ @resources_by_key = Hash.new
+ end
+
+ def keys
+ @resources_by_key.keys
+ end
+
+ def insert_as(resource, resource_type=resource.resource_name, instance_name=resource.name)
+ is_chef_resource!(resource)
+ key = ResourceSet.create_key(resource_type, instance_name)
+ @resources_by_key[key] = resource
+ end
+
+ def lookup(key)
+ case
+ when key.kind_of?(String)
+ lookup_by = key
+ when key.kind_of?(Chef::Resource)
+ lookup_by = ResourceSet.create_key(key.resource_name, key.name)
+ else
+ raise ArgumentError, "Must pass a Chef::Resource or String to lookup"
+ 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?)"
+ end
+ res
+ end
+
+ # Find existing resources by searching the list of existing resources. Possible
+ # forms are:
+ #
+ # find(:file => "foobar")
+ # find(:file => [ "foobar", "baz" ])
+ # find("file[foobar]", "file[baz]")
+ # find("file[foobar,baz]")
+ #
+ # Returns the matching resource, or an Array of matching resources.
+ #
+ # Raises an ArgumentError if you feed it bad lookup information
+ # Raises a Runtime Error if it can't find the resources you are looking for.
+ def find(*args)
+ results = Array.new
+ args.each do |arg|
+ case arg
+ when Hash
+ results << find_resource_by_hash(arg)
+ when String
+ results << find_resource_by_string(arg)
+ else
+ msg = "arguments to #{self.class.name}#find should be of the form :resource => 'name' or 'resource[name]'"
+ raise Chef::Exceptions::InvalidResourceSpecification, msg
+ end
+ end
+ flat_results = results.flatten
+ flat_results.length == 1 ? flat_results[0] : flat_results
+ end
+
+ # @depreciated
+ # resources is a poorly named, but we have to maintain it for back
+ # compat.
+ alias_method :resources, :find
+
+ # Returns true if +query_object+ is a valid string for looking up a
+ # resource, or raises InvalidResourceSpecification if not.
+ # === Arguments
+ # * query_object should be a string of the form
+ # "resource_type[resource_name]", a single element Hash (e.g., :service =>
+ # "apache2"), or a Chef::Resource (this is the happy path). Other arguments
+ # will raise an exception.
+ # === Returns
+ # * true returns true for all valid input.
+ # === Raises
+ # * Chef::Exceptions::InvalidResourceSpecification for all invalid input.
+ def validate_lookup_spec!(query_object)
+ case query_object
+ when Chef::Resource
+ true
+ when SINGLE_RESOURCE_MATCH, MULTIPLE_RESOURCE_MATCH
+ true
+ when Hash
+ true
+ when String
+ raise Chef::Exceptions::InvalidResourceSpecification,
+ "The string `#{query_object}' is not valid for resource collection lookup. Correct syntax is `resource_type[resource_name]'"
+ else
+ raise Chef::Exceptions::InvalidResourceSpecification,
+ "The object `#{query_object.inspect}' is not valid for resource collection lookup. " +
+ "Use a String like `resource_type[resource_name]' or a Chef::Resource object"
+ end
+ end
+
+ def self.create_key(resource_type, instance_name)
+ "#{resource_type}[#{instance_name}]"
+ end
+
+ private
+
+ def find_resource_by_hash(arg)
+ results = Array.new
+ arg.each do |resource_type, name_list|
+ instance_names = name_list.kind_of?(Array) ? name_list : [ name_list ]
+ instance_names.each do |instance_name|
+ results << lookup(ResourceSet.create_key(resource_type, instance_name))
+ end
+ end
+ return results
+ end
+
+ def find_resource_by_string(arg)
+ results = Array.new
+ case arg
+ when MULTIPLE_RESOURCE_MATCH
+ resource_type = $1
+ arg =~ /^.+\[(.+)\]$/
+ resource_list = $1
+ resource_list.split(",").each do |instance_name|
+ results << lookup(ResourceSet.create_key(resource_type, instance_name))
+ end
+ when SINGLE_RESOURCE_MATCH
+ resource_type = $1
+ name = $2
+ results << lookup(ResourceSet.create_key(resource_type, name))
+ else
+ raise ArgumentError, "Bad string format #{arg}, you must have a string like resource_type[name]!"
+ end
+ return results
+ end
+
+ end
+ end
+end