summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAdam Jacob <adam@opscode.com>2009-11-27 16:39:16 -0800
committerAdam Jacob <adam@opscode.com>2009-11-27 16:39:16 -0800
commit13ac6455d30e2964842fd56f370e4c555320cb81 (patch)
tree90285b594c16688bd14f8a3f333b8c7a4da4ee70
parent717e256329e72147d141464255ab3e9b20ef4e48 (diff)
downloadchef-13ac6455d30e2964842fd56f370e4c555320cb81.tar.gz
Attribute inclusion mixin, and features
-rw-r--r--Rakefile3
-rw-r--r--chef/lib/chef/compile.rb4
-rw-r--r--chef/lib/chef/cookbook.rb70
-rw-r--r--chef/lib/chef/mixin/language_include_attribute.rb57
-rw-r--r--chef/lib/chef/mixin/language_include_recipe.rb (renamed from chef/lib/chef/mixin/language_include.rb)3
-rw-r--r--chef/lib/chef/node.rb5
-rw-r--r--chef/lib/chef/recipe.rb4
-rw-r--r--chef/spec/unit/cookbook_spec.rb14
-rw-r--r--cucumber.yml1
-rw-r--r--features/data/cookbooks/attribute_include/README.rdoc8
-rw-r--r--features/data/cookbooks/attribute_include/attributes/a.rb4
-rw-r--r--features/data/cookbooks/attribute_include/attributes/b.rb2
-rw-r--r--features/data/cookbooks/attribute_include/metadata.rb6
-rw-r--r--features/data/cookbooks/attribute_include/recipes/default.rb23
-rw-r--r--features/data/cookbooks/recipe_include/recipes/default.rb2
-rw-r--r--features/language/attribute_inclusion.feature13
16 files changed, 184 insertions, 35 deletions
diff --git a/Rakefile b/Rakefile
index a51b62586c..72b45f408a 100644
--- a/Rakefile
+++ b/Rakefile
@@ -367,6 +367,9 @@ namespace :features do
Cucumber::Rake::Task.new(:recipe_include) do |t|
t.profile = "recipe_inclusion"
end
+ Cucumber::Rake::Task.new(:attribute_include) do |t|
+ t.profile = "attribute_inclusion"
+ end
end
Cucumber::Rake::Task.new(:lwrp) do |t|
diff --git a/chef/lib/chef/compile.rb b/chef/lib/chef/compile.rb
index dcdc4b7160..a44fa8792f 100644
--- a/chef/lib/chef/compile.rb
+++ b/chef/lib/chef/compile.rb
@@ -22,14 +22,14 @@ require 'chef/node'
require 'chef/role'
require 'chef/log'
require 'chef/mixin/deep_merge'
-require 'chef/mixin/language_include'
+require 'chef/mixin/language_include_recipe'
class Chef
class Compile
attr_accessor :node, :cookbook_loader, :collection, :definitions
- include Chef::Mixin::LanguageInclude
+ include Chef::Mixin::LanguageIncludeRecipe
# Creates a new Chef::Compile object and populates its fields. This object gets
# used by the Chef Server to generate a fully compiled recipe list for a node.
diff --git a/chef/lib/chef/cookbook.rb b/chef/lib/chef/cookbook.rb
index 0d92d02c4f..6bee31021b 100644
--- a/chef/lib/chef/cookbook.rb
+++ b/chef/lib/chef/cookbook.rb
@@ -27,9 +27,9 @@ class Chef
class Cookbook
include Chef::Mixin::ConvertToClassName
- attr_accessor :attribute_files, :definition_files, :template_files, :remote_files,
+ attr_accessor :definition_files, :template_files, :remote_files,
:lib_files, :resource_files, :provider_files, :name
- attr_reader :recipe_files
+ attr_reader :recipe_files, :attribute_files
# Creates a new Chef::Cookbook object.
#
@@ -38,6 +38,7 @@ class Chef
def initialize(name)
@name = name
@attribute_files = Array.new
+ @attribute_names = Hash.new
@definition_files = Array.new
@template_files = Array.new
@remote_files = Array.new
@@ -71,15 +72,23 @@ class Chef
# === Raises
# <ArgumentError>:: If the argument is not a kind_of? <Chef::Node>
def load_attributes(node)
- unless node.kind_of?(Chef::Node)
- raise ArgumentError, "You must pass a Chef::Node to load_attributes!"
- end
@attribute_files.each do |file|
- Chef::Log.debug("Loading attributes from #{file}")
- node.from_file(file)
+ load_attribute_file(file, node)
end
node
end
+
+ def load_attribute_file(file, node)
+ Chef::Log.debug("Loading attributes from #{file}")
+ node.from_file(file)
+ end
+
+ def load_attribute(name, node)
+ attr_name = shorten_name(name)
+ file = @attribute_files[@attribute_names[attr_name]]
+ load_attribute_file(file, node)
+ node
+ end
# Loads all the resource definitions in this cookbook.
#
@@ -119,20 +128,14 @@ class Chef
end
def recipe_files=(*args)
- @recipe_files = args.flatten
- @recipe_files.each_index do |i|
- file = @recipe_files[i]
- case file
- when /(.+\/)(.+).rb$/
- @recipe_names[$2] = i
- when /(.+).rb$/
- @recipe_names[$1] = i
- else
- @recipe_names[file] = i
- end
- end
+ @recipe_files, @recipe_names = set_with_names(args.flatten)
@recipe_files
end
+
+ def attribute_files=(*args)
+ @attribute_files, @attribute_names = set_with_names(args.flatten)
+ @attribute_files
+ end
def recipe?(name)
lookup_name = name
@@ -154,9 +157,7 @@ class Chef
def load_recipe(name, node, collection=nil, definitions=nil, cookbook_loader=nil)
cookbook_name = @name
- recipe_name = nil
- nmatch = name.match(/^(.+?)::(.+)$/)
- recipe_name = nmatch ? nmatch[2] : name
+ recipe_name = shorten_name(name)
unless @recipe_names.has_key?(recipe_name)
raise ArgumentError, "Cannot find a recipe matching #{recipe_name} in cookbook #{@name}"
@@ -167,6 +168,31 @@ class Chef
recipe.from_file(@recipe_files[@recipe_names[recipe_name]])
recipe
end
+
+ private
+
+ def shorten_name(name)
+ short_name = nil
+ nmatch = name.match(/^(.+?)::(.+)$/)
+ short_name = nmatch ? nmatch[2] : name
+ end
+
+ def set_with_names(file_list)
+ files = file_list
+ names = Hash.new
+ files.each_index do |i|
+ file = files[i]
+ case file
+ when /(.+\/)(.+).rb$/
+ names[$2] = i
+ when /(.+).rb$/
+ names[$1] = i
+ else
+ names[file] = i
+ end
+ end
+ [ files, names ]
+ end
end
end
diff --git a/chef/lib/chef/mixin/language_include_attribute.rb b/chef/lib/chef/mixin/language_include_attribute.rb
new file mode 100644
index 0000000000..79c5421a40
--- /dev/null
+++ b/chef/lib/chef/mixin/language_include_attribute.rb
@@ -0,0 +1,57 @@
+#
+# Author:: Adam Jacob (<adam@opscode.com>)
+# Copyright:: Copyright (c) 2008, 2009 Opscode, 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/log'
+
+class Chef
+ module Mixin
+ module LanguageIncludeAttribute
+
+ def include_attribute(*args)
+ if self.kind_of?(Chef::Node)
+ node = self
+ else
+ node = @node
+ end
+
+ args.flatten.each do |attrib|
+ if node.run_state[:seen_attributes].has_key?(attrib)
+ Chef::Log.debug("I am not loading attribute file #{attrib}, because I have already seen it.")
+ next
+ end
+
+ Chef::Log.debug("Loading Attribute #{attrib}")
+ node.run_state[:seen_attributes][recipe] = true
+
+ amatch = attrib.match(/(.+?)::(.+)/)
+ if amatch
+ cookbook = @cookbook_loader[amatch[1]]
+ cookbook.load_attribute(amatch[2], node)
+ else
+ cookbook = @cookbook_loader[amatch[1]]
+ cookbook.load_attribute("default", node)
+ end
+ end
+ true
+ end
+
+ end
+ end
+end
+
+
diff --git a/chef/lib/chef/mixin/language_include.rb b/chef/lib/chef/mixin/language_include_recipe.rb
index ff07f75c59..6e81862515 100644
--- a/chef/lib/chef/mixin/language_include.rb
+++ b/chef/lib/chef/mixin/language_include_recipe.rb
@@ -1,6 +1,5 @@
#
# Author:: Adam Jacob (<adam@opscode.com>)
-# Author:: Christopher Walters (<cw@opscode.com>)
# Copyright:: Copyright (c) 2008, 2009 Opscode, Inc.
# License:: Apache License, Version 2.0
#
@@ -21,7 +20,7 @@ require 'chef/log'
class Chef
module Mixin
- module LanguageInclude
+ module LanguageIncludeRecipe
def include_recipe(*args)
args.flatten.each do |recipe|
diff --git a/chef/lib/chef/node.rb b/chef/lib/chef/node.rb
index 6166555c67..b8bbfe2612 100644
--- a/chef/lib/chef/node.rb
+++ b/chef/lib/chef/node.rb
@@ -20,6 +20,7 @@ require 'chef/config'
require 'chef/mixin/check_helper'
require 'chef/mixin/params_validate'
require 'chef/mixin/from_file'
+require 'chef/mixin/language_include_attribute'
require 'chef/couchdb'
require 'chef/rest'
require 'chef/run_list'
@@ -35,6 +36,7 @@ class Chef
include Chef::Mixin::CheckHelper
include Chef::Mixin::FromFile
include Chef::Mixin::ParamsValidate
+ include Chef::Mixin::LanguageIncludeAttribute
DESIGN_DOCUMENT = {
"version" => 9,
@@ -134,7 +136,8 @@ class Chef
@run_state = {
:template_cache => Hash.new,
- :seen_recipes => Hash.new
+ :seen_recipes => Hash.new,
+ :seen_attributes => Hash.new
}
end
diff --git a/chef/lib/chef/recipe.rb b/chef/lib/chef/recipe.rb
index 24e1cc4f9c..d9a2362889 100644
--- a/chef/lib/chef/recipe.rb
+++ b/chef/lib/chef/recipe.rb
@@ -21,7 +21,7 @@ require 'chef/resource'
Dir[File.join(File.dirname(__FILE__), 'resource/**/*.rb')].sort.each { |lib| require lib }
require 'chef/mixin/from_file'
require 'chef/mixin/language'
-require 'chef/mixin/language_include'
+require 'chef/mixin/language_include_recipe'
require 'chef/mixin/recipe_definition_dsl_core'
require 'chef/resource_collection'
require 'chef/cookbook_loader'
@@ -32,7 +32,7 @@ class Chef
include Chef::Mixin::FromFile
include Chef::Mixin::Language
- include Chef::Mixin::LanguageInclude
+ include Chef::Mixin::LanguageIncludeRecipe
include Chef::Mixin::RecipeDefinitionDSLCore
attr_accessor :cookbook_name, :recipe_name, :recipe, :node, :collection,
diff --git a/chef/spec/unit/cookbook_spec.rb b/chef/spec/unit/cookbook_spec.rb
index 650d0dbf0e..9f9d4a24c1 100644
--- a/chef/spec/unit/cookbook_spec.rb
+++ b/chef/spec/unit/cookbook_spec.rb
@@ -54,10 +54,6 @@ describe Chef::Cookbook do
node.smokey.should eql("robinson")
end
- it "should raise an ArgumentError if you don't pass a node object to load_attributes" do
- lambda { @cookbook.load_attributes("snake oil") }.should raise_error(ArgumentError)
- end
-
it "should have a list of definition files" do
@cookbook.definition_files.should be_a_kind_of(Array)
end
@@ -130,5 +126,13 @@ describe Chef::Cookbook do
node.name "Julia Child"
lambda { @cookbook.load_recipe("smackdown", node) }.should raise_error(ArgumentError)
end
+
+ it "should allow you to load an attribute file by name via load_attribute" do
+ @cookbook.attribute_files = Dir[File.join(COOKBOOK_PATH, "attributes", "**", "*.rb")]
+ node = Chef::Node.new
+ node.name "Julia Child"
+ @cookbook.load_attribute("openldap::smokey", node)
+ node.smokey.should == "robinson"
+ end
-end \ No newline at end of file
+end
diff --git a/cucumber.yml b/cucumber.yml
index a63ea346ea..43d77cbd5e 100644
--- a/cucumber.yml
+++ b/cucumber.yml
@@ -41,6 +41,7 @@ provider_package_macports: --tags @macports --format pretty -r features/steps -r
language: --tags @language --format pretty -r features/steps -r features/support features
client_run_interval: --tags client_run_interval --format pretty -r features/steps -r features/support features
recipe_inclusion: --tags recipe_inclusion --format pretty -r features/steps -r features/support features
+attribute_inclusion: --tags @attribute_inclusion --format pretty -r features/steps -r features/support features
cookbooks: --tags @cookbooks --format pretty -r features/steps -r features/support features
provider_remote_file: --tags provider,remote_file --format pretty -r features/steps -r features/support features
provider_git: --tags provider,git --format pretty -r features/steps -r features/support features
diff --git a/features/data/cookbooks/attribute_include/README.rdoc b/features/data/cookbooks/attribute_include/README.rdoc
new file mode 100644
index 0000000000..8d774805b9
--- /dev/null
+++ b/features/data/cookbooks/attribute_include/README.rdoc
@@ -0,0 +1,8 @@
+= DESCRIPTION:
+
+= REQUIREMENTS:
+
+= ATTRIBUTES:
+
+= USAGE:
+
diff --git a/features/data/cookbooks/attribute_include/attributes/a.rb b/features/data/cookbooks/attribute_include/attributes/a.rb
new file mode 100644
index 0000000000..d6edaf4b91
--- /dev/null
+++ b/features/data/cookbooks/attribute_include/attributes/a.rb
@@ -0,0 +1,4 @@
+include_attribute 'attribute_include::b'
+node.set[:mars_volta] = node[:mars_volta_name]
+node.set[:mars_volta_is] = node[:mars_volta_will_be]
+
diff --git a/features/data/cookbooks/attribute_include/attributes/b.rb b/features/data/cookbooks/attribute_include/attributes/b.rb
new file mode 100644
index 0000000000..e30b2dc772
--- /dev/null
+++ b/features/data/cookbooks/attribute_include/attributes/b.rb
@@ -0,0 +1,2 @@
+node.set[:mars_volta_name] = 'mars_volta'
+node.set[:mars_volta_will_be] = 'dope'
diff --git a/features/data/cookbooks/attribute_include/metadata.rb b/features/data/cookbooks/attribute_include/metadata.rb
new file mode 100644
index 0000000000..07c1801d28
--- /dev/null
+++ b/features/data/cookbooks/attribute_include/metadata.rb
@@ -0,0 +1,6 @@
+maintainer "Opscode"
+maintainer_email "do_not_reply@opscode.com"
+license "Apache 2.0"
+description "Installs/Configures recipe_include"
+long_description IO.read(File.join(File.dirname(__FILE__), 'README.rdoc'))
+version "0.1"
diff --git a/features/data/cookbooks/attribute_include/recipes/default.rb b/features/data/cookbooks/attribute_include/recipes/default.rb
new file mode 100644
index 0000000000..37d1612938
--- /dev/null
+++ b/features/data/cookbooks/attribute_include/recipes/default.rb
@@ -0,0 +1,23 @@
+#
+# Cookbook Name:: recipe_include
+# Recipe:: second
+#
+# Copyright 2009, Opscode
+#
+# 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.
+#
+
+execute "append to #{node[:tmpdir]}/mars_volta" do
+ command "echo '#{node[:mars_volta]} is #{node[:mavolta_is]}' >> #{node[:tmpdir]}/mars_volta"
+end
+
diff --git a/features/data/cookbooks/recipe_include/recipes/default.rb b/features/data/cookbooks/recipe_include/recipes/default.rb
index 8132a1c571..f05c067f4b 100644
--- a/features/data/cookbooks/recipe_include/recipes/default.rb
+++ b/features/data/cookbooks/recipe_include/recipes/default.rb
@@ -1,5 +1,5 @@
#
-# Cookbook Name:: recipe_include
+# Cookbook Name:: attribute_include
# Recipe:: default
#
# Copyright 2009, Opscode
diff --git a/features/language/attribute_inclusion.feature b/features/language/attribute_inclusion.feature
new file mode 100644
index 0000000000..d5e8c992c7
--- /dev/null
+++ b/features/language/attribute_inclusion.feature
@@ -0,0 +1,13 @@
+@language @attribute_inclusion
+Feature: Attribute Inclusion
+ In order to encapsulate functionality and re-use it
+ As a developer
+ I want to include an attribute file from another one
+
+ Scenario: Include an attribute directly
+ Given a validated node
+ And it includes the recipe 'attribute_include'
+ When I run the chef-client
+ Then the run should exit '0'
+ And a file named 'mars_volta' should contain 'mars_volta is dope' only '1' time
+