poise 2.4.0 → 2.5.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 2670b11e79bcee699172c7eaa7a842df9432324e
4
- data.tar.gz: 56e5b571574d41de09f7af34da94034557fa741a
3
+ metadata.gz: 59e1a4b84effd92c53b370ae6e5ad4330ac48672
4
+ data.tar.gz: 8ed9df5c50afd344e838bf637c875cae8c1765f0
5
5
  SHA512:
6
- metadata.gz: 58b803a269f764c6a061077d27f608d14e14f572c2e016f3986eeee22adc39bf408683cac41c6714b32bc4ad56dba6d03e87095e1c228d6edebc6d744a685209
7
- data.tar.gz: 047b174a37deae87fb3658b6e465be97fe86826028d4575c2f46298d573115eb1c83794289df262b66f6771f9d538ea14f07851aeb139d779cd9f22a38b69874
6
+ metadata.gz: 2f924807105ed9ba4b41616df467768d4a5fc2f0259c8f83d8b6fba5b64d744e4cff6fa38ff66e1ab781f94dd6ed3c4f196aadae0733727cbe384569fc367a7b
7
+ data.tar.gz: ad8775e6a9e0c924e7633f390ca82f7982a4eddb32ca058e3b0e0e988da4766fd074c40022977899012571bacee33c882146f27bff3ae940483cb0f6057c8515
data/.travis.yml CHANGED
@@ -23,4 +23,6 @@ gemfile:
23
23
  - test/gemfiles/chef-12.1.gemfile
24
24
  - test/gemfiles/chef-12.2.gemfile
25
25
  - test/gemfiles/chef-12.3.gemfile
26
+ - test/gemfiles/chef-12.4.gemfile
27
+ - test/gemfiles/chef-12.5.gemfile
26
28
  - test/gemfiles/master.gemfile
data/CHANGELOG.md CHANGED
@@ -1,5 +1,18 @@
1
1
  # Changelog
2
2
 
3
+ ## v2.5.0
4
+
5
+ * New property for inversion resources: `provider_no_auto`. Set one or more
6
+ provider names that will be ignored for automatic resolution for that instance.
7
+ * Support `variables` as an alias for `options` in template content properties
8
+ to match the `template` resource.
9
+ * Template content properties are no longer validated after creation for
10
+ non-default actions.
11
+ * Formalize the extra-verbose logging mode for Poise and expose it via helpers.
12
+ * Extra-verbose logging mode can now be enabled by creating a `/poise_debug` file.
13
+ * New helper: `poise_shell_out`. Like normal `shell_out` but sets group and
14
+ environment variables automatically to better defaults.
15
+
3
16
  ## v2.4.0
4
17
 
5
18
  * Added return value to `Container#register_subresource` to track if the resource
data/README.md CHANGED
@@ -193,6 +193,15 @@ end
193
193
 
194
194
  This will be converted to `{key1: 'value1', key2: 'value2'}`. You can also pass a Hash to an option collector attribute just as you would with a normal attribute.
195
195
 
196
+ ## Debugging Poise
197
+
198
+ Poise has its own extra-verbose level of debug logging that can be enabled in
199
+ three different ways. You can either set the environment variable `$POISE_DEBUG`,
200
+ set a node attribute `node['POISE_DEBUG']`, or touch the file `/POISE_DEBUG`.
201
+ You will see a log message `Extra verbose logging enabled` at the start of the
202
+ run to confirm Poise debugging has been enabled. Make sure you also set Chef's
203
+ log level to `debug`, usually via `-l debug` on the command line.
204
+
196
205
  ## Upgrading from Poise 1.x
197
206
 
198
207
  The biggest change when upgrading from Poise 1.0 is that the mixin is no longer
data/lib/poise.rb CHANGED
@@ -30,6 +30,36 @@ module Poise
30
30
  autoload :Subcontext, 'poise/subcontext'
31
31
  autoload :Utils, 'poise/utils'
32
32
  autoload :VERSION, 'poise/version'
33
+
34
+ # Check if Poise's extra debugging output is enabled. This produces a *lot*
35
+ # of logging.
36
+ #
37
+ # @param node [Chef::Node, Chef::RunContext] Optional node to check for
38
+ # attributes. If not given, Chef.node is used instead.
39
+ # @return [Boolean]
40
+ def self.debug?(node=nil)
41
+ node = node.node if node.is_a?(Chef::RunContext)
42
+ node ||= Chef.node if defined?(Chef.node)
43
+ @debug_file_upper = ::File.exist?('/POISE_DEBUG') unless defined?(@debug_file_upper)
44
+ @debug_file_lower = ::File.exist?('/poise_debug') unless defined?(@debug_file_lower)
45
+ !!(
46
+ (ENV['POISE_DEBUG'] && ENV['POISE_DEBUG'] != 'false') ||
47
+ (ENV['poise_debug'] && ENV['poise_debug'] != 'false') ||
48
+ (node && node['POISE_DEBUG']) ||
49
+ (node && node['poise_debug']) ||
50
+ @debug_file_upper ||
51
+ @debug_file_lower
52
+ )
53
+ end
54
+
55
+ # Log a message only if Poise's extra debugging output is enabled.
56
+ #
57
+ # @see #debug?
58
+ # @param msg [String] Log message.
59
+ # @return [void]
60
+ def self.debug(msg)
61
+ Chef::Log.debug(msg) if debug?
62
+ end
33
63
  end
34
64
 
35
65
  # Callable form to allow passing in options:
@@ -71,3 +101,7 @@ def Poise(options={})
71
101
 
72
102
  mod
73
103
  end
104
+
105
+ # Display a message if poise_debug is enabled. Off in ChefSpec so I don't get
106
+ # extra logging stuff that I don't care about.
107
+ Poise.debug('[Poise] Extra verbose logging enabled') unless defined?(ChefSpec)
@@ -61,12 +61,12 @@ module Poise
61
61
  #
62
62
  # @see Resource::ResourceName.provides
63
63
  def provides(name, *args, &block)
64
+ super(name, *args, &block)
64
65
  ChefSpec.define_matcher(name) if defined?(ChefSpec)
65
66
  # Call #actions here to grab any actions from a parent class.
66
67
  actions.each do |action|
67
68
  ChefspecMatchers.create_matcher(name, action)
68
69
  end
69
- super(name, *args, &block)
70
70
  end
71
71
 
72
72
  # Create matchers for all declared actions.
@@ -76,7 +76,7 @@ module Poise
76
76
  super.tap do |actions|
77
77
  actions.each do |action|
78
78
  ChefspecMatchers.create_matcher(resource_name, action)
79
- end if resource_name
79
+ end if resource_name && resource_name != :resource && !names.empty?
80
80
  end
81
81
  end
82
82
 
@@ -65,9 +65,9 @@ module Poise
65
65
  # @return [String]
66
66
  def poise_defined_in_cookbook(run_context, file=nil)
67
67
  file ||= poise_defined_in
68
- Chef::Log.debug("[#{self.name}] Checking cookbook name for #{file}")
68
+ Poise.debug("[#{self.name}] Checking cookbook name for #{file}")
69
69
  Poise::Utils.find_cookbook_name(run_context, file).tap do |cookbook|
70
- Chef::Log.debug("[#{self.name}] found cookbook #{cookbook.inspect}")
70
+ Poise.debug("[#{self.name}] found cookbook #{cookbook.inspect}")
71
71
  end
72
72
  end
73
73
 
@@ -83,12 +83,23 @@ module Poise
83
83
  resource_names.concat(self.class.subclass_resource_equivalents) if self.class.respond_to?(:subclass_resource_equivalents)
84
84
  # Silly ruby tricks to find the first provider that exists and no more.
85
85
  provider_class = resource_names.lazy.map {|name| Poise::Helpers::Inversion.provider_for(name, node, val) }.select {|x| x }.first
86
- Chef::Log.debug("[#{self}] Checking for an inversion provider for #{val}: #{provider_class && provider_class.name}")
86
+ Poise.debug("[#{self}] Checking for an inversion provider for #{val}: #{provider_class && provider_class.name}")
87
87
  val = provider_class if provider_class
88
88
  end
89
89
  super
90
90
  end
91
91
 
92
+ # Set or return the array of provider names to be blocked from
93
+ # auto-resolution.
94
+ #
95
+ # @param val [String, Array<String>] Value to set.
96
+ # @return [Array<String>]
97
+ def provider_no_auto(val=nil)
98
+ # Coerce to an array.
99
+ val = Array(val).map(&:to_s) if val
100
+ set_or_return(:provider_no_auto, val, kind_of: Array, default: [])
101
+ end
102
+
92
103
  # @!classmethods
93
104
  module ClassMethods
94
105
  # Options resource class.
@@ -290,6 +301,8 @@ module Poise
290
301
  opts.update(run_state['*']) if run_state['*']
291
302
  # Options resource options for this provider.
292
303
  opts.update(run_state[provides]) if run_state[provides]
304
+ # Vomitdebug output for tracking down weirdness.
305
+ Poise.debug("[#{resource}] Resolved inversion options: #{opts.inspect}")
293
306
  end
294
307
  end
295
308
 
@@ -352,8 +365,8 @@ module Poise
352
365
  end
353
366
  return false unless resource_name_equivalents[inversion_resource]
354
367
  provider_name = resolve_inversion_provider(node, resource)
355
- Chef::Log.debug("[#{resource}] Checking provides? on #{self.name}. Got provider_name #{provider_name.inspect}")
356
- provider_name == provides.to_s || ( provider_name == 'auto' && provides_auto?(node, resource) )
368
+ Poise.debug("[#{resource}] Checking provides? on #{self.name}. Got provider_name #{provider_name.inspect}")
369
+ provider_name == provides.to_s || ( provider_name == 'auto' && !resource.provider_no_auto.include?(provides.to_s) && provides_auto?(node, resource) )
357
370
  end
358
371
 
359
372
  # Subclass hook to provide auto-detection for providers.
@@ -35,7 +35,7 @@ module Poise
35
35
  if defined?(sub_run_context.initialize_child_state)
36
36
  sub_run_context.initialize_child_state
37
37
  else
38
- # Audits was added in 12.1 I thin.
38
+ # Audits was added in 12.1 I think.
39
39
  sub_run_context.audits = {} if defined?(sub_run_context.audits)
40
40
  # Dup and clear to preserve the default behavior without copy-pasta.
41
41
  sub_run_context.immediate_notification_collection = parent_context.immediate_notification_collection.dup.clear
@@ -63,7 +63,8 @@ module Poise
63
63
  # we need to jump through some hoops to get it swapped into place.
64
64
  self_ = self
65
65
  order_fixer = Chef::Resource::RubyBlock.new('subresource_order_fixer', @run_context)
66
- order_fixer.declared_type = 'ruby_block'
66
+ # respond_to? is for <= 12.0.2, remove some day when I stop caring.
67
+ order_fixer.declared_type = 'ruby_block' if order_fixer.respond_to?(:declared_type=)
67
68
  order_fixer.block do
68
69
  Chef::Log.debug("[#{self_}] Running order fixer")
69
70
  collection = self_.run_context.resource_collection
@@ -68,6 +68,9 @@ module Poise
68
68
  # Template variables if using a template
69
69
  attribute("#{name_prefix}options", option_collector: true)
70
70
 
71
+ # Make an alias for #variables to match the template resource.
72
+ alias_method("#{name_prefix}variables", "#{name_prefix}options")
73
+
71
74
  # The big one, get/set content, but if you are getting and no
72
75
  # explicit content was given, try to render the template
73
76
  define_method("#{name_prefix}content") do |arg=nil, no_compute=false|
@@ -97,7 +100,7 @@ module Poise
97
100
  old_after_created = instance_method(:after_created)
98
101
  define_method(:after_created) do
99
102
  old_after_created.bind(self).call
100
- send("_#{name_prefix}validate")
103
+ send("_#{name_prefix}validate") if Array(action) == Array(self.class.default_action)
101
104
  end
102
105
  end
103
106
 
@@ -15,6 +15,7 @@
15
15
  #
16
16
 
17
17
  require 'poise/helpers'
18
+ require 'poise/utils'
18
19
 
19
20
 
20
21
  module Poise
@@ -35,6 +36,7 @@ module Poise
35
36
  include Poise::Helpers::IncludeRecipe
36
37
  include Poise::Helpers::LWRPPolyfill
37
38
  include Poise::Helpers::NotifyingBlock
39
+ include Poise::Utils::ShellOut
38
40
 
39
41
  # @!classmethods
40
42
  module ClassMethods
@@ -15,6 +15,7 @@
15
15
  #
16
16
 
17
17
  require 'poise/helpers'
18
+ require 'poise/utils'
18
19
 
19
20
 
20
21
  module Poise
@@ -41,6 +42,7 @@ module Poise
41
42
  include Poise::Helpers::ResourceName
42
43
  include Poise::Helpers::ResourceSubclass
43
44
  include Poise::Helpers::TemplateContent
45
+ include Poise::Utils::ShellOut
44
46
 
45
47
  # @!classmethods
46
48
  module ClassMethods
data/lib/poise/utils.rb CHANGED
@@ -20,6 +20,7 @@ require 'poise/error'
20
20
  module Poise
21
21
  module Utils
22
22
  autoload :ResourceProviderMixin, 'poise/utils/resource_provider_mixin'
23
+ autoload :ShellOut, 'poise/utils/shell_out'
23
24
 
24
25
  extend self
25
26
 
@@ -37,14 +38,14 @@ module Poise
37
38
  # end
38
39
  def find_cookbook_name(run_context, filename)
39
40
  possibles = {}
40
- Chef::Log.debug("[Poise] Checking cookbook for #{filename.inspect}")
41
+ Poise.debug("[Poise] Checking cookbook for #{filename.inspect}")
41
42
  run_context.cookbook_collection.each do |name, ver|
42
43
  # This special method is added by Halite::Gem#as_cookbook_version.
43
44
  if ver.respond_to?(:halite_root)
44
45
  # The join is there because ../poise-ruby/lib starts with ../poise so
45
46
  # we want a trailing /.
46
47
  if filename.start_with?(File.join(ver.halite_root, ''))
47
- Chef::Log.debug("[Poise] Found matching halite_root in #{name}: #{ver.halite_root.inspect}")
48
+ Poise.debug("[Poise] Found matching halite_root in #{name}: #{ver.halite_root.inspect}")
48
49
  possibles[ver.halite_root] = name
49
50
  end
50
51
  else
@@ -52,9 +53,9 @@ module Poise
52
53
  ver.segment_filenames(seg).each do |file|
53
54
  # Put this behind an environment variable because it is verbose
54
55
  # even for normal debugging-level output.
55
- Chef::Log.debug("[Poise] Checking #{seg} in #{name}: #{file.inspect}") if ENV['POISE_DEBUG'] || run_context.node['POISE_DEBUG']
56
+ Poise.debug("[Poise] Checking #{seg} in #{name}: #{file.inspect}")
56
57
  if file == filename
57
- Chef::Log.debug("[Poise] Found matching #{seg} in #{name}: #{file.inspect}")
58
+ Poise.debug("[Poise] Found matching #{seg} in #{name}: #{file.inspect}")
58
59
  possibles[file] = name
59
60
  end
60
61
  end
@@ -0,0 +1,85 @@
1
+ #
2
+ # Copyright 2015, Noah Kantrowitz
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+ #
16
+
17
+ require 'etc'
18
+
19
+ require 'chef/mixin/shell_out'
20
+
21
+
22
+ module Poise
23
+ module Utils
24
+ # A mixin to provider a better shell_out.
25
+ #
26
+ # @since 2.5.0
27
+ # @example
28
+ # Poise::Utils::ShellOut.poise_shell_out('ruby myapp.rb', user: 'myuser')
29
+ module ShellOut
30
+ extend self
31
+ include Chef::Mixin::ShellOut
32
+
33
+ # An enhanced version of Chef's `shell_out` which sets some default
34
+ # parameters. If possible it will set $HOME, $USER, $LOGNAME, and the
35
+ # group to run as.
36
+ #
37
+ # @param command_args [Array] Command arguments to be passed to `shell_out`.
38
+ # @param options [Hash<Symbol, Object>] Options to be passed to `shell_out`,
39
+ # with modifications.
40
+ # @return [Mixlib::ShellOut]
41
+ def poise_shell_out(*command_args, **options)
42
+ # Allow the env option shorthand.
43
+ options[:environment] ||= {}
44
+ if options[:env]
45
+ options[:environment].update(options[:env])
46
+ options.delete(:env)
47
+ end
48
+ # Convert environment keys to strings to be safe.
49
+ options[:environment] = options[:environment].inject({}) do |memo, (key, value)|
50
+ memo[key.to_s] = value.to_s
51
+ memo
52
+ end
53
+ # Populate some standard environment variables.
54
+ ent = begin
55
+ if options[:user].is_a?(Integer)
56
+ Etc.getpwuid(options[:user])
57
+ elsif options[:user]
58
+ Etc.getpwnam(options[:user])
59
+ end
60
+ rescue ArgumentError
61
+ nil
62
+ end
63
+ username = ent ? ent.name : options[:name]
64
+ if username
65
+ options[:environment]['HOME'] ||= Dir.home(username)
66
+ options[:environment]['USER'] ||= username
67
+ # On the off chance they set one manually but not the other.
68
+ options[:environment]['LOGNAME'] ||= options[:environment]['USER']
69
+ end
70
+ # Set the default group on Unix.
71
+ options[:group] ||= ent.gid if ent
72
+ # Call Chef's shell_out wrapper.
73
+ shell_out(*command_args, **options)
74
+ end
75
+
76
+ # The `error!` version of {#poise_shell_out}.
77
+ #
78
+ # @see #poise_shell_out
79
+ # @return [Mixlib::ShellOut]
80
+ def poise_shell_out!(*command_args)
81
+ poise_shell_out(*command_args).tap(&:error!)
82
+ end
83
+ end
84
+ end
85
+ end
data/lib/poise/version.rb CHANGED
@@ -16,5 +16,5 @@
16
16
 
17
17
 
18
18
  module Poise
19
- VERSION = '2.4.0'
19
+ VERSION = '2.5.0'
20
20
  end
@@ -16,4 +16,4 @@
16
16
 
17
17
  eval_gemfile File.expand_path('../../../Gemfile', __FILE__)
18
18
 
19
- gem 'chef', '~> 12.0.0'
19
+ gem 'chef', '~> 12.0.3'
@@ -16,4 +16,4 @@
16
16
 
17
17
  eval_gemfile File.expand_path('../../../Gemfile', __FILE__)
18
18
 
19
- gem 'chef', '~> 12.1.0'
19
+ gem 'chef', '~> 12.1.2'
@@ -16,4 +16,4 @@
16
16
 
17
17
  eval_gemfile File.expand_path('../../../Gemfile', __FILE__)
18
18
 
19
- gem 'chef', '~> 12.2.0'
19
+ gem 'chef', '~> 12.2.1'
@@ -0,0 +1,19 @@
1
+ #
2
+ # Copyright 2015, Noah Kantrowitz
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+ #
16
+
17
+ eval_gemfile File.expand_path('../../../Gemfile', __FILE__)
18
+
19
+ gem 'chef', '~> 12.4.3'
@@ -0,0 +1,19 @@
1
+ #
2
+ # Copyright 2015, Noah Kantrowitz
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+ #
16
+
17
+ eval_gemfile File.expand_path('../../../Gemfile', __FILE__)
18
+
19
+ gem 'chef', '~> 12.5.1'
@@ -279,6 +279,7 @@ describe Poise::Helpers::Inversion do
279
279
  resource(:poise_test_inversion, step_into: false) do
280
280
  include Poise
281
281
  provides(:poise_test_inversion)
282
+ attribute(:provider_no_auto, default: [])
282
283
  end
283
284
  provider(:poise_test_inversion) do
284
285
  include described_class
@@ -341,6 +342,17 @@ describe Poise::Helpers::Inversion do
341
342
  its(:enabled_handlers) { is_expected.to eq [provider(:poise_test_inversion), provider(:poise_test_inversion_other)] }
342
343
  its(:resolve) { is_expected.to eq provider(:poise_test_inversion) }
343
344
  end # /context with a subclassed resource using subclass_providers!
345
+
346
+ context 'with provider_no_auto' do
347
+ recipe(subject: false) do
348
+ poise_test_inversion 'test' do
349
+ provider_no_auto %w{inverted}
350
+ end
351
+ end
352
+ let(:test_resource) { chef_run.poise_test_inversion('test') }
353
+
354
+ its(:resolve) { is_expected.to eq provider(:poise_test_inversion_other) }
355
+ end # /context with provider_no_auto
344
356
  end # /describe provider resolution
345
357
  end # /describe Poise::Helpers::Inversion::Provider
346
358
  end
@@ -68,7 +68,7 @@ describe Poise::Helpers::TemplateContent do
68
68
  end
69
69
  end # /context with a template
70
70
 
71
- context 'with some template variables' do
71
+ context 'with some template options' do
72
72
  recipe do
73
73
  poise_test 'test' do
74
74
  source 'test.erb'
@@ -81,6 +81,21 @@ describe Poise::Helpers::TemplateContent do
81
81
  let(:required_template_options) { {'one' => '1', 'two' => 2} }
82
82
 
83
83
  it { is_expected.to run_poise_test('test').with(source: 'test.erb', options: required_template_options, content: 'rendered template') }
84
+ end # /context with some template options
85
+
86
+ context 'with some template variables' do
87
+ recipe do
88
+ poise_test 'test' do
89
+ source 'test.erb'
90
+ variables do
91
+ one '1'
92
+ two 2
93
+ end
94
+ end
95
+ end
96
+ let(:required_template_options) { {'one' => '1', 'two' => 2} }
97
+
98
+ it { is_expected.to run_poise_test('test').with(source: 'test.erb', variables: required_template_options, content: 'rendered template') }
84
99
  end # /context with some template variables
85
100
 
86
101
  context 'with explicit content' do
@@ -131,7 +146,7 @@ describe Poise::Helpers::TemplateContent do
131
146
  attribute(:config, template: true, required: true)
132
147
  end
133
148
 
134
- it { expect{chef_run}.to raise_error(Chef::Exceptions::ValidationFailed) }
149
+ it { expect{chef_run}.to raise_error Chef::Exceptions::ValidationFailed }
135
150
  end # /context with required content
136
151
 
137
152
  context 'with both source and content' do
@@ -142,6 +157,26 @@ describe Poise::Helpers::TemplateContent do
142
157
  end
143
158
  end
144
159
 
145
- it { expect{chef_run}.to raise_error(Chef::Exceptions::ValidationFailed) }
160
+ it { expect{chef_run}.to raise_error Chef::Exceptions::ValidationFailed }
146
161
  end # /context with both source and content
162
+
163
+ context 'with required content and a non-default action' do
164
+ resource(:poise_test) do
165
+ include Poise
166
+ attribute(:config, template: true, required: true)
167
+ actions(:one, :two)
168
+ end
169
+ provider(:poise_test) do
170
+ def action_one; end
171
+ def action_two; end
172
+ end
173
+ recipe do
174
+ poise_test 'test' do
175
+ action :two
176
+ end
177
+ end
178
+
179
+ it { run_chef }
180
+ it { expect { chef_run.poise_test('test').config_content }.to raise_error Chef::Exceptions::ValidationFailed }
181
+ end # /context with required content and a non-default action
147
182
  end
@@ -182,4 +182,137 @@ describe Poise do
182
182
  it 'has a fake name when used a function' do
183
183
  expect(Poise().name).to eq 'Poise'
184
184
  end # /it has a fake name when used a function
185
+
186
+ describe '.debug?' do
187
+ let(:debug_files) { [] }
188
+ before do
189
+ allow(File).to receive(:exist?).and_call_original
190
+ expect(File).to receive(:exist?).with(/\/poise_debug/i).twice {|path| debug_files.include?(path) }
191
+ end
192
+ around do |ex|
193
+ # Reset the stat checks both before and after.
194
+ begin
195
+ Poise.remove_instance_variable(:@debug_file_upper) if Poise.instance_variable_defined?(:@debug_file_upper)
196
+ Poise.remove_instance_variable(:@debug_file_lower) if Poise.instance_variable_defined?(:@debug_file_lower)
197
+ ex.run
198
+ ensure
199
+ Poise.remove_instance_variable(:@debug_file_upper) if Poise.instance_variable_defined?(:@debug_file_upper)
200
+ Poise.remove_instance_variable(:@debug_file_lower) if Poise.instance_variable_defined?(:@debug_file_lower)
201
+ end
202
+ end
203
+ subject { described_class.debug?(chef_runner.node) }
204
+
205
+ context 'with no flags' do
206
+ it { is_expected.to be false }
207
+ end # /context with no flags
208
+
209
+ context 'with $POISE_DEBUG' do
210
+ around do |ex|
211
+ begin
212
+ old = ENV['POISE_DEBUG']
213
+ ENV['POISE_DEBUG'] = '1'
214
+ ex.run
215
+ ensure
216
+ ENV['POISE_DEBUG'] = old
217
+ end
218
+ end
219
+
220
+ it { is_expected.to be true }
221
+ end # /context with $POISE_DEBUG
222
+
223
+ context 'with $POISE_DEBUG = false' do
224
+ around do |ex|
225
+ begin
226
+ old = ENV['POISE_DEBUG']
227
+ ENV['POISE_DEBUG'] = 'false'
228
+ ex.run
229
+ ensure
230
+ ENV['POISE_DEBUG'] = old
231
+ end
232
+ end
233
+
234
+ it { is_expected.to be false }
235
+ end # /context with $POISE_DEBUG = false
236
+
237
+ context 'with $poise_debug' do
238
+ around do |ex|
239
+ begin
240
+ old = ENV['poise_debug']
241
+ ENV['poise_debug'] = '1'
242
+ ex.run
243
+ ensure
244
+ ENV['poise_debug'] = old
245
+ end
246
+ end
247
+
248
+ it { is_expected.to be true }
249
+ end # /context with $poise_debug
250
+
251
+ context 'with $poise_debug = false' do
252
+ around do |ex|
253
+ begin
254
+ old = ENV['poise_debug']
255
+ ENV['poise_debug'] = 'false'
256
+ ex.run
257
+ ensure
258
+ ENV['poise_debug'] = old
259
+ end
260
+ end
261
+
262
+ it { is_expected.to be false }
263
+ end # /context with $poise_debug = false
264
+
265
+ context 'with node["POISE_DEBUG"]' do
266
+ before { default_attributes['POISE_DEBUG'] = true }
267
+ it { is_expected.to be true }
268
+ end # /context with node["POISE_DEBUG"]
269
+
270
+ context 'with node["poise_debug"]' do
271
+ before { default_attributes['poise_debug'] = true }
272
+ it { is_expected.to be true }
273
+ end # /context with node["poise_debug"]
274
+
275
+ context 'with /POISE_DEBUG' do
276
+ let(:debug_files) { %w{/POISE_DEBUG} }
277
+ it { is_expected.to be true }
278
+ end # /context with /POISE_DEBUG
279
+
280
+ context 'with /poise_debug' do
281
+ let(:debug_files) { %w{/poise_debug} }
282
+ it { is_expected.to be true }
283
+ end # /context with /poise_debug
284
+
285
+ context 'with a global node' do
286
+ before do
287
+ default_attributes['POISE_DEBUG'] = true
288
+ allow(Chef).to receive(:node).and_return(chef_runner.node)
289
+ end
290
+ subject { described_class.debug? }
291
+ it { is_expected.to be true }
292
+ end # /context with a global node
293
+
294
+ context 'with a run_context' do
295
+ before { default_attributes['poise_debug'] = true }
296
+ subject { described_class.debug?(chef_run.run_context) }
297
+ it { is_expected.to be true }
298
+ end # /context with a run_context
299
+ end # /describe .debug?
300
+
301
+ describe '.debug' do
302
+ context 'with debugging disabled' do
303
+ before { allow(described_class).to receive(:debug?).and_return(false) }
304
+ it do
305
+ expect(Chef::Log).to_not receive(:debug)
306
+ Poise.debug('msg')
307
+ end
308
+ end # /context with debugging disabled
309
+
310
+ context 'with debugging enabled' do
311
+ before { allow(described_class).to receive(:debug?).and_return(true) }
312
+ it do
313
+ expect(Chef::Log).to receive(:debug).with('msg')
314
+ Poise.debug('msg')
315
+ end
316
+ end # /context with debugging enabled
317
+ end # /describe .debug
185
318
  end
@@ -0,0 +1,104 @@
1
+ #
2
+ # Copyright 2015, Noah Kantrowitz
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+ #
16
+
17
+ require 'spec_helper'
18
+ require 'etc'
19
+
20
+ describe Poise::Utils::ShellOut do
21
+ let(:arg) { double('command argument') }
22
+ let(:cmd) { double('Mixlib::ShellOut') }
23
+
24
+ describe '.poise_shell_out' do
25
+ let(:user_ent) { double('Passwd', name: 'testuser', uid: 500, gid: 501) }
26
+ let(:command_args) { [arg] }
27
+ let(:expect_args) { [arg, {environment: {}}] }
28
+ before do
29
+ allow(Etc).to receive(:getpwuid).with(500).and_return(user_ent)
30
+ allow(Etc).to receive(:getpwnam).with('testuser').and_return(user_ent)
31
+ allow(Dir).to receive(:home).with('testuser').and_return('/home/testuser')
32
+ expect(described_class).to receive(:shell_out).with(*expect_args).and_return(cmd)
33
+ end
34
+ subject { described_class.poise_shell_out(*command_args) }
35
+
36
+ context 'with no user' do
37
+ it { is_expected.to be cmd }
38
+ end # /context with no user
39
+
40
+ context 'with a user' do
41
+ let(:command_args) { [arg, {user: 'testuser'}] }
42
+ let(:expect_args) { [arg, {user: 'testuser', group: 501, environment: {'HOME' => '/home/testuser', 'USER' => 'testuser', 'LOGNAME' => 'testuser'}}] }
43
+ it { is_expected.to be cmd }
44
+ end # /context with a user
45
+
46
+ context 'with a uid' do
47
+ let(:command_args) { [arg, {user: 500}] }
48
+ let(:expect_args) { [arg, {user: 500, group: 501, environment: {'HOME' => '/home/testuser', 'USER' => 'testuser', 'LOGNAME' => 'testuser'}}] }
49
+ it { is_expected.to be cmd }
50
+ end # /context with a uid
51
+
52
+ context 'with a group' do
53
+ let(:command_args) { [arg, {user: 'testuser', group: 'othergroup'}] }
54
+ let(:expect_args) { [arg, {user: 'testuser', group: 'othergroup', environment: {'HOME' => '/home/testuser', 'USER' => 'testuser', 'LOGNAME' => 'testuser'}}] }
55
+ it { is_expected.to be cmd }
56
+ end # /context with a group
57
+
58
+ context 'with a $HOME' do
59
+ let(:command_args) { [arg, {user: 'testuser', environment: {'HOME' => '/other'}}] }
60
+ let(:expect_args) { [arg, {user: 'testuser', group: 501, environment: {'HOME' => '/other', 'USER' => 'testuser', 'LOGNAME' => 'testuser'}}] }
61
+ it { is_expected.to be cmd }
62
+ end # /context with a $HOME
63
+
64
+ context 'with a $USER' do
65
+ let(:command_args) { [arg, {user: 'testuser', environment: {'USER' => 'other'}}] }
66
+ let(:expect_args) { [arg, {user: 'testuser', group: 501, environment: {'HOME' => '/home/testuser', 'USER' => 'other', 'LOGNAME' => 'other'}}] }
67
+ it { is_expected.to be cmd }
68
+ end # /context with a $USER
69
+
70
+ context 'with a bad user' do
71
+ let(:command_args) { [arg, {user: 'testuser'}] }
72
+ let(:expect_args) { [arg, {user: 'testuser', environment: {}}] }
73
+ before do
74
+ allow(Etc).to receive(:getpwnam).with('testuser').and_raise(ArgumentError)
75
+ end
76
+ it { is_expected.to be cmd }
77
+ end # /context with a bad user
78
+
79
+ context 'with an env option' do
80
+ let(:command_args) { [arg, {user: 'testuser', env: {FOO: 'BAR'}}] }
81
+ let(:expect_args) { [arg, {user: 'testuser', group: 501, environment: {'HOME' => '/home/testuser', 'USER' => 'testuser', 'LOGNAME' => 'testuser', 'FOO' => 'BAR'}}] }
82
+ it { is_expected.to be cmd }
83
+ end # /context with an env option
84
+
85
+ context 'on Windows' do
86
+ let(:command_args) { [arg, {user: 'testuser'}] }
87
+ let(:expect_args) { [arg, {user: 'testuser', environment: {}}] }
88
+ before do
89
+ allow(Etc).to receive(:getpwnam).with('testuser').and_return(nil)
90
+ end
91
+ it { is_expected.to be cmd }
92
+ end # /context on Windows
93
+ end # /describe .poise_shell_out
94
+
95
+ describe '.poise_shell_out!' do
96
+ subject { described_class.poise_shell_out!(arg) }
97
+
98
+ it do
99
+ expect(described_class).to receive(:poise_shell_out).with(arg).and_return(cmd)
100
+ expect(cmd).to receive(:error!)
101
+ is_expected.to be cmd
102
+ end
103
+ end # /describe .poise_shell_out!
104
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: poise
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.4.0
4
+ version: 2.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Noah Kantrowitz
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-09-26 00:00:00.000000000 Z
11
+ date: 2016-01-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: halite
@@ -89,6 +89,7 @@ files:
89
89
  - lib/poise/subcontext/runner.rb
90
90
  - lib/poise/utils.rb
91
91
  - lib/poise/utils/resource_provider_mixin.rb
92
+ - lib/poise/utils/shell_out.rb
92
93
  - lib/poise/version.rb
93
94
  - poise.gemspec
94
95
  - test/cookbooks/poise_test/attributes/default.rb
@@ -104,6 +105,8 @@ files:
104
105
  - test/gemfiles/chef-12.1.gemfile
105
106
  - test/gemfiles/chef-12.2.gemfile
106
107
  - test/gemfiles/chef-12.3.gemfile
108
+ - test/gemfiles/chef-12.4.gemfile
109
+ - test/gemfiles/chef-12.5.gemfile
107
110
  - test/gemfiles/chef-12.gemfile
108
111
  - test/gemfiles/master.gemfile
109
112
  - test/integration/default/serverspec/default_spec.rb
@@ -132,6 +135,7 @@ files:
132
135
  - test/spec/spec_helper.rb
133
136
  - test/spec/subcontext/resource_collection_spec.rb
134
137
  - test/spec/utils/resource_provider_mixin_spec.rb
138
+ - test/spec/utils/shell_out_spec.rb
135
139
  - test/spec/utils_spec.rb
136
140
  homepage: https://github.com/poise/poise
137
141
  licenses:
@@ -171,6 +175,8 @@ test_files:
171
175
  - test/gemfiles/chef-12.1.gemfile
172
176
  - test/gemfiles/chef-12.2.gemfile
173
177
  - test/gemfiles/chef-12.3.gemfile
178
+ - test/gemfiles/chef-12.4.gemfile
179
+ - test/gemfiles/chef-12.5.gemfile
174
180
  - test/gemfiles/chef-12.gemfile
175
181
  - test/gemfiles/master.gemfile
176
182
  - test/integration/default/serverspec/default_spec.rb
@@ -199,5 +205,6 @@ test_files:
199
205
  - test/spec/spec_helper.rb
200
206
  - test/spec/subcontext/resource_collection_spec.rb
201
207
  - test/spec/utils/resource_provider_mixin_spec.rb
208
+ - test/spec/utils/shell_out_spec.rb
202
209
  - test/spec/utils_spec.rb
203
210
  has_rdoc: