summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNoah Kantrowitz <noah@coderanger.net>2017-04-04 12:25:42 -0700
committerGitHub <noreply@github.com>2017-04-04 12:25:42 -0700
commita22235b58c28e754d4698d9bdf27a50be6276974 (patch)
tree9ac6fb83e92e8c882a85c621e5ee69fe31fe55b5
parentf38f957878057b0609d63dc1a735819c87e3c8c9 (diff)
parentbd7f7d1b07cbb19c9d08c273bc857a084ce4689b (diff)
downloadchef-a22235b58c28e754d4698d9bdf27a50be6276974.tar.gz
Merge pull request #6005 from coderanger/template-lazy
Allow lazy{} to be used in template resource variables.
-rw-r--r--lib/chef/provider/template/content.rb25
-rw-r--r--spec/data/cookbooks/openldap/templates/default/openldap_nested_variable_stuff.erb1
-rw-r--r--spec/functional/resource/template_spec.rb33
-rw-r--r--spec/unit/cookbook/syntax_check_spec.rb1
4 files changed, 59 insertions, 1 deletions
diff --git a/lib/chef/provider/template/content.rb b/lib/chef/provider/template/content.rb
index acf200621d..b40794564a 100644
--- a/lib/chef/provider/template/content.rb
+++ b/lib/chef/provider/template/content.rb
@@ -36,7 +36,30 @@ class Chef
private
def file_for_provider
- context = TemplateContext.new(new_resource.variables)
+ # Deal with any DelayedEvaluator values in the template variables.
+ visitor = lambda do |obj|
+ case obj
+ when Hash
+ # If this is an Attribute object, we need to change class otherwise
+ # we get the immutable behavior. This could probably be fixed by
+ # using Hash#transform_values once we only support Ruby 2.4.
+ obj_class = obj.is_a?(Chef::Node::ImmutableMash) ? Mash : obj.class
+ # Avoid mutating hashes in the resource in case we're changing anything.
+ obj.each_with_object(obj_class.new) do |(key, value), memo|
+ memo[key] = visitor.call(value)
+ end
+ when Array
+ # Avoid mutating arrays in the resource in case we're changing anything.
+ obj.map { |value| visitor.call(value) }
+ when DelayedEvaluator
+ new_resource.instance_eval(&obj)
+ else
+ obj
+ end
+ end
+ variables = visitor.call(new_resource.variables)
+
+ context = TemplateContext.new(variables)
context[:node] = run_context.node
context[:template_finder] = template_finder
diff --git a/spec/data/cookbooks/openldap/templates/default/openldap_nested_variable_stuff.erb b/spec/data/cookbooks/openldap/templates/default/openldap_nested_variable_stuff.erb
new file mode 100644
index 0000000000..5ebee33806
--- /dev/null
+++ b/spec/data/cookbooks/openldap/templates/default/openldap_nested_variable_stuff.erb
@@ -0,0 +1 @@
+super secret is <%= @secret.first["key"] -%>
diff --git a/spec/functional/resource/template_spec.rb b/spec/functional/resource/template_spec.rb
index 32529fbb0c..b9a39255f4 100644
--- a/spec/functional/resource/template_spec.rb
+++ b/spec/functional/resource/template_spec.rb
@@ -32,6 +32,7 @@ describe Chef::Resource::Template do
let(:node) do
node = Chef::Node.new
node.normal[:slappiness] = "a warm gun"
+ node.normal[:nested][:secret] = "value"
node
end
@@ -209,4 +210,36 @@ describe Chef::Resource::Template do
end
end
+ describe "when template variables contain lazy{} calls" do
+ it "resolves the DelayedEvaluator" do
+ resource.source("openldap_variable_stuff.conf.erb")
+ resource.variables(:secret => Chef::DelayedEvaluator.new { "nutella" })
+ resource.run_action(:create)
+ expect(IO.read(path)).to eq("super secret is nutella")
+ end
+
+ it "does not mutate the resource variables" do
+ resource.source("openldap_variable_stuff.conf.erb")
+ resource.variables(:secret => Chef::DelayedEvaluator.new { "nutella" })
+ resource.run_action(:create)
+ expect(resource.variables[:secret]).to be_a Chef::DelayedEvaluator
+ end
+
+ it "resolves the DelayedEvaluator when deeply nested" do
+ resource.source("openldap_nested_variable_stuff.erb")
+ resource.variables(:secret => [{ "key" => Chef::DelayedEvaluator.new { "nutella" } }])
+ resource.run_action(:create)
+ expect(IO.read(path)).to eq("super secret is nutella")
+ end
+ end
+
+ describe "when passing a node attribute mash as a template variable" do
+ it "uses the node attributes like a hash" do
+ resource.source("openldap_variable_stuff.conf.erb")
+ resource.variables(node[:nested])
+ resource.run_action(:create)
+ expect(IO.read(path)).to eq("super secret is value")
+ end
+ end
+
end
diff --git a/spec/unit/cookbook/syntax_check_spec.rb b/spec/unit/cookbook/syntax_check_spec.rb
index aa6fe49eb9..a24fa3ab2a 100644
--- a/spec/unit/cookbook/syntax_check_spec.rb
+++ b/spec/unit/cookbook/syntax_check_spec.rb
@@ -60,6 +60,7 @@ describe Chef::Cookbook::SyntaxCheck do
openldap_stuff.conf.erb
nested_openldap_partials.erb
nested_partial.erb
+ openldap_nested_variable_stuff.erb
openldap_variable_stuff.conf.erb
test.erb
some_windows_line_endings.erb