ruby-pwsh 1.1.0 → 1.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml 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: