Skip to content

Commit c92ee61

Browse files
(MODULES-10539) Remove commands idiom from PowerShell provider
Prior to this commit the PowerShell exec provider used the commands idiom to load the PowerShell executable path for use. Once the module was refactored to rely on the ruby-pwsh gem via the puppetlabs/pwshlib module, the code for determining the path was updated to depend on a helper function. However, the commands method is (apparently?) evaluated during catalogue compilation, causing the Puppet run to explode unexpectedly if the dependent module is not available. This commit removes the commands idiom and relies on the feature confine which should evaluate during a Puppet run and, when that feature is not found (because puppetlabs/pwshlib is not installed) it will report that the provider is not functional rather than blow up the entire Puppet run.
1 parent 63d7409 commit c92ee61

File tree

6 files changed

+78
-13
lines changed

6 files changed

+78
-13
lines changed

lib/puppet/provider/exec/powershell.rb

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,6 @@
44
confine :operatingsystem => :windows
55
confine :feature => :pwshlib
66

7-
def self.powershell_path
8-
begin
9-
require 'ruby-pwsh'
10-
Pwsh::Manager.powershell_path
11-
rescue
12-
nil
13-
end
14-
end
15-
commands :powershell => self.powershell_path
16-
177
desc <<-EOT
188
Executes Powershell commands. One of the `onlyif`, `unless`, or `creates`
199
parameters should be specified to ensure the command is idempotent.
@@ -57,7 +47,7 @@ def self.upgrade_message
5747

5848
def ps_manager
5949
debug_output = Puppet::Util::Log.level == :debug
60-
Pwsh::Manager.instance(command(:powershell), Pwsh::Manager.powershell_args, debug: debug_output)
50+
Pwsh::Manager.instance(Pwsh::Manager.powershell_path, Pwsh::Manager.powershell_args, debug: debug_output)
6151
end
6252

6353
def run(command, check = false)
@@ -72,7 +62,7 @@ def run(command, check = false)
7262
# we redirect powershell's stdin to read from the file. Current
7363
# versions of Windows use per-user temp directories with strong
7464
# permissions, but I'd rather not make (poor) assumptions.
75-
return super("cmd.exe /c \"\"#{native_path(command(:powershell))}\" #{legacy_args} -Command - < \"#{native_path}\"\"", check)
65+
return super("cmd.exe /c \"\"#{native_path(Pwsh::Manager.powershell_path)}\" #{legacy_args} -Command - < \"#{native_path}\"\"", check)
7666
end
7767
else
7868
return execute_resource(command, resource)

spec/acceptance/exec_powershell_spec.rb

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -465,4 +465,31 @@
465465
PS1
466466
it_should_behave_like 'standard exec', pimport
467467
end
468+
469+
# TODO: For some reason, Puppet still sees the dependent module as available during
470+
# a localhost run, but not when testing against a remote target.
471+
context 'without pwshlib available', unless: (ENV['TARGET_HOST'] == 'localhost') do
472+
before(:all) do
473+
remove_pwshlib
474+
end
475+
after(:all) do
476+
install_pwshlib
477+
end
478+
479+
let(:manifest) {
480+
<<-MANIFEST
481+
exec{'TestPowershell':
482+
command => 'Get-Process > c:/process.txt',
483+
unless => 'if(!(test-path "c:/process.txt")){exit 1}',
484+
provider => powershell,
485+
}
486+
MANIFEST
487+
}
488+
489+
it "Errors predictably" do
490+
apply_manifest(manifest, expect_failures: true) do |result|
491+
expect(result.stderr).to match(/Provider powershell is not functional on this host/)
492+
end
493+
end
494+
end
468495
end

spec/acceptance/exec_pwsh_spec.rb

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -517,5 +517,32 @@ def platform_string(windows, posix)
517517
PS1
518518
it_should_behave_like 'standard exec', pimport
519519
end
520+
521+
# TODO: For some reason, Puppet still sees the dependent module as available during
522+
# a localhost run, but not when testing against a remote target.
523+
describe 'without pwshlib available', unless: (ENV['TARGET_HOST'] == 'localhost') do
524+
before(:all) do
525+
remove_pwshlib
526+
end
527+
after(:all) do
528+
install_pwshlib
529+
end
530+
531+
let(:manifest) {
532+
<<-MANIFEST
533+
exec{'TestPowershell':
534+
command => 'Get-Process > /process.txt',
535+
unless => 'if(!(test-path "/process.txt")){exit 1}',
536+
provider => pwsh,
537+
}
538+
MANIFEST
539+
}
540+
541+
it "Errors predictably" do
542+
apply_manifest(manifest, expect_failures: true) do |result|
543+
expect(result.stderr).to match(/Provider pwsh is not functional on this host/)
544+
end
545+
end
546+
end
520547
end
521548
end

spec/spec_helper_acceptance_local.rb

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,13 +55,32 @@ def interpolate_powershell(command)
5555
"powershell.exe -NoProfile -EncodedCommand #{encoded_command}"
5656
end
5757

58+
def relative_folder(relative_path)
59+
expanded_path = File.expand_path(File.join(File.dirname(__FILE__), relative_path))
60+
Dir.open(expanded_path) if File.exist?(expanded_path)
61+
end
62+
63+
def remove_pwshlib
64+
uninstall_command = 'puppet module uninstall puppetlabs/pwshlib --force'
65+
uninstall_command += " --modulepath #{relative_folder('fixtures/modules').path}" if ENV['TARGET_HOST'] == 'localhost'
66+
Helper.instance.run_shell(uninstall_command, expect_failures: true) do |result|
67+
raise "Failed to uninstall puppetlabs/pwshlib" unless result.stderr =~ /Module 'puppetlabs-pwshlib' is not installed/ || result.exit_code == 0
68+
end
69+
end
70+
71+
def install_pwshlib
72+
install_command = 'puppet module install puppetlabs/pwshlib'
73+
install_command += " --modulepath #{relative_folder('fixtures/modules').path}" if ENV['TARGET_HOST'] == 'localhost'
74+
Helper.instance.run_shell(install_command)
75+
end
76+
5877
def localhost_windows?
5978
os[:family] == 'windows' && ENV['TARGET_HOST'] == 'localhost'
6079
end
6180

6281
RSpec.configure do |c|
6382
c.before :suite do
64-
Helper.instance.run_shell('puppet module install puppetlabs/pwshlib')
83+
install_pwshlib
6584
cleanup_files
6685
end
6786
end

spec/unit/provider/exec/powershell_spec.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
describe "#run" do
3939
context "stubbed calls" do
4040
before :each do
41+
require 'ruby-pwsh'
4142
Pwsh::Manager.stubs(:windows_powershell_supported?).returns(false)
4243
Puppet::Provider::Exec.any_instance.stubs(:run)
4344
end

spec/unit/provider/exec/pwsh_spec.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#! /usr/bin/env ruby
22
require 'spec_helper'
33
require 'puppet/util'
4+
require 'ruby-pwsh'
45

56
describe Puppet::Type.type(:exec).provider(:pwsh) do
67
# Override the run value so we can test the super call

0 commit comments

Comments
 (0)