Skip to content

Commit f607207

Browse files
(FM-8475) Replace library code
Prior to this commit the PowerShell module providers depended on a vendored version of the PowerShell code manager library in the PuppetX namespace. This commit updates the providers and their tests to leverage the ruby-pwsh gem from the pwshlib Puppet module instead. This reduces the amount of maintenance required and simplifies the code base.
1 parent 3360f98 commit f607207

File tree

14 files changed

+90
-2530
lines changed

14 files changed

+90
-2530
lines changed

.rubocop_todo.yml

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,19 @@
11
# This configuration was generated by
22
# `rubocop --auto-gen-config`
3-
# on 2018-08-13 13:07:27 +0800 using RuboCop version 0.49.1.
3+
# on 2019-10-18 11:01:56 -0500 using RuboCop version 0.49.1.
44
# The point is for the user to remove these configuration records
55
# one by one as the offenses are removed from the code base.
66
# Note that changes in the inspected code, or installation of new
77
# versions of RuboCop, may require this file to be generated again.
88

9-
# Offense count: 3
10-
RSpec/LetBeforeExamples:
9+
# Offense count: 4
10+
GetText/DecorateFunctionMessage:
1111
Exclude:
12-
- 'spec/integration/puppet_x/puppetlabs/powershell_manager_spec.rb'
12+
- 'lib/puppet/provider/exec/powershell.rb'
13+
- 'lib/puppet/provider/exec/pwsh.rb'
14+
- 'spec/spec_helper_acceptance.rb'
15+
16+
# Offense count: 1
17+
GetText/DecorateString:
18+
Exclude:
19+
- 'lib/puppet/provider/exec/powershell.rb'

lib/puppet/provider/exec/powershell.rb

Lines changed: 30 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,10 @@
11
require 'puppet/provider/exec'
2-
require File.join(File.dirname(__FILE__), '../../../puppet_x/puppetlabs/powershell/compatible_powershell_version')
3-
require File.join(File.dirname(__FILE__), '../../../puppet_x/puppetlabs/powershell/powershell_manager')
2+
require 'ruby-pwsh'
43

54
Puppet::Type.type(:exec).provide :powershell, :parent => Puppet::Provider::Exec do
65
confine :operatingsystem => :windows
76

8-
commands :powershell =>
9-
if File.exists?("#{ENV['SYSTEMROOT']}\\sysnative\\WindowsPowershell\\v1.0\\powershell.exe")
10-
"#{ENV['SYSTEMROOT']}\\sysnative\\WindowsPowershell\\v1.0\\powershell.exe"
11-
elsif File.exists?("#{ENV['SYSTEMROOT']}\\system32\\WindowsPowershell\\v1.0\\powershell.exe")
12-
"#{ENV['SYSTEMROOT']}\\system32\\WindowsPowershell\\v1.0\\powershell.exe"
13-
else
14-
'powershell.exe'
15-
end
7+
commands :powershell => Pwsh::Manager.powershell_path
168

179
desc <<-EOT
1810
Executes Powershell commands. One of the `onlyif`, `unless`, or `creates`
@@ -55,20 +47,13 @@ def self.upgrade_message
5547
@upgrade_warning_issued = true
5648
end
5749

58-
def self.powershell_args
59-
ps_args = ['-NoProfile', '-NonInteractive', '-NoLogo', '-ExecutionPolicy', 'Bypass']
60-
ps_args << '-Command' if !PuppetX::PowerShell::PowerShellManager.supported?
61-
62-
ps_args
63-
end
64-
6550
def ps_manager
6651
debug_output = Puppet::Util::Log.level == :debug
67-
PuppetX::PowerShell::PowerShellManager.instance(command(:powershell), self.class.powershell_args(), debug: debug_output)
52+
Pwsh::Manager.instance(command(:powershell), Pwsh::Manager.powershell_args, debug: debug_output)
6853
end
6954

7055
def run(command, check = false)
71-
if !PuppetX::PowerShell::PowerShellManager.supported?
56+
unless Pwsh::Manager.windows_powershell_supported?
7257
self.class.upgrade_message
7358
write_script(command) do |native_path|
7459
# Ideally, we could keep a handle open on the temp file in this
@@ -82,8 +67,33 @@ def run(command, check = false)
8267
return super("cmd.exe /c \"\"#{native_path(command(:powershell))}\" #{legacy_args} -Command - < \"#{native_path}\"\"", check)
8368
end
8469
else
85-
return ps_manager.execute_resource(command, resource)
70+
return execute_resource(command, resource)
71+
end
72+
end
73+
74+
def execute_resource(powershell_code, resource)
75+
working_dir = resource[:cwd]
76+
if (!working_dir.nil?)
77+
fail "Working directory '#{working_dir}' does not exist" unless File.directory?(working_dir)
78+
end
79+
timeout_ms = resource[:timeout].nil? ? nil : resource[:timeout] * 1000
80+
environment_variables = resource[:environment].nil? ? [] : resource[:environment]
81+
82+
result = ps_manager.execute(powershell_code, timeout_ms, working_dir, environment_variables)
83+
stdout = result[:stdout]
84+
native_out = result[:native_stdout]
85+
stderr = result[:stderr]
86+
exit_code = result[:exitcode]
87+
88+
unless stderr.nil?
89+
stderr.each { |e| Puppet.debug "STDERR: #{e.chop}" unless e.empty? }
8690
end
91+
92+
Puppet.debug "STDERR: #{result[:errormessage]}" unless result[:errormessage].nil?
93+
94+
output = Puppet::Util::Execution::ProcessOutput.new(stdout.to_s + native_out.to_s, exit_code)
95+
96+
return output, output
8797
end
8898

8999
def checkexe(command)

lib/puppet/provider/exec/pwsh.rb

Lines changed: 33 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
require 'puppet/provider/exec'
2+
require 'ruby-pwsh'
23

34
Puppet::Type.type(:exec).provide :pwsh, :parent => Puppet::Provider::Exec do
45
desc <<-EOT
@@ -17,8 +18,8 @@
1718
def run(command, check = false)
1819
@pwsh ||= get_pwsh_command
1920
self.fail 'pwsh could not be found' if @pwsh.nil?
20-
if PuppetX::PowerShell::PowerShellManager.supported_on_pwsh?
21-
return ps_manager.execute_resource(command, resource)
21+
if Pwsh::Manager.pwsh_supported?
22+
return execute_resource(command, resource)
2223
else
2324
write_script(command) do |native_path|
2425
# Ideally, we could keep a handle open on the temp file in this
@@ -49,35 +50,11 @@ def validatecmd(command)
4950
#
5051
# @return [String] the absolute path to the found pwsh executable. Returns nil when it does not exist
5152
def get_pwsh_command
52-
if Puppet::Util::Platform.windows?
53-
# Environment variables on Windows are not case sensitive however ruby hash keys are.
54-
# Convert all the key names to upcase so we can be sure to find PATH etc.
55-
# Also while ruby can have difficulty changing the case of some UTF8 characters, we're
56-
# only going to use plain ASCII names so this is safe.
57-
current_env = Hash[Puppet::Util.get_environment.map {|k, v| [k.upcase, v] }]
58-
else
59-
# We don't force a case change on non-Windows platforms because it is perfectly
60-
# ok to have 'Path' and 'PATH'
61-
current_env = Puppet::Util.get_environment
62-
end
6353
# If the resource specifies a search path use that. Otherwise use the default
6454
# PATH from the environment.
65-
search_paths = @resource.nil? || @resource['path'].nil? ?
66-
current_env['PATH'] :
67-
resource[:path].join(File::PATH_SEPARATOR)
68-
69-
# If we're on Windows, try the default installation locations as a last resort.
70-
# https://docs.microsoft.com/en-us/powershell/scripting/install/installing-powershell-core-on-windows?view=powershell-6#msi
71-
if Puppet::Util::Platform.windows?
72-
search_paths += ";#{current_env['PROGRAMFILES']}\\PowerShell\\6" +
73-
";#{current_env['PROGRAMFILES(X86)']}\\PowerShell\\6"
74-
end
75-
76-
# Note that just like when we run the command in Puppet::Provider::Exec, the
77-
# resource[:path] replaces the PATH, it doesn't add to it.
78-
Puppet::Util.withenv({'PATH' => search_paths}, Puppet::Util.default_env) do
79-
return Puppet::Util.which('pwsh')
80-
end
55+
@resource.nil? || @resource['path'].nil? ?
56+
Pwsh::Manager.pwsh_path :
57+
Pwsh::Manager.pwsh_path(resource[:path])
8158
end
8259

8360
def pwsh_args
@@ -89,10 +66,35 @@ def pwsh_args
8966
# Retrieves the PowerShell manager specific to our pwsh binary in this resource
9067
#
9168
# @api private
92-
# @return [PuppetX::PowerShell::PowerShellManager] The PowerShell manager for this resource
69+
# @return [Pwsh::Manager] The PowerShell manager for this resource
9370
def ps_manager
9471
debug_output = Puppet::Util::Log.level == :debug
95-
PuppetX::PowerShell::PowerShellManager.instance(@pwsh, pwsh_args, debug: debug_output)
72+
Pwsh::Manager.instance(@pwsh, pwsh_args, debug: debug_output)
73+
end
74+
75+
def execute_resource(powershell_code, resource)
76+
working_dir = resource[:cwd]
77+
if (!working_dir.nil?)
78+
fail "Working directory '#{working_dir}' does not exist" unless File.directory?(working_dir)
79+
end
80+
timeout_ms = resource[:timeout].nil? ? nil : resource[:timeout] * 1000
81+
environment_variables = resource[:environment].nil? ? [] : resource[:environment]
82+
83+
result = ps_manager.execute(powershell_code, timeout_ms, working_dir, environment_variables)
84+
stdout = result[:stdout]
85+
native_out = result[:native_stdout]
86+
stderr = result[:stderr]
87+
exit_code = result[:exitcode]
88+
89+
unless stderr.nil?
90+
stderr.each { |e| Puppet.debug "STDERR: #{e.chop}" unless e.empty? }
91+
end
92+
93+
Puppet.debug "STDERR: #{result[:errormessage]}" unless result[:errormessage].nil?
94+
95+
output = Puppet::Util::Execution::ProcessOutput.new(stdout.to_s + native_out.to_s, exit_code)
96+
97+
return output, output
9698
end
9799

98100
def write_script(content, &block)

lib/puppet_x/puppetlabs/powershell/compatible_powershell_version.rb

Lines changed: 0 additions & 51 deletions
This file was deleted.

0 commit comments

Comments
 (0)