poise 2.4.0 → 2.5.0

Sign up to get free protection for your applications and to get access to all the features.
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: