summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Manifest.txt98
-rw-r--r--examples/sample_definition.rb6
-rw-r--r--examples/sample_recipe.rb2
-rw-r--r--lib/chef/config.rb78
-rw-r--r--lib/chef/cookbook.rb13
-rw-r--r--lib/chef/cookbook_loader.rb7
-rw-r--r--lib/chef/mixin/from_file.rb12
-rw-r--r--lib/chef/mixin/params_validate.rb162
-rw-r--r--lib/chef/node.rb21
-rw-r--r--lib/chef/recipe.rb49
-rw-r--r--lib/chef/resource.rb9
-rw-r--r--lib/chef/resource/file.rb4
-rw-r--r--spec/data/config.rb2
-rw-r--r--spec/data/cookbooks/openldap/recipes/default.rb3
-rw-r--r--spec/lib/chef/resource/cat.rb4
-rw-r--r--spec/lib/chef/resource/zen_master.rb4
-rw-r--r--spec/unit/chef_spec.rb2
-rw-r--r--spec/unit/config_spec.rb51
-rw-r--r--spec/unit/cookbook_loader_spec.rb9
-rw-r--r--spec/unit/cookbook_spec.rb2
-rw-r--r--spec/unit/mixin/params_validate_spec.rb298
-rw-r--r--spec/unit/node_spec.rb14
-rw-r--r--spec/unit/provider/file_spec.rb2
-rw-r--r--spec/unit/provider_spec.rb2
-rw-r--r--spec/unit/recipe_spec.rb22
-rw-r--r--spec/unit/resource/file_spec.rb2
-rw-r--r--spec/unit/resource_collection_spec.rb2
-rw-r--r--spec/unit/resource_definition_spec.rb2
-rw-r--r--spec/unit/resource_spec.rb2
29 files changed, 769 insertions, 115 deletions
diff --git a/Manifest.txt b/Manifest.txt
index a3bb60aaff..d21fe642aa 100644
--- a/Manifest.txt
+++ b/Manifest.txt
@@ -1,7 +1,101 @@
+.gitignore
History.txt
Manifest.txt
README.txt
Rakefile
-bin/chef
+docs/chef-head.txt
+docs/design/HighLevel.graffle
+docs/recipe.rb
+examples/config.rb
+examples/mrepo/Rakefile
+examples/node.rb
+examples/node.yml
+examples/sample_definition.rb
+examples/sample_recipe.rb
lib/chef.rb
-test/test_chef.rb \ No newline at end of file
+lib/chef/config.rb
+lib/chef/cookbook.rb
+lib/chef/cookbook_loader.rb
+lib/chef/mixin/check_helper.rb
+lib/chef/mixin/from_file.rb
+lib/chef/mixin/params_validate.rb
+lib/chef/node.rb
+lib/chef/provider.rb
+lib/chef/provider/file.rb
+lib/chef/recipe.rb
+lib/chef/resource.rb
+lib/chef/resource/file.rb
+lib/chef/resource_collection.rb
+lib/chef/resource_definition.rb
+server/chef-head/Rakefile
+server/chef-head/app/controllers/application.rb
+server/chef-head/app/controllers/exceptions.rb
+server/chef-head/app/controllers/nodes.rb
+server/chef-head/app/helpers/global_helpers.rb
+server/chef-head/app/helpers/nodes_helper.rb
+server/chef-head/app/models/node.rb
+server/chef-head/app/views/exceptions/internal_server_error.html.erb
+server/chef-head/app/views/exceptions/not_acceptable.html.erb
+server/chef-head/app/views/exceptions/not_found.html.erb
+server/chef-head/app/views/layout/application.html.erb
+server/chef-head/app/views/nodes/delete.html.erb
+server/chef-head/app/views/nodes/edit.html.erb
+server/chef-head/app/views/nodes/index.html.erb
+server/chef-head/app/views/nodes/new.html.erb
+server/chef-head/app/views/nodes/show.html.erb
+server/chef-head/config/environments/development.rb
+server/chef-head/config/environments/production.rb
+server/chef-head/config/environments/test.rb
+server/chef-head/config/init.rb
+server/chef-head/config/rack.rb
+server/chef-head/config/router.rb
+server/chef-head/public/images/merb.jpg
+server/chef-head/public/merb.fcgi
+server/chef-head/public/stylesheets/master.css
+server/chef-head/spec/controllers/nodes_spec.rb
+server/chef-head/spec/helpers/nodes_helpers.rb
+server/chef-head/spec/spec.opts
+server/chef-head/spec/spec_helper.rb
+server/chef-head/spec/views/nodes/delete.html.erb_spec.rb
+server/chef-head/spec/views/nodes/edit.html.erb_spec.rb
+server/chef-head/spec/views/nodes/index.html.erb_spec.rb
+server/chef-head/spec/views/nodes/new.html.erb_spec.rb
+server/chef-head/spec/views/nodes/show.html.erb_spec.rb
+spec/data/bad-config.rb
+spec/data/config.rb
+spec/data/cookbooks/openldap/attributes/default.rb
+spec/data/cookbooks/openldap/attributes/smokey.rb
+spec/data/cookbooks/openldap/definitions/client.rb
+spec/data/cookbooks/openldap/definitions/server.rb
+spec/data/cookbooks/openldap/ignore
+spec/data/cookbooks/openldap/recipes/gigantor.rb
+spec/data/definitions/test.rb
+spec/data/kitchen/openldap/attributes/default.rb
+spec/data/kitchen/openldap/attributes/robinson.rb
+spec/data/kitchen/openldap/definitions/client.rb
+spec/data/kitchen/openldap/definitions/drewbarrymore.rb
+spec/data/kitchen/openldap/recipes/gigantor.rb
+spec/data/kitchen/openldap/recipes/ignoreme.rb
+spec/data/kitchen/openldap/recipes/woot.rb
+spec/data/nodes/test.rb
+spec/data/recipes/test.rb
+spec/data/seattle.txt
+spec/lib/chef/resource/cat.rb
+spec/lib/chef/resource/zen_master.rb
+spec/rcov.opts
+spec/spec.opts
+spec/spec_helper.rb
+spec/unit/chef_spec.rb
+spec/unit/config_spec.rb
+spec/unit/cookbook_loader_spec.rb
+spec/unit/cookbook_spec.rb
+spec/unit/mixin/params_validate_spec.rb
+spec/unit/node_spec.rb
+spec/unit/provider/file_spec.rb
+spec/unit/provider_spec.rb
+spec/unit/recipe_spec.rb
+spec/unit/resource/file_spec.rb
+spec/unit/resource_collection_spec.rb
+spec/unit/resource_definition_spec.rb
+spec/unit/resource_spec.rb
+tasks/rspec.rb
diff --git a/examples/sample_definition.rb b/examples/sample_definition.rb
index fa4ddfe120..9264a4ba3b 100644
--- a/examples/sample_definition.rb
+++ b/examples/sample_definition.rb
@@ -3,6 +3,12 @@ web_server "monchichi" do
two "something else"
end
+runit_service "bobo" do
+ directory "monkey"
+ downif "/bin/false is true"
+ templatedir "something"
+end
+
define :runit_service, :directory => "/etc/sv", :downif => "/bin/false", :templatedir => nil do
require_recipe "runit"
diff --git a/examples/sample_recipe.rb b/examples/sample_recipe.rb
index 2eb4ba7f2c..234a1587a4 100644
--- a/examples/sample_recipe.rb
+++ b/examples/sample_recipe.rb
@@ -10,7 +10,6 @@ service "apache2" do
end
file "/etc/nsswitch.conf" do
- insure "present"
owner "root"
group "root"
mode 0644
@@ -18,7 +17,6 @@ file "/etc/nsswitch.conf" do
end
file "/etc/ldap.conf" do
- insure "present"
owner "root"
group "root"
mode 0644
diff --git a/lib/chef/config.rb b/lib/chef/config.rb
index 6c0402bdda..191de2504c 100644
--- a/lib/chef/config.rb
+++ b/lib/chef/config.rb
@@ -19,51 +19,59 @@
#
require File.join(File.dirname(__FILE__), "mixin", "check_helper")
+require File.join(File.dirname(__FILE__), "mixin", "from_file")
+
+# Chef::Config[:variable]
+# @config = Chef::Config.new()
+#
+# Chef::ConfigFast << Chef::Config
+#
+# Chef::Config.from_file(foo)
+# Chef::Resource.from_file (NoMethodError)
+# Chef::Config[:cookbook_path]
+# Chef::Config.cookbook_path
+# Chef::Config.cookbook_path "one", "two"
class Chef
class Config
-
include Chef::Mixin::CheckHelper
+
+ @configuration = {
+ :cookbook_path => [ "/etc/chef/site-cookbook", "/etc/chef/cookbook" ]
+ }
- 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)
+ class << self
+ include Chef::Mixin::FromFile
+
+ def configure(&block)
+ yield @configuration
+ end
+
+ def [](config_option)
+ if @configuration.has_key?(config_option.to_sym)
+ @configuration[config_option.to_sym]
+ else
+ raise ArgumentError, "Cannot find configuration option #{config_option.to_s}"
end
- else
- raise IOError, "Cannot find or read #{file}!"
end
- config
- end
+
+ def []=(config_option, value)
+ @configuration[config_option.to_sym] = value
+ 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!"
+ def method_missing(method_symbol, *args)
+ if @configuration.has_key?(method_symbol)
+ if args.length == 1
+ @configuration[method_symbol] = args[0]
+ elsif args.length > 1
+ @configuration[method_symbol] = args
end
+ return @configuration[method_symbol]
+ else
+ raise ArgumentError, "Cannot find configuration option #{method_symbol.to_s}"
end
- @cookbook_path = flat_args
end
- end
-
- def set_defaults
- @cookbook_path = [
- "/etc/chef/site-cookbook",
- "/etc/chef/cookbook",
- ]
- end
+
+ end # class << self
end
end \ No newline at end of file
diff --git a/lib/chef/cookbook.rb b/lib/chef/cookbook.rb
index c69491c2f2..218ecb3c10 100644
--- a/lib/chef/cookbook.rb
+++ b/lib/chef/cookbook.rb
@@ -86,20 +86,17 @@ class Chef
results
end
- def load_recipe(name, node, collection=nil, definitions=nil, config=nil)
+ def load_recipe(name, node, collection=nil, definitions=nil, cookbook_loader=nil)
cookbook_name = @name
recipe_name = nil
- case name
- when /^(.+)::(.+)$/
- recipe_name = $2
- else
- recipe_name = name
- end
+ nmatch = name.match(/^(.+)::(.+)$/)
+ recipe_name = nmatch ? nmatch[2] : name
+
unless @recipe_names.has_key?(recipe_name)
raise ArgumentError, "Cannot find a recipe matching #{recipe_name} in cookbook #{@name}"
end
recipe = Chef::Recipe.new(cookbook_name, recipe_name, node,
- collection, definitions, config)
+ collection, definitions, cookbook_loader)
recipe.from_file(@recipe_files[@recipe_names[recipe_name]])
recipe
end
diff --git a/lib/chef/cookbook_loader.rb b/lib/chef/cookbook_loader.rb
index d585b1e440..24ec01e574 100644
--- a/lib/chef/cookbook_loader.rb
+++ b/lib/chef/cookbook_loader.rb
@@ -21,19 +21,18 @@
class Chef
class CookbookLoader
- attr_accessor :cookbook, :config
+ attr_accessor :cookbook
include Enumerable
- def initialize(config)
- @config = config
+ def initialize()
@cookbook = Hash.new
load_cookbooks
end
def load_cookbooks
cookbook_settings = Hash.new
- @config.cookbook_path.each do |cb_path|
+ Chef::Config.cookbook_path.each do |cb_path|
Dir[File.join(cb_path, "*")].each do |cookbook|
next unless File.directory?(cookbook)
cookbook_name = File.basename(cookbook).to_sym
diff --git a/lib/chef/mixin/from_file.rb b/lib/chef/mixin/from_file.rb
index 68f614c07a..b1ad600ef8 100644
--- a/lib/chef/mixin/from_file.rb
+++ b/lib/chef/mixin/from_file.rb
@@ -1,3 +1,8 @@
+#
+# Chef::Mixin::FromFile
+#
+# A mixin that adds instance_eval support to a given object.
+#
# Author:: Adam Jacob (<adam@hjksolutions.com>)
# Copyright:: Copyright (c) 2008 HJK Solutions, LLC
# License:: GNU General Public License version 2 or later
@@ -19,7 +24,12 @@
class Chef
module Mixin
- module FromFile
+ module FromFile
+
+ # Loads a given ruby file, and runs instance_eval against it in the context of the current
+ # object.
+ #
+ # Raises an IOError if the file cannot be found, or is not readable.
def from_file(filename)
if File.exists?(filename) && File.readable?(filename)
self.instance_eval(IO.read(filename), filename, 1)
diff --git a/lib/chef/mixin/params_validate.rb b/lib/chef/mixin/params_validate.rb
new file mode 100644
index 0000000000..4c6b5f6612
--- /dev/null
+++ b/lib/chef/mixin/params_validate.rb
@@ -0,0 +1,162 @@
+#
+# Chef::Mixin::ParamsValidate
+#
+# Because I can't deal with not having named params. Strongly based on Dave Rolsky's excellent
+# Params::Validate module for Perl. Please don't blame him, though, if you hate this. :)
+#
+# 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 ParamsValidate
+
+ # Takes a hash of options, along with a map to validate them. Returns the original
+ # options hash, plus any changes that might have been made (through things like setting
+ # default values in the validation map)
+ #
+ # For example:
+ #
+ # validate({ :one => "neat" }, { :one => { :kind_of => String }})
+ #
+ # Would raise an exception if the value of :one above is not a kind_of? string. Valid
+ # map options are:
+ #
+ # :default:: Sets the default value for this parameter.
+ # :callbacks:: Takes a hash of Procs, which should return true if the argument is valid.
+ # The key will be inserted into the error message if the Proc does not return true:
+ # "Option #{key}'s value #{value} #{message}!"
+ # :kind_of:: Ensure that the value is a kind_of?(Whatever)
+ # :respond_to:: Esnure that the value has a given method. Takes one method name or an array of
+ # method names.
+ # :required:: Raise an exception if this parameter is missing. Valid values are true or false,
+ # by default, options are not required.
+ # :regex:: Match the value of the paramater against a regular expression.
+ def validate(opts, map)
+ #--
+ # validate works by taking the keys in the validation map, assuming it's a hash, and
+ # looking for _pv_:symbol as methods. Assuming it find them, it calls the right
+ # one.
+ #++
+ raise ArgumentError, "Options must be a hash" unless opts.kind_of?(Hash)
+ raise ArgumentError, "Validation Map must be a hash" unless map.kind_of?(Hash)
+
+ map.each do |key, validation|
+ unless key.kind_of?(Symbol) || key.kind_of?(String)
+ raise ArgumentError, "Validation map keys must be symbols or strings!"
+ end
+ case validation
+ when true
+ _pv_required(opts, key)
+ when false
+ true
+ when Hash
+ validation.each do |check, carg|
+ check_method = "_pv_#{check.to_s}"
+ if self.respond_to?(check_method, true)
+ self.send(check_method, opts, key, carg)
+ else
+ raise ArgumentError, "Validation map has unknown check: #{check}"
+ end
+ end
+ end
+ end
+ opts
+ end
+
+ private
+
+ # Return the value of a parameter, or nil if it doesn't exist.
+ def _pv_opts_lookup(opts, key)
+ if opts.has_key?(key.to_s)
+ opts[key.to_s]
+ elsif opts.has_key?(key.to_sym)
+ opts[key.to_sym]
+ else
+ nil
+ end
+ end
+
+ # Raise an exception if the parameter is not found.
+ def _pv_required(opts, key, is_required=true)
+ if is_required
+ if opts.has_key?(key.to_s) || opts.has_key?(key.to_sym)
+ true
+ else
+ raise ArgumentError, "Required argument #{key} is missing!"
+ end
+ end
+ end
+
+ # Raise an exception if the parameter is not a kind_of?(to_be)
+ def _pv_kind_of(opts, key, to_be)
+ value = _pv_opts_lookup(opts, key)
+ if value != nil
+ unless value.kind_of?(to_be)
+ raise ArgumentError, "Option #{key} must be a kind of #{to_be}! You passed #{to_be.inspect}."
+ end
+ end
+ end
+
+ # Raise an exception if the parameter does not respond to a given set of methods.
+ def _pv_respond_to(opts, key, method_name_list)
+ value = _pv_opts_lookup(opts, key)
+ if value != nil
+ method_name_list.to_a.each do |method_name|
+ unless value.respond_to?(method_name)
+ raise ArgumentError, "Option #{key} must have a #{method_name} method!"
+ end
+ end
+ end
+ end
+
+ # Assign a default value to a parameter.
+ def _pv_default(opts, key, default_value)
+ value = _pv_opts_lookup(opts, key)
+ if value == nil
+ opts[key] = default_value
+ end
+ end
+
+ # Check a parameter against a regular expression.
+ def _pv_regex(opts, key, regex)
+ value = _pv_opts_lookup(opts, key)
+ if value != nil
+ if regex.match(value) == nil
+ raise ArgumentError, "Option #{key}'s value #{value} does not match regular expression #{regex.to_s}"
+ end
+ end
+ end
+
+ # Check a parameter against a hash of proc's.
+ def _pv_callbacks(opts, key, callbacks)
+ raise ArgumentError, "Callback list must be a hash!" unless callbacks.kind_of?(Hash)
+ value = _pv_opts_lookup(opts, key)
+ if value != nil
+ callbacks.each do |message, zeproc|
+ if zeproc.call(value) != true
+ raise ArgumentError, "Option #{key}'s value #{value} #{message}!"
+ end
+ end
+ end
+ end
+ end
+ end
+end
+
diff --git a/lib/chef/node.rb b/lib/chef/node.rb
index 69dc6ab3f0..d5896fbd95 100644
--- a/lib/chef/node.rb
+++ b/lib/chef/node.rb
@@ -1,4 +1,7 @@
#
+# Chef::Node
+#
+#
# Author:: Adam Jacob (<adam@hjksolutions.com>)
# Copyright:: Copyright (c) 2008 HJK Solutions, LLC
# License:: GNU General Public License version 2 or later
@@ -29,12 +32,14 @@ class Chef
include Chef::Mixin::CheckHelper
include Chef::Mixin::FromFile
+ # Create a new Chef::Node object.
def initialize()
@name = nil
@attribute = Hash.new
@recipe_list = Array.new
end
+ # Set the name of this Node, or return the current name.
def name(arg=nil)
set_if_args(@name, arg) do |a|
case a
@@ -46,6 +51,7 @@ class Chef
end
end
+ # Return an attribute of this node. Returns nil if the attribute is not found.
def [](attrib)
if @attribute.has_key?(attrib)
@attribute[attrib]
@@ -56,6 +62,15 @@ class Chef
end
end
+ # Iterates over each attribute, passing the attribute and value to the block.
+ def each_attribute(&block)
+ @attribute.each do |k,v|
+ yield(k, v)
+ end
+ end
+
+ # Return true if this Node has a given attribute, false if not. Takes either a symbol or
+ # a string.
def attribute?(attrib)
result = false
result = @attribute.has_key?(attrib)
@@ -63,10 +78,13 @@ class Chef
return @attribute.has_key?(attrib.to_sym)
end
+ # Returns true if this Node expects a given recipe, false if not.
def recipe?(recipe_name)
@recipe_list.detect { |r| r == recipe_name } ? true : false
end
+ # Returns an Array of recipes. If you call it with arguments, they will become the new
+ # list of recipes.
def recipes(*args)
if args.length > 0
@recipe_list = args.flatten
@@ -75,6 +93,9 @@ class Chef
end
end
+ # Set an attribute based on the missing method. If you pass an argument, we'll use that
+ # to set the attribute values. Otherwise, we'll wind up just returning the attributes
+ # value.
def method_missing(symbol, *args)
if args.length != 0
@attribute[symbol] = args.length == 1 ? args[0] : args
diff --git a/lib/chef/recipe.rb b/lib/chef/recipe.rb
index 81fb979de2..af1cbd2d77 100644
--- a/lib/chef/recipe.rb
+++ b/lib/chef/recipe.rb
@@ -26,30 +26,47 @@ class Chef
include Chef::Mixin::FromFile
attr_accessor :cookbook_name, :recipe_name, :recipe, :node, :collection,
- :definitions, :config, :params
+ :definitions, :params, :cookbook_loader
- def initialize(cookbook_name, recipe_name, node, collection=nil, definitions=nil, config=nil)
+ def initialize(cookbook_name, recipe_name, node, collection=nil, definitions=nil, cookbook_loader=nil)
@cookbook_name = cookbook_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
+
+ if cookbook_loader
+ @cookbook_loader = cookbook_loader
+ else
+ @cookbook_loader = Chef::CookbookLoader.new()
+ end
+
@params = Hash.new
end
+ def require_recipe(*args)
+ args.flatten.each do |recipe|
+ rmatch = recipe.match(/(.+?)::(.+)/)
+ if rmatch
+ cookbook = @cookbook_loader[rmatch[1]]
+ cookbook.load_recipe(rmatch[2], @node, @collection, @definitions, @cookbook_loader)
+ else
+ cookbook = @cookbook_loader[recipe]
+ cookbook.load_recipe("default", @node, @collection, @definitions, @cookbook_loader)
+ end
+ end
+ end
+
def resources(*args)
@collection.resources(*args)
end
@@ -58,26 +75,28 @@ class Chef
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.
+ # to.
if @definitions.has_key?(method_symbol)
new_def = @definitions[method_symbol].dup
new_def.instance_eval(&block)
- new_recipe = Chef::Recipe.new(@cookbook_name, @recipe_name, @node, @collection, @definitions, @config)
+ new_recipe = Chef::Recipe.new(@cookbook_name, @recipe_name, @node, @collection, @definitions, @cookbook_loader)
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}"
+ mn = method_name.match(/^(.+)_(.+)$/)
+ if mn
+ rname = "Chef::Resource::#{mn[1].capitalize}#{mn[2].capitalize}"
+ else
+ short_match = method_name.match(/^(.+)$/)
+ if short_match
+ rname = "Chef::Resource::#{short_match[1].capitalize}"
+ end
end
begin
args << @collection
- args << @config
resource = eval(rname).new(*args)
resource.params = @params
resource.instance_eval(&block)
diff --git a/lib/chef/resource.rb b/lib/chef/resource.rb
index 2d7b90ed7f..fab6279a0e 100644
--- a/lib/chef/resource.rb
+++ b/lib/chef/resource.rb
@@ -26,21 +26,16 @@ class Chef
include Chef::Mixin::CheckHelper
- attr_accessor :tag, :actions, :config, :params
+ attr_accessor :tag, :actions, :params
attr_reader :name, :noop, :resource_name, :collection, :notifies, :subscribes
- def initialize(name, collection=nil, config=nil)
+ def initialize(name, collection=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
diff --git a/lib/chef/resource/file.rb b/lib/chef/resource/file.rb
index 3132aa5a1a..59c51ba8d3 100644
--- a/lib/chef/resource/file.rb
+++ b/lib/chef/resource/file.rb
@@ -22,9 +22,9 @@ class Chef
class Resource
class File < Chef::Resource
- def initialize(name, collection=nil, config=nil)
+ def initialize(name, collection=nil)
@resource_name = :file
- super(name, collection, config)
+ super(name, collection)
@path = name
@backup = true
@action = "create"
diff --git a/spec/data/config.rb b/spec/data/config.rb
index 2b1fcdc341..0b3340ce57 100644
--- a/spec/data/config.rb
+++ b/spec/data/config.rb
@@ -2,5 +2,5 @@
# Sample Chef Config File
#
-cookbook_path = "/etc/chef/cookbook", "/etc/chef/site-cookbook"
+cookbook_path "/etc/chef/cookbook", "/etc/chef/site-cookbook"
diff --git a/spec/data/cookbooks/openldap/recipes/default.rb b/spec/data/cookbooks/openldap/recipes/default.rb
new file mode 100644
index 0000000000..0ac8a9bb4b
--- /dev/null
+++ b/spec/data/cookbooks/openldap/recipes/default.rb
@@ -0,0 +1,3 @@
+cat "blanket" do
+ pretty_kitty true
+end
diff --git a/spec/lib/chef/resource/cat.rb b/spec/lib/chef/resource/cat.rb
index d9f3c657e0..5b66c9cabd 100644
--- a/spec/lib/chef/resource/cat.rb
+++ b/spec/lib/chef/resource/cat.rb
@@ -21,9 +21,9 @@ class Chef
class Resource
class Cat < Chef::Resource
- def initialize(name, collection=nil, config=nil)
+ def initialize(name, collection=nil)
@resource_name = :cat
- super(name, collection, config)
+ super(name, collection)
end
def pretty_kitty(arg=nil)
diff --git a/spec/lib/chef/resource/zen_master.rb b/spec/lib/chef/resource/zen_master.rb
index 3559b3272c..91ae87b246 100644
--- a/spec/lib/chef/resource/zen_master.rb
+++ b/spec/lib/chef/resource/zen_master.rb
@@ -22,9 +22,9 @@ class Chef
class ZenMaster < Chef::Resource
attr_reader :peace
- def initialize(name, collection=nil, config=nil)
+ def initialize(name, collection=nil)
@resource_name = :zen_master
- super(name, collection, config)
+ super(name, collection)
end
def peace(tf)
diff --git a/spec/unit/chef_spec.rb b/spec/unit/chef_spec.rb
index a75e3ad548..cfb6cd4dac 100644
--- a/spec/unit/chef_spec.rb
+++ b/spec/unit/chef_spec.rb
@@ -18,7 +18,7 @@
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
-require File.join(File.dirname(__FILE__), "..", "spec_helper")
+require File.expand_path(File.join(File.dirname(__FILE__), "..", "spec_helper"))
describe Chef do
it "should have a version defined" do
diff --git a/spec/unit/config_spec.rb b/spec/unit/config_spec.rb
index dec94796e0..4148336078 100644
--- a/spec/unit/config_spec.rb
+++ b/spec/unit/config_spec.rb
@@ -18,55 +18,70 @@
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
-require File.join(File.dirname(__FILE__), "..", "spec_helper")
+require File.expand_path(File.join(File.dirname(__FILE__), "..", "spec_helper"))
describe Chef::Config do
- before(:each) do
- @config = Chef::Config.new
- end
it "should load a .rb file in context" do
lambda {
- Chef::Config.load_file(File.join(File.dirname(__FILE__), "..", "data", "config.rb"))
+ Chef::Config.from_file(File.join(File.dirname(__FILE__), "..", "data", "config.rb"))
}.should_not raise_error
end
- it "should raise a NoMethodError with an explanation if you have a bad config file" do
+ it "should raise an ArgumentError with an explanation if you try and set a non-existent variable" do
lambda {
- Chef::Config.load_file(File.join(File.dirname(__FILE__), "..", "data", "bad-config.rb"))
- }.should raise_error(NoMethodError)
+ Chef::Config.from_file(File.join(File.dirname(__FILE__), "..", "data", "bad-config.rb"))
+ }.should raise_error(ArgumentError)
end
it "should raise an IOError if it can't find the file" do
lambda {
- Chef::Config.load_file("/tmp/timmytimmytimmy")
+ Chef::Config.from_file("/tmp/timmytimmytimmy")
}.should raise_error(IOError)
end
it "should have a default cookbook_path" do
- @config.cookbook_path.should be_kind_of(Array)
+ Chef::Config.cookbook_path.should be_kind_of(Array)
end
it "should allow you to set a cookbook_path with a string" do
- @config.cookbook_path("/etc/chef/cookbook")
- @config.cookbook_path.should eql(["/etc/chef/cookbook"])
+ Chef::Config.cookbook_path("/etc/chef/cookbook")
+ Chef::Config.cookbook_path.should eql("/etc/chef/cookbook")
end
it "should allow you to set a cookbook_path with multiple strings" do
- @config.cookbook_path("/etc/chef/cookbook", "/etc/chef/upstream-cookbooks")
- @config.cookbook_path.should eql([
+ Chef::Config.cookbook_path("/etc/chef/cookbook", "/etc/chef/upstream-cookbooks")
+ Chef::Config.cookbook_path.should eql([
"/etc/chef/cookbook",
"/etc/chef/upstream-cookbooks"
])
end
it "should allow you to set a cookbook_path with an array" do
- @config.cookbook_path ["one", "two"]
- @config.cookbook_path.should eql(["one", "two"])
+ Chef::Config.cookbook_path ["one", "two"]
+ Chef::Config.cookbook_path.should eql(["one", "two"])
+ end
+
+ it "should allow you to reference a value by index" do
+ Chef::Config[:cookbook_path].should be_kind_of(Array)
+ end
+
+ it "should allow you to set a value by index" do
+ Chef::Config[:cookbook_path] = "one"
+ Chef::Config[:cookbook_path].should == "one"
+ end
+
+ it "should allow you to set config values with a block" do
+ Chef::Config.configure do |c|
+ c[:cookbook_path] = "monkey_rabbit"
+ c[:otherthing] = "boo"
+ end
+ Chef::Config.cookbook_path.should == "monkey_rabbit"
+ Chef::Config.otherthing.should == "boo"
end
- it "should not allow you to set a cookbook_path with anything else" do
- lambda { @config.cookbook_path :symbol }.should raise_error(ArgumentError)
+ it "should raise an ArgumentError if you access a config option that does not exist" do
+ lambda { Chef::Config[:snob_hobbery] }.should raise_error(ArgumentError)
end
end \ No newline at end of file
diff --git a/spec/unit/cookbook_loader_spec.rb b/spec/unit/cookbook_loader_spec.rb
index 3da3e644ec..d66034ce7d 100644
--- a/spec/unit/cookbook_loader_spec.rb
+++ b/spec/unit/cookbook_loader_spec.rb
@@ -18,16 +18,15 @@
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
-require File.join(File.dirname(__FILE__), "..", "spec_helper")
+require File.expand_path(File.join(File.dirname(__FILE__), "..", "spec_helper"))
describe Chef::CookbookLoader do
before(:each) do
- config = Chef::Config.new
- config.cookbook_path [
+ Chef::Config.cookbook_path [
File.join(File.dirname(__FILE__), "..", "data", "cookbooks"),
File.join(File.dirname(__FILE__), "..", "data", "kitchen")
]
- @cl = Chef::CookbookLoader.new(config)
+ @cl = Chef::CookbookLoader.new()
end
it "should be a Chef::CookbookLoader object" do
@@ -56,7 +55,7 @@ describe Chef::CookbookLoader do
end
it "should find all the cookbooks in the cookbook path" do
- @cl.config.cookbook_path << File.join(File.dirname(__FILE__), "..", "data", "hidden-cookbooks")
+ Chef::Config.cookbook_path << File.join(File.dirname(__FILE__), "..", "data", "hidden-cookbooks")
@cl.load_cookbooks
@cl.detect { |cb| cb.name == :openldap }.should_not eql(nil)
@cl.detect { |cb| cb.name == :apache2 }.should_not eql(nil)
diff --git a/spec/unit/cookbook_spec.rb b/spec/unit/cookbook_spec.rb
index 1e44f519f7..f702fe32c1 100644
--- a/spec/unit/cookbook_spec.rb
+++ b/spec/unit/cookbook_spec.rb
@@ -18,7 +18,7 @@
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
-require File.join(File.dirname(__FILE__), "..", "spec_helper")
+require File.expand_path(File.join(File.dirname(__FILE__), "..", "spec_helper"))
describe Chef::Cookbook do
COOKBOOK_PATH = File.join(File.dirname(__FILE__), "..", "data", "cookbooks", "openldap")
diff --git a/spec/unit/mixin/params_validate_spec.rb b/spec/unit/mixin/params_validate_spec.rb
new file mode 100644
index 0000000000..3ade2b3c2d
--- /dev/null
+++ b/spec/unit/mixin/params_validate_spec.rb
@@ -0,0 +1,298 @@
+# 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.expand_path(File.join(File.dirname(__FILE__), "..", "..", "spec_helper"))
+
+class TinyClass
+ include Chef::Mixin::ParamsValidate
+
+ def music(is_good=true)
+ is_good
+ end
+end
+
+describe Chef::Mixin::ParamsValidate do
+ before(:each) do
+ @vo = TinyClass.new()
+ end
+
+ it "should allow a hash and a hash as arguments to validate" do
+ lambda { @vo.validate({:one => "two"}, {}) }.should_not raise_error(ArgumentError)
+ end
+
+ it "should raise an argument error if validate is called incorrectly" do
+ lambda { @vo.validate("one", "two") }.should raise_error(ArgumentError)
+ end
+
+ it "should require validation map keys to be symbols or strings" do
+ lambda { @vo.validate({:one => "two"}, { :one => true }) }.should_not raise_error(ArgumentError)
+ lambda { @vo.validate({:one => "two"}, { "one" => true }) }.should_not raise_error(ArgumentError)
+ lambda { @vo.validate({:one => "two"}, { Hash.new => true }) }.should raise_error(ArgumentError)
+ end
+
+ it "should allow options to be required with true" do
+ lambda { @vo.validate({:one => "two"}, { :one => true }) }.should_not raise_error(ArgumentError)
+ end
+
+ it "should allow options to be optional with false" do
+ lambda { @vo.validate({}, {:one => false})}.should_not raise_error(ArgumentError)
+ end
+
+ it "should allow you to check what kind_of? thing an argument is with kind_of" do
+ lambda {
+ @vo.validate(
+ {:one => "string"},
+ {
+ :one => {
+ :kind_of => String
+ }
+ }
+ )
+ }.should_not raise_error(ArgumentError)
+
+ lambda {
+ @vo.validate(
+ {:one => "string"},
+ {
+ :one => {
+ :kind_of => Array
+ }
+ }
+ )
+ }.should raise_error(ArgumentError)
+ end
+
+ it "should allow you to specify an argument is required with required" do
+ lambda {
+ @vo.validate(
+ {:one => "string"},
+ {
+ :one => {
+ :required => true
+ }
+ }
+ )
+ }.should_not raise_error(ArgumentError)
+
+ lambda {
+ @vo.validate(
+ {:two => "string"},
+ {
+ :one => {
+ :required => true
+ }
+ }
+ )
+ }.should raise_error(ArgumentError)
+
+ lambda {
+ @vo.validate(
+ {:two => "string"},
+ {
+ :one => {
+ :required => false
+ }
+ }
+ )
+ }.should_not raise_error(ArgumentError)
+ end
+
+ it "should allow you to specify whether an object has a method with respond_to" do
+ lambda {
+ @vo.validate(
+ {:one => @vo},
+ {
+ :one => {
+ :respond_to => "validate"
+ }
+ }
+ )
+ }.should_not raise_error(ArgumentError)
+
+ lambda {
+ @vo.validate(
+ {:one => @vo},
+ {
+ :one => {
+ :respond_to => "monkey"
+ }
+ }
+ )
+ }.should raise_error(ArgumentError)
+ end
+
+ it "should allow you to specify whether an object has all the given methods with respond_to and an array" do
+ lambda {
+ @vo.validate(
+ {:one => @vo},
+ {
+ :one => {
+ :respond_to => ["validate", "music"]
+ }
+ }
+ )
+ }.should_not raise_error(ArgumentError)
+
+ lambda {
+ @vo.validate(
+ {:one => @vo},
+ {
+ :one => {
+ :respond_to => ["monkey", "validate"]
+ }
+ }
+ )
+ }.should raise_error(ArgumentError)
+ end
+
+ it "should let you set a default value with default => value" do
+ arguments = Hash.new
+ @vo.validate(arguments, {
+ :one => {
+ :default => "is the loneliest number"
+ }
+ })
+ arguments[:one].should == "is the loneliest number"
+ end
+
+ it "should let you check regular expressions" do
+ lambda {
+ @vo.validate(
+ { :one => "is good" },
+ {
+ :one => {
+ :regex => /^is good$/
+ }
+ }
+ )
+ }.should_not raise_error(ArgumentError)
+
+ lambda {
+ @vo.validate(
+ { :one => "is good" },
+ {
+ :one => {
+ :regex => /^is bad$/
+ }
+ }
+ )
+ }.should raise_error(ArgumentError)
+ end
+
+ it "should let you specify your own callbacks" do
+ lambda {
+ @vo.validate(
+ { :one => "is good" },
+ {
+ :one => {
+ :callbacks => {
+ "should be equal to is good" => lambda { |a|
+ a == "is good"
+ },
+ }
+ }
+ }
+ )
+ }.should_not raise_error(ArgumentError)
+
+ lambda {
+ @vo.validate(
+ { :one => "is bad" },
+ {
+ :one => {
+ :callbacks => {
+ "should be equal to 'is good'" => lambda { |a|
+ a == "is good"
+ },
+ }
+ }
+ }
+ )
+ }.should raise_error(ArgumentError)
+ end
+
+ it "should let you combine checks" do
+ args = { :one => "is good", :two => "is bad" }
+ lambda {
+ @vo.validate(
+ args,
+ {
+ :one => {
+ :kind_of => String,
+ :respond_to => [ :to_s, :upcase ],
+ :regex => /^is good/,
+ :callbacks => {
+ "should be your friend" => lambda { |a|
+ a == "is good"
+ }
+ },
+ :required => true
+ },
+ :two => {
+ :kind_of => String,
+ :required => false
+ },
+ :three => { :default => "neato mosquito" }
+ }
+ )
+ }.should_not raise_error(ArgumentError)
+ args[:three].should == "neato mosquito"
+ lambda {
+ @vo.validate(
+ args,
+ {
+ :one => {
+ :kind_of => String,
+ :respond_to => [ :to_s, :upcase ],
+ :regex => /^is good/,
+ :callbacks => {
+ "should be your friend" => lambda { |a|
+ a == "is good"
+ }
+ },
+ :required => true
+ },
+ :two => {
+ :kind_of => Hash,
+ :required => false
+ },
+ :three => { :default => "neato mosquito" }
+ }
+ )
+ }.should raise_error(ArgumentError)
+ end
+
+ it "should raise an ArgumentError if the validation map has an unknown check" do
+ lambda { @vo.validate(
+ { :one => "two" },
+ {
+ :one => {
+ :busted => "check"
+ }
+ }
+ )
+ }.should raise_error(ArgumentError)
+ end
+
+ it "should accept keys that are strings in the options" do
+ lambda {
+ @vo.validate({ "one" => "two" }, { :one => { :regex => /^two$/ }})
+ }.should_not raise_error(ArgumentError)
+ end
+end \ No newline at end of file
diff --git a/spec/unit/node_spec.rb b/spec/unit/node_spec.rb
index e5a92486e5..a8c456e8f5 100644
--- a/spec/unit/node_spec.rb
+++ b/spec/unit/node_spec.rb
@@ -18,7 +18,7 @@
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
-require File.join(File.dirname(__FILE__), "..", "spec_helper")
+require File.expand_path(File.join(File.dirname(__FILE__), "..", "spec_helper"))
describe Chef::Node do
before(:each) do
@@ -104,5 +104,17 @@ describe Chef::Node do
lambda { @node.from_file("/tmp/monkeydiving") }.should raise_error(IOError)
end
+ it "should allow you to iterate over attributes with each_attribute" do
+ @node.sunshine "is bright"
+ @node.canada "is a nice place"
+ seen_attributes = Hash.new
+ @node.each_attribute do |a,v|
+ seen_attributes[a] = v
+ end
+ seen_attributes.should have_key(:sunshine)
+ seen_attributes.should have_key(:canada)
+ seen_attributes[:sunshine].should == "is bright"
+ seen_attributes[:canada].should == "is a nice place"
+ end
end \ No newline at end of file
diff --git a/spec/unit/provider/file_spec.rb b/spec/unit/provider/file_spec.rb
index 2ee6b1960e..4a98e88df0 100644
--- a/spec/unit/provider/file_spec.rb
+++ b/spec/unit/provider/file_spec.rb
@@ -20,7 +20,7 @@
require 'ostruct'
-require File.join(File.dirname(__FILE__), "..", "..", "spec_helper")
+require File.expand_path(File.join(File.dirname(__FILE__), "..", "..", "spec_helper"))
describe Chef::Provider::File do
before(:each) do
diff --git a/spec/unit/provider_spec.rb b/spec/unit/provider_spec.rb
index 51980cbe99..71cc1a47e3 100644
--- a/spec/unit/provider_spec.rb
+++ b/spec/unit/provider_spec.rb
@@ -18,7 +18,7 @@
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
-require File.join(File.dirname(__FILE__), "..", "spec_helper")
+require File.expand_path(File.join(File.dirname(__FILE__), "..", "spec_helper"))
describe Chef::Provider do
before(:each) do
diff --git a/spec/unit/recipe_spec.rb b/spec/unit/recipe_spec.rb
index e02973d73c..3c33a6d485 100644
--- a/spec/unit/recipe_spec.rb
+++ b/spec/unit/recipe_spec.rb
@@ -18,7 +18,7 @@
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
-require File.join(File.dirname(__FILE__), "..", "spec_helper")
+require File.expand_path(File.join(File.dirname(__FILE__), "..", "spec_helper"))
describe Chef::Recipe do
before(:each) do
@@ -110,7 +110,7 @@ CODE
@recipe.resources(:zen_master => "lao tzu").something.should eql(true)
end
- it "should load a node from a ruby file" do
+ it "should load a resource from a ruby file" do
@recipe.from_file(File.join(File.dirname(__FILE__), "..", "data", "recipes", "test.rb"))
res = @recipe.resources(:file => "/etc/nsswitch.conf")
res.name.should eql("/etc/nsswitch.conf")
@@ -123,5 +123,23 @@ CODE
it "should raise an exception if the file cannot be found or read" do
lambda { @recipe.from_file("/tmp/monkeydiving") }.should raise_error(IOError)
end
+
+ it "should evaluate another recipe with recipe_require" do
+ Chef::Config.cookbook_path File.join(File.dirname(__FILE__), "..", "data", "cookbooks")
+ @recipe.cookbook_loader.load_cookbooks
+ @recipe.require_recipe "openldap::gigantor"
+ res = @recipe.resources(:cat => "blanket")
+ res.name.should eql("blanket")
+ res.pretty_kitty.should eql(false)
+ end
+
+ it "should load the default recipe for a cookbook if require_recipe is called without a ::" do
+ Chef::Config.cookbook_path File.join(File.dirname(__FILE__), "..", "data", "cookbooks")
+ @recipe.cookbook_loader.load_cookbooks
+ @recipe.require_recipe "openldap"
+ res = @recipe.resources(:cat => "blanket")
+ res.name.should eql("blanket")
+ res.pretty_kitty.should eql(true)
+ end
end \ No newline at end of file
diff --git a/spec/unit/resource/file_spec.rb b/spec/unit/resource/file_spec.rb
index 474c58f0d1..bffb4e43f8 100644
--- a/spec/unit/resource/file_spec.rb
+++ b/spec/unit/resource/file_spec.rb
@@ -17,7 +17,7 @@
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
-require File.join(File.dirname(__FILE__), "..", "..", "spec_helper")
+require File.expand_path(File.join(File.dirname(__FILE__), "..", "..", "spec_helper"))
describe Chef::Resource::File do
diff --git a/spec/unit/resource_collection_spec.rb b/spec/unit/resource_collection_spec.rb
index 6f6f195513..10f7d43cde 100644
--- a/spec/unit/resource_collection_spec.rb
+++ b/spec/unit/resource_collection_spec.rb
@@ -17,7 +17,7 @@
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
-require File.join(File.dirname(__FILE__), "..", "spec_helper")
+require File.expand_path(File.join(File.dirname(__FILE__), "..", "spec_helper"))
describe Chef::ResourceCollection do
diff --git a/spec/unit/resource_definition_spec.rb b/spec/unit/resource_definition_spec.rb
index 8bcd9c52f9..8b8ee16f3a 100644
--- a/spec/unit/resource_definition_spec.rb
+++ b/spec/unit/resource_definition_spec.rb
@@ -18,7 +18,7 @@
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
-require File.join(File.dirname(__FILE__), "..", "spec_helper")
+require File.expand_path(File.join(File.dirname(__FILE__), "..", "spec_helper"))
describe Chef::ResourceDefinition do
before(:each) do
diff --git a/spec/unit/resource_spec.rb b/spec/unit/resource_spec.rb
index f767fe8348..d6db1f2d74 100644
--- a/spec/unit/resource_spec.rb
+++ b/spec/unit/resource_spec.rb
@@ -18,7 +18,7 @@
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
-require File.join(File.dirname(__FILE__), "..", "spec_helper")
+require File.expand_path(File.join(File.dirname(__FILE__), "..", "spec_helper"))
describe Chef::Resource do
before(:each) do