diff options
author | Adam Jacob <adam@hjksolutions.com> | 2008-03-10 00:38:43 -0700 |
---|---|---|
committer | Adam Jacob <adam@hjksolutions.com> | 2008-03-10 00:38:43 -0700 |
commit | 3dd77b260393bae93bb27677e3f8a45f407981c1 (patch) | |
tree | d017427ddcd5733caf7c0ceeec8ea72abbb107fa /lib/chef | |
parent | b4beed548959ca63365ca3d799c59a155047b5ff (diff) | |
download | chef-3dd77b260393bae93bb27677e3f8a45f407981c1.tar.gz |
Added rcov coverage, lots of tests, definitions, node support
Diffstat (limited to 'lib/chef')
-rw-r--r-- | lib/chef/config.rb | 69 | ||||
-rw-r--r-- | lib/chef/mixin/check_helper.rb | 33 | ||||
-rw-r--r-- | lib/chef/mixin/from_file.rb | 32 | ||||
-rw-r--r-- | lib/chef/node.rb | 91 | ||||
-rw-r--r-- | lib/chef/recipe.rb | 96 | ||||
-rw-r--r-- | lib/chef/resource.rb | 123 | ||||
-rw-r--r-- | lib/chef/resource/file.rb | 113 | ||||
-rw-r--r-- | lib/chef/resource_collection.rb | 155 | ||||
-rw-r--r-- | lib/chef/resource_definition.rb | 63 |
9 files changed, 775 insertions, 0 deletions
diff --git a/lib/chef/config.rb b/lib/chef/config.rb new file mode 100644 index 0000000000..6c0402bdda --- /dev/null +++ b/lib/chef/config.rb @@ -0,0 +1,69 @@ +# +# Author:: Adam Jacob (<adam@hjksolutions.com>) +# Copyright:: Copyright (c) 2008 HJK Solutions, LLC +# License:: GNU General Public License version 2 or later +# +# This program and entire repository is free software; you can +# redistribute it and/or modify it under the terms of the GNU +# General Public License as published by the Free Software +# Foundation; either version 2 of the License, or any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +# + +require File.join(File.dirname(__FILE__), "mixin", "check_helper") + +class Chef + class Config + + include Chef::Mixin::CheckHelper + + def initialize + set_defaults + end + + def self.load_file(file) + config = Chef::Config.new + if File.exists?(file) && File.readable?(file) + begin + config.instance_eval(IO.read(file), file, 1) + rescue NoMethodError => e + new_message = "You probably tried to use a config variable that doesn't exist!\n" + new_message += e.message + raise e.exception(new_message) + end + else + raise IOError, "Cannot find or read #{file}!" + end + config + end + + def cookbook_path(*args) + if args.length == 0 + @cookbook_path + else + flat_args = args.flatten + flat_args.each do |a| + unless a.kind_of?(String) + raise ArgumentError, "You must pass strings to cookbook_path!" + end + end + @cookbook_path = flat_args + end + end + + def set_defaults + @cookbook_path = [ + "/etc/chef/site-cookbook", + "/etc/chef/cookbook", + ] + end + end +end
\ No newline at end of file diff --git a/lib/chef/mixin/check_helper.rb b/lib/chef/mixin/check_helper.rb new file mode 100644 index 0000000000..a4208c7e49 --- /dev/null +++ b/lib/chef/mixin/check_helper.rb @@ -0,0 +1,33 @@ +# Author:: Adam Jacob (<adam@hjksolutions.com>) +# Copyright:: Copyright (c) 2008 HJK Solutions, LLC +# License:: GNU General Public License version 2 or later +# +# This program and entire repository is free software; you can +# redistribute it and/or modify it under the terms of the GNU +# General Public License as published by the Free Software +# Foundation; either version 2 of the License, or any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +# + +class Chef + module Mixin + module CheckHelper + def set_if_args(thing, arguments) + raise ArgumentError, "Must call set_if_args with a block!" unless Kernel.block_given? + if arguments != nil + yield(arguments) + else + thing + end + end + end + end +end diff --git a/lib/chef/mixin/from_file.rb b/lib/chef/mixin/from_file.rb new file mode 100644 index 0000000000..68f614c07a --- /dev/null +++ b/lib/chef/mixin/from_file.rb @@ -0,0 +1,32 @@ +# Author:: Adam Jacob (<adam@hjksolutions.com>) +# Copyright:: Copyright (c) 2008 HJK Solutions, LLC +# License:: GNU General Public License version 2 or later +# +# This program and entire repository is free software; you can +# redistribute it and/or modify it under the terms of the GNU +# General Public License as published by the Free Software +# Foundation; either version 2 of the License, or any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +# + +class Chef + module Mixin + module FromFile + def from_file(filename) + if File.exists?(filename) && File.readable?(filename) + self.instance_eval(IO.read(filename), filename, 1) + else + raise IOError, "Cannot open or read #{filename}!" + end + end + end + end +end diff --git a/lib/chef/node.rb b/lib/chef/node.rb new file mode 100644 index 0000000000..bcda384d09 --- /dev/null +++ b/lib/chef/node.rb @@ -0,0 +1,91 @@ +# +# Author:: Adam Jacob (<adam@hjksolutions.com>) +# Copyright:: Copyright (c) 2008 HJK Solutions, LLC +# License:: GNU General Public License version 2 or later +# +# This program and entire repository is free software; you can +# redistribute it and/or modify it under the terms of the GNU +# General Public License as published by the Free Software +# Foundation; either version 2 of the License, or any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +# + +require File.join(File.dirname(__FILE__), "mixin", "check_helper") +require File.join(File.dirname(__FILE__), "mixin", "from_file") + +class Chef + class Node + + attr_accessor :attribute, :recipe_list + + include Chef::Mixin::CheckHelper + include Chef::Mixin::FromFile + + def initialize() + @name = nil + @attribute = Hash.new + @recipe_list = Array.new + end + + def name(arg=nil) + set_if_args(@name, arg) do |a| + case a + when String + @name = a + else + raise ArgumentError, "The nodes name must be a string" + end + end + end + + def [](attrib) + if @attribute.has_key?(attrib) + @attribute[attrib] + elsif @attribute.has_key?(attrib.to_s) + @attribute[attrib.to_s] + else + nil + end + end + + def attribute?(attrib) + result = false + result = @attribute.has_key?(attrib) + return result if result + return @attribute.has_key?(attrib.to_sym) + end + + def recipe?(recipe_name) + @recipe_list.detect { |r| r == recipe_name } ? true : false + end + + def recipes(*args) + if args.length > 0 + @recipe_list = args.flatten + else + @recipe_list + end + end + + def method_missing(symbol, *args) + if args.length != 0 + @attribute[symbol] = args.length == 1 ? args[0] : args + else + if self[symbol] + @attribute[symbol] + else + raise ArgumentError, "Attribute #{symbol.to_s} is not defined!" + end + end + end + + end +end
\ No newline at end of file diff --git a/lib/chef/recipe.rb b/lib/chef/recipe.rb new file mode 100644 index 0000000000..17d14ef0bf --- /dev/null +++ b/lib/chef/recipe.rb @@ -0,0 +1,96 @@ +# +# Author:: Adam Jacob (<adam@hjksolutions.com>) +# Copyright:: Copyright (c) 2008 HJK Solutions, LLC +# License:: GNU General Public License version 2 or later +# +# This program and entire repository is free software; you can +# redistribute it and/or modify it under the terms of the GNU +# General Public License as published by the Free Software +# Foundation; either version 2 of the License, or any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +# + +require File.join(File.dirname(__FILE__), "mixin", "from_file") + +class Chef + class Recipe + + include Chef::Mixin::FromFile + + attr_accessor :module_name, :recipe_name, :recipe, :node, :collection, + :definitions, :config, :params + + def initialize(module_name, recipe_name, node, collection=nil, definitions=nil, config=nil) + @module_name = module_name + @recipe_name = recipe_name + @node = node + if collection + @collection = collection + else + @collection = Chef::ResourceCollection.new() + end + if config + @config = config + else + @config = Chef::Config.new() + end + if definitions + @definitions = definitions + else + @definitions = Hash.new + end + @params = Hash.new + end + + def resources(*args) + @collection.resources(*args) + end + + def method_missing(method_symbol, *args, &block) + resource = nil + # If we have a definition that matches, we want to use that instead. This should + # let you do some really crazy over-riding of "native" types, if you really want + # to. + if @definitions.has_key?(method_symbol) + new_def = @definitions[method_symbol].dup + new_def.instance_eval(&block) + new_recipe = Chef::Recipe.new(@module_name, @recipe_name, @node, @collection, @definitions, @config) + new_recipe.params = new_def.params + new_recipe.instance_eval(&new_def.recipe) + else + method_name = method_symbol.to_s + # Otherwise, we're rocking the regular resource call route. + rname = nil + case method_name + when /^(.+)_(.+)$/ + rname = "Chef::Resource::#{$1.capitalize}#{$2.capitalize}" + when /^(.+)$/ + rname = "Chef::Resource::#{$1.capitalize}" + end + begin + args << @collection + args << @config + resource = eval(rname).new(*args) + resource.params = @params + resource.instance_eval(&block) + rescue Exception => e + if e.kind_of?(NameError) && e.to_s =~ /Chef::Resource/ + raise NameError, "Cannot find #{rname} for #{method_name}\nOriginal: #{e.to_s}" + else + raise e + end + end + @collection << resource + resource + end + end + end +end
\ No newline at end of file diff --git a/lib/chef/resource.rb b/lib/chef/resource.rb new file mode 100644 index 0000000000..2d7b90ed7f --- /dev/null +++ b/lib/chef/resource.rb @@ -0,0 +1,123 @@ +# +# Author:: Adam Jacob (<adam@hjksolutions.com>) +# Copyright:: Copyright (c) 2008 HJK Solutions, LLC +# License:: GNU General Public License version 2 or later +# +# This program and entire repository is free software; you can +# redistribute it and/or modify it under the terms of the GNU +# General Public License as published by the Free Software +# Foundation; either version 2 of the License, or any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +# + +require File.join(File.dirname(__FILE__), "mixin", "check_helper") +require 'yaml' + +class Chef + class Resource + + include Chef::Mixin::CheckHelper + + attr_accessor :tag, :actions, :config, :params + attr_reader :name, :noop, :resource_name, :collection, :notifies, :subscribes + + def initialize(name, collection=nil, config=nil) + @name = name + if collection + @collection = collection + else + @collection = Chef::ResourceCollection.new() + end + if config + @config = config + else + @config = Chef::Config.new() + end + @tag = [ name.to_s ] + @noop = nil + @before = nil + @actions = Hash.new + @params = Hash.new + end + + def name(name=nil) + set_if_args(@name, name) do + raise ArgumentError, "name must be a string!" unless name.kind_of?(String) + @name = name + end + end + + def noop(tf=nil) + set_if_args(@noop, tf) do + raise ArgumentError, "noop must be true or false!" unless tf == true || tf == false + @noop = tf + end + end + + def notifies(action, resources, timing=:delayed) + timing = check_timing(timing) + rarray = resources.kind_of?(Array) ? resources : [ resources ] + rarray.each do |resource| + action_sym = action.to_sym + if @actions.has_key?(action_sym) + @actions[action_sym][timing] << resource + else + @actions[action_sym] = Hash.new + @actions[action_sym][:delayed] = Array.new + @actions[action_sym][:immediate] = Array.new + @actions[action_sym][timing] << resource + end + end + true + end + + def resources(*args) + @collection.resources(*args) + end + + def subscribes(action, resources, timing=:delayed) + timing = check_timing(timing) + rarray = resources.kind_of?(Array) ? resources : [ resources ] + rarray.each do |resource| + action_sym = action.to_sym + if resource.actions.has_key?(action_sym) + resource.actions[action_sym][timing] << self + else + resource.actions[action_sym] = Hash.new + resource.actions[action_sym][:delayed] = Array.new + resource.actions[action_sym][:immediate] = Array.new + resource.actions[action_sym][timing] << self + end + end + true + end + + def is(*args) + return *args + end + + def to_s + "#{@resource_name}[#{@name}]" + end + + private + + def check_timing(timing) + unless timing == :delayed || timing == :immediate || timing == :immediately + raise ArgumentError, "Timing must be :delayed or :immediate(ly), you said #{timing}" + end + if timing == :immediately + timing = :immediate + end + timing + end + end +end
\ No newline at end of file diff --git a/lib/chef/resource/file.rb b/lib/chef/resource/file.rb new file mode 100644 index 0000000000..0a2edb56a5 --- /dev/null +++ b/lib/chef/resource/file.rb @@ -0,0 +1,113 @@ +# +# Author:: Adam Jacob (<adam@hjksolutions.com>) +# Copyright:: Copyright (c) 2008 HJK Solutions, LLC +# License:: GNU General Public License version 2 or later +# +# This program and entire repository is free software; you can +# redistribute it and/or modify it under the terms of the GNU +# General Public License as published by the Free Software +# Foundation; either version 2 of the License, or any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +# + +class Chef + class Resource + class File < Chef::Resource + attr_reader :backup, :checksum, :insure, :group, :mode, :owner, :path + + def initialize(name, collection=nil, config=nil) + @resource_name = :file + super(name, collection, config) + @path = name + @backup = true + @checksum = "md5sum" + end + + def backup(arg=nil) + set_if_args(@backup, arg) do + case arg + when true, false, Integer + @backup = arg + else + raise ArgumentError, "backup must be true, false, or a number!" + end + end + end + + def checksum(arg=nil) + set_if_args(@checksum, arg) do + case arg + when "md5sum", "mtime" + @checksum = arg + else + raise ArgumentError, "checksum must be md5sum or mtime!" + end + end + end + + def insure(arg=nil) + set_if_args(@insure, arg) do + case arg + when "absent", "present" + @insure = arg + else + raise ArgumentError, "insure must be absent or present!" + end + end + end + + def group(arg=nil) + set_if_args(@group, arg) do + case arg + when /^([a-z]|[A-Z]|[0-9]|_|-)+$/, Integer + @group = arg + else + raise ArgumentError, "group must match /^([a-z]|[A-Z]|[0-9]|_|-)$/, Integer!" + end + end + end + + def mode(arg=nil) + set_if_args(@mode, arg) do + case "#{arg.to_s}" + when /^\d{3,4}$/ + @mode = arg + else + raise ArgumentError, "mode must be a valid unix file mode - 3 or 4 digets!" + end + end + end + + def owner(arg=nil) + set_if_args(@owner, arg) do + case arg + when /^([a-z]|[A-Z]|[0-9]|_|-)+$/, Integer + @owner = arg + else + raise ArgumentError, "group must match /^([a-z]|[A-Z]|[0-9]|_|-)$/, Integer!" + end + end + end + + def path(arg=nil) + set_if_args(@path, arg) do + case arg + when String + @path = arg + else + raise ArgumentError, "path must be a string!" + end + end + end + + end + end +end
\ No newline at end of file diff --git a/lib/chef/resource_collection.rb b/lib/chef/resource_collection.rb new file mode 100644 index 0000000000..dc93cfb4fa --- /dev/null +++ b/lib/chef/resource_collection.rb @@ -0,0 +1,155 @@ +# +# Author:: Adam Jacob (<adam@hjksolutions.com>) +# Copyright:: Copyright (c) 2008 HJK Solutions, LLC +# License:: GNU General Public License version 2 or later +# +# This program and entire repository is free software; you can +# redistribute it and/or modify it under the terms of the GNU +# General Public License as published by the Free Software +# Foundation; either version 2 of the License, or any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +# + +class Chef + class ResourceCollection + include Enumerable + + def initialize + @resources = Array.new + @resources_by_name = Hash.new + end + + def [](index) + @resources[index] + end + + def []=(index, arg) + is_chef_resource(arg) + @resources[index] = arg + @resources_by_name[arg.to_s] = index + end + + def <<(*args) + args.flatten.each do |a| + is_chef_resource(a) + @resources << a + @resources_by_name[a.to_s] = @resources.length - 1 + end + end + + def push(*args) + args.flatten.each do |a| + is_chef_resource(a) + @resources.push(a) + @resources_by_name[a.to_s] = @resources.length - 1 + end + end + + def each + @resources.each do |r| + yield r + end + end + + def each_index + @resources.each_index do |i| + yield i + end + end + + def lookup(resource) + lookup_by = nil + if resource.kind_of?(Chef::Resource) + lookup_by = resource.to_s + elsif resource.kind_of?(String) + lookup_by = resource + else + raise ArgumentError, "Must pass a Chef::Resource or String to lookup" + end + res = @resources_by_name[lookup_by] + unless res + raise ArgumentError, "Cannot find a resource matching #{lookup_by} (did you define it first?)" + end + @resources[res] + end + + # Find existing resources by searching the list of existing resources. Possible + # forms are: + # + # resources(:file => "foobar") + # resources(:file => [ "foobar", "baz" ]) + # resources("file[foobar]", "file[baz]") + # resources("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 resources(*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 + raise ArgumentError, "resources takes arguments as a hash or strings!" + end + end + flat_results = results.flatten + flat_results.length == 1 ? flat_results[0] : flat_results + end + + private + + def find_resource_by_hash(arg) + results = Array.new + arg.each do |resource_name, name_list| + names = name_list.kind_of?(Array) ? name_list : [ name_list ] + names.each do |name| + res_name = "#{resource_name.to_s}[#{name}]" + results << lookup(res_name) + end + end + return results + end + + def find_resource_by_string(arg) + results = Array.new + case arg + when /^(.+)\[(.+?),(.+)\]$/ + resource_type = $1 + arg =~ /^.+\[(.+)\]$/ + resource_list = $1 + resource_list.split(",").each do |name| + resource_name = "#{resource_type}[#{name}]" + results << lookup(resource_name) + end + when /^(.+)\[(.+)\]$/ + resource_type = $1 + name = $2 + resource_name = "#{resource_type}[#{name}]" + results << lookup(resource_name) + else + raise ArgumentError, "You must have a string like resource_type[name]!" + end + return results + end + + def is_chef_resource(arg) + unless arg.kind_of?(Chef::Resource) + raise ArgumentError, "Members must be Chef::Resource's" + end + true + end + end +end
\ No newline at end of file diff --git a/lib/chef/resource_definition.rb b/lib/chef/resource_definition.rb new file mode 100644 index 0000000000..ddc529b7d2 --- /dev/null +++ b/lib/chef/resource_definition.rb @@ -0,0 +1,63 @@ +# +# Author:: Adam Jacob (<adam@hjksolutions.com>) +# Copyright:: Copyright (c) 2008 HJK Solutions, LLC +# License:: GNU General Public License version 2 or later +# +# This program and entire repository is free software; you can +# redistribute it and/or modify it under the terms of the GNU +# General Public License as published by the Free Software +# Foundation; either version 2 of the License, or any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +# + +require File.join(File.dirname(__FILE__), "mixin", "from_file") + +class Chef + class ResourceDefinition + + include Chef::Mixin::FromFile + + attr_accessor :name, :params, :recipe + + def initialize + @name = nil + @params = Hash.new + @recipe = nil + end + + def define(resource_name, prototype_params=nil, &block) + unless resource_name.kind_of?(Symbol) + raise ArgumentError, "You must use a symbol when defining a new resource!" + end + @name = resource_name + if prototype_params + unless prototype_params.kind_of?(Hash) + raise ArgumentError, "You must pass a hash as the prototype parameters for a definition." + end + @params = prototype_params + end + if Kernel.block_given? + @recipe = block + else + raise ArgumentError, "You must pass a block to a definition." + end + true + end + + # When we do the resource definition, we're really just setting new values for + # the paramaters we prototyped at the top. This method missing is as simple as + # it gets. + def method_missing(symbol, *args) + @params[symbol] = args.length == 1 ? args[0] : args + end + + end +end
\ No newline at end of file |