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 +4 -4
- data/CHANGELOG.md +48 -4
- data/CONTRIBUTING.md +1 -1
- data/README.md +4 -4
- data/appveyor.yml +1 -1
- data/lib/puppet/provider/dsc_base_provider/dsc_base_provider.rb +140 -47
- data/lib/puppet/provider/dsc_base_provider/invoke_dsc_resource_functions.ps1 +4 -0
- data/lib/pwsh.rb +3 -3
- data/lib/pwsh/util.rb +7 -7
- data/lib/pwsh/version.rb +1 -1
- data/metadata.json +2 -2
- 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: 06ed8290e061a3f294b067867612332e2d48bb2e8d13e54f884d9681ce1f72c3
|
4
|
+
data.tar.gz: c5f9507058ff31dda8f97b732adfd9a046580b58f8b04d369f3d6ab98b3fcaf1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f0500d503a3faf6f40983b823d00d0acf0f6b72d3f01f651a51755d5a78787143f89950450b241f646b6b756be1d0f95c3f28d2c7bf8edfdc753c44f60892b3f
|
7
|
+
data.tar.gz: 2f7834903250dd77a18ffc81120ec1c48ae8a5facc8f32988542abe0e3af5ce8d30a1d1a795c806f7b295eb33a438967ddfa69165ce8bb9a351bf37e6c177abb
|
data/CHANGELOG.md
CHANGED
@@ -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)
|
data/CONTRIBUTING.md
CHANGED
@@ -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 "
|
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
|
77
|
+
1. Ensure that the release branch is up to date with the main:
|
78
78
|
```bash
|
79
|
-
git push upstream upstream/
|
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
|
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
|
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
|
data/appveyor.yml
CHANGED
@@ -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
|
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
|
-
|
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
|
283
|
+
# If a resource is found, it's present, so refill this Puppet-only key
|
203
284
|
data.merge!({ name: name_hash[:name] })
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
#
|
209
|
-
|
210
|
-
if
|
211
|
-
|
212
|
-
|
213
|
-
|
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
|
-
|
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] =
|
285
|
-
|
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
|
-
|
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
|
-
|
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] =
|
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
|
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
|
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
|
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
|
-
|
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
|
-
|
705
|
+
case value
|
706
|
+
when Puppet::Pops::Types::PSensitiveType::Sensitive
|
614
707
|
"#{value.unwrap}#PuppetSensitive"
|
615
|
-
|
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
|
-
|
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++
|
data/lib/pwsh.rb
CHANGED
@@ -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.
|
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...
|
data/lib/pwsh/util.rb
CHANGED
@@ -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)
|
120
|
+
if %i[true false].include?(object) || %w[trueclass falseclass].include?(object.class.name.downcase)
|
121
121
|
"$#{object}"
|
122
|
-
elsif object.
|
122
|
+
elsif object.instance_of?(Symbol) || object.class.ancestors.include?(Numeric)
|
123
123
|
object.to_s
|
124
|
-
elsif object.
|
124
|
+
elsif object.instance_of?(String)
|
125
125
|
"'#{escape_quotes(object)}'"
|
126
|
-
elsif object.
|
127
|
-
|
128
|
-
elsif object.
|
129
|
-
|
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
|
data/lib/pwsh/version.rb
CHANGED
data/metadata.json
CHANGED
@@ -1,11 +1,11 @@
|
|
1
1
|
{
|
2
2
|
"name": "puppetlabs-pwshlib",
|
3
|
-
"version": "0.
|
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/
|
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.
|
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-
|
11
|
+
date: 2020-12-16 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: PowerShell code manager for ruby.
|
14
14
|
email:
|