ruby-pwsh 0.10.1 → 0.10.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +29 -25
- data/lib/puppet/provider/dsc_base_provider/dsc_base_provider.rb +3 -0
- data/lib/pwsh/version.rb +1 -1
- data/lib/pwsh.rb +1 -1
- data/lib/templates/init.ps1 +11 -1
- data/spec/acceptance/dsc/basic.rb +205 -0
- data/spec/acceptance/dsc/cim_instances.rb +82 -0
- data/spec/acceptance/dsc/class.rb +129 -0
- data/spec/acceptance/dsc/complex.rb +139 -0
- data/spec/exit-27.ps1 +1 -0
- data/spec/spec_helper.rb +16 -0
- data/spec/unit/puppet/provider/dsc_base_provider/dsc_base_provider_spec.rb +2026 -0
- data/spec/unit/pwsh/util_spec.rb +286 -0
- data/spec/unit/pwsh/version_spec.rb +10 -0
- data/spec/unit/pwsh/windows_powershell_spec.rb +116 -0
- data/spec/unit/pwsh_spec.rb +823 -0
- metadata +17 -22
- data/.gitattributes +0 -2
- data/.github/workflows/ci.yml +0 -109
- data/.gitignore +0 -23
- data/.pmtignore +0 -21
- data/.rspec +0 -3
- data/CHANGELOG.md +0 -196
- data/CODEOWNERS +0 -2
- data/CONTRIBUTING.md +0 -155
- data/DESIGN.md +0 -70
- data/Gemfile +0 -54
- data/LICENSE.txt +0 -21
- data/Rakefile +0 -188
- data/design-comms.png +0 -0
- data/metadata.json +0 -82
- data/pwshlib.md +0 -92
- data/ruby-pwsh.gemspec +0 -39
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: adc4879de83f4b7756c10664ab59c44ab3b34e93e848ebedcefb049c969137f8
|
4
|
+
data.tar.gz: 7ffc7b8c36775a252075fe3c0bffbb60c8b2e287bcbec65d61c1594f6ff4522a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 638fb1d09d7c0ec4fe29ee0473dba74cdbf2aa142a730eed6c43b0e472ec2f3a7452a87e18ff8c36a4dd95f0897ec8388d30357406481aea8772d409087183b7
|
7
|
+
data.tar.gz: d5de2cb597e68c7c911b36c1cd92cbfc50a13916570f744bc8674b138ed62c30cc728ac2dba8f50a2856e6915ceb48ceede851c6f11a91cf8cca1af2d6cdfe9c
|
data/README.md
CHANGED
@@ -74,47 +74,51 @@ 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.
|
77
|
+
1. From main, checkout a new working branch for the release prep (where xyz is the appropriate version, sans periods):
|
78
78
|
```bash
|
79
|
-
git
|
79
|
+
git checkout -b maint-release_prep_xyz
|
80
80
|
```
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
1. Update the version in `lib/pwsh/version.rb` and `metadata.json` to the appropriate version for the new release.
|
86
|
-
1. Run the changelog update task (make sure to verify the changelog, correctly tagging PRs as needed):
|
81
|
+
|
82
|
+
2. Update the version in `lib/pwsh/version.rb` and `metadata.json` to the appropriate version for the new release.
|
83
|
+
|
84
|
+
3. Run the changelog update task (make sure to verify the changelog, correctly tagging PRs as needed):
|
87
85
|
```bash
|
88
86
|
bundle exec rake changelog
|
89
87
|
```
|
90
|
-
|
91
|
-
|
88
|
+
|
89
|
+
4. Commit your changes with a short, sensible commit message, like:
|
90
|
+
```bash
|
92
91
|
git add lib/pwsh/version.rb
|
93
92
|
git add metadata.json
|
94
93
|
git add CHANGELOG.md
|
95
94
|
git commit -m '(MAINT) Prep for x.y.z release'
|
96
95
|
```
|
97
|
-
|
98
|
-
|
99
|
-
git push -u origin maint/release/prep-xyz
|
100
|
-
```
|
101
|
-
1. Ensure tests pass and the code is merged to `release`.
|
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:
|
96
|
+
|
97
|
+
5. Push your changes and submit a pull request for review _against main:
|
103
98
|
```bash
|
104
|
-
|
99
|
+
git push -u origin maint_release_prep_xyz
|
105
100
|
```
|
106
|
-
|
101
|
+
|
102
|
+
6. Ensure tests pass and the code is merged to `main`.
|
103
|
+
|
104
|
+
7. Once the release_prep PR has been merged, checkout main and pull down the latests changes.
|
107
105
|
```bash
|
108
|
-
|
109
|
-
|
106
|
+
git checkout main
|
107
|
+
git pull
|
110
108
|
```
|
111
|
-
|
112
|
-
|
109
|
+
|
110
|
+
8. Assuming that the release_prep merge commit is at the HEAD of main we can simply create and push a tag as follows (replacing xyz with the appropriate version).
|
113
111
|
```bash
|
114
|
-
|
112
|
+
git tag -a xyx -m "Release xyz"
|
113
|
+
git push --follow-tags
|
115
114
|
```
|
116
|
-
|
117
|
-
|
115
|
+
|
116
|
+
9. Execute the publish workflow. This will:
|
117
|
+
- Create a GitHub release
|
118
|
+
- Build and publish the Gem
|
119
|
+
- Build and publish the Puppet module
|
120
|
+
|
121
|
+
10. Finally check that the expected versions are present on rubygems.org and the Forge.
|
118
122
|
|
119
123
|
## Known Issues
|
120
124
|
|
@@ -79,6 +79,9 @@ class Puppet::Provider::DscBaseProvider
|
|
79
79
|
end
|
80
80
|
downcased_result = recursively_downcase(canonicalized)
|
81
81
|
downcased_resource = recursively_downcase(r)
|
82
|
+
# Ensure that metaparameters are preserved when we canonicalize the resource.
|
83
|
+
metaparams = downcased_resource.select { |key, _value| Puppet::Type.metaparam?(key) }
|
84
|
+
canonicalized.merge!(metaparams) unless metaparams.nil?
|
82
85
|
downcased_result.each do |key, value|
|
83
86
|
# Canonicalize to the manifest value unless the downcased strings match and the attribute is not an enum:
|
84
87
|
# - When the values don't match at all, the manifest value is desired;
|
data/lib/pwsh/version.rb
CHANGED
data/lib/pwsh.rb
CHANGED
@@ -406,7 +406,7 @@ Invoke-PowerShellUserCode @params
|
|
406
406
|
#
|
407
407
|
# @return[String] Unique string representing the manager instance.
|
408
408
|
def self.instance_key(cmd, args, options)
|
409
|
-
cmd + args.join(' ') + options
|
409
|
+
cmd + args.join(' ') + options.to_s
|
410
410
|
end
|
411
411
|
|
412
412
|
# Return whether or not a particular stream is valid and readable
|
data/lib/templates/init.ps1
CHANGED
@@ -35,8 +35,18 @@ $global:ourFunctions = @'
|
|
35
35
|
function Reset-ProcessEnvironmentVariables {
|
36
36
|
param($CachedEnvironmentVariables)
|
37
37
|
|
38
|
+
# When Protected Event Logging and PowerShell Script Block logging are enabled together
|
39
|
+
# the SystemRoot environment variable is a requirement. If it is removed as part of this purge
|
40
|
+
# it causes the PowerShell process to crash, therefore breaking the pipe between Ruby and the
|
41
|
+
# remote PowerShell session.
|
42
|
+
# The least descructive way to avoid this is to filter out SystemRoot when pulling our current list
|
43
|
+
# of environment variables. Then we can continue safely with the removal.
|
44
|
+
$CurrentEnvironmentVariables = Get-ChildItem -Path Env:\* |
|
45
|
+
Where-Object {$_.Name -ne "SystemRoot"}
|
46
|
+
|
38
47
|
# Delete existing environment variables
|
39
|
-
|
48
|
+
$CurrentEnvironmentVariables |
|
49
|
+
ForEach-Object -Process { Remove-Item -Path "ENV:\$($_.Name)" -ErrorAction SilentlyContinue -WarningAction SilentlyContinue -Recurse }
|
40
50
|
|
41
51
|
# Re-add the cached environment variables
|
42
52
|
$CachedEnvironmentVariables |
|
@@ -0,0 +1,205 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
require 'ruby-pwsh'
|
5
|
+
require 'securerandom'
|
6
|
+
|
7
|
+
powershell = Pwsh::Manager.instance(Pwsh::Manager.powershell_path, Pwsh::Manager.powershell_args)
|
8
|
+
module_path = File.expand_path('../../fixtures/modules', File.dirname(__FILE__))
|
9
|
+
powershellget_path = File.expand_path('powershellget/lib/puppet_x/powershellget/dsc_resources/PowerShellGet', module_path)
|
10
|
+
local_user = ['dsc', SecureRandom.uuid.slice(0, 7)].join('_')
|
11
|
+
local_pw = SecureRandom.uuid
|
12
|
+
|
13
|
+
def execute_reset_command(reset_command)
|
14
|
+
manager = Pwsh::Manager.instance(Pwsh::Manager.powershell_path, Pwsh::Manager.powershell_args)
|
15
|
+
result = manager.execute(reset_command)
|
16
|
+
raise result[:errormessage] unless result[:errormessage].nil?
|
17
|
+
end
|
18
|
+
|
19
|
+
RSpec.describe 'DSC Acceptance: Basic' do
|
20
|
+
let(:puppet_apply) do
|
21
|
+
"bundle exec puppet apply --modulepath #{module_path} --detailed-exitcodes --debug --trace"
|
22
|
+
end
|
23
|
+
let(:command) { "#{puppet_apply} -e \"#{manifest}\"" }
|
24
|
+
|
25
|
+
context 'Updating' do
|
26
|
+
let(:manifest) do
|
27
|
+
# This very awkward pattern is because we're not writing
|
28
|
+
# manifest files and need to pass them directly to puppet apply.
|
29
|
+
[
|
30
|
+
"dsc_psrepository { 'Trust PSGallery':",
|
31
|
+
"dsc_name => 'PSGallery',",
|
32
|
+
"dsc_ensure => 'Present',",
|
33
|
+
"dsc_installationpolicy => 'Trusted'",
|
34
|
+
'}'
|
35
|
+
].join(' ')
|
36
|
+
end
|
37
|
+
|
38
|
+
before(:all) do
|
39
|
+
reset_command = <<~RESET_COMMAND
|
40
|
+
$ErrorActionPreference = 'Stop'
|
41
|
+
Import-Module PowerShellGet
|
42
|
+
$ResetParameters = @{
|
43
|
+
Name = 'PSRepository'
|
44
|
+
ModuleName = '#{powershellget_path}'
|
45
|
+
Method = 'Set'
|
46
|
+
Property = @{
|
47
|
+
Name = 'PSGallery'
|
48
|
+
Ensure = 'Present'
|
49
|
+
InstallationPolicy = 'Untrusted'
|
50
|
+
}
|
51
|
+
}
|
52
|
+
Invoke-DscResource @ResetParameters | ConvertTo-Json -Compress
|
53
|
+
RESET_COMMAND
|
54
|
+
execute_reset_command(reset_command)
|
55
|
+
end
|
56
|
+
|
57
|
+
it 'applies idempotently' do
|
58
|
+
first_run_result = powershell.execute(command)
|
59
|
+
expect(first_run_result[:exitcode]).to be(2)
|
60
|
+
expect(first_run_result[:native_stdout]).to match(/dsc_installationpolicy changed 'Untrusted' to 'Trusted'/)
|
61
|
+
expect(first_run_result[:native_stdout]).to match(/Updating: Finished/)
|
62
|
+
expect(first_run_result[:native_stdout]).to match(/Applied catalog/)
|
63
|
+
second_run_result = powershell.execute(command)
|
64
|
+
expect(second_run_result[:exitcode]).to be(0)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
context 'Creating' do
|
68
|
+
let(:manifest) do
|
69
|
+
[
|
70
|
+
"dsc_psmodule { 'Install BurntToast':",
|
71
|
+
"dsc_name => 'BurntToast',",
|
72
|
+
"dsc_ensure => 'Present',",
|
73
|
+
'}'
|
74
|
+
].join(' ')
|
75
|
+
end
|
76
|
+
|
77
|
+
before(:all) do
|
78
|
+
reset_command = <<~RESET_COMMAND
|
79
|
+
$ErrorActionPreference = 'Stop'
|
80
|
+
Import-Module PowerShellGet
|
81
|
+
Get-InstalledModule -Name BurntToast -ErrorAction SilentlyContinue |
|
82
|
+
Uninstall-Module -Force
|
83
|
+
RESET_COMMAND
|
84
|
+
execute_reset_command(reset_command)
|
85
|
+
end
|
86
|
+
|
87
|
+
it 'applies idempotently' do
|
88
|
+
first_run_result = powershell.execute(command)
|
89
|
+
expect(first_run_result[:exitcode]).to be(2)
|
90
|
+
expect(first_run_result[:native_stdout]).to match(/dsc_ensure changed 'Absent' to 'Present'/)
|
91
|
+
expect(first_run_result[:native_stdout]).to match(/Creating: Finished/)
|
92
|
+
expect(first_run_result[:native_stdout]).to match(/Applied catalog/)
|
93
|
+
second_run_result = powershell.execute(command)
|
94
|
+
expect(second_run_result[:exitcode]).to be(0)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
context 'Deleting' do
|
99
|
+
let(:manifest) do
|
100
|
+
[
|
101
|
+
"dsc_psmodule { 'Install BurntToast':",
|
102
|
+
"dsc_name => 'BurntToast',",
|
103
|
+
"dsc_ensure => 'Absent',",
|
104
|
+
'}'
|
105
|
+
].join(' ')
|
106
|
+
end
|
107
|
+
|
108
|
+
before(:all) do
|
109
|
+
reset_command = <<~RESET_COMMAND
|
110
|
+
$ErrorActionPreference = 'Stop'
|
111
|
+
Import-Module PowerShellGet
|
112
|
+
$Installed = Get-InstalledModule -Name BurntToast -ErrorAction SilentlyContinue
|
113
|
+
If($null -eq $Installed) {
|
114
|
+
Install-Module -Name BurntToast -Scope AllUsers -Force
|
115
|
+
}
|
116
|
+
RESET_COMMAND
|
117
|
+
execute_reset_command(reset_command)
|
118
|
+
end
|
119
|
+
|
120
|
+
it 'applies idempotently' do
|
121
|
+
first_run_result = powershell.execute(command)
|
122
|
+
expect(first_run_result[:exitcode]).to be(2)
|
123
|
+
expect(first_run_result[:native_stdout]).to match(/dsc_ensure changed 'Present' to 'Absent'/)
|
124
|
+
expect(first_run_result[:native_stdout]).to match(/Deleting: Finished/)
|
125
|
+
expect(first_run_result[:native_stdout]).to match(/Applied catalog/)
|
126
|
+
second_run_result = powershell.execute(command)
|
127
|
+
expect(second_run_result[:exitcode]).to be(0)
|
128
|
+
end
|
129
|
+
end
|
130
|
+
context 'PSDscRunAsCredential' do
|
131
|
+
before(:all) do
|
132
|
+
prep_command = <<~PREP_USER.strip
|
133
|
+
$ErrorActionPreference = 'Stop'
|
134
|
+
$User = Get-LocalUser -Name #{local_user} -ErrorAction SilentlyContinue
|
135
|
+
If ($null -eq $User) {
|
136
|
+
$Secure = ConvertTo-SecureString -String '#{local_pw}' -AsPlainText -Force
|
137
|
+
$User = New-LocalUser -Name #{local_user} -Password $Secure -Verbose
|
138
|
+
}
|
139
|
+
If ($User.Name -notin (Get-LocalGroupMember -Group Administrators).Name) {
|
140
|
+
Add-LocalGroupMember -Group Administrators -Member $User -Verbose
|
141
|
+
}
|
142
|
+
Get-LocalGroupMember -Group Administrators |
|
143
|
+
Where-Object Name -match '#{local_user}'
|
144
|
+
PREP_USER
|
145
|
+
execute_reset_command(prep_command)
|
146
|
+
end
|
147
|
+
after(:all) do
|
148
|
+
cleanup_command = <<~CLEANUP_USER.strip
|
149
|
+
Remove-LocalUser -Name #{local_user} -ErrorAction Stop
|
150
|
+
CLEANUP_USER
|
151
|
+
execute_reset_command(cleanup_command)
|
152
|
+
end
|
153
|
+
|
154
|
+
context 'with a valid credential' do
|
155
|
+
let(:manifest) do
|
156
|
+
[
|
157
|
+
"dsc_psrepository { 'Trust PSGallery':",
|
158
|
+
"dsc_name => 'PSGallery',",
|
159
|
+
"dsc_ensure => 'Present',",
|
160
|
+
"dsc_installationpolicy => 'Trusted',",
|
161
|
+
'dsc_psdscrunascredential => {',
|
162
|
+
"'user' => '#{local_user}',",
|
163
|
+
"'password' => Sensitive('#{local_pw}')",
|
164
|
+
'}',
|
165
|
+
'}'
|
166
|
+
].join(' ')
|
167
|
+
end
|
168
|
+
|
169
|
+
it 'applies idempotently without leaking secrets' do
|
170
|
+
first_run_result = powershell.execute(command)
|
171
|
+
expect(first_run_result[:exitcode]).to be(2)
|
172
|
+
expect(first_run_result[:native_stdout]).to match(/dsc_installationpolicy changed 'Untrusted' to 'Trusted'/)
|
173
|
+
expect(first_run_result[:native_stdout]).to match(/Updating: Finished/)
|
174
|
+
expect(first_run_result[:native_stdout]).to match(/Applied catalog/)
|
175
|
+
expect(first_run_result[:native_stdout]).to match(/'#<Sensitive \[value redacted\]>'/)
|
176
|
+
expect(first_run_result[:native_stdout]).not_to match(local_pw)
|
177
|
+
second_run_result = powershell.execute(command)
|
178
|
+
expect(second_run_result[:exitcode]).to be(0)
|
179
|
+
end
|
180
|
+
end
|
181
|
+
context 'with an invalid credential' do
|
182
|
+
let(:manifest) do
|
183
|
+
[
|
184
|
+
"dsc_psrepository { 'Trust PSGallery':",
|
185
|
+
"dsc_name => 'PSGallery',",
|
186
|
+
"dsc_ensure => 'Present',",
|
187
|
+
"dsc_installationpolicy => 'Trusted',",
|
188
|
+
'dsc_psdscrunascredential => {',
|
189
|
+
"'user' => 'definitely_do_not_exist_here',",
|
190
|
+
"'password' => Sensitive('#{local_pw}')",
|
191
|
+
'}',
|
192
|
+
'}'
|
193
|
+
].join(' ')
|
194
|
+
end
|
195
|
+
|
196
|
+
it 'errors loudly without leaking secrets' do
|
197
|
+
first_run_result = powershell.execute(command)
|
198
|
+
expect(first_run_result[:exitcode]).to be(4)
|
199
|
+
expect(first_run_result[:stderr].first).to match(/dsc_psrepository: The user name or password is incorrect/)
|
200
|
+
expect(first_run_result[:native_stdout]).to match(/'#<Sensitive \[value redacted\]>'/)
|
201
|
+
expect(first_run_result[:native_stdout]).not_to match(local_pw)
|
202
|
+
end
|
203
|
+
end
|
204
|
+
end
|
205
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
# TODO: Test against mcollera/AccessControlDsc for CIM instance behavior
|
3
|
+
# 1. Make sure valid nested CIM instances can be passed to Invoke-DscResource
|
4
|
+
# 2. Make sure nested CIM instances can be read back from Invoke-DscResource
|
5
|
+
|
6
|
+
# frozen_string_literal: true
|
7
|
+
|
8
|
+
require 'spec_helper'
|
9
|
+
require 'ruby-pwsh'
|
10
|
+
|
11
|
+
# Needs to be declared here so it is usable in before and it blocks alike
|
12
|
+
test_manifest = File.expand_path('../../fixtures/test.pp', File.dirname(__FILE__))
|
13
|
+
fixtures_path = File.expand_path('../../fixtures', File.dirname(__FILE__))
|
14
|
+
|
15
|
+
def execute_reset_command(reset_command)
|
16
|
+
manager = Pwsh::Manager.instance(Pwsh::Manager.powershell_path, Pwsh::Manager.powershell_args)
|
17
|
+
result = manager.execute(reset_command)
|
18
|
+
raise result[:errormessage] unless result[:errormessage].nil?
|
19
|
+
end
|
20
|
+
|
21
|
+
RSpec.describe 'DSC Acceptance: Complex' do
|
22
|
+
let(:powershell) { Pwsh::Manager.instance(Pwsh::Manager.powershell_path, Pwsh::Manager.powershell_args) }
|
23
|
+
let(:module_path) { File.expand_path('../../fixtures/modules', File.dirname(__FILE__)) }
|
24
|
+
let(:puppet_apply) do
|
25
|
+
"bundle exec puppet apply #{test_manifest} --modulepath #{module_path} --detailed-exitcodes --trace"
|
26
|
+
end
|
27
|
+
|
28
|
+
context 'Managing the access control list of a folder' do
|
29
|
+
before(:each) do
|
30
|
+
reset_command = <<~RESET_COMMAND
|
31
|
+
$TestFolderPath = Join-Path -Path "#{fixtures_path}" -Childpath access_control
|
32
|
+
# Delete the test folder if it exists (to clear access control modifications)
|
33
|
+
If (Test-Path -Path $TestFolderPath -PathType Container) {
|
34
|
+
Remove-Item $TestFolderPath -Recurse -Force
|
35
|
+
}
|
36
|
+
# Create the test folder
|
37
|
+
New-Item $TestFolderPath -ItemType Directory
|
38
|
+
RESET_COMMAND
|
39
|
+
execute_reset_command(reset_command)
|
40
|
+
end
|
41
|
+
|
42
|
+
it 'applies idempotently' do
|
43
|
+
content = <<~MANIFEST.strip
|
44
|
+
$test_folder_path = "#{fixtures_path}/access_control"
|
45
|
+
# Configure access to the test folder
|
46
|
+
dsc_ntfsaccessentry {'Test':
|
47
|
+
dsc_path => $test_folder_path,
|
48
|
+
dsc_accesscontrollist => [
|
49
|
+
{
|
50
|
+
principal => 'Everyone',
|
51
|
+
forceprincipal => true,
|
52
|
+
accesscontrolentry => [
|
53
|
+
{
|
54
|
+
accesscontroltype => 'Allow',
|
55
|
+
filesystemrights => ['FullControl'],
|
56
|
+
inheritance => 'This folder and files',
|
57
|
+
ensure => 'Present',
|
58
|
+
cim_instance_type => 'NTFSAccessControlEntry',
|
59
|
+
}
|
60
|
+
]
|
61
|
+
}
|
62
|
+
]
|
63
|
+
}
|
64
|
+
MANIFEST
|
65
|
+
File.open(test_manifest, 'w') { |file| file.write(content) }
|
66
|
+
# Apply the test manifest
|
67
|
+
first_run_result = powershell.execute(puppet_apply)
|
68
|
+
expect(first_run_result[:exitcode]).to be(2)
|
69
|
+
# Access Control Set
|
70
|
+
expect(first_run_result[:native_stdout]).to match(/dsc_accesscontrollist: dsc_accesscontrollist changed/)
|
71
|
+
expect(first_run_result[:native_stdout]).to match(%r{dsc_ntfsaccessentry\[{:name=>"Test", :dsc_path=>".+/spec/fixtures/access_control"}\]: Updating: Finished})
|
72
|
+
expect(first_run_result[:stderr]).not_to match(/Error/)
|
73
|
+
expect(first_run_result[:stderr]).not_to match(/Warning: Provider returned data that does not match the Type Schema/)
|
74
|
+
expect(first_run_result[:stderr]).not_to match(/Value type mismatch/)
|
75
|
+
# Run finished
|
76
|
+
expect(first_run_result[:native_stdout]).to match(/Applied catalog/)
|
77
|
+
# Second run is idempotent
|
78
|
+
second_run_result = powershell.execute(puppet_apply)
|
79
|
+
expect(second_run_result[:exitcode]).to be(0)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
@@ -0,0 +1,129 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
require 'ruby-pwsh'
|
5
|
+
|
6
|
+
powershell = Pwsh::Manager.instance(Pwsh::Manager.powershell_path, Pwsh::Manager.powershell_args)
|
7
|
+
module_path = File.expand_path('../../fixtures/modules', File.dirname(__FILE__))
|
8
|
+
psrc_path = File.expand_path('../../fixtures/example.psrc', File.dirname(__FILE__))
|
9
|
+
|
10
|
+
def execute_reset_command(reset_command)
|
11
|
+
manager = Pwsh::Manager.instance(Pwsh::Manager.powershell_path, Pwsh::Manager.powershell_args)
|
12
|
+
result = manager.execute(reset_command)
|
13
|
+
raise result[:errormessage] unless result[:errormessage].nil?
|
14
|
+
end
|
15
|
+
|
16
|
+
RSpec.describe 'DSC Acceptance: Class-Based Resource' do
|
17
|
+
let(:puppet_apply) do
|
18
|
+
"bundle exec puppet apply --modulepath #{module_path} --detailed-exitcodes --debug --trace"
|
19
|
+
end
|
20
|
+
let(:command) { "#{puppet_apply} -e \"#{manifest}\"" }
|
21
|
+
|
22
|
+
context 'Creating' do
|
23
|
+
let(:manifest) do
|
24
|
+
# This very awkward pattern is because we're not writing
|
25
|
+
# manifest files and need to pass them directly to puppet apply.
|
26
|
+
[
|
27
|
+
"dsc_jearolecapabilities { 'ExampleRoleCapability':",
|
28
|
+
"dsc_ensure => 'Present',",
|
29
|
+
"dsc_path => '#{psrc_path}',",
|
30
|
+
"dsc_description => 'Example role capability file'",
|
31
|
+
'}'
|
32
|
+
].join(' ')
|
33
|
+
end
|
34
|
+
|
35
|
+
before(:each) do
|
36
|
+
reset_command = <<~RESET_COMMAND
|
37
|
+
$PsrcPath = '#{psrc_path}'
|
38
|
+
# Delete the test PSRC fixture if it exists
|
39
|
+
If (Test-Path -Path $PsrcPath -PathType Leaf) {
|
40
|
+
Remove-Item $PsrcPath -Force
|
41
|
+
}
|
42
|
+
RESET_COMMAND
|
43
|
+
execute_reset_command(reset_command)
|
44
|
+
end
|
45
|
+
|
46
|
+
it 'applies idempotently' do
|
47
|
+
first_run_result = powershell.execute(command)
|
48
|
+
expect(first_run_result[:exitcode]).to be(2)
|
49
|
+
expect(first_run_result[:native_stdout]).to match(//)
|
50
|
+
expect(first_run_result[:native_stdout]).to match(/dsc_description changed to 'Example role capability file'/)
|
51
|
+
expect(first_run_result[:native_stdout]).to match(/Creating: Finished/)
|
52
|
+
expect(first_run_result[:native_stdout]).to match(/Applied catalog/)
|
53
|
+
second_run_result = powershell.execute(command)
|
54
|
+
expect(second_run_result[:exitcode]).to be(0)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
context 'Updating' do
|
59
|
+
let(:manifest) do
|
60
|
+
# This very awkward pattern is because we're not writing
|
61
|
+
# manifest files and need to pass them directly to puppet apply.
|
62
|
+
[
|
63
|
+
"dsc_jearolecapabilities { 'ExampleRoleCapability':",
|
64
|
+
"dsc_ensure => 'Present',",
|
65
|
+
"dsc_path => '#{psrc_path}',",
|
66
|
+
"dsc_description => 'Updated role capability file'",
|
67
|
+
'}'
|
68
|
+
].join(' ')
|
69
|
+
end
|
70
|
+
|
71
|
+
before(:each) do
|
72
|
+
reset_command = <<~RESET_COMMAND
|
73
|
+
$PsrcPath = '#{psrc_path}'
|
74
|
+
# Delete the test PSRC fixture if it exists
|
75
|
+
If (Test-Path -Path $PsrcPath -PathType Leaf) {
|
76
|
+
Remove-Item $PsrcPath -Force
|
77
|
+
}
|
78
|
+
# Create the test PSRC fixture
|
79
|
+
New-Item $PsrcPath -ItemType File -Value "@{'Description' = 'Example role capability file'}"
|
80
|
+
RESET_COMMAND
|
81
|
+
execute_reset_command(reset_command)
|
82
|
+
end
|
83
|
+
|
84
|
+
it 'applies idempotently' do
|
85
|
+
first_run_result = powershell.execute(command)
|
86
|
+
expect(first_run_result[:exitcode]).to be(2)
|
87
|
+
expect(first_run_result[:native_stdout]).to match(/dsc_description changed 'Example role capability file' to 'Updated role capability file'/)
|
88
|
+
expect(first_run_result[:native_stdout]).to match(/Updating: Finished/)
|
89
|
+
expect(first_run_result[:native_stdout]).to match(/Applied catalog/)
|
90
|
+
second_run_result = powershell.execute(command)
|
91
|
+
expect(second_run_result[:exitcode]).to be(0)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
context 'Deleting' do
|
96
|
+
let(:manifest) do
|
97
|
+
# This very awkward pattern is because we're not writing
|
98
|
+
# manifest files and need to pass them directly to puppet apply.
|
99
|
+
[
|
100
|
+
"dsc_jearolecapabilities { 'ExampleRoleCapability':",
|
101
|
+
"dsc_ensure => 'Absent',",
|
102
|
+
"dsc_path => '#{psrc_path}'",
|
103
|
+
'}'
|
104
|
+
].join(' ')
|
105
|
+
end
|
106
|
+
|
107
|
+
before(:each) do
|
108
|
+
reset_command = <<~RESET_COMMAND
|
109
|
+
$PsrcPath = '#{psrc_path}'
|
110
|
+
# Delete the test PSRC fixture if it exists
|
111
|
+
If (!(Test-Path -Path $PsrcPath -PathType Leaf)) {
|
112
|
+
# Create the test PSRC fixture
|
113
|
+
New-Item $PsrcPath -ItemType File -Value "@{'Description' = 'Updated'}"
|
114
|
+
}
|
115
|
+
RESET_COMMAND
|
116
|
+
execute_reset_command(reset_command)
|
117
|
+
end
|
118
|
+
|
119
|
+
it 'applies idempotently' do
|
120
|
+
first_run_result = powershell.execute(command)
|
121
|
+
expect(first_run_result[:exitcode]).to be(2)
|
122
|
+
expect(first_run_result[:native_stdout]).to match(/dsc_ensure changed 'Present' to 'Absent'/)
|
123
|
+
expect(first_run_result[:native_stdout]).to match(/Deleting: Finished/)
|
124
|
+
expect(first_run_result[:native_stdout]).to match(/Applied catalog/)
|
125
|
+
second_run_result = powershell.execute(command)
|
126
|
+
expect(second_run_result[:exitcode]).to be(0)
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|