diff options
author | tyler-ball <tyleraball@gmail.com> | 2014-10-16 10:32:49 -0500 |
---|---|---|
committer | tyler-ball <tyleraball@gmail.com> | 2014-10-16 10:33:02 -0500 |
commit | 2cae7f7b39fd5dc34eefd5e0700bdbd693c6cba5 (patch) | |
tree | 72509bcdf57aab18b9e60542e412350fab3d032d /lib/chef/resource_collection | |
parent | 72dd653d9481848a7489845a46851c66964c5a37 (diff) | |
download | chef-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.rb | 100 | ||||
-rw-r--r-- | lib/chef/resource_collection/resource_set.rb | 169 |
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 |