ruby-pwsh 1.1.0 → 1.1.1

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
  SHA256:
3
- metadata.gz: eb7a2c9a103865f74de54ae3a977a70382a2b18ff2e1f8f830b25ef50f4ba1d2
4
- data.tar.gz: 7ca9acbd7478367673a8f761a0b51ddf5f0359246b3ca72f7fe9b8e4c3da34a6
3
+ metadata.gz: 1ac282abeea132104fda1b3fc2f4743f4b99603cdd6b73a42b7063641c9e65d9
4
+ data.tar.gz: 410bc1d7a7b08366a89019324b172219102197f8aa6891bcfaa1729e3bd76925
5
5
  SHA512:
6
- metadata.gz: 830c6e92076e50675f1ce02445f9fd9952545987af24e152bb164b11223d35d47d3619c997bf51b9b09293b22d69d2c832e689f59cfbad1118663203af374046
7
- data.tar.gz: 5e107bcb95cc294f2c421d565c3376b21a7272b4bd4e4c32684f4481577398e2fa54c5005f8e6d990a7d9ffebf2db5eca5dbdb7eba2b2c7ddb2660ca65315f04
6
+ metadata.gz: 0fd8c7af3f87ce61121a7404b66cfae5cf78fea8bdb885dc7715467bb5092bd974a9fd4d7f94824fe10675d56b4e4dc7b439826f95bc5d9672f14fcb74692501
7
+ data.tar.gz: 198328e45920aa2794cab2984e090c14c81ce56b4b038e4ae0b7f22ad66d327d0bbd34b5726709108c14609324dba1687a83a2f67026a2d8abf12d749067ca27
@@ -44,6 +44,7 @@ class Puppet::Provider::DscBaseProvider # rubocop:disable Metrics/ClassLength
44
44
  # @param context [Object] the Puppet runtime context to operate in and send feedback to
45
45
  # @param resources [Hash] the hash of the resource to canonicalize from either manifest or invocation
46
46
  # @return [Hash] returns a hash representing the current state of the object, if it exists
47
+ # rubocop:disable Metrics/BlockLength, Metrics/MethodLength
47
48
  def canonicalize(context, resources)
48
49
  canonicalized_resources = []
49
50
  resources.collect do |r|
@@ -83,9 +84,18 @@ class Puppet::Provider::DscBaseProvider # rubocop:disable Metrics/ClassLength
83
84
  downcased_result.each do |key, value|
84
85
  # Canonicalize to the manifest value unless the downcased strings match and the attribute is not an enum:
85
86
  # - 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, prefer the casing of the manifest enum.
87
- # - When the values match case insensitively and the attribute is not an enum, prefer the casing from invoke_get_method
88
- canonicalized[key] = r[key] unless same?(value, downcased_resource[key]) && !enum_attributes(context).include?(key)
87
+ # - When the values match case insensitively but the attribute is an enum, and the casing from invoke_get_method
88
+ # is not int the enum, prefer the casing of the manifest enum.
89
+ # - When the values match case insensitively and the attribute is not an enum, or is an enum and invoke_get_method casing
90
+ # is in the enum, prefer the casing from invoke_get_method
91
+ is_enum = enum_attributes(context).include?(key)
92
+ canonicalized_value_in_enum = if is_enum
93
+ enum_values(context, key).include?(canonicalized[key])
94
+ else
95
+ false
96
+ end
97
+ match_insensitively = same?(value, downcased_resource[key])
98
+ canonicalized[key] = r[key] unless match_insensitively && (canonicalized_value_in_enum || !is_enum)
89
99
  canonicalized.delete(key) unless downcased_resource.key?(key)
90
100
  end
91
101
  # Cache the actually canonicalized resource separately
@@ -104,6 +114,7 @@ class Puppet::Provider::DscBaseProvider # rubocop:disable Metrics/ClassLength
104
114
  context.debug("Canonicalized Resources: #{canonicalized_resources}")
105
115
  canonicalized_resources
106
116
  end
117
+ # rubocop:enable Metrics/BlockLength, Metrics/MethodLength
107
118
 
108
119
  # Attempts to retrieve an instance of the DSC resource, invoking the `Get` method and passing any
109
120
  # namevars as the Properties to Invoke-DscResource. The result object, if any, is compared to the
@@ -299,24 +310,16 @@ class Puppet::Provider::DscBaseProvider # rubocop:disable Metrics/ClassLength
299
310
  # notify and retry
300
311
  context.notice("Retrying: attempt #{try} of #{max_retry_count}.")
301
312
  data = JSON.parse(yield)
302
- # if no error, break
303
- if data['errormessage'].nil?
304
- break
305
- # check if error matches error matcher supplied
306
- elsif data['errormessage'].match?(error_matcher)
307
- # if last attempt, return error
308
- if try == max_retry_count
309
- context.notice("Attempt #{try} of #{max_retry_count} failed. No more retries.")
310
- # all attempts failed, raise error
311
- return context.err(data['errormessage'])
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
313
+ # if no error, assume successful invocation and break
314
+ break if data['errormessage'].nil?
315
+
316
+ # notify of failed retry
317
+ context.notice("Attempt #{try} of #{max_retry_count} failed.")
318
+ # return if error does not match expceted error, or all retries exhausted
319
+ return context.err(data['errormessage']) unless data['errormessage'].match?(error_matcher) && try < max_retry_count
320
+
321
+ # else, retry
322
+ next
320
323
  end
321
324
  data
322
325
  end
@@ -348,7 +351,7 @@ class Puppet::Provider::DscBaseProvider # rubocop:disable Metrics/ClassLength
348
351
  # @param context [Object] the Puppet runtime context to operate in and send feedback to
349
352
  # @param name_hash [Hash] the hash of namevars to be passed as properties to `Invoke-DscResource`
350
353
  # @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)
354
+ def invoke_get_method(context, name_hash) # rubocop:disable Metrics/AbcSize
352
355
  context.debug("retrieving #{name_hash.inspect}")
353
356
 
354
357
  query_props = name_hash.select { |k, v| mandatory_get_attributes(context).include?(k) || (k == :dsc_psdscrunascredential && !v.nil?) }
@@ -391,6 +394,8 @@ class Puppet::Provider::DscBaseProvider # rubocop:disable Metrics/ClassLength
391
394
  # If a resource is found, it's present, so refill this Puppet-only key
392
395
  data[:name] = name_hash[:name]
393
396
 
397
+ data = stringify_nil_attributes(context, data)
398
+
394
399
  # Have to check for this to avoid a weird canonicalization warning
395
400
  # The Resource API calls canonicalize against the current state which
396
401
  # will lead to dsc_ensure being set to absent in the name_hash even if
@@ -660,6 +665,20 @@ class Puppet::Provider::DscBaseProvider # rubocop:disable Metrics/ClassLength
660
665
  context.type.attributes.select { |_attribute, properties| properties[:mandatory_for_set] }.keys
661
666
  end
662
667
 
668
+ # Parses the DSC resource type definition to retrieve the names of any attributes which are specifed as required strings
669
+ # This is used to ensure that any nil values are converted to empty strings to match puppets expecetd value
670
+ # @param context [Object] the Puppet runtime context to operate in and send feedback to
671
+ # @param data [Hash] the hash of properties returned from the DSC resource
672
+ # @return [Hash] returns a data hash with any nil values converted to empty strings
673
+ def stringify_nil_attributes(context, data)
674
+ nil_strings = data.select { |_name, value| value.nil? }.keys
675
+ string_attrs = context.type.attributes.select { |_name, properties| properties[:type] == 'String' }.keys
676
+ string_attrs.each do |attribute|
677
+ data[attribute] = '' if nil_strings.include?(attribute)
678
+ end
679
+ data
680
+ end
681
+
663
682
  # Parses the DSC resource type definition to retrieve the names of any attributes which are specified as namevars
664
683
  #
665
684
  # @param context [Object] the Puppet runtime context to operate in and send feedback to
@@ -686,6 +705,28 @@ class Puppet::Provider::DscBaseProvider # rubocop:disable Metrics/ClassLength
686
705
  context.type.attributes.select { |_name, properties| properties[:type].include?('Enum[') }.keys
687
706
  end
688
707
 
708
+ # Parses the DSC resource type definition to retrieve the values of any attributes which are specified as enums
709
+ #
710
+ # @param context [Object] the Puppet runtime context to operate in and send feedback to
711
+ # @param attribute [String] the enum attribute to retrieve the allowed values from
712
+ # @return [Array] returns an array of attribute names as symbols which are enums
713
+ def enum_values(context, attribute)
714
+ # Get the attribute's type string for the given key
715
+ type_string = context.type.attributes[attribute][:type]
716
+
717
+ # Return an empty array if the key doesn't have an Enum type or doesn't exist
718
+ return [] unless type_string&.include?('Enum[')
719
+
720
+ # Extract the enum values from the type string
721
+ enum_content = type_string.match(/Enum\[(.*?)\]/)&.[](1)
722
+
723
+ # Return an empty array if we couldn't find the enum values
724
+ return [] if enum_content.nil?
725
+
726
+ # Return an array of the enum values, stripped of extra whitespace and quote marks
727
+ enum_content.split(',').map { |val| val.strip.delete('\'') }
728
+ end
729
+
689
730
  # Look through a fully formatted string, replacing all instances where a value matches the formatted properties
690
731
  # of an instantiated variable with references to the variable instead. This allows us to pass complex and nested
691
732
  # CIM instances to the Invoke-DscResource parameter hash without constructing them *in* the hash.
data/lib/pwsh/version.rb CHANGED
@@ -2,5 +2,5 @@
2
2
 
3
3
  module Pwsh
4
4
  # The version of the ruby-pwsh gem
5
- VERSION = '1.1.0'
5
+ VERSION = '1.1.1'
6
6
  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
@@ -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-6] of 5/).exactly(5).times
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-6] of 5 failed/).exactly(5).times
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,6 +829,7 @@ 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
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.1.0
4
+ version: 1.1.1
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-01-31 00:00:00.000000000 Z
11
+ date: 2024-02-21 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: PowerShell code manager for ruby.
14
14
  email: