summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordanielsdeleo <dan@opscode.com>2012-10-19 15:58:41 -0700
committerdanielsdeleo <dan@opscode.com>2012-10-19 15:58:41 -0700
commitd90433ae23ec93dc9e9804c721911462c7a1b331 (patch)
treebc594753736164e616ec0c1c587bde42b6893627
parentd489549de16f15660c600dc100f22084194feeca (diff)
parent3fe49d7751a0194790b887708b28ca31d7046053 (diff)
downloadchef-d90433ae23ec93dc9e9804c721911462c7a1b331.tar.gz
Merge branch 'CHEF-2992'
-rw-r--r--chef/lib/chef/dsl.rb5
-rw-r--r--chef/lib/chef/dsl/data_query.rb66
-rw-r--r--chef/lib/chef/dsl/include_attribute.rb60
-rw-r--r--chef/lib/chef/dsl/include_recipe.rb42
-rw-r--r--chef/lib/chef/dsl/platform_introspection.rb215
-rw-r--r--chef/lib/chef/dsl/recipe.rb84
-rw-r--r--chef/lib/chef/mixin/language.rb231
-rw-r--r--chef/lib/chef/mixin/language_include_attribute.rb44
-rw-r--r--chef/lib/chef/mixin/language_include_recipe.rb38
-rw-r--r--chef/lib/chef/mixin/recipe_definition_dsl_core.rb69
-rw-r--r--chef/lib/chef/mixins.rb4
-rw-r--r--chef/lib/chef/node.rb72
-rw-r--r--chef/lib/chef/provider.rb12
-rw-r--r--chef/lib/chef/provider/deploy.rb3
-rw-r--r--chef/lib/chef/recipe.rb16
-rw-r--r--chef/lib/chef/resource.rb4
-rw-r--r--chef/lib/chef/run_context.rb74
-rw-r--r--chef/lib/chef/shell/ext.rb4
-rw-r--r--chef/spec/spec_helper.rb1
-rw-r--r--chef/spec/unit/cookbook_spec.rb19
-rw-r--r--chef/spec/unit/dsl/data_query_spec.rb66
-rw-r--r--chef/spec/unit/dsl/platfrom_introspection_spec.rb (renamed from chef/spec/unit/mixin/language_spec.rb)143
-rw-r--r--chef/spec/unit/formatters/error_inspectors/resource_failure_inspector_spec.rb2
-rw-r--r--chef/spec/unit/node_spec.rb112
-rw-r--r--chef/spec/unit/provider/package/apt_spec.rb1
-rw-r--r--chef/spec/unit/provider/package/ips_spec.rb1
-rw-r--r--chef/spec/unit/recipe_spec.rb4
-rw-r--r--chef/spec/unit/run_context_spec.rb18
28 files changed, 769 insertions, 641 deletions
diff --git a/chef/lib/chef/dsl.rb b/chef/lib/chef/dsl.rb
new file mode 100644
index 0000000000..74244fafbb
--- /dev/null
+++ b/chef/lib/chef/dsl.rb
@@ -0,0 +1,5 @@
+require 'chef/dsl/recipe'
+require 'chef/dsl/platform_introspection'
+require 'chef/dsl/data_query'
+require 'chef/dsl/include_recipe'
+require 'chef/dsl/include_attribute'
diff --git a/chef/lib/chef/dsl/data_query.rb b/chef/lib/chef/dsl/data_query.rb
new file mode 100644
index 0000000000..ef5b490020
--- /dev/null
+++ b/chef/lib/chef/dsl/data_query.rb
@@ -0,0 +1,66 @@
+#
+# Author:: Adam Jacob (<adam@opscode.com>)
+# Copyright:: Copyright (c) 2008 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/search/query'
+require 'chef/data_bag'
+require 'chef/data_bag_item'
+require 'chef/encrypted_data_bag_item'
+
+class Chef
+ module DSL
+
+ # ==Chef::DSL::DataQuery
+ # Provides DSL for querying data from the chef-server via search or data
+ # bag.
+ module DataQuery
+
+ def search(*args, &block)
+ # If you pass a block, or have at least the start argument, do raw result parsing
+ #
+ # Otherwise, do the iteration for the end user
+ if Kernel.block_given? || args.length >= 4
+ Chef::Search::Query.new.search(*args, &block)
+ else
+ results = Array.new
+ Chef::Search::Query.new.search(*args) do |o|
+ results << o
+ end
+ results
+ end
+ end
+
+ def data_bag(bag)
+ DataBag.validate_name!(bag.to_s)
+ rbag = DataBag.load(bag)
+ rbag.keys
+ rescue Exception
+ Log.error("Failed to list data bag items in data bag: #{bag.inspect}")
+ raise
+ end
+
+ def data_bag_item(bag, item)
+ DataBag.validate_name!(bag.to_s)
+ DataBagItem.validate_id!(item)
+ DataBagItem.load(bag, item)
+ rescue Exception
+ Log.error("Failed to load data bag item: #{bag.inspect} #{item.inspect}")
+ raise
+ end
+ end
+ end
+end
diff --git a/chef/lib/chef/dsl/include_attribute.rb b/chef/lib/chef/dsl/include_attribute.rb
new file mode 100644
index 0000000000..d8342af6a7
--- /dev/null
+++ b/chef/lib/chef/dsl/include_attribute.rb
@@ -0,0 +1,60 @@
+#
+# 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 DSL
+ module IncludeAttribute
+
+ # Loads the attribute file specified by the short name of the
+ # file, e.g., loads specified cookbook's
+ # "attributes/mailservers.rb"
+ # if passed
+ # "mailservers"
+ def include_attribute(*attr_file_specs)
+ attr_file_specs.flatten.each do |attr_file_spec|
+ cookbook_name, attr_file = parse_attribute_file_spec(attr_file_spec)
+ if run_context.loaded_fully_qualified_attribute?(cookbook_name, attr_file)
+ Chef::Log.debug("I am not loading attribute file #{cookbook_name}::#{attr_file}, because I have already seen it.")
+ else
+ Chef::Log.debug("Loading Attribute #{cookbook_name}::#{attr_file}")
+ run_context.loaded_attribute(cookbook_name, attr_file)
+ attr_file_path = run_context.resolve_attribute(cookbook_name, attr_file)
+ node.from_file(attr_file_path)
+ end
+ end
+ true
+ end
+
+ # Takes a attribute file specification, like "apache2" or "mysql::server"
+ # and converts it to a 2 element array of [cookbook_name, attribute_file_name]
+ def parse_attribute_file_spec(file_spec)
+ if match = file_spec.match(/(.+?)::(.+)/)
+ [match[1], match[2]]
+ else
+ [file_spec, "default"]
+ end
+ end
+
+ end
+ end
+end
+
+
+
diff --git a/chef/lib/chef/dsl/include_recipe.rb b/chef/lib/chef/dsl/include_recipe.rb
new file mode 100644
index 0000000000..8cbee7a733
--- /dev/null
+++ b/chef/lib/chef/dsl/include_recipe.rb
@@ -0,0 +1,42 @@
+#
+# 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 DSL
+ module IncludeRecipe
+
+ def include_recipe(*recipe_names)
+ run_context.include_recipe(*recipe_names)
+ end
+
+ def load_recipe(recipe_name)
+ run_context.load_recipe(recipe_name)
+ end
+
+ def require_recipe(*args)
+ Chef::Log.warn("require_recipe is deprecated and will be removed in a future release, please use include_recipe")
+ include_recipe(*args)
+ end
+
+ end
+ end
+end
+
+
diff --git a/chef/lib/chef/dsl/platform_introspection.rb b/chef/lib/chef/dsl/platform_introspection.rb
new file mode 100644
index 0000000000..211def2797
--- /dev/null
+++ b/chef/lib/chef/dsl/platform_introspection.rb
@@ -0,0 +1,215 @@
+#
+# Author:: Adam Jacob (<adam@opscode.com>)
+# Copyright:: Copyright (c) 2008 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.
+#
+
+class Chef
+ module DSL
+
+ # == Chef::DSL::PlatformIntrospection
+ # Provides the DSL for platform-dependent switch logic, such as
+ # #value_for_platform.
+ module PlatformIntrospection
+
+ # Implementation class for determining platform dependent values
+ class PlatformDependentValue
+
+ # Create a platform dependent value object.
+ # === Arguments
+ # platform_hash (Hash) a hash of the same structure as Chef::Platform,
+ # like this:
+ # {
+ # :debian => {:default => 'the value for all debian'}
+ # [:centos, :redhat, :fedora] => {:default => "value for all EL variants"}
+ # :ubuntu => { :default => "default for ubuntu", '10.04' => "value for 10.04 only"},
+ # :default => "the default when nothing else matches"
+ # }
+ # * platforms can be specified as Symbols or Strings
+ # * multiple platforms can be grouped by using an Array as the key
+ # * values for platforms need to be Hashes of the form:
+ # {platform_version => value_for_that_version}
+ # * the exception to the above is the default value, which is given as
+ # :default => default_value
+ def initialize(platform_hash)
+ @values = {}
+ platform_hash.each { |platforms, value| set(platforms, value)}
+ end
+
+ def value_for_node(node)
+ platform, version = node[:platform].to_s, node[:platform_version].to_s
+ if @values.key?(platform) && @values[platform].key?(version)
+ @values[platform][version]
+ elsif @values.key?(platform) && @values[platform].key?("default")
+ @values[platform]["default"]
+ elsif @values.key?("default")
+ @values["default"]
+ else
+ nil
+ end
+ end
+
+ private
+
+ def set(platforms, value)
+ if platforms.to_s == 'default'
+ @values["default"] = value
+ else
+ assert_valid_platform_values!(platforms, value)
+ Array(platforms).each { |platform| @values[platform.to_s] = normalize_keys(value)}
+ value
+ end
+ end
+
+ def normalize_keys(hash)
+ hash.inject({}) do |h, key_value|
+ keys, value = *key_value
+ Array(keys).each do |key|
+ h[key.to_s] = value
+ end
+ h
+ end
+ end
+
+ def assert_valid_platform_values!(platforms, value)
+ unless value.kind_of?(Hash)
+ msg = "platform dependent values must be specified in the format :platform => {:version => value} "
+ msg << "you gave a value #{value.inspect} for platform(s) #{platforms}"
+ raise ArgumentError, msg
+ end
+ end
+ end
+
+
+
+ # Given a hash similar to the one we use for Platforms, select a value from the hash. Supports
+ # per platform defaults, along with a single base default. Arrays may be passed as hash keys and
+ # will be expanded.
+ #
+ # === Parameters
+ # platform_hash:: A platform-style hash.
+ #
+ # === Returns
+ # value:: Whatever the most specific value of the hash is.
+ def value_for_platform(platform_hash)
+ PlatformDependentValue.new(platform_hash).value_for_node(node)
+ end
+
+ # Given a list of platforms, returns true if the current recipe is being run on a node with
+ # that platform, false otherwise.
+ #
+ # === Parameters
+ # args:: A list of platforms. Each platform can be in string or symbol format.
+ #
+ # === Returns
+ # true:: If the current platform is in the list
+ # false:: If the current platform is not in the list
+ def platform?(*args)
+ has_platform = false
+
+ args.flatten.each do |platform|
+ has_platform = true if platform.to_s == node[:platform]
+ end
+
+ has_platform
+ end
+
+
+
+ # Implementation class for determining platform family dependent values
+ class PlatformFamilyDependentValue
+
+ # Create a platform family dependent value object.
+ # === Arguments
+ # platform_family_hash (Hash) a map of platform families to values.
+ # like this:
+ # {
+ # :rhel => "value for all EL variants"
+ # :fedora => "value for fedora variants fedora and amazon" ,
+ # [:fedora, :rhel] => "value for all known redhat variants"
+ # :debian => "value for debian variants including debian, ubuntu, mint" ,
+ # :default => "the default when nothing else matches"
+ # }
+ # * platform families can be specified as Symbols or Strings
+ # * multiple platform families can be grouped by using an Array as the key
+ # * values for platform families can be any object, with no restrictions. Some examples:
+ # - [:stop, :start]
+ # - "mysql-devel"
+ # - { :key => "value" }
+ def initialize(platform_family_hash)
+ @values = {}
+ @values["default"] = nil
+ platform_family_hash.each { |platform_families, value| set(platform_families, value)}
+ end
+
+ def value_for_node(node)
+ if node.key?(:platform_family)
+ platform_family = node[:platform_family].to_s
+ if @values.key?(platform_family)
+ @values[platform_family]
+ else
+ @values["default"]
+ end
+ else
+ @values["default"]
+ end
+ end
+
+ private
+
+ def set(platform_family, value)
+ if platform_family.to_s == 'default'
+ @values["default"] = value
+ else
+ Array(platform_family).each { |family| @values[family.to_s] = value }
+ value
+ end
+ end
+ end
+
+
+ # Given a hash mapping platform families to values, select a value from the hash. Supports a single
+ # base default if platform family is not in the map. Arrays may be passed as hash keys and will be
+ # expanded
+ #
+ # === Parameters
+ # platform_family_hash:: A hash in the form { platform_family_name => value }
+ #
+ # === Returns
+ # value:: Whatever the most specific value of the hash is.
+ def value_for_platform_family(platform_family_hash)
+ PlatformFamilyDependentValue.new(platform_family_hash).value_for_node(node)
+ end
+
+ # Given a list of platform families, returns true if the current recipe is being run on a
+ # node within that platform family, false otherwise.
+ #
+ # === Parameters
+ # args:: A list of platform families. Each platform family can be in string or symbol format.
+ #
+ # === Returns
+ # true:: if the current node platform family is in the list.
+ # false:: if the current node platform family is not in the list.
+ def platform_family?(*args)
+ has_pf = false
+ args.flatten.each do |platform_family|
+ has_pf = true if platform_family.to_s == node[:platform_family]
+ end
+ has_pf
+ end
+
+ end
+ end
+end
diff --git a/chef/lib/chef/dsl/recipe.rb b/chef/lib/chef/dsl/recipe.rb
new file mode 100644
index 0000000000..1bfe8da0e0
--- /dev/null
+++ b/chef/lib/chef/dsl/recipe.rb
@@ -0,0 +1,84 @@
+#--
+# 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
+#
+# 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_platform_map'
+require 'chef/mixin/convert_to_class_name'
+require 'chef/mixin/language'
+
+class Chef
+ module DSL
+
+ # == Chef::DSL::Recipe
+ # Provides the primary recipe DSL functionality for defining Chef resource
+ # objects via method calls.
+ module Recipe
+
+ include Chef::Mixin::ConvertToClassName
+
+ def method_missing(method_symbol, *args, &block)
+ # 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 run_context.definitions.has_key?(method_symbol)
+ # This dupes the high level object, but we still need to dup the params
+ new_def = run_context.definitions[method_symbol].dup
+ new_def.params = new_def.params.dup
+ new_def.node = run_context.node
+ # This sets up the parameter overrides
+ new_def.instance_eval(&block) if block
+ new_recipe = Chef::Recipe.new(cookbook_name, @recipe_name, run_context)
+ new_recipe.params = new_def.params
+ new_recipe.params[:name] = args[0]
+ new_recipe.instance_eval(&new_def.recipe)
+ else
+ # Otherwise, we're rocking the regular resource call route.
+
+ # Checks the new platform => short_name => resource mapping initially
+ # then fall back to the older approach (Chef::Resource.const_get) for
+ # backward compatibility
+ resource_class = Chef::Resource.resource_for_node(method_symbol, run_context.node)
+
+ super unless resource_class
+ raise ArgumentError, "You must supply a name when declaring a #{method_symbol} resource" unless args.size > 0
+
+ # If we have a resource like this one, we want to steal its state
+ args << run_context
+ resource = resource_class.new(*args)
+ resource.load_prior_resource
+ resource.cookbook_name = cookbook_name
+ resource.recipe_name = @recipe_name
+ resource.params = @params
+ resource.source_line = caller[0]
+ # Determine whether this resource is being created in the context of an enclosing Provider
+ resource.enclosing_provider = self.is_a?(Chef::Provider) ? self : nil
+ # Evaluate resource attribute DSL
+ resource.instance_eval(&block) if block
+
+ # Run optional resource hook
+ resource.after_created
+
+ run_context.resource_collection.insert(resource)
+ resource
+ end
+ end
+
+ end
+ end
+end
diff --git a/chef/lib/chef/mixin/language.rb b/chef/lib/chef/mixin/language.rb
index 52b2065755..3aa6a6d800 100644
--- a/chef/lib/chef/mixin/language.rb
+++ b/chef/lib/chef/mixin/language.rb
@@ -16,233 +16,20 @@
# limitations under the License.
#
-require 'chef/search/query'
-require 'chef/data_bag'
-require 'chef/data_bag_item'
-require 'chef/encrypted_data_bag_item'
+require 'chef/dsl/platform_introspection'
+require 'chef/dsl/data_query'
class Chef
module Mixin
- module Language
-
- # Implementation class for determining platform dependent values
- class PlatformDependentValue
-
- # Create a platform dependent value object.
- # === Arguments
- # platform_hash (Hash) a hash of the same structure as Chef::Platform,
- # like this:
- # {
- # :debian => {:default => 'the value for all debian'}
- # [:centos, :redhat, :fedora] => {:default => "value for all EL variants"}
- # :ubuntu => { :default => "default for ubuntu", '10.04' => "value for 10.04 only"},
- # :default => "the default when nothing else matches"
- # }
- # * platforms can be specified as Symbols or Strings
- # * multiple platforms can be grouped by using an Array as the key
- # * values for platforms need to be Hashes of the form:
- # {platform_version => value_for_that_version}
- # * the exception to the above is the default value, which is given as
- # :default => default_value
- def initialize(platform_hash)
- @values = {}
- platform_hash.each { |platforms, value| set(platforms, value)}
- end
-
- def value_for_node(node)
- platform, version = node[:platform].to_s, node[:platform_version].to_s
- if @values.key?(platform) && @values[platform].key?(version)
- @values[platform][version]
- elsif @values.key?(platform) && @values[platform].key?("default")
- @values[platform]["default"]
- elsif @values.key?("default")
- @values["default"]
- else
- nil
- end
- end
-
- private
-
- def set(platforms, value)
- if platforms.to_s == 'default'
- @values["default"] = value
- else
- assert_valid_platform_values!(platforms, value)
- Array(platforms).each { |platform| @values[platform.to_s] = normalize_keys(value)}
- value
- end
- end
-
- def normalize_keys(hash)
- hash.inject({}) do |h, key_value|
- keys, value = *key_value
- Array(keys).each do |key|
- h[key.to_s] = value
- end
- h
- end
- end
-
- def assert_valid_platform_values!(platforms, value)
- unless value.kind_of?(Hash)
- msg = "platform dependent values must be specified in the format :platform => {:version => value} "
- msg << "you gave a value #{value.inspect} for platform(s) #{platforms}"
- raise ArgumentError, msg
- end
- end
- end
-
-
-
- # Given a hash similar to the one we use for Platforms, select a value from the hash. Supports
- # per platform defaults, along with a single base default. Arrays may be passed as hash keys and
- # will be expanded.
- #
- # === Parameters
- # platform_hash:: A platform-style hash.
- #
- # === Returns
- # value:: Whatever the most specific value of the hash is.
- def value_for_platform(platform_hash)
- PlatformDependentValue.new(platform_hash).value_for_node(node)
- end
-
- # Given a list of platforms, returns true if the current recipe is being run on a node with
- # that platform, false otherwise.
- #
- # === Parameters
- # args:: A list of platforms. Each platform can be in string or symbol format.
- #
- # === Returns
- # true:: If the current platform is in the list
- # false:: If the current platform is not in the list
- def platform?(*args)
- has_platform = false
- args.flatten.each do |platform|
- has_platform = true if platform.to_s == node[:platform]
- end
-
- has_platform
- end
-
-
-
- # Implementation class for determining platform family dependent values
- class PlatformFamilyDependentValue
-
- # Create a platform family dependent value object.
- # === Arguments
- # platform_family_hash (Hash) a map of platform families to values.
- # like this:
- # {
- # :rhel => "value for all EL variants"
- # :fedora => "value for fedora variants fedora and amazon" ,
- # [:fedora, :rhel] => "value for all known redhat variants"
- # :debian => "value for debian variants including debian, ubuntu, mint" ,
- # :default => "the default when nothing else matches"
- # }
- # * platform families can be specified as Symbols or Strings
- # * multiple platform families can be grouped by using an Array as the key
- # * values for platform families can be any object, with no restrictions. Some examples:
- # - [:stop, :start]
- # - "mysql-devel"
- # - { :key => "value" }
- def initialize(platform_family_hash)
- @values = {}
- @values["default"] = nil
- platform_family_hash.each { |platform_families, value| set(platform_families, value)}
- end
-
- def value_for_node(node)
- if node.key?(:platform_family)
- platform_family = node[:platform_family].to_s
- if @values.key?(platform_family)
- @values[platform_family]
- else
- @values["default"]
- end
- else
- @values["default"]
- end
- end
-
- private
-
- def set(platform_family, value)
- if platform_family.to_s == 'default'
- @values["default"] = value
- else
- Array(platform_family).each { |family| @values[family.to_s] = value }
- value
- end
- end
- end
-
-
- # Given a hash mapping platform families to values, select a value from the hash. Supports a single
- # base default if platform family is not in the map. Arrays may be passed as hash keys and will be
- # expanded.
- #
- # === Parameters
- # platform_family_hash:: A hash in the form { platform_family_name => value }
- #
- # === Returns
- # value:: Whatever the most specific value of the hash is.
- def value_for_platform_family(platform_family_hash)
- PlatformFamilyDependentValue.new(platform_family_hash).value_for_node(node)
- end
-
- # Given a list of platform families, returns true if the current recipe is being run on a
- # node within that platform family, false otherwise.
- #
- # === Parameters
- # args:: A list of platform families. Each platform family can be in string or symbol format.
- #
- # === Returns
- # true:: if the current node platform family is in the list.
- # false:: if the current node platform family is not in the list.
- def platform_family?(*args)
- has_pf = false
- args.flatten.each do |platform_family|
- has_pf = true if platform_family.to_s == node[:platform_family]
- end
- has_pf
- end
-
- def search(*args, &block)
- # If you pass a block, or have at least the start argument, do raw result parsing
- #
- # Otherwise, do the iteration for the end user
- if Kernel.block_given? || args.length >= 4
- Chef::Search::Query.new.search(*args, &block)
- else
- results = Array.new
- Chef::Search::Query.new.search(*args) do |o|
- results << o
- end
- results
- end
- end
-
- def data_bag(bag)
- DataBag.validate_name!(bag.to_s)
- rbag = DataBag.load(bag)
- rbag.keys
- rescue Exception
- Log.error("Failed to list data bag items in data bag: #{bag.inspect}")
- raise
- end
+ # == [DEPRECATED] Chef::Mixin::Language
+ # This module is deprecated and remains only for backwards compatibility.
+ #
+ # See Chef::DSL::PlatformIntrospection and Chef::DSL::DataQuery
+ module Language
- def data_bag_item(bag, item)
- DataBag.validate_name!(bag.to_s)
- DataBagItem.validate_id!(item)
- DataBagItem.load(bag, item)
- rescue Exception
- Log.error("Failed to load data bag item: #{bag.inspect} #{item.inspect}")
- raise
- end
+ include Chef::DSL::PlatformIntrospection
+ include Chef::DSL::DataQuery
end
end
diff --git a/chef/lib/chef/mixin/language_include_attribute.rb b/chef/lib/chef/mixin/language_include_attribute.rb
index 5d926a6761..283773b25d 100644
--- a/chef/lib/chef/mixin/language_include_attribute.rb
+++ b/chef/lib/chef/mixin/language_include_attribute.rb
@@ -6,9 +6,9 @@
# 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.
@@ -16,46 +16,14 @@
# limitations under the License.
#
-require 'chef/log'
+require 'chef/dsl/include_attribute'
class Chef
module Mixin
- module LanguageIncludeAttribute
-
- # Loads the attribute file specified by the short name of the
- # file, e.g., loads specified cookbook's
- # "attributes/mailservers.rb"
- # if passed
- # "mailservers"
- def include_attribute(*fully_qualified_attribute_short_filenames)
- if self.kind_of?(Chef::Node)
- node = self
- else
- node = @node
- end
-
- fully_qualified_attribute_short_filenames.flatten.each do |fully_qualified_attribute_short_filename|
- if node.run_state[:seen_attributes].has_key?(fully_qualified_attribute_short_filename)
- Chef::Log.debug("I am not loading attribute file #{fully_qualified_attribute_short_filename}, because I have already seen it.")
- next
- end
-
- Chef::Log.debug("Loading Attribute #{fully_qualified_attribute_short_filename}")
- node.run_state[:seen_attributes][fully_qualified_attribute_short_filename] = true
-
- if amatch = fully_qualified_attribute_short_filename.match(/(.+?)::(.+)/)
- cookbook_name = amatch[1].to_sym
- node.load_attribute_by_short_filename(amatch[2], cookbook_name)
- else
- cookbook_name = fully_qualified_attribute_short_filename.to_sym
- node.load_attribute_by_short_filename("default", cookbook_name)
- end
- end
- true
- end
- end
+ # DEPRECATED: This is just here for compatibility, use
+ # Chef::DSL::IncludeAttribute instead.
+ LanguageIncludeAttribute = Chef::DSL::IncludeAttribute
end
end
-
diff --git a/chef/lib/chef/mixin/language_include_recipe.rb b/chef/lib/chef/mixin/language_include_recipe.rb
index c819211feb..0566046560 100644
--- a/chef/lib/chef/mixin/language_include_recipe.rb
+++ b/chef/lib/chef/mixin/language_include_recipe.rb
@@ -16,43 +16,11 @@
# limitations under the License.
#
-require 'chef/log'
+require 'chef/dsl/include_recipe'
class Chef
module Mixin
- module LanguageIncludeRecipe
-
- def include_recipe(*recipe_names)
- result_recipes = Array.new
- recipe_names.flatten.each do |recipe_name|
- if node.run_state[:seen_recipes].has_key?(recipe_name) or node.run_state[:seen_recipes].has_key?(recipe_name + "::default")
- Chef::Log.debug("I am not loading #{recipe_name}, because I have already seen it.")
- next
- end
-
- result_recipes << load_recipe(recipe_name)
- end
- result_recipes
- end
-
- def load_recipe(recipe_name)
- Chef::Log.debug("Loading Recipe #{recipe_name} via include_recipe")
- node.run_state[:seen_recipes][recipe_name] = true
-
- cookbook_name, recipe_short_name = Chef::Recipe.parse_recipe_name(recipe_name)
-
- run_context = self.is_a?(Chef::RunContext) ? self : self.run_context
- cookbook = run_context.cookbook_collection[cookbook_name]
- cookbook.load_recipe(recipe_short_name, run_context)
- end
-
-
- def require_recipe(*args)
- Chef::Log.warn("require_recipe is deprecated and will be removed in a future release, please use include_recipe")
- include_recipe(*args)
- end
-
- end
+ LanguageIncludeRecipe = Chef::DSL::IncludeRecipe
end
end
-
+
diff --git a/chef/lib/chef/mixin/recipe_definition_dsl_core.rb b/chef/lib/chef/mixin/recipe_definition_dsl_core.rb
index cf89600654..ff422d892f 100644
--- a/chef/lib/chef/mixin/recipe_definition_dsl_core.rb
+++ b/chef/lib/chef/mixin/recipe_definition_dsl_core.rb
@@ -17,70 +17,17 @@
# limitations under the License.
#
-require 'chef/resource'
-require 'chef/resource_platform_map'
-require 'chef/mixin/convert_to_class_name'
-require 'chef/mixin/language'
+###
+# NOTE: This file and constant are here only for backwards compatibility.
+# New code should use Chef::DSL::Recipe instead.
+#
+# This constant (module name) will eventually be deprecated and then removed.
+###
-#--
-# UGH. this is a circular require that will cause an uninitialized constant
-# error, but this file really does depend on Chef::Recipe. oh well.
-# require 'chef/recipe'
+require 'chef/dsl/recipe'
class Chef
module Mixin
- module RecipeDefinitionDSLCore
-
- include Chef::Mixin::ConvertToClassName
- include Chef::Mixin::Language
-
- def method_missing(method_symbol, *args, &block)
- # 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 run_context.definitions.has_key?(method_symbol)
- # This dupes the high level object, but we still need to dup the params
- new_def = run_context.definitions[method_symbol].dup
- new_def.params = new_def.params.dup
- new_def.node = run_context.node
- # This sets up the parameter overrides
- new_def.instance_eval(&block) if block
- new_recipe = Chef::Recipe.new(cookbook_name, @recipe_name, run_context)
- new_recipe.params = new_def.params
- new_recipe.params[:name] = args[0]
- new_recipe.instance_eval(&new_def.recipe)
- else
- # Otherwise, we're rocking the regular resource call route.
-
- # Checks the new platform => short_name => resource mapping initially
- # then fall back to the older approach (Chef::Resource.const_get) for
- # backward compatibility
- resource_class = Chef::Resource.resource_for_node(method_symbol, run_context.node)
-
- super unless resource_class
- raise ArgumentError, "You must supply a name when declaring a #{method_symbol} resource" unless args.size > 0
-
- # If we have a resource like this one, we want to steal its state
- args << run_context
- resource = resource_class.new(*args)
- resource.load_prior_resource
- resource.cookbook_name = cookbook_name
- resource.recipe_name = @recipe_name
- resource.params = @params
- resource.source_line = caller[0]
- # Determine whether this resource is being created in the context of an enclosing Provider
- resource.enclosing_provider = self.is_a?(Chef::Provider) ? self : nil
- # Evaluate resource attribute DSL
- resource.instance_eval(&block) if block
-
- # Run optional resource hook
- resource.after_created
-
- run_context.resource_collection.insert(resource)
- resource
- end
- end
-
- end
+ RecipeDefinitionDSLCore = Chef::DSL::Recipe
end
end
diff --git a/chef/lib/chef/mixins.rb b/chef/lib/chef/mixins.rb
index e95acbdaae..557932c0e6 100644
--- a/chef/lib/chef/mixins.rb
+++ b/chef/lib/chef/mixins.rb
@@ -7,12 +7,8 @@ require 'chef/mixin/create_path'
require 'chef/mixin/deep_merge'
require 'chef/mixin/enforce_ownership_and_permissions'
require 'chef/mixin/from_file'
-require 'chef/mixin/language'
-require 'chef/mixin/language_include_attribute'
-require 'chef/mixin/language_include_recipe'
require 'chef/mixin/params_validate'
require 'chef/mixin/path_sanity'
-require 'chef/mixin/recipe_definition_dsl_core'
require 'chef/mixin/template'
require 'chef/mixin/securable'
require 'chef/mixin/xml_escape'
diff --git a/chef/lib/chef/node.rb b/chef/lib/chef/node.rb
index d0b073d6a3..1229e0db28 100644
--- a/chef/lib/chef/node.rb
+++ b/chef/lib/chef/node.rb
@@ -21,13 +21,12 @@
require 'forwardable'
require 'chef/config'
-require 'chef/cookbook/cookbook_collection'
require 'chef/nil_argument'
require 'chef/mixin/check_helper'
require 'chef/mixin/params_validate'
require 'chef/mixin/from_file'
-require 'chef/mixin/language_include_attribute'
require 'chef/mixin/deep_merge'
+require 'chef/dsl/include_attribute'
require 'chef/environment'
require 'chef/couchdb'
require 'chef/rest'
@@ -48,15 +47,13 @@ class Chef
attr_accessor :recipe_list, :couchdb, :couchdb_rev, :run_state, :run_list
attr_reader :couchdb_id
- # TODO: 5/18/2010 cw/timh. cookbook_collection should be removed
- # from here and for any place it's needed, it should be accessed
- # through a Chef::RunContext
- attr_accessor :cookbook_collection
+ attr_accessor :run_context
- include Chef::Mixin::CheckHelper
include Chef::Mixin::FromFile
+ include Chef::DSL::IncludeAttribute
+
+ include Chef::Mixin::CheckHelper
include Chef::Mixin::ParamsValidate
- include Chef::Mixin::LanguageIncludeAttribute
include Chef::IndexQueue::Indexable
DESIGN_DOCUMENT = {
@@ -165,14 +162,7 @@ class Chef
@couchdb_id = nil
@couchdb = couchdb || Chef::CouchDB.new
- @run_state = {
- :template_cache => Hash.new,
- :seen_recipes => Hash.new,
- :seen_attributes => Hash.new
- }
- # TODO: 5/20/2010 need this here as long as other objects try to access
- # the cookbook collection via Node, otherwise get NoMethodError on nil.
- @cookbook_collection = CookbookCollection.new
+ @run_state = {}
end
def couchdb_id=(value)
@@ -189,24 +179,6 @@ class Chef
Chef::REST.new(Chef::Config[:chef_server_url])
end
- # Find a recipe for this Chef::Node by fqdn. Will search first for
- # Chef::Config["node_path"]/fqdn.rb, then hostname.rb, then default.rb.
- #
- # Returns a new Chef::Node object.
- #
- # Raises an ArgumentError if it cannot find the node.
- def find_file(fqdn)
- host_parts = fqdn.split(".")
- hostname = host_parts[0]
-
- [fqdn, hostname, "default"].each { |fname|
- node_file = File.join(Chef::Config[:node_path], "#{fname.to_s}.rb")
- return self.from_file(node_file) if File.exists?(node_file)
- }
-
- raise ArgumentError, "Cannot find a node matching #{fqdn}, not even with default.rb!"
- end
-
# Set the name of this Node, or return the current name.
def name(arg=nil)
if arg != nil
@@ -351,12 +323,11 @@ class Chef
#
# First, the run list is consulted to see whether the recipe is
# explicitly included. If it's not there, it looks in
- # run_state[:seen_recipes], which is populated by include_recipe
- # statements in the DSL (and thus would not be in the run list).
+ # `node[:recipes]`, which is populated when the run_list is expanded
#
# NOTE: It's used by cookbook authors
def recipe?(recipe_name)
- run_list.include?(recipe_name) || run_state[:seen_recipes].include?(recipe_name)
+ run_list.include?(recipe_name) || self[recipes].include?(recipe_name)
end
# Returns true if this Node expects a given role, false if not.
@@ -652,32 +623,5 @@ class Chef
"node[#{name}]"
end
- # Load all attribute files for all cookbooks associated with this
- # node.
- def load_attributes
- cookbook_collection.values.each do |cookbook|
- cookbook.segment_filenames(:attributes).each do |segment_filename|
- Chef::Log.debug("Node #{name} loading cookbook #{cookbook.name}'s attribute file #{segment_filename}")
- self.from_file(segment_filename)
- end
- end
- end
-
- # Used by DSL.
- # Loads the attribute file specified by the short name of the
- # file, e.g., loads specified cookbook's
- # "attributes/mailservers.rb"
- # if passed
- # "mailservers"
- def load_attribute_by_short_filename(name, src_cookbook_name)
- src_cookbook = cookbook_collection[src_cookbook_name]
- raise Chef::Exceptions::CookbookNotFound, "could not find cookbook #{src_cookbook_name} while loading attribute #{name}" unless src_cookbook
-
- attribute_filename = src_cookbook.attribute_filenames_by_short_filename[name]
- raise Chef::Exceptions::AttributeNotFound, "could not find filename for attribute #{name} in cookbook #{src_cookbook_name}" unless attribute_filename
-
- self.from_file(attribute_filename)
- self
- end
end
end
diff --git a/chef/lib/chef/provider.rb b/chef/lib/chef/provider.rb
index d392c299c1..7bbcc3b915 100644
--- a/chef/lib/chef/provider.rb
+++ b/chef/lib/chef/provider.rb
@@ -19,12 +19,12 @@
require 'chef/mixin/from_file'
require 'chef/mixin/convert_to_class_name'
-require 'chef/mixin/recipe_definition_dsl_core'
+require 'chef/dsl/recipe'
require 'chef/mixin/enforce_ownership_and_permissions'
require 'chef/mixin/why_run'
class Chef
class Provider
- include Chef::Mixin::RecipeDefinitionDSLCore
+ include Chef::DSL::Recipe
include Chef::Mixin::WhyRun
include Chef::Mixin::EnforceOwnershipAndPermissions
@@ -192,7 +192,13 @@ class Chef
new_provider_class = Class.new self do |cls|
- include Chef::Mixin::RecipeDefinitionDSLCore
+ include Chef::DSL::Recipe
+
+ # These were previously provided by Chef::Mixin::RecipeDefinitionDSLCore.
+ # They are not included by its replacment, Chef::DSL::Recipe, but
+ # they may be used in existing LWRPs.
+ include Chef::DSL::PlatformIntrospection
+ include Chef::DSL::DataQuery
def load_current_resource
# silence Chef::Exceptions::Override exception
diff --git a/chef/lib/chef/provider/deploy.rb b/chef/lib/chef/provider/deploy.rb
index 2920917d11..60c626ab08 100644
--- a/chef/lib/chef/provider/deploy.rb
+++ b/chef/lib/chef/provider/deploy.rb
@@ -20,12 +20,13 @@ require "chef/mixin/command"
require "chef/mixin/from_file"
require "chef/provider/git"
require "chef/provider/subversion"
+require 'chef/dsl/recipe'
class Chef
class Provider
class Deploy < Chef::Provider
- include Chef::Mixin::RecipeDefinitionDSLCore
+ include Chef::DSL::Recipe
include Chef::Mixin::FromFile
include Chef::Mixin::Command
diff --git a/chef/lib/chef/recipe.rb b/chef/lib/chef/recipe.rb
index 258a56e715..aca35db049 100644
--- a/chef/lib/chef/recipe.rb
+++ b/chef/lib/chef/recipe.rb
@@ -18,10 +18,12 @@
#
-require 'chef/mixin/recipe_definition_dsl_core'
+require 'chef/dsl/recipe'
+require 'chef/dsl/data_query'
+require 'chef/dsl/platform_introspection'
+require 'chef/dsl/include_recipe'
+
require 'chef/mixin/from_file'
-require 'chef/mixin/language'
-require 'chef/mixin/language_include_recipe'
require 'chef/mixin/deprecation'
@@ -30,10 +32,12 @@ class Chef
# A Recipe object is the context in which Chef recipes are evaluated.
class Recipe
+ include Chef::DSL::DataQuery
+ include Chef::DSL::PlatformIntrospection
+ include Chef::DSL::IncludeRecipe
+ include Chef::DSL::Recipe
+
include Chef::Mixin::FromFile
- include Chef::Mixin::Language
- include Chef::Mixin::LanguageIncludeRecipe
- include Chef::Mixin::RecipeDefinitionDSLCore
include Chef::Mixin::Deprecation
attr_accessor :cookbook_name, :recipe_name, :recipe, :params, :run_context
diff --git a/chef/lib/chef/resource.rb b/chef/lib/chef/resource.rb
index 536f75ca88..9a1b983360 100644
--- a/chef/lib/chef/resource.rb
+++ b/chef/lib/chef/resource.rb
@@ -19,7 +19,7 @@
require 'chef/mixin/params_validate'
require 'chef/mixin/check_helper'
-require 'chef/mixin/language'
+require 'chef/dsl/platform_introspection'
require 'chef/mixin/convert_to_class_name'
require 'chef/resource/conditional'
require 'chef/resource_collection'
@@ -121,7 +121,7 @@ F
include Chef::Mixin::CheckHelper
include Chef::Mixin::ParamsValidate
- include Chef::Mixin::Language
+ include Chef::DSL::PlatformIntrospection
include Chef::Mixin::ConvertToClassName
include Chef::Mixin::Deprecation
diff --git a/chef/lib/chef/run_context.rb b/chef/lib/chef/run_context.rb
index 8805800b5a..625a993941 100644
--- a/chef/lib/chef/run_context.rb
+++ b/chef/lib/chef/run_context.rb
@@ -21,16 +21,12 @@ require 'chef/resource_collection'
require 'chef/node'
require 'chef/role'
require 'chef/log'
-require 'chef/mixin/language_include_recipe'
class Chef
# == Chef::RunContext
# Value object that loads and tracks the context of a Chef run
class RunContext
- # Used to load the node's recipes after expanding its run list
- include Chef::Mixin::LanguageIncludeRecipe
-
attr_reader :node, :cookbook_collection, :definitions
# Needs to be settable so deploy can run a resource_collection independent
@@ -39,6 +35,9 @@ class Chef
attr_reader :events
+ attr_reader :loaded_recipes
+ attr_reader :loaded_attributes
+
# Creates a new Chef::RunContext object and populates its fields. This object gets
# used by the Chef Server to generate a fully compiled recipe list for a node.
#
@@ -51,11 +50,11 @@ class Chef
@immediate_notification_collection = Hash.new {|h,k| h[k] = []}
@delayed_notification_collection = Hash.new {|h,k| h[k] = []}
@definitions = Hash.new
+ @loaded_recipes = {}
+ @loaded_attributes = {}
@events = events
- # TODO: 5/18/2010 cw/timh - See note on Chef::Node's
- # cookbook_collection attr_accessor
- node.cookbook_collection = cookbook_collection
+ @node.run_context = self
end
def load(run_list_expansion)
@@ -74,8 +73,6 @@ class Chef
@events.recipe_load_start(run_list_expansion.recipes.size)
run_list_expansion.recipes.each do |recipe|
begin
- # TODO: timh/cw, 5-14-2010: It's distasteful to be including
- # the DSL in a class outside the context of the DSL
include_recipe(recipe)
rescue Chef::Exceptions::RecipeNotFound => e
@events.recipe_not_found(e)
@@ -95,6 +92,16 @@ class Chef
cookbook.recipe_filenames_by_name[recipe_short_name]
end
+ def resolve_attribute(cookbook_name, attr_file_name)
+ cookbook = cookbook_collection[cookbook_name]
+ raise Chef::Exceptions::CookbookNotFound, "could not find cookbook #{cookbook_name} while loading attribute #{name}" unless cookbook
+
+ attribute_filename = cookbook.attribute_filenames_by_short_filename[attr_file_name]
+ raise Chef::Exceptions::AttributeNotFound, "could not find filename for attribute #{attr_file_name} in cookbook #{cookbook_name}" unless attribute_filename
+
+ attribute_filename
+ end
+
def notifies_immediately(notification)
nr = notification.notifying_resource
if nr.instance_of?(Chef::Resource)
@@ -129,8 +136,54 @@ class Chef
end
end
+ def include_recipe(*recipe_names)
+ result_recipes = Array.new
+ recipe_names.flatten.each do |recipe_name|
+ if result = load_recipe(recipe_name)
+ result_recipes << result
+ end
+ end
+ result_recipes
+ end
+
+ def load_recipe(recipe_name)
+ Chef::Log.debug("Loading Recipe #{recipe_name} via include_recipe")
+
+ cookbook_name, recipe_short_name = Chef::Recipe.parse_recipe_name(recipe_name)
+ if loaded_fully_qualified_recipe?(cookbook_name, recipe_short_name)
+ Chef::Log.debug("I am not loading #{recipe_name}, because I have already seen it.")
+ false
+ else
+ loaded_recipe(cookbook_name, recipe_short_name)
+
+ cookbook = cookbook_collection[cookbook_name]
+ cookbook.load_recipe(recipe_short_name, self)
+ end
+ end
+
+ def loaded_fully_qualified_recipe?(cookbook, recipe)
+ @loaded_recipes.has_key?("#{cookbook}::#{recipe}")
+ end
+
+ def loaded_recipe?(recipe)
+ cookbook, recipe_name = Chef::Recipe.parse_recipe_name(recipe)
+ loaded_fully_qualified_recipe?(cookbook, recipe_name)
+ end
+
+ def loaded_fully_qualified_attribute?(cookbook, attribute_file)
+ @loaded_attributes.has_key?("#{cookbook}::#{attribute_file}")
+ end
+
+ def loaded_attribute(cookbook, attribute_file)
+ @loaded_attributes["#{cookbook}::#{attribute_file}"] = true
+ end
+
private
+ def loaded_recipe(cookbook, recipe)
+ @loaded_recipes["#{cookbook}::#{recipe}"] = true
+ end
+
def load_libraries
@events.library_load_start(count_files_by_segment(:libraries))
@@ -189,7 +242,8 @@ class Chef
foreach_cookbook_load_segment(:attributes) do |cookbook_name, filename|
begin
Chef::Log.debug("Node #{@node.name} loading cookbook #{cookbook_name}'s attribute file #{filename}")
- @node.from_file(filename)
+ attr_file_basename = ::File.basename(filename, ".rb")
+ @node.include_attribute("#{cookbook_name}::#{attr_file_basename}")
rescue Exception => e
@events.attribute_file_load_failed(filename, e)
raise
diff --git a/chef/lib/chef/shell/ext.rb b/chef/lib/chef/shell/ext.rb
index 12d424e6d7..30d841e4cd 100644
--- a/chef/lib/chef/shell/ext.rb
+++ b/chef/lib/chef/shell/ext.rb
@@ -19,6 +19,7 @@
require 'tempfile'
require 'chef/recipe'
require 'fileutils'
+require 'chef/dsl/platform_introspection'
require 'chef/version'
require 'chef/shell/shell_session'
require 'chef/shell/model_wrapper'
@@ -559,7 +560,8 @@ E
obj.instance_eval(&MainContextExtensions)
obj.instance_eval(&RESTApiExtensions)
obj.extend(FileUtils)
- obj.extend(Chef::Mixin::Language)
+ obj.extend(Chef::DSL::PlatformIntrospection)
+ obj.extend(Chef::DSL::DataQuery)
end
def self.extend_context_node(node_obj)
diff --git a/chef/spec/spec_helper.rb b/chef/spec/spec_helper.rb
index 2e0bca0b0c..1d101022ac 100644
--- a/chef/spec/spec_helper.rb
+++ b/chef/spec/spec_helper.rb
@@ -38,6 +38,7 @@ require 'chef'
require 'chef/knife'
Chef::Knife.load_commands
require 'chef/mixins'
+require 'chef/dsl'
require 'chef/application'
require 'chef/applications'
diff --git a/chef/spec/unit/cookbook_spec.rb b/chef/spec/unit/cookbook_spec.rb
index e494e81124..c28a5c7a2a 100644
--- a/chef/spec/unit/cookbook_spec.rb
+++ b/chef/spec/unit/cookbook_spec.rb
@@ -68,20 +68,6 @@ describe Chef::CookbookVersion do
@cookbook.preferred_filename(@node, :files, 'a-filename', 'the-checksum').should be_nil
end
-# TODO: timh, cw: 5/20/2010: removed CookbookVersion.recipe? as it's not used; see cookbook.rb
-# it "should allow you to test for a recipe with recipe?" do
-# @cookbook.recipe_filenames = [ "one", "two" ]
-# @cookbook.recipe?("one").should eql(true)
-# @cookbook.recipe?("shanghai").should eql(false)
-# end
-
-# TODO: timh, cw: 5/20/2010: removed CookbookVersion.recipe? as it's not used; see cookbook.rb
-# it "should allow you to test for a recipe? with a fq recipe name" do
-# @cookbook.recipe_filenames = [ "one", "two" ]
-# @cookbook.recipe?("openldap::one").should eql(true)
-# @cookbook.recipe?("shanghai::city").should eql(false)
-# end
-
it "should allow you to include a fully-qualified recipe using the DSL" do
# DSL method include_recipe allows multiple arguments, so extract the first
recipe = @run_context.include_recipe("openldap::gigantor").first
@@ -95,9 +81,4 @@ describe Chef::CookbookVersion do
lambda { @cookbook.load_recipe("doesnt_exist", @node) }.should raise_error(ArgumentError)
end
- it "should allow you to load an attribute file by name via load_attribute" do
- @node.include_attribute("openldap::smokey")
- @node.smokey.should == "robinson"
- end
-
end
diff --git a/chef/spec/unit/dsl/data_query_spec.rb b/chef/spec/unit/dsl/data_query_spec.rb
new file mode 100644
index 0000000000..8960ad9957
--- /dev/null
+++ b/chef/spec/unit/dsl/data_query_spec.rb
@@ -0,0 +1,66 @@
+#
+# Author:: Seth Falcon (<seth@opscode.com>)
+# Copyright:: Copyright (c) 2010 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 'spec_helper'
+require 'chef/dsl/data_query'
+
+class DataQueryDSLTester
+ include Chef::DSL::DataQuery
+end
+
+describe Chef::DSL::DataQuery do
+ before(:each) do
+ @language = DataQueryDSLTester.new
+ @node = Hash.new
+ @language.stub!(:node).and_return(@node)
+ end
+
+ describe "when loading data bags and items" do
+ it "lists the items in a data bag" do
+ Chef::DataBag.should_receive(:load).with("bag_name").and_return("item_1" => "http://url_for/item_1", "item_2" => "http://url_for/item_2")
+ @language.data_bag("bag_name").sort.should == %w[item_1 item_2]
+ end
+
+ it "validates the name of the data bag you're trying to load" do
+ lambda {@language.data_bag("!# %^&& ")}.should raise_error(Chef::Exceptions::InvalidDataBagName)
+ end
+
+ it "fetches a data bag item" do
+ @item = Chef::DataBagItem.new
+ @item.data_bag("bag_name")
+ @item.raw_data = {"id" => "item_name", "FUU" => "FUU"}
+ Chef::DataBagItem.should_receive(:load).with("bag_name", "item_name").and_return(@item)
+ @language.data_bag_item("bag_name", "item_name").should == @item
+ end
+
+ it "validates the name of the data bag you're trying to load an item from" do
+ lambda {@language.data_bag_item(" %%^& ", "item_name")}.should raise_error(Chef::Exceptions::InvalidDataBagName)
+ end
+
+ it "validates the id of the data bag item you're trying to load" do
+ lambda {@language.data_bag_item("bag_name", " 987 (*&()")}.should raise_error(Chef::Exceptions::InvalidDataBagItemID)
+ end
+
+ it "validates that the id of the data bag item is not nil" do
+ lambda {@language.data_bag_item("bag_name", nil)}.should raise_error(Chef::Exceptions::InvalidDataBagItemID)
+ end
+
+ end
+
+end
+
diff --git a/chef/spec/unit/mixin/language_spec.rb b/chef/spec/unit/dsl/platfrom_introspection_spec.rb
index 42f6b6bbe3..e6cc7ad9ff 100644
--- a/chef/spec/unit/mixin/language_spec.rb
+++ b/chef/spec/unit/dsl/platfrom_introspection_spec.rb
@@ -17,13 +17,13 @@
#
require 'spec_helper'
-require 'chef/mixin/language'
+require 'chef/dsl/platform_introspection'
class LanguageTester
- include Chef::Mixin::Language
+ include Chef::DSL::PlatformIntrospection
end
-describe Chef::Mixin::Language do
+describe Chef::DSL::PlatformIntrospection do
before(:each) do
@language = LanguageTester.new
@node = Hash.new
@@ -35,13 +35,13 @@ describe Chef::Mixin::Language do
"1.2.3" => "#{x}-1.2.3"
}
end
- @platform_hash["debian"] = {["5", "6"] => "debian-5/6", "default" => "debian"}
+ @platform_hash["debian"] = {["5", "6"] => "debian-5/6", "default" => "debian"}
@platform_hash["default"] = "default"
- @platform_family_hash = {
- "debian" => "debian value",
- [:rhel, :fedora] => "redhatty value",
- "suse" => "suse value",
+ @platform_family_hash = {
+ "debian" => "debian value",
+ [:rhel, :fedora] => "redhatty value",
+ "suse" => "suse value",
:default => "default value"
}
end
@@ -51,28 +51,28 @@ describe Chef::Mixin::Language do
@language.value_for_platform(@platform_hash).should == "default"
end
- it "returns a default value when there is no known platform family" do
- @language.value_for_platform_family(@platform_family_hash).should == "default value"
+ it "returns a default value when there is no known platform family" do
+ @language.value_for_platform_family(@platform_family_hash).should == "default value"
end
-
+
it "returns a default value when the current platform doesn't match" do
@node[:platform] = "not-a-known-platform"
@language.value_for_platform(@platform_hash).should == "default"
end
- it "returns a default value when current platform_family doesn't match" do
+ it "returns a default value when current platform_family doesn't match" do
@node[:platform_family] = "ultra-derived-linux"
- @language.value_for_platform_family(@platform_family_hash).should == "default value"
+ @language.value_for_platform_family(@platform_family_hash).should == "default value"
end
-
+
it "returns a value based on the current platform" do
@node[:platform] = "openbsd"
@language.value_for_platform(@platform_hash).should == "openbsd"
end
- it "returns a value based on the current platform family" do
+ it "returns a value based on the current platform family" do
@node[:platform_family] = "debian"
- @language.value_for_platform_family(@platform_family_hash).should == "debian value"
+ @language.value_for_platform_family(@platform_family_hash).should == "debian value"
end
it "returns a version-specific value based on the current platform" do
@@ -101,52 +101,52 @@ describe Chef::Mixin::Language do
end
end
- describe "when checking platform?" do
+ describe "when checking platform?" do
before(:each) do
@language = LanguageTester.new
@node = Hash.new
@language.stub!(:node).and_return(@node)
end
-
- it "returns true if the node is a provided platform and platforms are provided as symbols" do
+
+ it "returns true if the node is a provided platform and platforms are provided as symbols" do
@node[:platform] = 'ubuntu'
@language.platform?([:redhat, :ubuntu]).should == true
end
-
- it "returns true if the node is a provided platform and platforms are provided as strings" do
+
+ it "returns true if the node is a provided platform and platforms are provided as strings" do
@node[:platform] = 'ubuntu'
@language.platform?(["redhat", "ubuntu"]).should == true
end
-
- it "returns false if the node is not of the provided platforms" do
+
+ it "returns false if the node is not of the provided platforms" do
@node[:platform] = 'ubuntu'
@language.platform?(:splatlinux).should == false
end
end
-
- describe "when checking platform_family?" do
+
+ describe "when checking platform_family?" do
before(:each) do
@language = LanguageTester.new
@node = Hash.new
@language.stub!(:node).and_return(@node)
end
-
- it "returns true if the node is in a provided platform family and families are provided as symbols" do
+
+ it "returns true if the node is in a provided platform family and families are provided as symbols" do
@node[:platform_family] = 'debian'
@language.platform_family?([:rhel, :debian]).should == true
end
-
- it "returns true if the node is a provided platform and platforms are provided as strings" do
+
+ it "returns true if the node is a provided platform and platforms are provided as strings" do
@node[:platform_family] = 'rhel'
@language.platform_family?(["rhel", "debian"]).should == true
end
-
- it "returns false if the node is not of the provided platforms" do
+
+ it "returns false if the node is not of the provided platforms" do
@node[:platform_family] = 'suse'
@language.platform_family?(:splatlinux).should == false
end
-
- it "returns false if the node is not of the provided platforms and platform_family is not set" do
+
+ it "returns false if the node is not of the provided platforms and platform_family is not set" do
@language.platform_family?(:splatlinux).should == false
end
@@ -173,44 +173,12 @@ describe Chef::Mixin::Language do
@node[:platform] = "debian"
@node[:platform_version] = '4.0'
@language.value_for_platform(@platform_hash).should == [:restart, :reload]
- end
- end
-
- describe "when loading data bags and items" do
- it "lists the items in a data bag" do
- Chef::DataBag.should_receive(:load).with("bag_name").and_return("item_1" => "http://url_for/item_1", "item_2" => "http://url_for/item_2")
- @language.data_bag("bag_name").sort.should == %w[item_1 item_2]
- end
-
- it "validates the name of the data bag you're trying to load" do
- lambda {@language.data_bag("!# %^&& ")}.should raise_error(Chef::Exceptions::InvalidDataBagName)
end
-
- it "fetches a data bag item" do
- @item = Chef::DataBagItem.new
- @item.data_bag("bag_name")
- @item.raw_data = {"id" => "item_name", "FUU" => "FUU"}
- Chef::DataBagItem.should_receive(:load).with("bag_name", "item_name").and_return(@item)
- @language.data_bag_item("bag_name", "item_name").should == @item
- end
-
- it "validates the name of the data bag you're trying to load an item from" do
- lambda {@language.data_bag_item(" %%^& ", "item_name")}.should raise_error(Chef::Exceptions::InvalidDataBagName)
- end
-
- it "validates the id of the data bag item you're trying to load" do
- lambda {@language.data_bag_item("bag_name", " 987 (*&()")}.should raise_error(Chef::Exceptions::InvalidDataBagItemID)
- end
-
- it "validates that the id of the data bag item is not nil" do
- lambda {@language.data_bag_item("bag_name", nil)}.should raise_error(Chef::Exceptions::InvalidDataBagItemID)
- end
-
end
end
-describe Chef::Mixin::Language::PlatformDependentValue do
+describe Chef::DSL::PlatformIntrospection::PlatformDependentValue do
before do
platform_hash = {
:openbsd => {:default => 'free, functional, secure'},
@@ -218,7 +186,7 @@ describe Chef::Mixin::Language::PlatformDependentValue do
:ubuntu => {'10.04' => 'using upstart more', :default => 'using init more'},
:default => 'bork da bork'
}
- @platform_specific_value = Chef::Mixin::Language::PlatformDependentValue.new(platform_hash)
+ @platform_specific_value = Chef::DSL::PlatformIntrospection::PlatformDependentValue.new(platform_hash)
end
it "returns the default value when the platform doesn't match" do
@@ -246,29 +214,29 @@ describe Chef::Mixin::Language::PlatformDependentValue do
it "returns nil if there is no default and no platforms match" do
# this matches the behavior in the original implementation.
# whether or not it's correct is another matter.
- platform_specific_value = Chef::Mixin::Language::PlatformDependentValue.new({})
+ platform_specific_value = Chef::DSL::PlatformIntrospection::PlatformDependentValue.new({})
platform_specific_value.value_for_node(:platform => 'foo').should be_nil
end
it "raises an argument error if the platform hash is not correctly structured" do
bad_hash = {:ubuntu => :foo} # should be :ubuntu => {:default => 'foo'}
- lambda {Chef::Mixin::Language::PlatformDependentValue.new(bad_hash)}.should raise_error(ArgumentError)
+ lambda {Chef::DSL::PlatformIntrospection::PlatformDependentValue.new(bad_hash)}.should raise_error(ArgumentError)
end
end
-describe Chef::Mixin::Language::PlatformFamilyDependentValue do
+describe Chef::DSL::PlatformIntrospection::PlatformFamilyDependentValue do
before do
- @array_values = [:stop, :start, :reload]
+ @array_values = [:stop, :start, :reload]
- @platform_family_hash = {
- "debian" => "debian value",
- [:rhel, "fedora"] => "redhatty value",
- "suse" => @array_values,
+ @platform_family_hash = {
+ "debian" => "debian value",
+ [:rhel, "fedora"] => "redhatty value",
+ "suse" => @array_values,
:gentoo => "gentoo value",
:default => "default value"
}
-
- @platform_family_value = Chef::Mixin::Language::PlatformFamilyDependentValue.new(@platform_family_hash)
+
+ @platform_family_value = Chef::DSL::PlatformIntrospection::PlatformFamilyDependentValue.new(@platform_family_hash)
end
it "returns the default value when the platform family doesn't match" do
@@ -277,28 +245,27 @@ describe Chef::Mixin::Language::PlatformFamilyDependentValue do
it "returns a value for the platform family when it was set as a string but fetched as a symbol" do
- @platform_family_value.value_for_node(:platform_family => :debian).should == "debian value"
+ @platform_family_value.value_for_node(:platform_family => :debian).should == "debian value"
end
-
-
+
it "returns a value for the platform family when it was set as a symbol but fetched as a string" do
- @platform_family_value.value_for_node(:platform_family => "gentoo").should == "gentoo value"
+ @platform_family_value.value_for_node(:platform_family => "gentoo").should == "gentoo value"
end
-
- it "returns an array value stored for a platform family" do
+
+ it "returns an array value stored for a platform family" do
@platform_family_value.value_for_node(:platform_family => "suse").should == @array_values
end
it "returns a value for the platform family when it was set within an array hash key as a symbol" do
- @platform_family_value.value_for_node(:platform_family => :rhel).should == "redhatty value"
+ @platform_family_value.value_for_node(:platform_family => :rhel).should == "redhatty value"
end
-
+
it "returns a value for the platform family when it was set within an array hash key as a string" do
- @platform_family_value.value_for_node(:platform_family => "fedora").should == "redhatty value"
+ @platform_family_value.value_for_node(:platform_family => "fedora").should == "redhatty value"
end
-
+
it "returns nil if there is no default and no platforms match" do
- platform_specific_value = Chef::Mixin::Language::PlatformFamilyDependentValue.new({})
+ platform_specific_value = Chef::DSL::PlatformIntrospection::PlatformFamilyDependentValue.new({})
platform_specific_value.value_for_node(:platform_family => 'foo').should be_nil
end
diff --git a/chef/spec/unit/formatters/error_inspectors/resource_failure_inspector_spec.rb b/chef/spec/unit/formatters/error_inspectors/resource_failure_inspector_spec.rb
index 277e710ddf..54a57d8077 100644
--- a/chef/spec/unit/formatters/error_inspectors/resource_failure_inspector_spec.rb
+++ b/chef/spec/unit/formatters/error_inspectors/resource_failure_inspector_spec.rb
@@ -19,7 +19,7 @@
require 'spec_helper'
describe Chef::Formatters::ErrorInspectors::ResourceFailureInspector do
- include Chef::Mixin::RecipeDefinitionDSLCore
+ include Chef::DSL::Recipe
def run_context
node = Chef::Node.new
diff --git a/chef/spec/unit/node_spec.rb b/chef/spec/unit/node_spec.rb
index 2be154c5b3..4577d5098b 100644
--- a/chef/spec/unit/node_spec.rb
+++ b/chef/spec/unit/node_spec.rb
@@ -21,7 +21,6 @@ require 'ostruct'
describe Chef::Node do
before(:each) do
- Chef::Config.node_path(File.expand_path(File.join(CHEF_SPEC_DATA, "nodes")))
@node = Chef::Node.new()
end
@@ -63,12 +62,9 @@ describe Chef::Node do
end
describe "run_state" do
- it "should have a template_cache hash" do
- @node.run_state[:template_cache].should be_a_kind_of(Hash)
- end
-
- it "should have a seen_recipes hash" do
- @node.run_state[:seen_recipes].should be_a_kind_of(Hash)
+ it "is an empty hash" do
+ @node.run_state.should respond_to(:keys)
+ @node.run_state.should be_empty
end
end
@@ -123,18 +119,6 @@ describe Chef::Node do
end
describe "attributes" do
- it "should be loaded from the node's cookbooks" do
- @cookbook_repo = File.expand_path(File.join(File.dirname(__FILE__), "..", "data", "cookbooks"))
- cl = Chef::CookbookLoader.new(@cookbook_repo)
- cl.load_cookbooks
- @node.cookbook_collection = Chef::CookbookCollection.new(cl)
- @node.load_attributes
- @node.ldap_server.should eql("ops1prod")
- @node.ldap_basedn.should eql("dc=hjksolutions,dc=com")
- @node.ldap_replication_password.should eql("forsure")
- @node.smokey.should eql("robinson")
- end
-
it "should have attributes" do
@node.attribute.should be_a_kind_of(Hash)
end
@@ -440,33 +424,34 @@ describe Chef::Node do
end
end
- # TODO: timh, cw: 2010-5-19: Node.recipe? deprecated. See node.rb
- # describe "recipes" do
- # it "should have a RunList of recipes that should be applied" do
- # @node.recipes.should be_a_kind_of(Chef::RunList)
- # end
- #
- # it "should allow you to query whether or not it has a recipe applied with recipe?" do
- # @node.recipes << "sunrise"
- # @node.recipe?("sunrise").should eql(true)
- # @node.recipe?("not at home").should eql(false)
- # end
- #
- # it "should allow you to query whether or not a recipe has been applied, even if it was included" do
- # @node.run_state[:seen_recipes]["snakes"] = true
- # @node.recipe?("snakes").should eql(true)
- # end
- #
- # it "should return false if a recipe has not been seen" do
- # @node.recipe?("snakes").should eql(false)
- # end
- #
- # it "should allow you to set recipes with arguments" do
- # @node.recipes "one", "two"
- # @node.recipe?("one").should eql(true)
- # @node.recipe?("two").should eql(true)
- # end
- # end
+ describe "when evaluating attributes files" do
+ before do
+ @node = Chef::Node.new
+
+ @cookbook_repo = File.expand_path(File.join(CHEF_SPEC_DATA, "cookbooks"))
+ @cookbook_loader = Chef::CookbookLoader.new(@cookbook_repo)
+ @cookbook_loader.load_cookbooks
+
+ @cookbook_collection = Chef::CookbookCollection.new(@cookbook_loader.cookbooks_by_name)
+
+ @events = Chef::EventDispatch::Dispatcher.new
+ @run_context = Chef::RunContext.new(@node, @cookbook_collection, @events)
+
+ @node.include_attribute("openldap::default")
+ @node.include_attribute("openldap::smokey")
+ end
+
+ it "sets attributes from the files" do
+ @node.ldap_server.should eql("ops1prod")
+ @node.ldap_basedn.should eql("dc=hjksolutions,dc=com")
+ @node.ldap_replication_password.should eql("forsure")
+ @node.smokey.should eql("robinson")
+ end
+
+ it "gives a sensible error when attempting to load a missing attributes file" do
+ lambda { @node.include_attribute("nope-this::doesnt-exist") }.should raise_error(Chef::Exceptions::CookbookNotFound)
+ end
+ end
describe "roles" do
it "should allow you to query whether or not it has a recipe applied with role?" do
@@ -514,37 +499,6 @@ describe Chef::Node do
end
end
- describe "find_file" do
- it "should load a node from a file by fqdn" do
- @node.find_file("test.example.com")
- @node.name.should == "test.example.com"
- @node.chef_environment.should == "dev"
- end
-
- it "should load a node from a file by hostname" do
- File.stub!(:exists?).and_return(true)
- File.should_receive(:exists?).with(File.join(Chef::Config[:node_path], "test.example.com.rb")).and_return(false)
- @node.find_file("test.example.com")
- @node.name.should == "test.example.com-short"
- end
-
- it "should load a node from the default file" do
- File.stub!(:exists?).and_return(true)
- File.should_receive(:exists?).with(File.join(Chef::Config[:node_path], "test.example.com.rb")).and_return(false)
- File.should_receive(:exists?).with(File.join(Chef::Config[:node_path], "test.rb")).and_return(false)
- @node.find_file("test.example.com")
- @node.name.should == "test.example.com-default"
- end
-
- it "should raise an ArgumentError if it cannot find any node file at all" do
- File.stub!(:exists?).and_return(true)
- File.should_receive(:exists?).with(File.join(Chef::Config[:node_path], "test.example.com.rb")).and_return(false)
- File.should_receive(:exists?).with(File.join(Chef::Config[:node_path], "test.rb")).and_return(false)
- File.should_receive(:exists?).with(File.join(Chef::Config[:node_path], "default.rb")).and_return(false)
- lambda { @node.find_file("test.example.com") }.should raise_error(ArgumentError)
- end
- end
-
describe "update_from!" do
before(:each) do
@node.name("orig")
@@ -607,7 +561,7 @@ describe Chef::Node do
describe "json" do
it "should serialize itself as json", :json => true do
- @node.find_file("test.example.com")
+ @node.from_file(File.expand_path("nodes/test.example.com.rb", CHEF_SPEC_DATA))
json = Chef::JSONCompat.to_json(@node)
json.should =~ /json_class/
json.should =~ /name/
@@ -628,7 +582,7 @@ describe Chef::Node do
end
it "should deserialize itself from json", :json => true do
- @node.find_file("test.example.com")
+ @node.from_file(File.expand_path("nodes/test.example.com.rb", CHEF_SPEC_DATA))
json = Chef::JSONCompat.to_json(@node)
serialized_node = Chef::JSONCompat.from_json(json)
serialized_node.should be_a_kind_of(Chef::Node)
diff --git a/chef/spec/unit/provider/package/apt_spec.rb b/chef/spec/unit/provider/package/apt_spec.rb
index e40a640837..06ada5189e 100644
--- a/chef/spec/unit/provider/package/apt_spec.rb
+++ b/chef/spec/unit/provider/package/apt_spec.rb
@@ -22,7 +22,6 @@ require 'ostruct'
describe Chef::Provider::Package::Apt do
before(:each) do
@node = Chef::Node.new
- @node.cookbook_collection = {}
@events = Chef::EventDispatch::Dispatcher.new
@run_context = Chef::RunContext.new(@node, {}, @events)
@new_resource = Chef::Resource::Package.new("irssi", @run_context)
diff --git a/chef/spec/unit/provider/package/ips_spec.rb b/chef/spec/unit/provider/package/ips_spec.rb
index dad880a93b..641a527012 100644
--- a/chef/spec/unit/provider/package/ips_spec.rb
+++ b/chef/spec/unit/provider/package/ips_spec.rb
@@ -24,7 +24,6 @@ require 'ostruct'
describe Chef::Provider::Package::Ips do
before(:each) do
@node = Chef::Node.new
- @node.cookbook_collection = {}
@events = Chef::EventDispatch::Dispatcher.new
@run_context = Chef::RunContext.new(@node, {}, @events)
@new_resource = Chef::Resource::Package.new("crypto/gnupg", @run_context)
diff --git a/chef/spec/unit/recipe_spec.rb b/chef/spec/unit/recipe_spec.rb
index 797e566190..4615bcb4d4 100644
--- a/chef/spec/unit/recipe_spec.rb
+++ b/chef/spec/unit/recipe_spec.rb
@@ -206,9 +206,9 @@ describe Chef::Recipe do
res.pretty_kitty.should eql(true)
end
- it "should store that it has seen a recipe in node.run_state[:seen_recipes]" do
+ it "should store that it has seen a recipe in the run_context" do
@run_context.include_recipe "openldap"
- @node.run_state[:seen_recipes].should have_key("openldap")
+ @run_context.loaded_recipe?("openldap").should be_true
end
it "should not include the same recipe twice" do
diff --git a/chef/spec/unit/run_context_spec.rb b/chef/spec/unit/run_context_spec.rb
index 7bdcc60de0..51fa0e81f9 100644
--- a/chef/spec/unit/run_context_spec.rb
+++ b/chef/spec/unit/run_context_spec.rb
@@ -24,13 +24,12 @@ Chef::Log.level = :debug
describe Chef::RunContext do
before(:each) do
- Chef::Config.node_path(File.expand_path(File.join(CHEF_SPEC_DATA, "run_context", "nodes")))
@chef_repo_path = File.expand_path(File.join(CHEF_SPEC_DATA, "run_context", "cookbooks"))
cl = Chef::CookbookLoader.new(@chef_repo_path)
cl.load_cookbooks
@cookbook_collection = Chef::CookbookCollection.new(cl)
@node = Chef::Node.new
- @node.find_file("run_context")
+ @node.run_list << "test" << "test::one" << "test::two"
@events = Chef::EventDispatch::Dispatcher.new
@run_context = Chef::RunContext.new(@node, @cookbook_collection, @events)
end
@@ -55,12 +54,25 @@ describe Chef::RunContext do
end
it "should load all the recipes specified for this node" do
- @run_context.resource_collection[0].to_s.should == "cat[einstein]"
+ @run_context.resource_collection[0].to_s.should == "cat[einstein]"
@run_context.resource_collection[1].to_s.should == "cat[loulou]"
@run_context.resource_collection[2].to_s.should == "cat[birthday]"
@run_context.resource_collection[3].to_s.should == "cat[peanut]"
@run_context.resource_collection[4].to_s.should == "cat[fat peanut]"
end
+
+ it "loads all the attribute files in the cookbook collection" do
+ @run_context.loaded_fully_qualified_attribute?("test", "george").should be_true
+ @node[:george].should == "washington"
+ end
+
+ it "registers attributes files as loaded so they won't be reloaded" do
+ # This test unfortunately is pretty tightly intertwined with the
+ # implementation of how nodes load attribute files, but is the only
+ # convenient way to test this behavior.
+ @node.should_not_receive(:from_file)
+ @node.include_attribute("test::george")
+ end
end
end