ruby-pwsh 0.5.0 → 0.6.3
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/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:
|