ruby-pwsh 0.5.0 → 0.6.3

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: 83a03013a6f1fd8f72b90d29d76f211cf1fbba6f32a8e5275bc7b9ce29d7a52a
4
- data.tar.gz: 8ce907ddb3d833eec4a193ce994e05a990ccc2f20e46518674896efa14bd6328
3
+ metadata.gz: 06ed8290e061a3f294b067867612332e2d48bb2e8d13e54f884d9681ce1f72c3
4
+ data.tar.gz: c5f9507058ff31dda8f97b732adfd9a046580b58f8b04d369f3d6ab98b3fcaf1
5
5
  SHA512:
6
- metadata.gz: 71abf1b0cc94d5f742ae6240d08fff15f86e588157a4a482501f2383ac11e5f3644fb43702af5071720193303fa803debeed362bb20f2efec205b0137acb115e
7
- data.tar.gz: b9c9ce3518e6cbc27c6b0f8126519a1c1ea53158424f72162b75e23ecd28415e80cf5df4e9dc762aadd93a99e30e16a5a91dc405cd9d8571a53184bbe04e4373
6
+ metadata.gz: f0500d503a3faf6f40983b823d00d0acf0f6b72d3f01f651a51755d5a78787143f89950450b241f646b6b756be1d0f95c3f28d2c7bf8edfdc753c44f60892b3f
7
+ data.tar.gz: 2f7834903250dd77a18ffc81120ec1c48ae8a5facc8f32988542abe0e3af5ce8d30a1d1a795c806f7b295eb33a438967ddfa69165ce8bb9a351bf37e6c177abb
@@ -2,6 +2,54 @@
2
2
 
3
3
  All notable changes to this project will be documented in this file.The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](http://semver.org).
4
4
 
5
+ ## [0.6.3](https://github.com/puppetlabs/ruby-pwsh/tree/0.6.3) (2020-12-16)
6
+
7
+ [Full Changelog](https://github.com/puppetlabs/ruby-pwsh/compare/0.6.2...0.6.3)
8
+
9
+ ### Fixed
10
+
11
+ - \(MAINT\) Add handling for when dsc\_ensure is stripped [\#78](https://github.com/puppetlabs/ruby-pwsh/pull/78) ([michaeltlombardi](https://github.com/michaeltlombardi))
12
+
13
+ ## [0.6.2](https://github.com/puppetlabs/ruby-pwsh/tree/0.6.2) (2020-12-09)
14
+
15
+ [Full Changelog](https://github.com/puppetlabs/ruby-pwsh/compare/0.6.1...0.6.2)
16
+
17
+ ### Fixed
18
+
19
+ - \(MAINT\) Ensure parameters are canonicalized [\#75](https://github.com/puppetlabs/ruby-pwsh/pull/75) ([michaeltlombardi](https://github.com/michaeltlombardi))
20
+
21
+ ## [0.6.1](https://github.com/puppetlabs/ruby-pwsh/tree/0.6.1) (2020-11-25)
22
+
23
+ [Full Changelog](https://github.com/puppetlabs/ruby-pwsh/compare/0.6.0...0.6.1)
24
+
25
+ ### Fixed
26
+
27
+ - \(maint\) - Removal of inappropriate terminology [\#70](https://github.com/puppetlabs/ruby-pwsh/pull/70) ([pmcmaw](https://github.com/pmcmaw))
28
+ - \(Maint\) Fix ensurability in the dsc base provider [\#69](https://github.com/puppetlabs/ruby-pwsh/pull/69) ([michaeltlombardi](https://github.com/michaeltlombardi))
29
+
30
+ ## [0.6.0](https://github.com/puppetlabs/ruby-pwsh/tree/0.6.0) (2020-11-24)
31
+
32
+ [Full Changelog](https://github.com/puppetlabs/ruby-pwsh/compare/0.5.1...0.6.0)
33
+
34
+ ### Added
35
+
36
+ - \(GH-81\) Handle parameters in the dsc base provider [\#62](https://github.com/puppetlabs/ruby-pwsh/pull/62) ([michaeltlombardi](https://github.com/michaeltlombardi))
37
+ - \(GH-74\) Remove special handling for ensure in the dsc base provider [\#61](https://github.com/puppetlabs/ruby-pwsh/pull/61) ([michaeltlombardi](https://github.com/michaeltlombardi))
38
+ - \(GH-59\) Refactor away from Simple Provider [\#60](https://github.com/puppetlabs/ruby-pwsh/pull/60) ([michaeltlombardi](https://github.com/michaeltlombardi))
39
+
40
+ ### Fixed
41
+
42
+ - \(GH-57\) Handle datetimes in dsc [\#58](https://github.com/puppetlabs/ruby-pwsh/pull/58) ([michaeltlombardi](https://github.com/michaeltlombardi))
43
+ - \(GH-55\) Handle intentionally empty arrays [\#56](https://github.com/puppetlabs/ruby-pwsh/pull/56) ([michaeltlombardi](https://github.com/michaeltlombardi))
44
+
45
+ ## [0.5.1](https://github.com/puppetlabs/ruby-pwsh/tree/0.5.1) (2020-09-25)
46
+
47
+ [Full Changelog](https://github.com/puppetlabs/ruby-pwsh/compare/0.5.0...0.5.1)
48
+
49
+ ### Fixed
50
+
51
+ - \(MAINT\) Ensure dsc provider finds dsc resources during agent run [\#45](https://github.com/puppetlabs/ruby-pwsh/pull/45) ([michaeltlombardi](https://github.com/michaeltlombardi))
52
+
5
53
  ## [0.5.0](https://github.com/puppetlabs/ruby-pwsh/tree/0.5.0) (2020-08-20)
6
54
 
7
55
  [Full Changelog](https://github.com/puppetlabs/ruby-pwsh/compare/0.4.1...0.5.0)
@@ -22,10 +70,6 @@ All notable changes to this project will be documented in this file.The format i
22
70
 
23
71
  [Full Changelog](https://github.com/puppetlabs/ruby-pwsh/compare/0.3.0...0.4.0)
24
72
 
25
- ### Added
26
-
27
- - \(MODULES-10389\) Add puppet feature for dependent modules to leverage [\#20](https://github.com/puppetlabs/ruby-pwsh/pull/20) ([sanfrancrisko](https://github.com/sanfrancrisko))
28
-
29
73
  ## [0.3.0](https://github.com/puppetlabs/ruby-pwsh/tree/0.3.0) (2019-12-04)
30
74
 
31
75
  [Full Changelog](https://github.com/puppetlabs/ruby-pwsh/compare/0.2.0...0.3.0)
@@ -79,7 +79,7 @@ process as easy as possible.
79
79
 
80
80
  2. Sending your patches
81
81
 
82
- To submit your changes via a GitHub pull request, we _highly_ recommend that you have them on a topic branch, instead of directly on "master".
82
+ To submit your changes via a GitHub pull request, we _highly_ recommend that you have them on a topic branch, instead of directly on "main".
83
83
  It makes things much easier to keep track of, especially if you decide to work on another thing before your first change is merged in.
84
84
 
85
85
  GitHub has some pretty good [general documentation](http://help.github.com/) on using their site.
data/README.md CHANGED
@@ -74,9 +74,9 @@ To install this gem onto your local machine, run `bundle exec rake install`. To
74
74
 
75
75
  Steps to release an update to the gem and module include:
76
76
 
77
- 1. Ensure that the release branch is up to date with the master:
77
+ 1. Ensure that the release branch is up to date with the main:
78
78
  ```bash
79
- git push upstream upstream/master:release --force
79
+ git push upstream upstream/main:release --force
80
80
  ```
81
81
  1. Checkout a new working branch for the release prep (where xyz is the appropriate version, sans periods):
82
82
  ```bash
@@ -96,7 +96,7 @@ Steps to release an update to the gem and module include:
96
96
  ```
97
97
  1. Push your changes and submit a pull request for review _against the **release** branch_:
98
98
  ```bash
99
- git push -u origin maint/release-prep-xyz
99
+ git push -u origin maint/release/prep-xyz
100
100
  ```
101
101
  1. Ensure tests pass and the code is merged to `release`.
102
102
  1. Grab the commit hash from the merge commit on release, use that as the tag for the version (replacing `x.y.z` with the appropriate version and `commithash` with the relevant one), then push the tags to upstream:
@@ -114,6 +114,6 @@ Steps to release an update to the gem and module include:
114
114
  bundle exec rake build_module
115
115
  ```
116
116
  1. Publish the updated module version (found in the `pkg` folder) to [the Forge](https://forge.puppet.com/puppetlabs/pwshlib).
117
- 1. Submit the [mergeback PR from the release branch to master](https://github.com/puppetlabs/ruby-pwsh/compare/master...release).
117
+ 1. Submit the [mergeback PR from the release branch to main](https://github.com/puppetlabs/ruby-pwsh/compare/main...release).
118
118
 
119
119
  ## Known Issues
@@ -2,7 +2,7 @@
2
2
  version: 1.1.x.{build}
3
3
  branches:
4
4
  only:
5
- - master
5
+ - main
6
6
  - release
7
7
  clone_depth: 10
8
8
  environment:
@@ -1,12 +1,11 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'puppet/resource_api/simple_provider'
4
3
  require 'securerandom'
5
4
  require 'ruby-pwsh'
6
5
  require 'pathname'
7
6
  require 'json'
8
7
 
9
- class Puppet::Provider::DscBaseProvider < Puppet::ResourceApi::SimpleProvider
8
+ class Puppet::Provider::DscBaseProvider
10
9
  # Initializes the provider, preparing the class variables which cache:
11
10
  # - the canonicalized resources across calls
12
11
  # - query results
@@ -15,6 +14,7 @@ class Puppet::Provider::DscBaseProvider < Puppet::ResourceApi::SimpleProvider
15
14
  @@cached_canonicalized_resource = []
16
15
  @@cached_query_results = []
17
16
  @@logon_failures = []
17
+ super
18
18
  end
19
19
 
20
20
  # Look through a cache to retrieve the hashes specified, if they have been cached.
@@ -50,6 +50,8 @@ class Puppet::Provider::DscBaseProvider < Puppet::ResourceApi::SimpleProvider
50
50
  canonicalized = r.dup
51
51
  @@cached_canonicalized_resource << r.dup
52
52
  else
53
+ parameters = r.select { |name, _properties| parameter_attributes(context).include?(name) }
54
+ canonicalized.merge!(parameters)
53
55
  canonicalized[:name] = r[:name]
54
56
  if r[:dsc_psdscrunascredential].nil?
55
57
  canonicalized.delete(:dsc_psdscrunascredential)
@@ -109,6 +111,78 @@ class Puppet::Provider::DscBaseProvider < Puppet::ResourceApi::SimpleProvider
109
111
  end
110
112
  end
111
113
 
114
+ # Determines whether a resource is ensurable and which message to write (create, update, or delete),
115
+ # then passes the appropriate values along to the various sub-methods which themselves call the Set
116
+ # method of Invoke-DscResource. Implementation borrowed directly from the Resource API Simple Provider
117
+ #
118
+ # @param context [Object] the Puppet runtime context to operate in and send feedback to
119
+ # @param changes [Hash] the hash of whose key is the name_hash and value is the is and should hashes
120
+ def set(context, changes)
121
+ changes.each do |name, change|
122
+ is = change.key?(:is) ? change[:is] : (get(context, [name]) || []).find { |r| r[:name] == name }
123
+ context.type.check_schema(is) unless change.key?(:is)
124
+
125
+ should = change[:should]
126
+
127
+ name_hash = if context.type.namevars.length > 1
128
+ # pass a name_hash containing the values of all namevars
129
+ name_hash = {}
130
+ context.type.namevars.each do |namevar|
131
+ name_hash[namevar] = change[:should][namevar]
132
+ end
133
+ name_hash
134
+ else
135
+ name
136
+ end
137
+
138
+ # for compatibility sake, we use dsc_ensure instead of ensure, so context.type.ensurable? does not work
139
+ if context.type.attributes.key?(:dsc_ensure)
140
+ is = create_absent(:name, name) if is.nil?
141
+ should = create_absent(:name, name) if should.nil?
142
+
143
+ # HACK: If the DSC Resource is ensurable but doesn't report a default value
144
+ # for ensure, we assume it to be `Present` - this is the most common pattern.
145
+ should_ensure = should[:dsc_ensure].nil? ? 'Present' : should[:dsc_ensure].to_s
146
+ # HACK: Sometimes dsc_ensure is removed???? If it's gone, pretend it's absent??
147
+ is_ensure = is[:dsc_ensure].nil? ? 'Absent' : is[:dsc_ensure].to_s
148
+
149
+ if is_ensure == 'Absent' && should_ensure == 'Present'
150
+ context.creating(name) do
151
+ create(context, name_hash, should)
152
+ end
153
+ elsif is_ensure == 'Present' && should_ensure == 'Present'
154
+ context.updating(name) do
155
+ update(context, name_hash, should)
156
+ end
157
+ elsif is_ensure == 'Present' && should_ensure == 'Absent'
158
+ context.deleting(name) do
159
+ delete(context, name_hash)
160
+ end
161
+ end
162
+ else
163
+ context.updating(name) do
164
+ update(context, name_hash, should)
165
+ end
166
+ end
167
+ end
168
+ end
169
+
170
+ # Creates a hash with the name / name_hash and sets dsc_ensure to absent for comparison
171
+ # purposes; this handles cases where the resource isn't found on the node.
172
+ #
173
+ # @param namevar [Object] the name of the variable being used for the resource name
174
+ # @param title [Hash] the hash of namevar properties and their values
175
+ # @return [Hash] returns a hash representing the absent state of the resource
176
+ def create_absent(namevar, title)
177
+ result = if title.is_a? Hash
178
+ title.dup
179
+ else
180
+ { namevar => title }
181
+ end
182
+ result[:dsc_ensure] = 'Absent'
183
+ result
184
+ end
185
+
112
186
  # Attempts to set an instance of the DSC resource, invoking the `Set` method and thinly wrapping
113
187
  # the `invoke_set_method` method; whether this method, `update`, or `delete` is called is entirely
114
188
  # up to the Resource API based on the results
@@ -158,9 +232,7 @@ class Puppet::Provider::DscBaseProvider < Puppet::ResourceApi::SimpleProvider
158
232
  context.debug("retrieving #{name_hash.inspect}")
159
233
 
160
234
  # Do not bother running if the logon credentials won't work
161
- unless name_hash[:dsc_psdscrunascredential].nil?
162
- return name_hash if logon_failed_already?(name_hash[:dsc_psdscrunascredential])
163
- end
235
+ return name_hash if !name_hash[:dsc_psdscrunascredential].nil? && logon_failed_already?(name_hash[:dsc_psdscrunascredential])
164
236
 
165
237
  query_props = name_hash.select { |k, v| mandatory_get_attributes(context).include?(k) || (k == :dsc_psdscrunascredential && !v.nil?) }
166
238
  resource = should_to_resource(query_props, context, 'get')
@@ -190,28 +262,36 @@ class Puppet::Provider::DscBaseProvider < Puppet::ResourceApi::SimpleProvider
190
262
  # DSC gives back information we don't care about; filter down to only
191
263
  # those properties exposed in the type definition.
192
264
  valid_attributes = context.type.attributes.keys.collect(&:to_s)
265
+ parameters = context.type.attributes.select { |_name, properties| [properties[:behaviour]].collect.include?(:parameter) }.keys.collect(&:to_s)
193
266
  data.select! { |key, _value| valid_attributes.include?("dsc_#{key.downcase}") }
267
+ data.reject! { |key, _value| parameters.include?("dsc_#{key.downcase}") }
194
268
  # Canonicalize the results to match the type definition representation;
195
269
  # failure to do so will prevent the resource_api from comparing the result
196
270
  # to the should hash retrieved from the resource definition in the manifest.
197
- data.keys.each do |key|
271
+ data.keys.each do |key| # rubocop:disable Style/HashEachMethods
198
272
  type_key = "dsc_#{key.downcase}".to_sym
199
273
  data[type_key] = data.delete(key)
200
274
  camelcase_hash_keys!(data[type_key]) if data[type_key].is_a?(Enumerable)
275
+ # Convert DateTime back to appropriate type
276
+ data[type_key] = Puppet::Pops::Time::Timestamp.parse(data[type_key]) if context.type.attributes[type_key][:mof_type] =~ /DateTime/i
277
+ # PowerShell does not distinguish between a return of empty array/string
278
+ # and null but Puppet does; revert to those values if specified.
279
+ if data[type_key].nil? && query_props.keys.include?(type_key) && query_props[type_key].is_a?(Array)
280
+ data[type_key] = query_props[type_key].empty? ? query_props[type_key] : []
281
+ end
201
282
  end
202
- # If a resource is found, it's present, so refill these two Puppet-only keys
283
+ # If a resource is found, it's present, so refill this Puppet-only key
203
284
  data.merge!({ name: name_hash[:name] })
204
- if ensurable?(context)
205
- ensure_value = data.key?(:dsc_ensure) ? data[:dsc_ensure].downcase : 'present'
206
- data.merge!({ ensure: ensure_value })
207
- end
208
- # TODO: Handle PSDscRunAsCredential flapping
209
- # Resources do not return the account under which they were discovered, so re-add that
210
- if name_hash[:dsc_psdscrunascredential].nil?
211
- data.delete(:dsc_psdscrunascredential)
212
- else
213
- data.merge!({ dsc_psdscrunascredential: name_hash[:dsc_psdscrunascredential] })
214
- end
285
+
286
+ # Have to check for this to avoid a weird canonicalization warning
287
+ # The Resource API calls canonicalize against the current state which
288
+ # will lead to dsc_ensure being set to absent in the name_hash even if
289
+ # it was set to present in the manifest
290
+ name_hash_has_nil_keys = name_hash.select { |_k, v| v.nil? }.count.positive?
291
+ # We want to throw away all of the empty keys if and only if the manifest
292
+ # declaration is for an absent resource and the resource is actually absent
293
+ data.reject! { |_k, v| v.nil? } if data[:dsc_ensure] == 'Absent' && name_hash[:dsc_ensure] == 'Absent' && !name_hash_has_nil_keys
294
+
215
295
  # Cache the query to prevent a second lookup
216
296
  @@cached_query_results << data.dup if fetch_cached_hashes(@@cached_query_results, [data]).empty?
217
297
  context.debug("Returned to Puppet as #{data}")
@@ -229,9 +309,7 @@ class Puppet::Provider::DscBaseProvider < Puppet::ResourceApi::SimpleProvider
229
309
  context.debug("Invoking Set Method for '#{name}' with #{should.inspect}")
230
310
 
231
311
  # Do not bother running if the logon credentials won't work
232
- unless should[:dsc_psdscrunascredential].nil?
233
- return nil if logon_failed_already?(should[:dsc_psdscrunascredential])
234
- end
312
+ return nil if !should[:dsc_psdscrunascredential].nil? && logon_failed_already?(should[:dsc_psdscrunascredential])
235
313
 
236
314
  apply_props = should.select { |k, _v| k.to_s =~ /^dsc_/ }
237
315
  resource = should_to_resource(apply_props, context, 'set')
@@ -265,7 +343,6 @@ class Puppet::Provider::DscBaseProvider < Puppet::ResourceApi::SimpleProvider
265
343
  resource[k] = context.type.definition[k]
266
344
  end
267
345
  should.each do |k, v|
268
- next if k == :ensure
269
346
  # PSDscRunAsCredential is considered a namevar and will always be passed, even if nil
270
347
  # To prevent flapping during runs, remove it from the resource definition unless specified
271
348
  next if k == :dsc_psdscrunascredential && v.nil?
@@ -278,11 +355,15 @@ class Puppet::Provider::DscBaseProvider < Puppet::ResourceApi::SimpleProvider
278
355
  end
279
356
  resource[:dsc_invoke_method] = dsc_invoke_method
280
357
 
281
- # Because Puppet adds all of the modules to the LOAD_PATH we can be sure that the appropriate module lives here
358
+ # Because Puppet adds all of the modules to the LOAD_PATH we can be sure that the appropriate module lives here during an apply;
282
359
  # PROBLEM: This currently uses the downcased name, we need to capture the module name in the metadata I think.
360
+ # During a Puppet agent run, the code lives in the cache so we can use the file expansion to discover the correct folder.
283
361
  root_module_path = $LOAD_PATH.select { |path| path.match?(%r{#{resource[:dscmeta_module_name].downcase}/lib}) }.first
284
- resource[:vendored_modules_path] = File.expand_path(root_module_path + '/puppet_x/dsc_resources')
285
- # resource[:vendored_modules_path] = File.expand_path(Pathname.new(__FILE__).dirname + '../../../' + 'puppet_x/dsc_resources')
362
+ resource[:vendored_modules_path] = if root_module_path.nil?
363
+ File.expand_path(Pathname.new(__FILE__).dirname + '../../../' + 'puppet_x/dsc_resources') # rubocop:disable Style/StringConcatenation
364
+ else
365
+ File.expand_path("#{root_module_path}/puppet_x/dsc_resources")
366
+ end
286
367
  resource[:attributes] = nil
287
368
  context.debug("should_to_resource: #{resource.inspect}")
288
369
  resource
@@ -327,7 +408,7 @@ class Puppet::Provider::DscBaseProvider < Puppet::ResourceApi::SimpleProvider
327
408
  # @return [Enumerable] returns the input object with hash keys recursively camelCased
328
409
  def camelcase_hash_keys!(enumerable)
329
410
  if enumerable.is_a?(Hash)
330
- enumerable.keys.each do |key|
411
+ enumerable.keys.each do |key| # rubocop:disable Style/HashEachMethods
331
412
  name = key.dup
332
413
  name[0] = name[0].downcase
333
414
  enumerable[name] = enumerable.delete(key)
@@ -359,14 +440,6 @@ class Puppet::Provider::DscBaseProvider < Puppet::ResourceApi::SimpleProvider
359
440
  end
360
441
  end
361
442
 
362
- # Checks to see whether the DSC resource being managed is defined as ensurable
363
- #
364
- # @param context [Object] the Puppet runtime context to operate in and send feedback to
365
- # @return [Bool] returns true if the DSC Resource is ensurable, otherwise false.
366
- def ensurable?(context)
367
- context.type.attributes.keys.include?(:ensure)
368
- end
369
-
370
443
  # Parses the DSC resource type definition to retrieve the names of any attributes which are specified as mandatory for get operations
371
444
  #
372
445
  # @param context [Object] the Puppet runtime context to operate in and send feedback to
@@ -391,6 +464,14 @@ class Puppet::Provider::DscBaseProvider < Puppet::ResourceApi::SimpleProvider
391
464
  context.type.attributes.select { |_attribute, properties| properties[:behaviour] == :namevar }.keys
392
465
  end
393
466
 
467
+ # Parses the DSC resource type definition to retrieve the names of any attributes which are specified as parameters
468
+ #
469
+ # @param context [Object] the Puppet runtime context to operate in and send feedback to
470
+ # @return [Array] returns an array of attribute names as symbols which are parameters
471
+ def parameter_attributes(context)
472
+ context.type.attributes.select { |_name, properties| properties[:behaviour] == :parameter }.keys
473
+ end
474
+
394
475
  # Look through a fully formatted string, replacing all instances where a value matches the formatted properties
395
476
  # of an instantiated variable with references to the variable instead. This allows us to pass complex and nested
396
477
  # CIM instances to the Invoke-DscResource parameter hash without constructing them *in* the hash.
@@ -437,8 +518,7 @@ class Puppet::Provider::DscBaseProvider < Puppet::ResourceApi::SimpleProvider
437
518
  # @param credential_hash [Hash] the Properties which define the PSCredential Object
438
519
  # @return [String] A line of PowerShell which defines the PSCredential object and stores it to a variable
439
520
  def format_pscredential(variable_name, credential_hash)
440
- definition = "$#{variable_name} = New-PSCredential -User #{credential_hash['user']} -Password '#{credential_hash['password']}' # PuppetSensitive"
441
- definition
521
+ "$#{variable_name} = New-PSCredential -User #{credential_hash['user']} -Password '#{credential_hash['password']}' # PuppetSensitive"
442
522
  end
443
523
 
444
524
  # Parses a resource definition (as from `should_to_resource`) for any properties which are CIM instances
@@ -518,8 +598,7 @@ class Puppet::Provider::DscBaseProvider < Puppet::ResourceApi::SimpleProvider
518
598
  # EVEN WORSE HACK - this one we can't even be sure it's a cim instance...
519
599
  # but I don't _think_ anything but nested cim instances show up as hashes inside an array
520
600
  definition = definition.gsub('@(@{', '[CimInstance[]]@(@{')
521
- definition = interpolate_variables(definition)
522
- definition
601
+ interpolate_variables(definition)
523
602
  end
524
603
 
525
604
  # Munge a resource definition (as from `should_to_resource`) into valid PowerShell which represents
@@ -544,18 +623,32 @@ class Puppet::Provider::DscBaseProvider < Puppet::ResourceApi::SimpleProvider
544
623
  resource[:parameters].each do |property_name, property_hash|
545
624
  # strip dsc_ from the beginning of the property name declaration
546
625
  name = property_name.to_s.gsub(/^dsc_/, '').to_sym
547
- params[:Property][name] = if property_hash[:mof_type] == 'PSCredential'
626
+ params[:Property][name] = case property_hash[:mof_type]
627
+ when 'PSCredential'
548
628
  # format can't unwrap Sensitive strings nested in arbitrary hashes/etc, so make
549
629
  # the Credential hash interpolable as it will be replaced by a variable reference.
550
630
  {
551
631
  'user' => property_hash[:value]['user'],
552
632
  'password' => escape_quotes(property_hash[:value]['password'].unwrap)
553
633
  }
634
+ when 'DateTime'
635
+ # These have to be handled specifically because they rely on the *Puppet* DateTime,
636
+ # not a generic ruby data type (and so can't go in the shared util in ruby-pwsh)
637
+ "[DateTime]#{property_hash[:value].format('%FT%T%z')}"
554
638
  else
555
639
  property_hash[:value]
556
640
  end
557
641
  end
558
642
  params_block = interpolate_variables("$InvokeParams = #{format(params)}")
643
+ # Move the Apostrophe for DateTime declarations
644
+ params_block = params_block.gsub("'[DateTime]", "[DateTime]'")
645
+ # HACK: Handle intentionally empty arrays - need to strongly type them because
646
+ # CIM instances do not do a consistent job of casting an empty array properly.
647
+ empty_array_parameters = resource[:parameters].select { |_k, v| v[:value].empty? }
648
+ empty_array_parameters.each do |name, properties|
649
+ param_block_name = name.to_s.gsub(/^dsc_/, '')
650
+ params_block = params_block.gsub("#{param_block_name} = @()", "#{param_block_name} = [#{properties[:mof_type]}]@()")
651
+ end
559
652
  # HACK: make CIM instances work:
560
653
  resource[:parameters].select { |_key, hash| hash[:mof_is_embedded] && hash[:mof_type] =~ /\[\]/ }.each do |_property_name, property_hash|
561
654
  formatted_property_hash = interpolate_variables(format(property_hash[:value]))
@@ -573,11 +666,11 @@ class Puppet::Provider::DscBaseProvider < Puppet::ResourceApi::SimpleProvider
573
666
  def ps_script_content(resource)
574
667
  template_path = File.expand_path('../', __FILE__)
575
668
  # Defines the helper functions
576
- functions = File.new(template_path + '/invoke_dsc_resource_functions.ps1').read
669
+ functions = File.new("#{template_path}/invoke_dsc_resource_functions.ps1").read
577
670
  # Defines the response hash and the runtime settings
578
- preamble = File.new(template_path + '/invoke_dsc_resource_preamble.ps1').read
671
+ preamble = File.new("#{template_path}/invoke_dsc_resource_preamble.ps1").read
579
672
  # The postscript defines the invocation error and result handling; expects `$InvokeParams` to be defined
580
- postscript = File.new(template_path + '/invoke_dsc_resource_postscript.ps1').read
673
+ postscript = File.new("#{template_path}/invoke_dsc_resource_postscript.ps1").read
581
674
  # The blocks define the variables to define for the postscript.
582
675
  credential_block = prepare_credentials(resource)
583
676
  cim_instances_block = prepare_cim_instances(resource)
@@ -585,8 +678,7 @@ class Puppet::Provider::DscBaseProvider < Puppet::ResourceApi::SimpleProvider
585
678
  # clean them out of the temporary cache now that they're not needed; failure to do so can goof up future executions in this run
586
679
  clear_instantiated_variables!
587
680
 
588
- content = [functions, preamble, credential_block, cim_instances_block, parameters_block, postscript].join("\n")
589
- content
681
+ [functions, preamble, credential_block, cim_instances_block, parameters_block, postscript].join("\n")
590
682
  end
591
683
 
592
684
  # Convert a Puppet/Ruby value into a PowerShell representation. Requires some slight additional
@@ -610,15 +702,16 @@ class Puppet::Provider::DscBaseProvider < Puppet::ResourceApi::SimpleProvider
610
702
  # @param value [Object] The object to unwrap sensitive data inside of
611
703
  # @return [Object] The object with any sensitive strings unwrapped and annotated
612
704
  def unwrap(value)
613
- if value.class.name == 'Puppet::Pops::Types::PSensitiveType::Sensitive'
705
+ case value
706
+ when Puppet::Pops::Types::PSensitiveType::Sensitive
614
707
  "#{value.unwrap}#PuppetSensitive"
615
- elsif value.class.name == 'Hash'
708
+ when Hash
616
709
  unwrapped = {}
617
710
  value.each do |k, v|
618
711
  unwrapped[k] = unwrap(v)
619
712
  end
620
713
  unwrapped
621
- elsif value.class.name == 'Array'
714
+ when Array
622
715
  unwrapped = []
623
716
  value.each do |v|
624
717
  unwrapped << unwrap(v)
@@ -68,6 +68,10 @@ Function ConvertTo-CanonicalResult {
68
68
  $Value = $null
69
69
  }
70
70
  }
71
+ elseif ($Result.$PropertyName.GetType().Name -match 'DateTime') {
72
+ # Handle DateTimes especially since they're an edge case
73
+ $Value = Get-Date $Result.$PropertyName -UFormat "%Y-%m-%dT%H:%M:%S%Z"
74
+ }
71
75
  else {
72
76
  # Looks like a nested CIM instance, recurse if we're not too deep in already.
73
77
  $RecursionLevel++
@@ -14,10 +14,10 @@ require 'logger'
14
14
  module Pwsh
15
15
  # Standard errors
16
16
  class Error < StandardError; end
17
+
17
18
  # Create an instance of a PowerShell host and manage execution of PowerShell code inside that host.
18
19
  class Manager
19
- attr_reader :powershell_command
20
- attr_reader :powershell_arguments
20
+ attr_reader :powershell_command, :powershell_arguments
21
21
 
22
22
  # We actually want this to be a class variable.
23
23
  @@instances = {} # rubocop:disable Style/ClassVars
@@ -70,7 +70,7 @@ module Pwsh
70
70
  def self.win32console_enabled?
71
71
  @win32console_enabled ||= defined?(Win32) &&
72
72
  defined?(Win32::Console) &&
73
- Win32::Console.class == Class
73
+ Win32::Console.instance_of?(Class)
74
74
  end
75
75
 
76
76
  # TODO: This thing isn't called anywhere and the variable it sets is never referenced...
@@ -117,16 +117,16 @@ module Pwsh
117
117
  #
118
118
  # @return [String] representation of the value for interpolation
119
119
  def format_powershell_value(object)
120
- if %i[true false].include?(object) || %w[trueclass falseclass].include?(object.class.name.downcase) # rubocop:disable Lint/BooleanSymbol
120
+ if %i[true false].include?(object) || %w[trueclass falseclass].include?(object.class.name.downcase)
121
121
  "$#{object}"
122
- elsif object.class.name == 'Symbol' || object.class.ancestors.include?(Numeric)
122
+ elsif object.instance_of?(Symbol) || object.class.ancestors.include?(Numeric)
123
123
  object.to_s
124
- elsif object.class.name == 'String'
124
+ elsif object.instance_of?(String)
125
125
  "'#{escape_quotes(object)}'"
126
- elsif object.class.name == 'Array'
127
- '@(' + object.collect { |item| format_powershell_value(item) }.join(', ') + ')'
128
- elsif object.class.name == 'Hash'
129
- '@{' + object.collect { |k, v| format_powershell_value(k) + ' = ' + format_powershell_value(v) }.join('; ') + '}'
126
+ elsif object.instance_of?(Array)
127
+ "@(#{object.collect { |item| format_powershell_value(item) }.join(', ')})"
128
+ elsif object.instance_of?(Hash)
129
+ "@{#{object.collect { |k, v| "#{format_powershell_value(k)} = #{format_powershell_value(v)}" }.join('; ')}}"
130
130
  else
131
131
  raise "unsupported type #{object.class} of value '#{object}'"
132
132
  end
@@ -2,5 +2,5 @@
2
2
 
3
3
  module Pwsh
4
4
  # The version of the ruby-pwsh gem
5
- VERSION = '0.5.0'
5
+ VERSION = '0.6.3'
6
6
  end
@@ -1,11 +1,11 @@
1
1
  {
2
2
  "name": "puppetlabs-pwshlib",
3
- "version": "0.4.1",
3
+ "version": "0.6.3",
4
4
  "author": "puppetlabs",
5
5
  "summary": "Provide library code for interoperating with PowerShell.",
6
6
  "license": "MIT",
7
7
  "source": "https://github.com/puppetlabs/ruby-pwsh",
8
- "project_page": "https://github.com/puppetlabs/ruby-pwsh/blob/master/pwshlib.md",
8
+ "project_page": "https://github.com/puppetlabs/ruby-pwsh/blob/main/pwshlib.md",
9
9
  "issues_url": "https://github.com/puppetlabs/ruby-pwsh/issues",
10
10
  "dependencies": [
11
11
 
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: 0.5.0
4
+ version: 0.6.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Puppet, Inc.
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-08-20 00:00:00.000000000 Z
11
+ date: 2020-12-16 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: PowerShell code manager for ruby.
14
14
  email: