Skip to content
Browse files

Attribute inclusion mixin, and features

  • Loading branch information...
1 parent 717e256 commit 13ac6455d30e2964842fd56f370e4c555320cb81 @adamhjk adamhjk committed Nov 27, 2009
View
3 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|
View
4 chef/lib/chef/compile.rb
@@ -22,14 +22,14 @@
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.
View
70 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 Cookbook
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 @@ def load_libraries
# === 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 @@ def load_providers
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 @@ def recipes
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 @@ def load_recipe(name, node, collection=nil, definitions=nil, cookbook_loader=nil
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
View
57 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
+
+
View
3 chef/lib/chef/mixin/language_include.rb → ...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 @@
class Chef
module Mixin
- module LanguageInclude
+ module LanguageIncludeRecipe
def include_recipe(*args)
args.flatten.each do |recipe|
View
5 chef/lib/chef/node.rb
@@ -20,6 +20,7 @@
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 Node
include Chef::Mixin::CheckHelper
include Chef::Mixin::FromFile
include Chef::Mixin::ParamsValidate
+ include Chef::Mixin::LanguageIncludeAttribute
DESIGN_DOCUMENT = {
"version" => 9,
@@ -134,7 +136,8 @@ def initialize
@run_state = {
:template_cache => Hash.new,
- :seen_recipes => Hash.new
+ :seen_recipes => Hash.new,
+ :seen_attributes => Hash.new
}
end
View
4 chef/lib/chef/recipe.rb
@@ -21,7 +21,7 @@
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 Recipe
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,
View
14 chef/spec/unit/cookbook_spec.rb
@@ -54,10 +54,6 @@
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 @@
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
+end
View
1 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
View
8 features/data/cookbooks/attribute_include/README.rdoc
@@ -0,0 +1,8 @@
+= DESCRIPTION:
+
+= REQUIREMENTS:
+
+= ATTRIBUTES:
+
+= USAGE:
+
View
4 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]
+
View
2 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'
View
6 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"
View
23 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
+
View
2 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
View
13 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
+

0 comments on commit 13ac645

Please sign in to comment.
Something went wrong with that request. Please try again.