chefspec 2.0.1 → 3.0.0.beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/chefspec.rb +30 -44
- data/lib/chefspec/api.rb +74 -0
- data/lib/chefspec/api/apt_package.rb +192 -0
- data/lib/chefspec/api/batch.rb +43 -0
- data/lib/chefspec/api/chef_gem.rb +191 -0
- data/lib/chefspec/api/cookbook_file.rb +166 -0
- data/lib/chefspec/api/cron.rb +80 -0
- data/lib/chefspec/api/deploy.rb +117 -0
- data/lib/chefspec/api/directory.rb +80 -0
- data/lib/chefspec/api/dpkg_package.rb +117 -0
- data/lib/chefspec/api/easy_install_package.rb +154 -0
- data/lib/chefspec/api/env.rb +117 -0
- data/lib/chefspec/api/erl_call.rb +43 -0
- data/lib/chefspec/api/execute.rb +43 -0
- data/lib/chefspec/api/file.rb +166 -0
- data/lib/chefspec/api/freebsd_package.rb +80 -0
- data/lib/chefspec/api/gem_package.rb +191 -0
- data/lib/chefspec/api/git.rb +117 -0
- data/lib/chefspec/api/group.rb +154 -0
- data/lib/chefspec/api/http_request.rb +228 -0
- data/lib/chefspec/api/ifconfig.rb +154 -0
- data/lib/chefspec/api/include_recipe.rb +26 -0
- data/lib/chefspec/api/ips_package.rb +117 -0
- data/lib/chefspec/api/link.rb +102 -0
- data/lib/chefspec/api/log.rb +43 -0
- data/lib/chefspec/api/macports_package.rb +154 -0
- data/lib/chefspec/api/mdadm.rb +117 -0
- data/lib/chefspec/api/mount.rb +192 -0
- data/lib/chefspec/api/notifications.rb +38 -0
- data/lib/chefspec/api/ohai.rb +43 -0
- data/lib/chefspec/api/package.rb +192 -0
- data/lib/chefspec/api/pacman_package.rb +155 -0
- data/lib/chefspec/api/portage_package.rb +155 -0
- data/lib/chefspec/api/powershell_script.rb +43 -0
- data/lib/chefspec/api/registry_key.rb +166 -0
- data/lib/chefspec/api/remote_directory.rb +120 -0
- data/lib/chefspec/api/remote_file.rb +166 -0
- data/lib/chefspec/api/render_file.rb +32 -0
- data/lib/chefspec/api/route.rb +80 -0
- data/lib/chefspec/api/rpm_package.rb +117 -0
- data/lib/chefspec/api/ruby_block.rb +37 -0
- data/lib/chefspec/api/script.rb +228 -0
- data/lib/chefspec/api/service.rb +246 -0
- data/lib/chefspec/api/smartos_package.rb +117 -0
- data/lib/chefspec/api/solaris_package.rb +80 -0
- data/lib/chefspec/api/subversion.rb +154 -0
- data/lib/chefspec/api/template.rb +166 -0
- data/lib/chefspec/api/user.rb +228 -0
- data/lib/chefspec/api/yum_package.rb +154 -0
- data/lib/chefspec/berkshelf.rb +37 -0
- data/lib/chefspec/deprecations.rb +151 -0
- data/lib/chefspec/errors.rb +99 -0
- data/lib/chefspec/expect_exception.rb +45 -0
- data/lib/chefspec/extensions/chef/client.rb +15 -0
- data/lib/chefspec/extensions/chef/conditional.rb +11 -0
- data/lib/chefspec/extensions/chef/data_query.rb +29 -0
- data/lib/chefspec/extensions/chef/lwrp_base.rb +44 -0
- data/lib/chefspec/extensions/chef/resource.rb +27 -0
- data/lib/chefspec/extensions/chef/securable.rb +19 -0
- data/lib/chefspec/formatter.rb +270 -0
- data/lib/chefspec/macros.rb +217 -0
- data/lib/chefspec/matchers.rb +9 -0
- data/lib/chefspec/matchers/include_recipe_matcher.rb +45 -0
- data/lib/chefspec/matchers/link_to_matcher.rb +28 -0
- data/lib/chefspec/matchers/notifications_matcher.rb +92 -0
- data/lib/chefspec/matchers/render_file_matcher.rb +72 -0
- data/lib/chefspec/matchers/resource_matcher.rb +143 -0
- data/lib/chefspec/renderer.rb +137 -0
- data/lib/chefspec/rspec.rb +17 -0
- data/lib/chefspec/runner.rb +274 -0
- data/lib/chefspec/stubs/command_registry.rb +11 -0
- data/lib/chefspec/stubs/command_stub.rb +37 -0
- data/lib/chefspec/stubs/data_bag_item_registry.rb +13 -0
- data/lib/chefspec/stubs/data_bag_item_stub.rb +25 -0
- data/lib/chefspec/stubs/data_bag_registry.rb +13 -0
- data/lib/chefspec/stubs/data_bag_stub.rb +23 -0
- data/lib/chefspec/stubs/registry.rb +32 -0
- data/lib/chefspec/stubs/search_registry.rb +13 -0
- data/lib/chefspec/stubs/search_stub.rb +25 -0
- data/lib/chefspec/stubs/stub.rb +37 -0
- data/lib/chefspec/version.rb +1 -2
- metadata +100 -103
- data/lib/chef/expect_exception.rb +0 -34
- data/lib/chef/formatters/chefspec.rb +0 -233
- data/lib/chef/knife/cookbook_create_specs.rb +0 -107
- data/lib/chefspec/chef_runner.rb +0 -275
- data/lib/chefspec/helpers/describe.rb +0 -17
- data/lib/chefspec/matchers/cron.rb +0 -7
- data/lib/chefspec/matchers/env.rb +0 -8
- data/lib/chefspec/matchers/execute.rb +0 -33
- data/lib/chefspec/matchers/file.rb +0 -83
- data/lib/chefspec/matchers/file_content.rb +0 -32
- data/lib/chefspec/matchers/group.rb +0 -8
- data/lib/chefspec/matchers/include_recipe.rb +0 -20
- data/lib/chefspec/matchers/link.rb +0 -14
- data/lib/chefspec/matchers/log.rb +0 -21
- data/lib/chefspec/matchers/notifications.rb +0 -43
- data/lib/chefspec/matchers/package.rb +0 -39
- data/lib/chefspec/matchers/python.rb +0 -7
- data/lib/chefspec/matchers/ruby_block.rb +0 -13
- data/lib/chefspec/matchers/script.rb +0 -34
- data/lib/chefspec/matchers/service.rb +0 -25
- data/lib/chefspec/matchers/shared.rb +0 -132
- data/lib/chefspec/matchers/user.rb +0 -8
- data/lib/chefspec/minitest.rb +0 -195
- data/lib/chefspec/monkey_patches/conditional.rb +0 -19
- data/lib/chefspec/monkey_patches/hash.rb +0 -23
- data/lib/chefspec/monkey_patches/lwrp_base.rb +0 -45
- data/lib/chefspec/monkey_patches/provider.rb +0 -43
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
module ChefSpec
|
|
2
|
+
module Matchers
|
|
3
|
+
require_relative 'matchers/include_recipe_matcher'
|
|
4
|
+
require_relative 'matchers/link_to_matcher'
|
|
5
|
+
require_relative 'matchers/notifications_matcher'
|
|
6
|
+
require_relative 'matchers/render_file_matcher'
|
|
7
|
+
require_relative 'matchers/resource_matcher'
|
|
8
|
+
end
|
|
9
|
+
end
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
module ChefSpec::Matchers
|
|
2
|
+
class IncludeRecipeMatcher
|
|
3
|
+
def initialize(recipe_name)
|
|
4
|
+
@recipe_name = with_default(recipe_name)
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
def matches?(runner)
|
|
8
|
+
@runner = runner
|
|
9
|
+
loaded_recipes.include?(@recipe_name)
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def description
|
|
13
|
+
"include recipe '#{@recipe_name}'"
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def failure_message_for_should
|
|
17
|
+
"expected #{loaded_recipes} to include '#{@recipe_name}'"
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def failure_message_for_should_not
|
|
21
|
+
"expected '#{@recipe_name}' to not be included"
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
private
|
|
25
|
+
#
|
|
26
|
+
# Automatically appends "+::default+" to recipes that need them.
|
|
27
|
+
#
|
|
28
|
+
# @param [String] name
|
|
29
|
+
#
|
|
30
|
+
# @return [String]
|
|
31
|
+
#
|
|
32
|
+
def with_default(name)
|
|
33
|
+
name.include?('::') ? name : "#{name}::default"
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
#
|
|
37
|
+
# The list of loaded recipes on the Chef run (normalized)
|
|
38
|
+
#
|
|
39
|
+
# @return [Array<String>]
|
|
40
|
+
#
|
|
41
|
+
def loaded_recipes
|
|
42
|
+
@runner.run_context.loaded_recipes.map { |name| with_default(name) }
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
module ChefSpec::Matchers
|
|
2
|
+
class LinkToMatcher
|
|
3
|
+
def initialize(path)
|
|
4
|
+
@path = path
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
def matches?(link)
|
|
8
|
+
@link = link
|
|
9
|
+
@link.is_a?(Chef::Resource::Link) && @path === @link.to
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def description
|
|
13
|
+
"link to '#{@path}'"
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def failure_message_for_should
|
|
17
|
+
if @link.nil?
|
|
18
|
+
"expected 'link[#{@path}]' with action ':create' to be in Chef run"
|
|
19
|
+
else
|
|
20
|
+
"expected '#{@link}' to link to '#{@path}' but was '#{@link.to}'"
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def failure_message_for_should_not
|
|
25
|
+
"expected '#{@link}' to not link to '#{@path}'"
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
module ChefSpec::Matchers
|
|
2
|
+
class NotificationsMatcher
|
|
3
|
+
def initialize(signature)
|
|
4
|
+
signature.match(/^([^\[]*)\[(.*)\]$/)
|
|
5
|
+
@expected_resource_type = $1
|
|
6
|
+
@expected_resource_name = $2
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def matches?(resource)
|
|
10
|
+
@resource = resource
|
|
11
|
+
|
|
12
|
+
block = Proc.new do |notified|
|
|
13
|
+
notified.resource.resource_name.to_s == @expected_resource_type &&
|
|
14
|
+
(@expected_resource_name === notified.resource.identity.to_s || @expected_resource_name === notified.resource.name.to_s) &&
|
|
15
|
+
matches_action?(notified)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
if @immediately
|
|
19
|
+
immediate_notifications.any?(&block)
|
|
20
|
+
elsif @delayed
|
|
21
|
+
delayed_notifications.any?(&block)
|
|
22
|
+
else
|
|
23
|
+
all_notifications.any?(&block)
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def to(action)
|
|
28
|
+
@action = action.to_sym
|
|
29
|
+
self
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def immediately
|
|
33
|
+
@immediately = true
|
|
34
|
+
self
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def delayed
|
|
38
|
+
@delayed = true
|
|
39
|
+
self
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def description
|
|
43
|
+
message = "notify #{@expected_resource_type}[#{@expected_resource_name}]"
|
|
44
|
+
message << " with action #{@action.inspect}" if @action
|
|
45
|
+
message << " immediately" if @immediately
|
|
46
|
+
message << " delayed" if @delayed
|
|
47
|
+
message
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def failure_message_for_should
|
|
51
|
+
message = "expected '#{@resource.resource_name}[#{@resource.name}]' to notify '#{@expected_resource_type}[#{@expected_resource_name}]'"
|
|
52
|
+
message << " with action #{@action.inspect}" if @action
|
|
53
|
+
message << " immediately" if @immediately
|
|
54
|
+
message << " delayed" if @delayed
|
|
55
|
+
message << ", but did not."
|
|
56
|
+
message << "\n\n"
|
|
57
|
+
message << "Other notifications were:\n#{format_notifications}"
|
|
58
|
+
message
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
private
|
|
62
|
+
def all_notifications
|
|
63
|
+
immediate_notifications + delayed_notifications
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def immediate_notifications
|
|
67
|
+
@resource.immediate_notifications
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def delayed_notifications
|
|
71
|
+
@resource.delayed_notifications
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def matches_action?(notification)
|
|
75
|
+
return true if @action.nil?
|
|
76
|
+
@action == notification.action.to_sym
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def format_notification(notification)
|
|
80
|
+
resource = notification.resource
|
|
81
|
+
type = notification.notifying_resource.immediate_notifications.include?(notification) ? :immediately : :delayed
|
|
82
|
+
|
|
83
|
+
"notifies :#{notification.action}, '#{resource.resource_name}[#{resource.name}]', :#{type}"
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def format_notifications
|
|
87
|
+
all_notifications.map do |notification|
|
|
88
|
+
' ' + format_notification(notification)
|
|
89
|
+
end.join("\n")
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
end
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
module ChefSpec::Matchers
|
|
2
|
+
class RenderFileMatcher
|
|
3
|
+
def initialize(path)
|
|
4
|
+
@path = path
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
def matches?(runner)
|
|
8
|
+
@runner = runner
|
|
9
|
+
resource && has_create_action? && matches_content?
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def with_content(expected_content)
|
|
13
|
+
@expected_content = expected_content
|
|
14
|
+
self
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def description
|
|
18
|
+
"render file '#{@path}'"
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def failure_message_for_should
|
|
22
|
+
message = "expected Chef run to render '#{@path}'"
|
|
23
|
+
message << " with:\n\n#{@expected_content}\n\nbut got:\n\n#{@actual_content}" if @expected_content
|
|
24
|
+
message
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def failure_message_for_should_not
|
|
28
|
+
message = "expected file '#{@path}'"
|
|
29
|
+
message << " with:\n\n#{@expected_content}\n\n" if @expected_content
|
|
30
|
+
message << " to not be in Chef run"
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
private
|
|
34
|
+
def resource
|
|
35
|
+
@resource ||= @runner.find_resource(:cookbook_file, @path) ||
|
|
36
|
+
@runner.find_resource(:file, @path) ||
|
|
37
|
+
@runner.find_resource(:template, @path)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
#
|
|
41
|
+
# Determines if the given resource has a create-like action.
|
|
42
|
+
#
|
|
43
|
+
# @param [Chef::Resource] resource
|
|
44
|
+
#
|
|
45
|
+
# @return [Boolean]
|
|
46
|
+
#
|
|
47
|
+
def has_create_action?
|
|
48
|
+
!([:create, :create_if_missing] & Array(resource.action).map(&:to_sym)).empty?
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
#
|
|
52
|
+
# Determines if the resources content matches the expected content.
|
|
53
|
+
#
|
|
54
|
+
# @param [Chef::Resource] resource
|
|
55
|
+
#
|
|
56
|
+
# @return [Boolean]
|
|
57
|
+
#
|
|
58
|
+
def matches_content?
|
|
59
|
+
return true if @expected_content.nil?
|
|
60
|
+
|
|
61
|
+
@actual_content = ChefSpec::Renderer.new(@runner, resource).content
|
|
62
|
+
|
|
63
|
+
return false if @actual_content.nil?
|
|
64
|
+
|
|
65
|
+
if @expected_content.is_a?(Regexp)
|
|
66
|
+
@actual_content =~ @expected_content
|
|
67
|
+
else
|
|
68
|
+
@actual_content.include?(@expected_content)
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
module ChefSpec::Matchers
|
|
2
|
+
class ResourceMatcher
|
|
3
|
+
def initialize(resource_name, expected_action, expected_identity)
|
|
4
|
+
@resource_name = resource_name
|
|
5
|
+
@expected_action = expected_action
|
|
6
|
+
@expected_identity = expected_identity
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def with(parameters = {})
|
|
10
|
+
params.merge!(parameters)
|
|
11
|
+
self
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
#
|
|
15
|
+
# Allow users to specify fancy #with matchers.
|
|
16
|
+
#
|
|
17
|
+
def method_missing(m, *args, &block)
|
|
18
|
+
if m.to_s =~ /^with_(.+)$/
|
|
19
|
+
with($1.to_sym => args.first)
|
|
20
|
+
self
|
|
21
|
+
else
|
|
22
|
+
super
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def matches?(runner)
|
|
27
|
+
@runner = runner
|
|
28
|
+
|
|
29
|
+
if resource
|
|
30
|
+
resource_actions.include?(@expected_action) && unmatched_parameters.empty?
|
|
31
|
+
else
|
|
32
|
+
false
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def failure_message_for_should
|
|
37
|
+
if resource
|
|
38
|
+
if resource_actions.include?(@expected_action)
|
|
39
|
+
"expected '#{resource.to_s}' to have parameters:" \
|
|
40
|
+
"\n\n" \
|
|
41
|
+
" " + unmatched_parameters.collect { |parameter, h|
|
|
42
|
+
"#{parameter} #{h[:expected].inspect}, was #{h[:actual].inspect}"
|
|
43
|
+
}.join("\n ")
|
|
44
|
+
|
|
45
|
+
else
|
|
46
|
+
"expected '#{resource.to_s}' actions #{resource_actions.inspect}" \
|
|
47
|
+
" to include ':#{@expected_action}'"
|
|
48
|
+
end
|
|
49
|
+
else
|
|
50
|
+
"expected '#{@resource_name}[#{@expected_identity}]' with" \
|
|
51
|
+
" action ':#{@expected_action}' to be in Chef run. Other" \
|
|
52
|
+
" #{@resource_name} resources:" \
|
|
53
|
+
"\n\n" \
|
|
54
|
+
" " + similar_resources.map(&:to_s).join("\n ")
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def failure_message_for_should_not
|
|
59
|
+
if resource
|
|
60
|
+
"expected '#{resource.to_s}' actions #{resource_actions.inspect} to not exist"
|
|
61
|
+
else
|
|
62
|
+
"expected '#{resource.to_s}' to not exist"
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def description
|
|
67
|
+
"#{@expected_action} #{@resource_name}"
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
private
|
|
71
|
+
def unmatched_parameters
|
|
72
|
+
return @_unmatched_parameters if @_unmatched_parameters
|
|
73
|
+
|
|
74
|
+
@_unmatched_parameters = {}
|
|
75
|
+
|
|
76
|
+
params.each do |parameter, expected|
|
|
77
|
+
unless matches_parameter?(parameter, expected)
|
|
78
|
+
@_unmatched_parameters[parameter] = {
|
|
79
|
+
expected: expected,
|
|
80
|
+
actual: safe_send(parameter),
|
|
81
|
+
}
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
@_unmatched_parameters
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def matches_parameter?(parameter, expected)
|
|
89
|
+
# Chef 11+ stores the source parameter internally as an Array
|
|
90
|
+
if parameter == :source
|
|
91
|
+
Array(expected) == Array(safe_send(parameter))
|
|
92
|
+
else
|
|
93
|
+
expected === safe_send(parameter)
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def safe_send(parameter)
|
|
98
|
+
resource.send(parameter)
|
|
99
|
+
rescue NoMethodError
|
|
100
|
+
nil
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
#
|
|
104
|
+
# Any other resources in the Chef run that have the same resource
|
|
105
|
+
# type. Used by {failure_message} to be ultra helpful.
|
|
106
|
+
#
|
|
107
|
+
# @return [Array<Chef::Resource>]
|
|
108
|
+
#
|
|
109
|
+
def similar_resources
|
|
110
|
+
@_similar_resources ||= @runner.find_resources(@resource_name)
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
#
|
|
114
|
+
# Find the resource in the Chef run by the given class name and
|
|
115
|
+
# resource identity/name.
|
|
116
|
+
#
|
|
117
|
+
# @see ChefSpec::Runner#find_resource
|
|
118
|
+
#
|
|
119
|
+
# @return [Chef::Resource, nil]
|
|
120
|
+
#
|
|
121
|
+
def resource
|
|
122
|
+
@_resource ||= @runner.find_resource(@resource_name, @expected_identity)
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
#
|
|
126
|
+
# The list of actions on this resource.
|
|
127
|
+
#
|
|
128
|
+
# @return [Array<Symbol>]
|
|
129
|
+
#
|
|
130
|
+
def resource_actions
|
|
131
|
+
@_resource_actions ||= Array(resource.action).map(&:to_sym)
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
#
|
|
135
|
+
# The list of parameters passed to the {with} matcher.
|
|
136
|
+
#
|
|
137
|
+
# @return [Hash]
|
|
138
|
+
#
|
|
139
|
+
def params
|
|
140
|
+
@_params ||= {}
|
|
141
|
+
end
|
|
142
|
+
end
|
|
143
|
+
end
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
begin
|
|
2
|
+
require 'chef/mixin/template'
|
|
3
|
+
require 'chef/provider/template_finder'
|
|
4
|
+
rescue LoadError
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
module ChefSpec
|
|
8
|
+
class Renderer
|
|
9
|
+
# @return [Chef::Runner]
|
|
10
|
+
attr_reader :chef_run
|
|
11
|
+
|
|
12
|
+
# @return [Chef::Resource]
|
|
13
|
+
attr_reader :resource
|
|
14
|
+
|
|
15
|
+
#
|
|
16
|
+
# Create a new Renderer for the given Chef run and resource.
|
|
17
|
+
#
|
|
18
|
+
# @param [Chef::Runner] chef_run
|
|
19
|
+
# the Chef run containing the resources
|
|
20
|
+
# @param [Chef::Resource] resource
|
|
21
|
+
# the resource to render content from
|
|
22
|
+
#
|
|
23
|
+
def initialize(chef_run, resource)
|
|
24
|
+
@chef_run = chef_run
|
|
25
|
+
@resource = resource
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
#
|
|
29
|
+
# The content of the resource (this method delegates to the)
|
|
30
|
+
# various private rendering methods.
|
|
31
|
+
#
|
|
32
|
+
# @return [String, nil]
|
|
33
|
+
# the contents of the file as a string, or nil if the resource
|
|
34
|
+
# does not contain or respond to a content renderer.
|
|
35
|
+
#
|
|
36
|
+
def content
|
|
37
|
+
case resource.resource_name.to_s
|
|
38
|
+
when 'template'
|
|
39
|
+
content_from_template(chef_run, resource)
|
|
40
|
+
when 'file'
|
|
41
|
+
content_from_file(chef_run, resource)
|
|
42
|
+
when 'cookbook_file'
|
|
43
|
+
content_from_cookbook_file(chef_run, resource)
|
|
44
|
+
else
|
|
45
|
+
nil
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
private
|
|
50
|
+
#
|
|
51
|
+
# Compute the contents of a template using Chef's templating logic.
|
|
52
|
+
#
|
|
53
|
+
# @param [Chef::RunContext] chef_run
|
|
54
|
+
# the run context for the node
|
|
55
|
+
# @param [Chef::Provider::Template] template
|
|
56
|
+
# the template resource
|
|
57
|
+
#
|
|
58
|
+
# @return [String]
|
|
59
|
+
#
|
|
60
|
+
def content_from_template(chef_run, template)
|
|
61
|
+
cookbook_name = template.cookbook || template.cookbook_name
|
|
62
|
+
template_location = cookbook_collection(chef_run.node)[cookbook_name].preferred_filename_on_disk_location(chef_run.node, :templates, template.source)
|
|
63
|
+
|
|
64
|
+
if Chef::Mixin::Template.const_defined?(:TemplateContext) # Chef 11+
|
|
65
|
+
template_context = Chef::Mixin::Template::TemplateContext.new([])
|
|
66
|
+
template_context.update({
|
|
67
|
+
:node => chef_run.node,
|
|
68
|
+
:template_finder => template_finder(chef_run, cookbook_name),
|
|
69
|
+
}.merge(template.variables))
|
|
70
|
+
template_context.render_template(template_location)
|
|
71
|
+
else
|
|
72
|
+
template.provider.new(template, chef_run.run_context).send(:render_with_context, template_location) do |file|
|
|
73
|
+
File.read(file.path)
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
#
|
|
79
|
+
# Get the contents of a file resource.
|
|
80
|
+
#
|
|
81
|
+
# @param [Chef::RunContext] chef_run
|
|
82
|
+
# the run context for the node
|
|
83
|
+
# @param [Chef::Provider::File] file
|
|
84
|
+
# the file resource
|
|
85
|
+
#
|
|
86
|
+
# @return [String]
|
|
87
|
+
#
|
|
88
|
+
def content_from_file(chef_run, file)
|
|
89
|
+
file.content
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
#
|
|
93
|
+
# Get the contents of a cookbook file using Chef.
|
|
94
|
+
#
|
|
95
|
+
# @param [Chef::RunContext] chef_run
|
|
96
|
+
# the run context for the node
|
|
97
|
+
# @param [Chef::Provider::CookbookFile] cookbook_file
|
|
98
|
+
# the file resource
|
|
99
|
+
#
|
|
100
|
+
def content_from_cookbook_file(chef_run, cookbook_file)
|
|
101
|
+
cookbook_name = cookbook_file.cookbook || cookbook_file.cookbook_name
|
|
102
|
+
cookbook = cookbook_collection(chef_run.node)[cookbook_name]
|
|
103
|
+
File.read(cookbook.preferred_filename_on_disk_location(chef_run.node, :files, cookbook_file.source, cookbook_file.path))
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
# The cookbook collection for the current Chef run context. Handles
|
|
107
|
+
# the differing cases between Chef 10 and Chef 11.
|
|
108
|
+
#
|
|
109
|
+
# @param [Chef::Node] node
|
|
110
|
+
# the Chef node to get the cookbook collection from
|
|
111
|
+
#
|
|
112
|
+
# @return [Array<Chef::Cookbook>]
|
|
113
|
+
def cookbook_collection(node)
|
|
114
|
+
if node.respond_to?(:run_context)
|
|
115
|
+
node.run_context.cookbook_collection # Chef 11+
|
|
116
|
+
else
|
|
117
|
+
node.cookbook_collection # Chef 10
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
# Return a new instance of the TemplateFinder if we are running on Chef 11.
|
|
122
|
+
#
|
|
123
|
+
# @param [Chef::RunContext] chef_run
|
|
124
|
+
# the run context for the noe
|
|
125
|
+
# @param [String] cookbook_name
|
|
126
|
+
# the name of the cookbook
|
|
127
|
+
#
|
|
128
|
+
# @return [Chef::Provider::TemplateFinder, nil]
|
|
129
|
+
def template_finder(chef_run, cookbook_name)
|
|
130
|
+
if Chef::Provider.const_defined?(:TemplateFinder) # Chef 11+
|
|
131
|
+
Chef::Provider::TemplateFinder.new(chef_run.run_context, cookbook_name, chef_run.node)
|
|
132
|
+
else
|
|
133
|
+
nil
|
|
134
|
+
end
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
end
|