ruby-pwsh 1.1.0 → 1.2.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 +4 -4
- data/README.md +4 -0
- data/lib/puppet/provider/dsc_base_provider/dsc_base_provider.rb +89 -27
- data/lib/puppet/provider/dsc_base_provider/invoke_dsc_resource_functions.ps1 +1 -1
- data/lib/pwsh/util.rb +3 -3
- data/lib/pwsh/version.rb +1 -1
- data/lib/pwsh.rb +1 -1
- data/spec/unit/puppet/provider/dsc_base_provider/dsc_base_provider_spec.rb +67 -21
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: e217873cdddb9b32ba467e0a9f5de6977c04b11a1c0788613dda6181e96a62bd
|
|
4
|
+
data.tar.gz: 8dc82dfad8869d7c632ba3d902b4e22c375aeb5988f84e359269163da885b604
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: a7e02f1cee48fa49316c133268a16f9bc3b8f195927834854c81eee134cdb7056710cd1be04eaf992ca036aa2b014175d06ebf8684eef6354ef8d10a07a62e31
|
|
7
|
+
data.tar.gz: da78f276002b67faf3716ce0b8157fe3cf0edbbeb5da3ae1145c3ed696e386838285138fdd0c75b8a592b677b7631c66ce07355a25788dee58354af0ecdd9eaa
|
data/README.md
CHANGED
|
@@ -86,6 +86,10 @@ The following platforms are supported:
|
|
|
86
86
|
- RedHat
|
|
87
87
|
- Ubuntu
|
|
88
88
|
|
|
89
|
+
## Limitations
|
|
90
|
+
|
|
91
|
+
- When PowerShell [Script Block Logging](https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_logging_windows?view=powershell-7.4#enabling-script-block-logging) is enabled, data marked as sensitive in your manifest may appear in these logs as plain text. It is **highly recommended**, by both Puppet and Microsoft, that you also enable [Protected Event Logging](https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_logging_windows?view=powershell-7.4#protected-event-logging) alongside this to encrypt the logs to protect this information.
|
|
92
|
+
|
|
89
93
|
## License
|
|
90
94
|
|
|
91
95
|
This codebase is licensed under Apache 2.0. However, the open source dependencies included in this codebase might be subject to other software licenses such as AGPL, GPL2.0, and MIT.
|
|
@@ -15,6 +15,7 @@ class Puppet::Provider::DscBaseProvider # rubocop:disable Metrics/ClassLength
|
|
|
15
15
|
@cached_query_results = []
|
|
16
16
|
@cached_test_results = []
|
|
17
17
|
@logon_failures = []
|
|
18
|
+
@timeout = nil # default timeout, ps_manager.execute is expecting nil by default..
|
|
18
19
|
super
|
|
19
20
|
end
|
|
20
21
|
|
|
@@ -44,6 +45,7 @@ class Puppet::Provider::DscBaseProvider # rubocop:disable Metrics/ClassLength
|
|
|
44
45
|
# @param context [Object] the Puppet runtime context to operate in and send feedback to
|
|
45
46
|
# @param resources [Hash] the hash of the resource to canonicalize from either manifest or invocation
|
|
46
47
|
# @return [Hash] returns a hash representing the current state of the object, if it exists
|
|
48
|
+
# rubocop:disable Metrics/BlockLength, Metrics/MethodLength
|
|
47
49
|
def canonicalize(context, resources)
|
|
48
50
|
canonicalized_resources = []
|
|
49
51
|
resources.collect do |r|
|
|
@@ -83,9 +85,18 @@ class Puppet::Provider::DscBaseProvider # rubocop:disable Metrics/ClassLength
|
|
|
83
85
|
downcased_result.each do |key, value|
|
|
84
86
|
# Canonicalize to the manifest value unless the downcased strings match and the attribute is not an enum:
|
|
85
87
|
# - When the values don't match at all, the manifest value is desired;
|
|
86
|
-
# - When the values match case insensitively but the attribute is an enum,
|
|
87
|
-
#
|
|
88
|
-
|
|
88
|
+
# - When the values match case insensitively but the attribute is an enum, and the casing from invoke_get_method
|
|
89
|
+
# is not int the enum, prefer the casing of the manifest enum.
|
|
90
|
+
# - When the values match case insensitively and the attribute is not an enum, or is an enum and invoke_get_method casing
|
|
91
|
+
# is in the enum, prefer the casing from invoke_get_method
|
|
92
|
+
is_enum = enum_attributes(context).include?(key)
|
|
93
|
+
canonicalized_value_in_enum = if is_enum
|
|
94
|
+
enum_values(context, key).include?(canonicalized[key])
|
|
95
|
+
else
|
|
96
|
+
false
|
|
97
|
+
end
|
|
98
|
+
match_insensitively = same?(value, downcased_resource[key])
|
|
99
|
+
canonicalized[key] = r[key] unless match_insensitively && (canonicalized_value_in_enum || !is_enum)
|
|
89
100
|
canonicalized.delete(key) unless downcased_resource.key?(key)
|
|
90
101
|
end
|
|
91
102
|
# Cache the actually canonicalized resource separately
|
|
@@ -104,6 +115,7 @@ class Puppet::Provider::DscBaseProvider # rubocop:disable Metrics/ClassLength
|
|
|
104
115
|
context.debug("Canonicalized Resources: #{canonicalized_resources}")
|
|
105
116
|
canonicalized_resources
|
|
106
117
|
end
|
|
118
|
+
# rubocop:enable Metrics/BlockLength, Metrics/MethodLength
|
|
107
119
|
|
|
108
120
|
# Attempts to retrieve an instance of the DSC resource, invoking the `Get` method and passing any
|
|
109
121
|
# namevars as the Properties to Invoke-DscResource. The result object, if any, is compared to the
|
|
@@ -240,18 +252,22 @@ class Puppet::Provider::DscBaseProvider # rubocop:disable Metrics/ClassLength
|
|
|
240
252
|
context.err('Logon credentials are invalid')
|
|
241
253
|
return nil
|
|
242
254
|
end
|
|
255
|
+
specify_dsc_timeout(name_hash)
|
|
243
256
|
resource = invocable_resource(props, context, method)
|
|
244
257
|
script_content = ps_script_content(resource)
|
|
258
|
+
context.debug("Invoke-DSC Timeout: #{@timeout} milliseconds") if @timeout
|
|
245
259
|
context.debug("Script:\n #{redact_secrets(script_content)}")
|
|
246
|
-
output = ps_manager.execute(remove_secret_identifiers(script_content))
|
|
260
|
+
output = ps_manager.execute(remove_secret_identifiers(script_content), @timeout)
|
|
247
261
|
|
|
248
|
-
if output.nil?
|
|
249
|
-
|
|
262
|
+
if output[:stdout].nil?
|
|
263
|
+
message = 'Nothing returned.'
|
|
264
|
+
message += " #{output[:errormessage]}" if output[:errormessage]&.match?(/PowerShell module timeout \(\d+ ms\) exceeded while executing/)
|
|
265
|
+
context.err(message)
|
|
250
266
|
return nil
|
|
251
267
|
end
|
|
252
268
|
|
|
253
269
|
begin
|
|
254
|
-
data = JSON.parse(output)
|
|
270
|
+
data = JSON.parse(output[:stdout])
|
|
255
271
|
rescue StandardError => e
|
|
256
272
|
context.err(e)
|
|
257
273
|
return nil
|
|
@@ -284,6 +300,18 @@ class Puppet::Provider::DscBaseProvider # rubocop:disable Metrics/ClassLength
|
|
|
284
300
|
data
|
|
285
301
|
end
|
|
286
302
|
|
|
303
|
+
# Sets the @timeout instance variable.
|
|
304
|
+
# @param name_hash [Hash] the hash of namevars to be passed as properties to `Invoke-DscResource`
|
|
305
|
+
# The @timeout variable is set to the value of name_hash[:dsc_timeout] in milliseconds
|
|
306
|
+
# If name_hash[:dsc_timeout] is nil, @timeout is not changed.
|
|
307
|
+
# If @timeout is already set to a value other than nil,
|
|
308
|
+
# it is changed only if it's different from name_hash[:dsc_timeout]..
|
|
309
|
+
def specify_dsc_timeout(name_hash)
|
|
310
|
+
return unless name_hash[:dsc_timeout] && (@timeout.nil? || @timeout != name_hash[:dsc_timeout])
|
|
311
|
+
|
|
312
|
+
@timeout = name_hash[:dsc_timeout] * 1000
|
|
313
|
+
end
|
|
314
|
+
|
|
287
315
|
# Retries Invoke-DscResource when returned error matches error regex supplied as param.
|
|
288
316
|
# @param context [Object] the Puppet runtime context to operate in and send feedback to
|
|
289
317
|
# @param max_retry_count [Int] max number of times to retry Invoke-DscResource
|
|
@@ -299,24 +327,16 @@ class Puppet::Provider::DscBaseProvider # rubocop:disable Metrics/ClassLength
|
|
|
299
327
|
# notify and retry
|
|
300
328
|
context.notice("Retrying: attempt #{try} of #{max_retry_count}.")
|
|
301
329
|
data = JSON.parse(yield)
|
|
302
|
-
# if no error, break
|
|
303
|
-
if data['errormessage'].nil?
|
|
304
|
-
|
|
305
|
-
#
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
end
|
|
313
|
-
# if not last attempt, notify, continue and retry
|
|
314
|
-
context.notice("Attempt #{try} of #{max_retry_count} failed.")
|
|
315
|
-
next
|
|
316
|
-
else
|
|
317
|
-
# if we get an unexpected error, return
|
|
318
|
-
return context.err(data['errormessage'])
|
|
319
|
-
end
|
|
330
|
+
# if no error, assume successful invocation and break
|
|
331
|
+
break if data['errormessage'].nil?
|
|
332
|
+
|
|
333
|
+
# notify of failed retry
|
|
334
|
+
context.notice("Attempt #{try} of #{max_retry_count} failed.")
|
|
335
|
+
# return if error does not match expceted error, or all retries exhausted
|
|
336
|
+
return context.err(data['errormessage']) unless data['errormessage'].match?(error_matcher) && try < max_retry_count
|
|
337
|
+
|
|
338
|
+
# else, retry
|
|
339
|
+
next
|
|
320
340
|
end
|
|
321
341
|
data
|
|
322
342
|
end
|
|
@@ -348,7 +368,7 @@ class Puppet::Provider::DscBaseProvider # rubocop:disable Metrics/ClassLength
|
|
|
348
368
|
# @param context [Object] the Puppet runtime context to operate in and send feedback to
|
|
349
369
|
# @param name_hash [Hash] the hash of namevars to be passed as properties to `Invoke-DscResource`
|
|
350
370
|
# @return [Hash] returns a hash representing the DSC resource munged to the representation the Puppet Type expects
|
|
351
|
-
def invoke_get_method(context, name_hash)
|
|
371
|
+
def invoke_get_method(context, name_hash) # rubocop:disable Metrics/AbcSize
|
|
352
372
|
context.debug("retrieving #{name_hash.inspect}")
|
|
353
373
|
|
|
354
374
|
query_props = name_hash.select { |k, v| mandatory_get_attributes(context).include?(k) || (k == :dsc_psdscrunascredential && !v.nil?) }
|
|
@@ -391,6 +411,8 @@ class Puppet::Provider::DscBaseProvider # rubocop:disable Metrics/ClassLength
|
|
|
391
411
|
# If a resource is found, it's present, so refill this Puppet-only key
|
|
392
412
|
data[:name] = name_hash[:name]
|
|
393
413
|
|
|
414
|
+
data = stringify_nil_attributes(context, data)
|
|
415
|
+
|
|
394
416
|
# Have to check for this to avoid a weird canonicalization warning
|
|
395
417
|
# The Resource API calls canonicalize against the current state which
|
|
396
418
|
# will lead to dsc_ensure being set to absent in the name_hash even if
|
|
@@ -660,6 +682,20 @@ class Puppet::Provider::DscBaseProvider # rubocop:disable Metrics/ClassLength
|
|
|
660
682
|
context.type.attributes.select { |_attribute, properties| properties[:mandatory_for_set] }.keys
|
|
661
683
|
end
|
|
662
684
|
|
|
685
|
+
# Parses the DSC resource type definition to retrieve the names of any attributes which are specified as required strings
|
|
686
|
+
# This is used to ensure that any nil values are converted to empty strings to match puppets expected value
|
|
687
|
+
# @param context [Object] the Puppet runtime context to operate in and send feedback to
|
|
688
|
+
# @param data [Hash] the hash of properties returned from the DSC resource
|
|
689
|
+
# @return [Hash] returns a data hash with any nil values converted to empty strings
|
|
690
|
+
def stringify_nil_attributes(context, data)
|
|
691
|
+
nil_attributes = data.select { |_name, value| value.nil? }.keys
|
|
692
|
+
nil_attributes.each do |nil_attr|
|
|
693
|
+
attribute_type = context.type.attributes[nil_attr][:type]
|
|
694
|
+
data[nil_attr] = '' if (attribute_type.include?('Enum[') && enum_values(context, nil_attr).include?('')) || attribute_type == 'String'
|
|
695
|
+
end
|
|
696
|
+
data
|
|
697
|
+
end
|
|
698
|
+
|
|
663
699
|
# Parses the DSC resource type definition to retrieve the names of any attributes which are specified as namevars
|
|
664
700
|
#
|
|
665
701
|
# @param context [Object] the Puppet runtime context to operate in and send feedback to
|
|
@@ -686,6 +722,28 @@ class Puppet::Provider::DscBaseProvider # rubocop:disable Metrics/ClassLength
|
|
|
686
722
|
context.type.attributes.select { |_name, properties| properties[:type].include?('Enum[') }.keys
|
|
687
723
|
end
|
|
688
724
|
|
|
725
|
+
# Parses the DSC resource type definition to retrieve the values of any attributes which are specified as enums
|
|
726
|
+
#
|
|
727
|
+
# @param context [Object] the Puppet runtime context to operate in and send feedback to
|
|
728
|
+
# @param attribute [String] the enum attribute to retrieve the allowed values from
|
|
729
|
+
# @return [Array] returns an array of attribute names as symbols which are enums
|
|
730
|
+
def enum_values(context, attribute)
|
|
731
|
+
# Get the attribute's type string for the given key
|
|
732
|
+
type_string = context.type.attributes[attribute][:type]
|
|
733
|
+
|
|
734
|
+
# Return an empty array if the key doesn't have an Enum type or doesn't exist
|
|
735
|
+
return [] unless type_string&.include?('Enum[')
|
|
736
|
+
|
|
737
|
+
# Extract the enum values from the type string
|
|
738
|
+
enum_content = type_string.match(/Enum\[(.*?)\]/)&.[](1)
|
|
739
|
+
|
|
740
|
+
# Return an empty array if we couldn't find the enum values
|
|
741
|
+
return [] if enum_content.nil?
|
|
742
|
+
|
|
743
|
+
# Return an array of the enum values, stripped of extra whitespace and quote marks
|
|
744
|
+
enum_content.split(',').map { |val| val.strip.delete('\'') }
|
|
745
|
+
end
|
|
746
|
+
|
|
689
747
|
# Look through a fully formatted string, replacing all instances where a value matches the formatted properties
|
|
690
748
|
# of an instantiated variable with references to the variable instead. This allows us to pass complex and nested
|
|
691
749
|
# CIM instances to the Invoke-DscResource parameter hash without constructing them *in* the hash.
|
|
@@ -1035,6 +1093,10 @@ class Puppet::Provider::DscBaseProvider # rubocop:disable Metrics/ClassLength
|
|
|
1035
1093
|
def ps_manager
|
|
1036
1094
|
debug_output = Puppet::Util::Log.level == :debug
|
|
1037
1095
|
# TODO: Allow you to specify an alternate path, either to pwsh generally or a specific pwsh path.
|
|
1038
|
-
|
|
1096
|
+
if Pwsh::Util.on_windows?
|
|
1097
|
+
Pwsh::Manager.instance(Pwsh::Manager.powershell_path, Pwsh::Manager.powershell_args, debug: debug_output)
|
|
1098
|
+
else
|
|
1099
|
+
Pwsh::Manager.instance(Pwsh::Manager.pwsh_path, Pwsh::Manager.pwsh_args, debug: debug_output)
|
|
1100
|
+
end
|
|
1039
1101
|
end
|
|
1040
1102
|
end
|
data/lib/pwsh/util.rb
CHANGED
|
@@ -7,12 +7,12 @@ module Pwsh
|
|
|
7
7
|
module_function
|
|
8
8
|
|
|
9
9
|
# Verifies whether or not the current context is running on a Windows node.
|
|
10
|
+
# Implementation copied from `facets`: https://github.com/rubyworks/facets/blob/main/lib/standard/facets/rbconfig.rb
|
|
10
11
|
#
|
|
11
12
|
# @return [Bool] true if on windows
|
|
12
13
|
def on_windows?
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
!!File::ALT_SEPARATOR
|
|
14
|
+
host_os = RbConfig::CONFIG['host_os']
|
|
15
|
+
!!(host_os =~ /mswin|mingw/)
|
|
16
16
|
end
|
|
17
17
|
|
|
18
18
|
# Verify paths specified are valid directories which exist.
|
data/lib/pwsh/version.rb
CHANGED
data/lib/pwsh.rb
CHANGED
|
@@ -380,7 +380,7 @@ module Pwsh
|
|
|
380
380
|
pwsh_paths << File.join(path, 'pwsh.exe') if File.exist?(File.join(path, 'pwsh.exe'))
|
|
381
381
|
end
|
|
382
382
|
else
|
|
383
|
-
search_paths.split(
|
|
383
|
+
search_paths.split(':').each do |path|
|
|
384
384
|
pwsh_paths << File.join(path, 'pwsh') if File.exist?(File.join(path, 'pwsh'))
|
|
385
385
|
end
|
|
386
386
|
end
|
|
@@ -179,6 +179,8 @@ RSpec.describe Puppet::Provider::DscBaseProvider do
|
|
|
179
179
|
end
|
|
180
180
|
|
|
181
181
|
it 'treats the manifest value as canonical' do
|
|
182
|
+
expect(context).to receive(:type).and_return(type)
|
|
183
|
+
expect(type).to receive(:attributes).and_return({ dsc_property: { type: "Enum['Dword']" } })
|
|
182
184
|
expect(canonicalized_resource.first[:dsc_property]).to eq('Dword')
|
|
183
185
|
end
|
|
184
186
|
end
|
|
@@ -539,7 +541,7 @@ RSpec.describe Puppet::Provider::DscBaseProvider do
|
|
|
539
541
|
|
|
540
542
|
context 'when the invocation script returns data without errors' do
|
|
541
543
|
before do
|
|
542
|
-
allow(ps_manager).to receive(:execute).with(script).and_return({ stdout: 'DSC Data' })
|
|
544
|
+
allow(ps_manager).to receive(:execute).with(script, nil).and_return({ stdout: 'DSC Data' })
|
|
543
545
|
allow(JSON).to receive(:parse).with('DSC Data').and_return(parsed_invocation_data)
|
|
544
546
|
allow(Puppet::Pops::Time::Timestamp).to receive(:parse).with('2100-01-01').and_return('TimeStamp:2100-01-01')
|
|
545
547
|
allow(provider).to receive(:fetch_cached_hashes).and_return([])
|
|
@@ -657,15 +659,15 @@ RSpec.describe Puppet::Provider::DscBaseProvider do
|
|
|
657
659
|
context 'when the DSC invocation errors' do
|
|
658
660
|
it 'writes an error and returns nil' do
|
|
659
661
|
expect(provider).not_to receive(:logon_failed_already?)
|
|
660
|
-
expect(ps_manager).to receive(:execute).with(script).and_return({ stdout: nil })
|
|
661
|
-
expect(context).to receive(:err).with('Nothing returned')
|
|
662
|
+
expect(ps_manager).to receive(:execute).with(script, nil).and_return({ stdout: nil })
|
|
663
|
+
expect(context).to receive(:err).with('Nothing returned.')
|
|
662
664
|
expect(result).to be_nil
|
|
663
665
|
end
|
|
664
666
|
end
|
|
665
667
|
|
|
666
668
|
context 'when handling DateTimes' do
|
|
667
669
|
before do
|
|
668
|
-
allow(ps_manager).to receive(:execute).with(script).and_return({ stdout: 'DSC Data' })
|
|
670
|
+
allow(ps_manager).to receive(:execute).with(script, nil).and_return({ stdout: 'DSC Data' })
|
|
669
671
|
allow(JSON).to receive(:parse).with('DSC Data').and_return(parsed_invocation_data)
|
|
670
672
|
allow(provider).to receive(:fetch_cached_hashes).and_return([])
|
|
671
673
|
end
|
|
@@ -717,7 +719,7 @@ RSpec.describe Puppet::Provider::DscBaseProvider do
|
|
|
717
719
|
context 'when the credential is invalid' do
|
|
718
720
|
before do
|
|
719
721
|
allow(provider).to receive(:logon_failed_already?).and_return(false)
|
|
720
|
-
allow(ps_manager).to receive(:execute).with(script).and_return({ stdout: 'DSC Data' })
|
|
722
|
+
allow(ps_manager).to receive(:execute).with(script, nil).and_return({ stdout: 'DSC Data' })
|
|
721
723
|
allow(JSON).to receive(:parse).with('DSC Data').and_return({ 'errormessage' => dsc_logon_failure_error })
|
|
722
724
|
allow(context).to receive(:err).with(name_hash[:name], puppet_logon_failure_error)
|
|
723
725
|
end
|
|
@@ -781,7 +783,7 @@ RSpec.describe Puppet::Provider::DscBaseProvider do
|
|
|
781
783
|
context 'when the invocation script returns nil' do
|
|
782
784
|
it 'errors via context but does not raise' do
|
|
783
785
|
expect(ps_manager).to receive(:execute).and_return({ stdout: nil })
|
|
784
|
-
expect(context).to receive(:err).with('Nothing returned')
|
|
786
|
+
expect(context).to receive(:err).with('Nothing returned.')
|
|
785
787
|
expect { result }.not_to raise_error
|
|
786
788
|
end
|
|
787
789
|
end
|
|
@@ -812,9 +814,9 @@ RSpec.describe Puppet::Provider::DscBaseProvider do
|
|
|
812
814
|
.exactly(5).times
|
|
813
815
|
expect(context).to receive(:notice).with(/Invoke-DscResource collision detected: Please stagger the timing of your Puppet runs as this can lead to unexpected behaviour./).once
|
|
814
816
|
expect(context).to receive(:notice).with('Sleeping for 60 seconds.').exactly(5).times
|
|
815
|
-
expect(context).to receive(:notice).with(/Retrying: attempt [1-
|
|
817
|
+
expect(context).to receive(:notice).with(/Retrying: attempt [1-5] of 5/).exactly(5).times
|
|
816
818
|
expect(ps_manager).to receive(:execute).and_return({ stdout: '{"errormessage": "The Invoke-DscResource cmdlet is in progress and must return before Invoke-DscResource can be invoked"}' })
|
|
817
|
-
expect(context).to receive(:notice).with(/Attempt [1-
|
|
819
|
+
expect(context).to receive(:notice).with(/Attempt [1-5] of 5 failed/).exactly(5).times
|
|
818
820
|
expect(context).to receive(:err).with(/The Invoke-DscResource cmdlet is in progress and must return before Invoke-DscResource can be invoked/)
|
|
819
821
|
allow(provider).to receive(:sleep)
|
|
820
822
|
expect(result).to be_nil
|
|
@@ -827,14 +829,35 @@ RSpec.describe Puppet::Provider::DscBaseProvider do
|
|
|
827
829
|
expect(context).to receive(:notice).with(/Retrying: attempt 1 of 5/).once
|
|
828
830
|
allow(provider).to receive(:sleep)
|
|
829
831
|
expect(ps_manager).to receive(:execute).and_return({ stdout: '{"errormessage": "Some unexpected error"}' }).once
|
|
832
|
+
expect(context).to receive(:notice).with(/Attempt 1 of 5 failed/).once
|
|
830
833
|
expect(context).to receive(:err).with(/Some unexpected error/)
|
|
831
834
|
expect(result).to be_nil
|
|
832
835
|
end
|
|
833
836
|
end
|
|
834
837
|
|
|
838
|
+
context 'when a dsc_timeout is specified' do
|
|
839
|
+
let(:should_hash) { name.merge(dsc_timeout: 5) }
|
|
840
|
+
let(:apply_props_with_timeout) { { dsc_name: 'foo', dsc_timeout: 5 } }
|
|
841
|
+
let(:resource_with_timeout) { "Resource: #{apply_props_with_timeout}" }
|
|
842
|
+
let(:script_with_timeout) { "Script: #{apply_props_with_timeout}" }
|
|
843
|
+
|
|
844
|
+
before do
|
|
845
|
+
allow(provider).to receive(:invocable_resource).with(apply_props_with_timeout, context, 'set').and_return(resource_with_timeout)
|
|
846
|
+
allow(provider).to receive(:ps_script_content).with(resource_with_timeout).and_return(script_with_timeout)
|
|
847
|
+
allow(provider).to receive(:remove_secret_identifiers).with(script_with_timeout).and_return(script_with_timeout)
|
|
848
|
+
end
|
|
849
|
+
|
|
850
|
+
it 'sets @timeout and passes it to ps_manager.execute' do
|
|
851
|
+
provider.instance_variable_set(:@timeout, nil)
|
|
852
|
+
expect(ps_manager).to receive(:execute).with(script_with_timeout, 5000).and_return({ stdout: '{"in_desired_state": true, "errormessage": null}' })
|
|
853
|
+
provider.invoke_set_method(context, name, should_hash)
|
|
854
|
+
expect(provider.instance_variable_get(:@timeout)).to eq(5000)
|
|
855
|
+
end
|
|
856
|
+
end
|
|
857
|
+
|
|
835
858
|
context 'when the invocation script returns data without errors' do
|
|
836
859
|
it 'filters for the correct properties to invoke and returns the results' do
|
|
837
|
-
expect(ps_manager).to receive(:execute).with("Script: #{apply_props}").and_return({ stdout: '{"in_desired_state": true, "errormessage": null}' })
|
|
860
|
+
expect(ps_manager).to receive(:execute).with("Script: #{apply_props}", nil).and_return({ stdout: '{"in_desired_state": true, "errormessage": null}' })
|
|
838
861
|
expect(context).not_to receive(:err)
|
|
839
862
|
expect(result).to eq({ 'in_desired_state' => true, 'errormessage' => nil })
|
|
840
863
|
end
|
|
@@ -2107,21 +2130,44 @@ RSpec.describe Puppet::Provider::DscBaseProvider do
|
|
|
2107
2130
|
end
|
|
2108
2131
|
|
|
2109
2132
|
describe '.ps_manager' do
|
|
2110
|
-
|
|
2111
|
-
|
|
2112
|
-
|
|
2113
|
-
|
|
2133
|
+
describe '.ps_manager on non-Windows' do
|
|
2134
|
+
before do
|
|
2135
|
+
allow(Pwsh::Util).to receive(:on_windows?).and_return(false)
|
|
2136
|
+
allow(Pwsh::Manager).to receive(:pwsh_path).and_return('pwsh')
|
|
2137
|
+
allow(Pwsh::Manager).to receive(:pwsh_args).and_return('args')
|
|
2138
|
+
end
|
|
2139
|
+
|
|
2140
|
+
it 'Initializes an instance of the Pwsh::Manager' do
|
|
2141
|
+
expect(Puppet::Util::Log).to receive(:level).and_return(:normal)
|
|
2142
|
+
expect(Pwsh::Manager).to receive(:instance).with('pwsh', 'args', debug: false)
|
|
2143
|
+
expect { provider.ps_manager }.not_to raise_error
|
|
2144
|
+
end
|
|
2114
2145
|
|
|
2115
|
-
|
|
2116
|
-
|
|
2117
|
-
|
|
2118
|
-
|
|
2146
|
+
it 'passes debug as true if Puppet::Util::Log.level is debug' do
|
|
2147
|
+
expect(Puppet::Util::Log).to receive(:level).and_return(:debug)
|
|
2148
|
+
expect(Pwsh::Manager).to receive(:instance).with('pwsh', 'args', debug: true)
|
|
2149
|
+
expect { provider.ps_manager }.not_to raise_error
|
|
2150
|
+
end
|
|
2119
2151
|
end
|
|
2120
2152
|
|
|
2121
|
-
|
|
2122
|
-
|
|
2123
|
-
|
|
2124
|
-
|
|
2153
|
+
describe '.ps_manager on Windows' do
|
|
2154
|
+
before do
|
|
2155
|
+
allow(Pwsh::Util).to receive(:on_windows?).and_return(true)
|
|
2156
|
+
allow(Pwsh::Manager).to receive(:powershell_path).and_return('pwsh')
|
|
2157
|
+
allow(Pwsh::Manager).to receive(:powershell_args).and_return('args')
|
|
2158
|
+
end
|
|
2159
|
+
|
|
2160
|
+
it 'Initializes an instance of the Pwsh::Manager' do
|
|
2161
|
+
expect(Puppet::Util::Log).to receive(:level).and_return(:normal)
|
|
2162
|
+
expect(Pwsh::Manager).to receive(:instance).with('pwsh', 'args', debug: false)
|
|
2163
|
+
expect { provider.ps_manager }.not_to raise_error
|
|
2164
|
+
end
|
|
2165
|
+
|
|
2166
|
+
it 'passes debug as true if Puppet::Util::Log.level is debug' do
|
|
2167
|
+
expect(Puppet::Util::Log).to receive(:level).and_return(:debug)
|
|
2168
|
+
expect(Pwsh::Manager).to receive(:instance).with('pwsh', 'args', debug: true)
|
|
2169
|
+
expect { provider.ps_manager }.not_to raise_error
|
|
2170
|
+
end
|
|
2125
2171
|
end
|
|
2126
2172
|
end
|
|
2127
2173
|
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: ruby-pwsh
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.
|
|
4
|
+
version: 1.2.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Puppet, Inc.
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2024-
|
|
11
|
+
date: 2024-08-15 00:00:00.000000000 Z
|
|
12
12
|
dependencies: []
|
|
13
13
|
description: PowerShell code manager for ruby.
|
|
14
14
|
email:
|