From 67f3ba114e27e8353b7844aede1c26b06fdd7a3e Mon Sep 17 00:00:00 2001 From: mwrock Date: Wed, 28 Oct 2020 15:44:50 -0700 Subject: convert most internal powershell_out to powershell_exec Signed-off-by: mwrock --- lib/chef/powershell.rb | 2 - lib/chef/provider/package/chocolatey.rb | 8 +- lib/chef/resource/hostname.rb | 2 +- lib/chef/resource/powershell_package_source.rb | 37 ++++---- lib/chef/resource/windows_ad_join.rb | 18 ++-- lib/chef/resource/windows_certificate.rb | 10 +- lib/chef/resource/windows_dfs_server.rb | 11 ++- lib/chef/resource/windows_firewall_profile.rb | 19 ++-- lib/chef/resource/windows_firewall_rule.rb | 20 ++-- lib/chef/resource/windows_security_policy.rb | 10 +- lib/chef/resource/windows_share.rb | 36 +++---- lib/chef/resource/windows_workgroup.rb | 8 +- .../functional/resource/chocolatey_package_spec.rb | 6 +- spec/functional/resource/dsc_script_spec.rb | 6 +- .../resource/powershell_package_source_spec.rb | 103 +++++++++++++++++++++ .../resource/windows_certificate_spec.rb | 16 ++-- .../resource/windows_firewall_rule_spec.rb | 93 +++++++++++++++++++ spec/functional/resource/windows_share_spec.rb | 103 +++++++++++++++++++++ spec/support/platform_helpers.rb | 10 +- spec/unit/provider/package/chocolatey_spec.rb | 3 +- .../resource/powershell_package_source_spec.rb | 40 ++++---- 21 files changed, 430 insertions(+), 131 deletions(-) create mode 100644 spec/functional/resource/powershell_package_source_spec.rb create mode 100644 spec/functional/resource/windows_firewall_rule_spec.rb create mode 100644 spec/functional/resource/windows_share_spec.rb diff --git a/lib/chef/powershell.rb b/lib/chef/powershell.rb index 5063e599c6..905b92ebfb 100644 --- a/lib/chef/powershell.rb +++ b/lib/chef/powershell.rb @@ -34,8 +34,6 @@ class Chef # @param script [String] script to run # @return [Object] output def initialize(script) - raise "Chef::PowerShell can only be used on the Windows platform." unless RUBY_PLATFORM.match?(/mswin|mingw32|windows/) - @dll ||= "Chef.PowerShell.Wrapper.dll" exec(script) end diff --git a/lib/chef/provider/package/chocolatey.rb b/lib/chef/provider/package/chocolatey.rb index 498a98f2d0..156568e584 100644 --- a/lib/chef/provider/package/chocolatey.rb +++ b/lib/chef/provider/package/chocolatey.rb @@ -151,7 +151,7 @@ class Chef @choco_exe ||= begin # if this check is in #define_resource_requirements, it won't get # run before choco.exe gets called from #load_current_resource. - exe_path = ::File.join(choco_install_path.to_s, "bin", "choco.exe") + exe_path = ::File.join(choco_install_path, "bin", "choco.exe") raise Chef::Exceptions::MissingLibrary, CHOCO_MISSING_MSG unless ::File.exist?(exe_path) exe_path @@ -160,9 +160,9 @@ class Chef # lets us mock out an incorrect value for testing. def choco_install_path - @choco_install_path ||= powershell_out!( - PATHFINDING_POWERSHELL_COMMAND - ).stdout.chomp + result = powershell_exec!(PATHFINDING_POWERSHELL_COMMAND).result + result = "" if result.empty? + result end # Helper to dispatch a choco command through shell_out using the timeout diff --git a/lib/chef/resource/hostname.rb b/lib/chef/resource/hostname.rb index 07a71864c2..27903e5807 100644 --- a/lib/chef/resource/hostname.rb +++ b/lib/chef/resource/hostname.rb @@ -240,7 +240,7 @@ class Chef unless Socket.gethostbyname(Socket.gethostname).first == new_resource.hostname converge_by "set hostname to #{new_resource.hostname}" do - powershell_out! <<~EOH + powershell_exec! <<~EOH $sysInfo = Get-WmiObject -Class Win32_ComputerSystem $sysInfo.Rename("#{new_resource.hostname}") EOH diff --git a/lib/chef/resource/powershell_package_source.rb b/lib/chef/resource/powershell_package_source.rb index e17c23abe2..066efc6a72 100644 --- a/lib/chef/resource/powershell_package_source.rb +++ b/lib/chef/resource/powershell_package_source.rb @@ -16,7 +16,6 @@ # require_relative "../resource" -require_relative "../json_compat" class Chef class Resource @@ -57,11 +56,11 @@ class Chef load_current_value do cmd = load_resource_state_script(source_name) - repo = powershell_out!(cmd) - if repo.stdout.empty? + repo = powershell_exec!(cmd) + if repo.result.empty? current_value_does_not_exist! else - status = Chef::JSONCompat.from_json(repo.stdout) + status = repo.result end url status["url"] trusted status["trusted"] @@ -78,28 +77,28 @@ class Chef if package_source_exists? converge_if_changed :url, :trusted, :publish_location, :script_source_location, :script_publish_location do update_cmd = build_ps_repository_command("Set", new_resource) - res = powershell_out(update_cmd) - raise "Failed to update #{new_resource.source_name}: #{res.stderr}" unless res.stderr.empty? + res = powershell_exec(update_cmd) + raise "Failed to update #{new_resource.source_name}: #{res.errors}" if res.error? end else converge_by("register source: #{new_resource.source_name}") do register_cmd = build_ps_repository_command("Register", new_resource) - res = powershell_out(register_cmd) - raise "Failed to register #{new_resource.source_name}: #{res.stderr}" unless res.stderr.empty? + res = powershell_exec(register_cmd) + raise "Failed to register #{new_resource.source_name}: #{res.errors}" if res.error? end end else if package_source_exists? converge_if_changed :url, :trusted, :provider_name do update_cmd = build_package_source_command("Set", new_resource) - res = powershell_out(update_cmd) - raise "Failed to update #{new_resource.source_name}: #{res.stderr}" unless res.stderr.empty? + res = powershell_exec(update_cmd) + raise "Failed to update #{new_resource.source_name}: #{res.errors}" if res.error? end else converge_by("register source: #{new_resource.source_name}") do register_cmd = build_package_source_command("Register", new_resource) - res = powershell_out(register_cmd) - raise "Failed to register #{new_resource.source_name}: #{res.stderr}" unless res.stderr.empty? + res = powershell_exec(register_cmd) + raise "Failed to register #{new_resource.source_name}: #{res.errors}" if res.error? end end end @@ -110,16 +109,16 @@ class Chef if package_source_exists? unregister_cmd = "Get-PackageSource -Name '#{new_resource.source_name}' | Unregister-PackageSource" converge_by("unregister source: #{new_resource.source_name}") do - res = powershell_out(unregister_cmd) - raise "Failed to unregister #{new_resource.source_name}: #{res.stderr}" unless res.stderr.empty? + res = powershell_exec(unregister_cmd) + raise "Failed to unregister #{new_resource.source_name}: #{res.errors}" if res.error? end end end action_class do def package_source_exists? - cmd = powershell_out!("(Get-PackageSource -Name '#{new_resource.source_name}' -WarningAction SilentlyContinue).Name") - cmd.stdout.downcase.strip == new_resource.source_name.downcase + cmd = powershell_exec!("(Get-PackageSource -Name '#{new_resource.source_name}' -ErrorAction SilentlyContinue).Name") + !cmd.result.empty? && cmd.result.to_s.downcase.strip == new_resource.source_name.downcase end def psrepository_cmdlet_appropriate? @@ -133,6 +132,7 @@ class Chef cmd << " -PublishLocation '#{new_resource.publish_location}'" if new_resource.publish_location cmd << " -ScriptSourceLocation '#{new_resource.script_source_location}'" if new_resource.script_source_location cmd << " -ScriptPublishLocation '#{new_resource.script_publish_location}'" if new_resource.script_publish_location + cmd << " | Out-Null" cmd end @@ -141,6 +141,7 @@ class Chef cmd << " -Location '#{new_resource.url}'" if new_resource.url cmd << " -Trusted:#{new_resource.trusted ? "$true" : "$false"}" cmd << " -ProviderName '#{new_resource.provider_name}'" if new_resource.provider_name + cmd << " | Out-Null" cmd end end @@ -157,11 +158,11 @@ class Chef if ((Get-PackageSource -Name '#{name}').ProviderName -eq 'PowerShellGet') { (Get-PSRepository -Name '#{name}') | Select @{n='source_name';e={$_.Name}}, @{n='url';e={$_.SourceLocation}}, @{n='trusted';e={$_.Trusted}}, @{n='provider_name';e={$_.PackageManagementProvider}}, @{n='publish_location';e={$_.PublishLocation}}, - @{n='script_source_location';e={$_.ScriptSourceLocation}}, @{n='script_publish_location';e={$_.ScriptPublishLocation}} | ConvertTo-Json + @{n='script_source_location';e={$_.ScriptSourceLocation}}, @{n='script_publish_location';e={$_.ScriptPublishLocation}} } else { (Get-PackageSource -Name '#{name}') | Select @{n='source_name';e={$_.Name}}, @{n='url';e={$_.Location}}, - @{n='provider_name';e={$_.ProviderName}}, @{n='trusted';e={$_.IsTrusted}} | ConvertTo-Json + @{n='provider_name';e={$_.ProviderName}}, @{n='trusted';e={$_.IsTrusted}} } } EOH diff --git a/lib/chef/resource/windows_ad_join.rb b/lib/chef/resource/windows_ad_join.rb index 6201b57379..731ce9333e 100644 --- a/lib/chef/resource/windows_ad_join.rb +++ b/lib/chef/resource/windows_ad_join.rb @@ -109,12 +109,12 @@ class Chef cmd << " -Force" converge_by("join Active Directory domain #{new_resource.domain_name}") do - ps_run = powershell_out(cmd) + ps_run = powershell_exec(cmd) if ps_run.error? if sensitive? raise "Failed to join the domain #{new_resource.domain_name}: *suppressed sensitive resource output*" else - raise "Failed to join the domain #{new_resource.domain_name}: #{ps_run.stderr}" + raise "Failed to join the domain #{new_resource.domain_name}: #{ps_run.errors}" end end @@ -143,12 +143,12 @@ class Chef cmd << " -Force" converge_by("leave Active Directory domain #{node_domain}") do - ps_run = powershell_out(cmd) + ps_run = powershell_exec(cmd) if ps_run.error? if sensitive? raise "Failed to leave the domain #{node_domain}: *suppressed sensitive resource output*" else - raise "Failed to leave the domain #{node_domain}: #{ps_run.stderr}" + raise "Failed to leave the domain #{node_domain}: #{ps_run.errors}" end end @@ -170,10 +170,10 @@ class Chef # workgroup the node is a member of. # def node_domain - node_domain = powershell_out!("(Get-WmiObject Win32_ComputerSystem).Domain") - raise "Failed to check if the system is joined to the domain #{new_resource.domain_name}: #{node_domain.stderr}}" if node_domain.error? + node_domain = powershell_exec!("(Get-WmiObject Win32_ComputerSystem).Domain") + raise "Failed to check if the system is joined to the domain #{new_resource.domain_name}: #{node_domain.errors}}" if node_domain.error? - node_domain.stdout.downcase.strip + node_domain.result.downcase.strip end # @@ -182,10 +182,10 @@ class Chef # workgroup. # def node_workgroup - node_workgroup = powershell_out!("(Get-WmiObject Win32_ComputerSystem).Workgroup") + node_workgroup = powershell_exec!("(Get-WmiObject Win32_ComputerSystem).Workgroup") raise "Failed to check if the system is currently a member of a workgroup" if node_workgroup.error? - node_workgroup.stdout.downcase.strip + node_workgroup.result end # diff --git a/lib/chef/resource/windows_certificate.rb b/lib/chef/resource/windows_certificate.rb index 68874af4d0..2c8c7c72ff 100644 --- a/lib/chef/resource/windows_certificate.rb +++ b/lib/chef/resource/windows_certificate.rb @@ -207,16 +207,16 @@ class Chef when ".der" out_file.puts(cert_obj.to_der) when ".cer" - cert_out = powershell_out("openssl x509 -text -inform DER -in #{cert_obj.to_pem} -outform CER").stdout + cert_out = shell_out("openssl x509 -text -inform DER -in #{cert_obj.to_pem} -outform CER").stdout out_file.puts(cert_out) when ".crt" - cert_out = powershell_out("openssl x509 -text -inform DER -in #{cert_obj.to_pem} -outform CRT").stdout + cert_out = shell_out("openssl x509 -text -inform DER -in #{cert_obj.to_pem} -outform CRT").stdout out_file.puts(cert_out) when ".pfx" - cert_out = powershell_out("openssl pkcs12 -export -nokeys -in #{cert_obj.to_pem} -outform PFX").stdout + cert_out = shell_out("openssl pkcs12 -export -nokeys -in #{cert_obj.to_pem} -outform PFX").stdout out_file.puts(cert_out) when ".p7b" - cert_out = powershell_out("openssl pkcs7 -export -nokeys -in #{cert_obj.to_pem} -outform P7B").stdout + cert_out = shell_out("openssl pkcs7 -export -nokeys -in #{cert_obj.to_pem} -outform P7B").stdout out_file.puts(cert_out) else Chef::Log.info("Supported certificate format .pem, .der, .cer, .crt, .pfx and .p7b") @@ -327,7 +327,7 @@ class Chef # @return [Boolean] Whether the certificate file is binary encoded or not # def binary_cert? - powershell_out!("file -b --mime-encoding #{new_resource.source}").stdout.strip == "binary" + shell_out!("file -b --mime-encoding #{new_resource.source}").stdout.strip == "binary" end # Imports the certificate object into cert store diff --git a/lib/chef/resource/windows_dfs_server.rb b/lib/chef/resource/windows_dfs_server.rb index 84b2a18c91..fc161f8189 100644 --- a/lib/chef/resource/windows_dfs_server.rb +++ b/lib/chef/resource/windows_dfs_server.rb @@ -49,14 +49,14 @@ class Chef default: 3600 load_current_value do - ps_results = powershell_out("Get-DfsnServerConfiguration -ComputerName '#{ENV["COMPUTERNAME"]}' | Select LdapTimeoutSec, PreferLogonDC, EnableSiteCostedReferrals, SyncIntervalSec, UseFqdn | ConvertTo-Json") + ps_results = powershell_exec("Get-DfsnServerConfiguration -ComputerName '#{ENV["COMPUTERNAME"]}' | Select LdapTimeoutSec, PreferLogonDC, EnableSiteCostedReferrals, SyncIntervalSec, UseFqdn") if ps_results.error? raise "The dfs_server resource failed to fetch the current state via the Get-DfsnServerConfiguration PowerShell cmdlet. Is the DFS Windows feature installed?" end - Chef::Log.debug("The Get-DfsnServerConfiguration results were #{ps_results.stdout}") - results = Chef::JSONCompat.from_json(ps_results.stdout) + Chef::Log.debug("The Get-DfsnServerConfiguration results were #{ps_results.result}") + results = ps_results.result use_fqdn results["UseFqdn"] || false ldap_timeout_secs results["LdapTimeoutSec"] @@ -69,7 +69,10 @@ class Chef description "Configure DFS settings." converge_if_changed do - powershell_out("Set-DfsnServerConfiguration -ComputerName '#{ENV["COMPUTERNAME"]}' EnableSiteCostedReferrals $#{new_resource.enable_site_costed_referrals} -UseFqdn $#{new_resource.use_fqdn} -LdapTimeoutSec #{new_resource.ldap_timeout_secs} -PreferLogonDC $#{new_resource.prefer_login_dc} -SyncIntervalSec #{new_resource.sync_interval_secs}") + dfs_cmd = "Set-DfsnServerConfiguration -ComputerName '#{ENV["COMPUTERNAME"]}' -UseFqdn $#{new_resource.use_fqdn} -LdapTimeoutSec #{new_resource.ldap_timeout_secs} -SyncIntervalSec #{new_resource.sync_interval_secs}" + dfs_cmd << " -EnableSiteCostedReferrals $#{new_resource.enable_site_costed_referrals}" if new_resource.enable_site_costed_referrals != current_resource.enable_site_costed_referrals + dfs_cmd << " -PreferLogonDC $#{new_resource.prefer_login_dc}" if new_resource.prefer_login_dc != current_resource.prefer_login_dc + powershell_exec!(dfs_cmd) end end end diff --git a/lib/chef/resource/windows_firewall_profile.rb b/lib/chef/resource/windows_firewall_profile.rb index f67d8fb8ed..ada9729699 100644 --- a/lib/chef/resource/windows_firewall_profile.rb +++ b/lib/chef/resource/windows_firewall_profile.rb @@ -83,11 +83,11 @@ class Chef load_current_value do |desired| ps_get_net_fw_profile = load_firewall_state(desired.profile) - output = powershell_out(ps_get_net_fw_profile) - if output.stdout.empty? + output = powershell_exec(ps_get_net_fw_profile) + if output.result.empty? current_value_does_not_exist! else - state = Chef::JSONCompat.from_json(output.stdout) + state = output.result end default_inbound_action state["default_inbound_action"] @@ -130,7 +130,7 @@ class Chef unless firewall_enabled?(new_resource.profile) converge_by "Enable the #{new_resource.profile} Firewall Profile" do cmd = "Set-NetFirewallProfile -Profile #{new_resource.profile} -Enabled \"True\"" - powershell_out!(cmd) + powershell_exec!(cmd) end end end @@ -139,7 +139,7 @@ class Chef if firewall_enabled?(new_resource.profile) converge_by "Disable the #{new_resource.profile} Firewall Profile" do cmd = "Set-NetFirewallProfile -Profile #{new_resource.profile} -Enabled \"False\"" - powershell_out!(cmd) + powershell_exec!(cmd) end end end @@ -166,12 +166,7 @@ class Chef return $true } else {return $false} CODE - firewall_status = powershell_out(cmd).stdout - if /True/.match?(firewall_status) - true - elsif /False/.match?(firewall_status) - false - end + powershell_exec!(cmd).result end end @@ -193,7 +188,7 @@ class Chef allow_user_ports = $#{profile_name}.AllowUserPorts.ToString() allow_unicast_response = $#{profile_name}.AllowUnicastResponseToMulticast.ToString() display_notification = $#{profile_name}.NotifyOnListen.ToString() - }) | ConvertTo-Json + }) EOH end end diff --git a/lib/chef/resource/windows_firewall_rule.rb b/lib/chef/resource/windows_firewall_rule.rb index 2010c15f89..a6f0614362 100644 --- a/lib/chef/resource/windows_firewall_rule.rb +++ b/lib/chef/resource/windows_firewall_rule.rb @@ -19,8 +19,6 @@ # limitations under the License. # -require_relative "../json_compat" - class Chef class Resource class WindowsFirewallRule < Chef::Resource @@ -159,11 +157,11 @@ class Chef load_current_value do load_state_cmd = load_firewall_state(rule_name) - output = powershell_out(load_state_cmd) - if output.stdout.empty? + output = powershell_exec(load_state_cmd) + if output.result.empty? current_value_does_not_exist! else - state = Chef::JSONCompat.from_json(output.stdout) + state = output.result end # Need to reverse `$rule.Profile.ToString()` in powershell command @@ -194,17 +192,17 @@ class Chef :remote_port, :direction, :protocol, :icmp_type, :firewall_action, :profile, :program, :service, :interface_type, :enabled do cmd = firewall_command("Set") - powershell_out!(cmd) + powershell_exec!(cmd) end converge_if_changed :group do - powershell_out!("Remove-NetFirewallRule -Name '#{new_resource.rule_name}'") + powershell_exec!("Remove-NetFirewallRule -Name '#{new_resource.rule_name}'") cmd = firewall_command("New") - powershell_out!(cmd) + powershell_exec!(cmd) end else converge_by("create firewall rule #{new_resource.rule_name}") do cmd = firewall_command("New") - powershell_out!(cmd) + powershell_exec!(cmd) end end end @@ -214,7 +212,7 @@ class Chef if current_resource converge_by("delete firewall rule #{new_resource.rule_name}") do - powershell_out!("Remove-NetFirewallRule -Name '#{new_resource.rule_name}'") + powershell_exec!("Remove-NetFirewallRule -Name '#{new_resource.rule_name}'") end else Chef::Log.info("Firewall rule \"#{new_resource.rule_name}\" doesn't exist. Skipping.") @@ -320,7 +318,7 @@ class Chef service = $serviceFilter.Service interface_type = $interfaceTypeFilter.InterfaceType.ToString() enabled = [bool]::Parse($rule.Enabled.ToString()) - }) | ConvertTo-Json + }) EOH end end diff --git a/lib/chef/resource/windows_security_policy.rb b/lib/chef/resource/windows_security_policy.rb index 069f240ce5..1b0a285197 100644 --- a/lib/chef/resource/windows_security_policy.rb +++ b/lib/chef/resource/windows_security_policy.rb @@ -106,11 +106,11 @@ class Chef MinimumPasswordAge = $security_options_hash.MinimumPasswordAge NewGuestName = $security_options_hash.NewGuestName LockoutBadCount = $security_options_hash.LockoutBadCount - }) | ConvertTo-Json + }) CODE - output = powershell_out(powershell_code) - current_value_does_not_exist! if output.stdout.empty? - state = Chef::JSONCompat.from_json(output.stdout) + output = powershell_exec(powershell_code) + current_value_does_not_exist! if output.result.empty? + state = output.result if desired.secoption == "ResetLockoutCount" || desired.secoption == "LockoutDuration" if state["LockoutBadCount"] == "0" @@ -144,7 +144,7 @@ class Chef Remove-Item $env:TEMP\\#{security_option}_Export.inf -force EOH - powershell_out!(cmd) + powershell_exec!(cmd) end end end diff --git a/lib/chef/resource/windows_share.rb b/lib/chef/resource/windows_share.rb index 47bf6cfb19..fe1e976747 100644 --- a/lib/chef/resource/windows_share.rb +++ b/lib/chef/resource/windows_share.rb @@ -20,7 +20,6 @@ # require_relative "../resource" -require_relative "../json_compat" require_relative "../util/path_helper" class Chef @@ -123,19 +122,19 @@ class Chef # this command selects individual objects because EncryptData & CachingMode have underlying # types that get converted to their Integer values by ConvertTo-Json & we need to make sure # those get written out as strings - share_state_cmd = "Get-SmbShare -Name '#{desired.share_name}' | Select-Object Name,Path, Description, Temporary, CATimeout, ContinuouslyAvailable, ConcurrentUserLimit, EncryptData | ConvertTo-Json -Compress" + share_state_cmd = "Get-SmbShare -Name '#{desired.share_name}' | Select-Object Name,Path, Description, Temporary, CATimeout, ContinuouslyAvailable, ConcurrentUserLimit, EncryptData" Chef::Log.debug("Running '#{share_state_cmd}' to determine share state'") - ps_results = powershell_out(share_state_cmd) + ps_results = powershell_exec(share_state_cmd) # detect a failure without raising and then set current_resource to nil if ps_results.error? - Chef::Log.debug("Error fetching share state: #{ps_results.stderr}") + Chef::Log.debug("Error fetching share state: #{ps_results.errors}") current_value_does_not_exist! end - Chef::Log.debug("The Get-SmbShare results were #{ps_results.stdout}") - results = Chef::JSONCompat.from_json(ps_results.stdout) + Chef::Log.debug("The Get-SmbShare results were #{ps_results.result}") + results = ps_results.result path results["Path"] description results["Description"] @@ -147,18 +146,18 @@ class Chef encrypt_data results["EncryptData"] # folder_enumeration_mode results['FolderEnumerationMode'] - perm_state_cmd = %{Get-SmbShareAccess -Name "#{desired.share_name}" | Select-Object AccountName,AccessControlType,AccessRight | ConvertTo-Json -Compress} + perm_state_cmd = %{Get-SmbShareAccess -Name "#{desired.share_name}" | Select-Object AccountName,AccessControlType,AccessRight} Chef::Log.debug("Running '#{perm_state_cmd}' to determine share permissions state'") - ps_perm_results = powershell_out(perm_state_cmd) + ps_perm_results = powershell_exec(perm_state_cmd) # we raise here instead of warning like above because we'd only get here if the above Get-SmbShare # command was successful and that continuing would leave us with 1/2 known state raise "Could not determine #{desired.share_name} share permissions by running '#{perm_state_cmd}'" if ps_perm_results.error? - Chef::Log.debug("The Get-SmbShareAccess results were #{ps_perm_results.stdout}") + Chef::Log.debug("The Get-SmbShareAccess results were #{ps_perm_results.result}") - f_users, c_users, r_users = parse_permissions(ps_perm_results.stdout) + f_users, c_users, r_users = parse_permissions(ps_perm_results.result) full_users f_users change_users c_users @@ -167,8 +166,7 @@ class Chef # given the string output of Get-SmbShareAccess parse out # arrays of full access users, change users, and read only users - def parse_permissions(results_string) - json_results = Chef::JSONCompat.from_json(results_string) + def parse_permissions(json_results) json_results = [json_results] unless json_results.is_a?(Array) # single result is not an array f_users = [] @@ -246,14 +244,16 @@ class Chef delete_command = "Remove-SmbShare -Name '#{new_resource.share_name}' -Force" Chef::Log.debug("Running '#{delete_command}' to remove the share") - powershell_out!(delete_command) + powershell_exec!(delete_command) end def update_share - update_command = "Set-SmbShare -Name '#{new_resource.share_name}' -Description '#{new_resource.description}' -Force" + update_command = "Set-SmbShare -Name '#{new_resource.share_name}' -Description '#{new_resource.description}' -ConcurrentUserLimit #{new_resource.concurrent_user_limit} -CATimeout #{new_resource.ca_timeout} -EncryptData:#{bool_string(new_resource.encrypt_data)} -ContinuouslyAvailable:#{bool_string(new_resource.continuously_available)} -Force" + update_command << " -ScopeName #{new_resource.scope_name}" unless new_resource.scope_name == "*" # passing * causes the command to fail + update_command << " -Temporary:#{bool_string(new_resource.temporary)}" if new_resource.temporary # only set true Chef::Log.debug("Running '#{update_command}' to update the share") - powershell_out!(update_command) + powershell_exec!(update_command) end def create_share @@ -264,7 +264,7 @@ class Chef share_cmd << " -Temporary:#{bool_string(new_resource.temporary)}" if new_resource.temporary # only set true Chef::Log.debug("Running '#{share_cmd}' to create the share") - powershell_out!(share_cmd) + powershell_exec!(share_cmd) # New-SmbShare adds the "Everyone" user with read access no matter what so we need to remove it # before we add our permissions @@ -299,7 +299,7 @@ class Chef grant_command = "Grant-SmbShareAccess -Name '#{new_resource.share_name}' -AccountName \"#{new_resource.send("#{perm_type}_users").join('","')}\" -Force -AccessRight #{perm_type}" Chef::Log.debug("Running '#{grant_command}' to update the share permissions") - powershell_out!(grant_command) + powershell_exec!(grant_command) end end @@ -330,7 +330,7 @@ class Chef def revoke_user_permissions(users) revoke_command = "Revoke-SmbShareAccess -Name '#{new_resource.share_name}' -AccountName \"#{users.join('","')}\" -Force" Chef::Log.debug("Running '#{revoke_command}' to revoke share permissions") - powershell_out!(revoke_command) + powershell_exec!(revoke_command) end # convert True/False into "$True" & "$False" diff --git a/lib/chef/resource/windows_workgroup.rb b/lib/chef/resource/windows_workgroup.rb index e506b51257..3c49f7cb3e 100644 --- a/lib/chef/resource/windows_workgroup.rb +++ b/lib/chef/resource/windows_workgroup.rb @@ -92,8 +92,8 @@ class Chef unless workgroup_member? converge_by("join workstation workgroup #{new_resource.workgroup_name}") do - ps_run = powershell_out(join_command) - raise "Failed to join the workgroup #{new_resource.workgroup_name}: #{ps_run.stderr}}" if ps_run.error? + ps_run = powershell_exec(join_command) + raise "Failed to join the workgroup #{new_resource.workgroup_name}: #{ps_run.errors}}" if ps_run.error? unless new_resource.reboot == :never reboot "Reboot to join workgroup #{new_resource.workgroup_name}" do @@ -119,10 +119,10 @@ class Chef # @return [Boolean] is the node a member of the workgroup specified in the resource def workgroup_member? - node_workgroup = powershell_out!("(Get-WmiObject -Class Win32_ComputerSystem).Workgroup") + node_workgroup = powershell_exec!("(Get-WmiObject -Class Win32_ComputerSystem).Workgroup") raise "Failed to determine if system already a member of workgroup #{new_resource.workgroup_name}" if node_workgroup.error? - node_workgroup.stdout.downcase.strip == new_resource.workgroup_name.downcase + String(node_workgroup.result).downcase.strip == new_resource.workgroup_name.downcase end end end diff --git a/spec/functional/resource/chocolatey_package_spec.rb b/spec/functional/resource/chocolatey_package_spec.rb index 24975d2e01..e55c1a453c 100644 --- a/spec/functional/resource/chocolatey_package_spec.rb +++ b/spec/functional/resource/chocolatey_package_spec.rb @@ -16,13 +16,13 @@ # limitations under the License. # require "spec_helper" -require "chef/mixin/powershell_out" +require "chef/mixin/shell_out" describe Chef::Resource::ChocolateyPackage, :windows_only, :choco_installed do - include Chef::Mixin::PowershellOut + include Chef::Mixin::ShellOut let(:package_name) { "test-A" } - let(:package_list) { proc { powershell_out!("choco list -lo -r #{Array(package_name).join(" ")}").stdout.chomp } } + let(:package_list) { proc { shell_out!("choco list -lo -r #{Array(package_name).join(" ")}").stdout.chomp } } let(:package_source) { File.join(CHEF_SPEC_ASSETS, "chocolatey_feed") } let(:run_context) do diff --git a/spec/functional/resource/dsc_script_spec.rb b/spec/functional/resource/dsc_script_spec.rb index 83544cee04..9d18e2f85d 100644 --- a/spec/functional/resource/dsc_script_spec.rb +++ b/spec/functional/resource/dsc_script_spec.rb @@ -17,13 +17,13 @@ # require "spec_helper" -require "chef/mixin/powershell_out" +require "chef/mixin/powershell_exec" require "chef/mixin/windows_architecture_helper" require "support/shared/integration/integration_helper" describe Chef::Resource::DscScript, :windows_powershell_dsc_only do include Chef::Mixin::WindowsArchitectureHelper - include Chef::Mixin::PowershellOut + include Chef::Mixin::PowershellExec before(:all) do @temp_dir = ::Dir.mktmpdir("dsc-functional-test") # enable the HTTP listener if it is not already enabled needed by underlying DSC engine @@ -33,7 +33,7 @@ describe Chef::Resource::DscScript, :windows_powershell_dsc_only do winrm create winrm/config/Listener?Address=*+Transport=HTTP } CODE - powershell_out!(winrm_code) + powershell_exec!(winrm_code) end after(:all) do diff --git a/spec/functional/resource/powershell_package_source_spec.rb b/spec/functional/resource/powershell_package_source_spec.rb new file mode 100644 index 0000000000..fa95415788 --- /dev/null +++ b/spec/functional/resource/powershell_package_source_spec.rb @@ -0,0 +1,103 @@ +# +# Author:: Matt Wrock () +# Copyright:: Copyright (c) Chef Software Inc. +# License:: Apache License, Version 2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +require "spec_helper" +require "chef/mixin/powershell_exec" + +describe Chef::Resource::PowershellPackageSource, :windows_only do + include Chef::Mixin::PowershellExec + + let(:source_name) { "fake" } + let(:url) { "https://www.nuget.org/api/v2" } + let(:trusted) { true } + + let(:run_context) do + Chef::RunContext.new(Chef::Node.new, {}, Chef::EventDispatch::Dispatcher.new) + end + + subject do + new_resource = Chef::Resource::PowershellPackageSource.new("test powershell package source", run_context) + new_resource.source_name source_name + new_resource.url url + new_resource.trusted trusted + new_resource.provider_name provider_name + new_resource + end + + let(:provider) do + provider = subject.provider_for_action(subject.action) + provider + end + + shared_examples "package_source" do + context "register a package source" do + after { remove_package_source } + + it "registers the package source" do + subject.run_action(:register) + expect(get_installed_package_source_name).to eq(source_name) + end + + it "does not register the package source if already installed" do + subject.run_action(:register) + subject.run_action(:register) + expect(subject).not_to be_updated_by_last_action + end + + it "updates an existing package source if changed" do + subject.run_action(:register) + subject.trusted !trusted + subject.run_action(:register) + expect(subject).to be_updated_by_last_action + end + end + + context "unregister a package source" do + it "unregisters the package source" do + subject.run_action(:register) + subject.run_action(:unregister) + expect(get_installed_package_source_name).to be_empty + end + + it "does not unregister the package source if not already installed" do + subject.run_action(:unregister) + expect(subject).not_to be_updated_by_last_action + end + end + end + + context "with NuGet provider" do + let(:provider_name) { "NuGet" } + + it_behaves_like "package_source" + end + + context "with PowerShellGet provider" do + let(:provider_name) { "PowerShellGet" } + + it_behaves_like "package_source" + end + + def get_installed_package_source_name + powershell_exec!("(Get-PackageSource -Name #{source_name} -ErrorAction SilentlyContinue).Name").result + end + + def remove_package_source + pkg_to_remove = Chef::Resource::PowershellPackageSource.new(source_name, run_context) + pkg_to_remove.run_action(:unregister) + end +end \ No newline at end of file diff --git a/spec/functional/resource/windows_certificate_spec.rb b/spec/functional/resource/windows_certificate_spec.rb index 9c996fe1f8..20d444dd59 100644 --- a/spec/functional/resource/windows_certificate_spec.rb +++ b/spec/functional/resource/windows_certificate_spec.rb @@ -16,18 +16,18 @@ # require "spec_helper" -require "chef/mixin/powershell_out" +require "chef/mixin/powershell_exec" require "chef/resource/windows_certificate" module WindowsCertificateHelper - include Chef::Mixin::PowershellOut + include Chef::Mixin::PowershellExec def create_store(store) path = "Cert:\\LocalMachine\\" + store command = <<~EOC New-Item -Path #{path} EOC - powershell_out(command) + powershell_exec(command) end def cleanup(store) @@ -35,15 +35,19 @@ module WindowsCertificateHelper command = <<~EOC Remove-Item -Path #{path} -Recurse EOC - powershell_out(command) + powershell_exec(command) end def no_of_certificates path = "Cert:\\LocalMachine\\" + store + # Seems weird that we have to call dir twice right? + # The powershell pki module cache the last dir in module session state + # Issuing dir with a different arg (-Force) seems to refresh that state. command = <<~EOC - Write-Host (dir #{path} | measure).Count; + dir #{path} -Force | Out-Null + (dir #{path} | measure).Count EOC - powershell_out(command).stdout.to_i + powershell_exec(command).result.to_i end end diff --git a/spec/functional/resource/windows_firewall_rule_spec.rb b/spec/functional/resource/windows_firewall_rule_spec.rb new file mode 100644 index 0000000000..86220c1b71 --- /dev/null +++ b/spec/functional/resource/windows_firewall_rule_spec.rb @@ -0,0 +1,93 @@ +# +# Author:: Matt Wrock () +# Copyright:: Copyright (c) Chef Software Inc. +# License:: Apache License, Version 2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +require "spec_helper" +require "chef/mixin/powershell_exec" + +describe Chef::Resource::WindowsFirewallRule, :windows_only do + include Chef::Mixin::PowershellExec + + let(:rule_name) { "fake_rule" } + let(:remote_port) { "5555" } + let(:enabled) { false } + + let(:run_context) do + Chef::RunContext.new(Chef::Node.new, {}, Chef::EventDispatch::Dispatcher.new) + end + + subject do + new_resource = Chef::Resource::WindowsFirewallRule.new("test firewall rule", run_context) + new_resource.rule_name rule_name + new_resource.remote_port remote_port + new_resource.enabled enabled + new_resource + end + + let(:provider) do + provider = subject.provider_for_action(subject.action) + provider + end + + context "create a new rule" do + after { delete_rule } + + it "creates the rule" do + subject.run_action(:create) + expect(get_installed_rule_name).to eq(rule_name) + expect(get_installed_rule_remote_port).to eq(remote_port) + end + + it "does not create rule if it already exists" do + subject.run_action(:create) + subject.run_action(:create) + expect(subject).not_to be_updated_by_last_action + end + + it "updates the rule if it changed" do + subject.run_action(:create) + subject.remote_port = "7777" + subject.run_action(:create) + expect(get_installed_rule_remote_port).to eq("7777") + end + end + + context "delete a rule" do + it "deletes an existing rule" do + subject.run_action(:create) + subject.run_action(:delete) + expect(get_installed_rule_name).to be_empty + end + + it "does not delete rule if it does not exist" do + subject.run_action(:delete) + expect(subject).not_to be_updated_by_last_action + end + end + + def get_installed_rule_name + powershell_exec!("(Get-NetFirewallRule -Name #{rule_name} -ErrorAction SilentlyContinue).Name").result + end + + def get_installed_rule_remote_port + powershell_exec!("((Get-NetFirewallRule -Name #{rule_name} -ErrorAction SilentlyContinue) | Get-NetFirewallPortFilter).RemotePort").result + end + + def delete_rule + rule_to_remove = Chef::Resource::WindowsFirewallRule.new(rule_name, run_context) + rule_to_remove.run_action(:delete) + end +end diff --git a/spec/functional/resource/windows_share_spec.rb b/spec/functional/resource/windows_share_spec.rb new file mode 100644 index 0000000000..6fae7d45d3 --- /dev/null +++ b/spec/functional/resource/windows_share_spec.rb @@ -0,0 +1,103 @@ +# +# Author:: Matt Wrock () +# Copyright:: Copyright (c) Chef Software Inc. +# License:: Apache License, Version 2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +require "spec_helper" +require "chef/mixin/powershell_exec" + +describe Chef::Resource::WindowsShare, :windows_only do + include Chef::Mixin::PowershellExec + + let(:share_name) { "fake_share" } + let(:path) { ENV["temp"] } + let(:concurrent_user_limit) { 7 } + let(:full_users) { ["#{ENV["USERNAME"]}"] } + + let(:run_context) do + node = Chef::Node.new + node.default["hostname"] = ENV["COMPUTERNAME"] + Chef::RunContext.new(node, {}, Chef::EventDispatch::Dispatcher.new) + end + + subject do + new_resource = Chef::Resource::WindowsShare.new("test windows share", run_context) + new_resource.share_name share_name + new_resource.path path + new_resource.concurrent_user_limit concurrent_user_limit + new_resource.full_users full_users + new_resource + end + + let(:provider) do + provider = subject.provider_for_action(subject.action) + provider + end + + context "create a new share" do + after { delete_share } + + it "creates the share" do + subject.run_action(:create) + share = get_installed_share + expect(share["Name"]).to eq(share_name) + expect(share["Path"]).to eq(path) + expect(get_installed_share_access["AccountName"]).to eq("#{ENV["COMPUTERNAME"]}\\#{full_users[0]}") + end + + it "does not create share if it already exists" do + subject.run_action(:create) + subject.run_action(:create) + expect(subject).not_to be_updated_by_last_action + end + + it "updates the share if it changed" do + subject.run_action(:create) + subject.concurrent_user_limit 8 + subject.full_users ["BUILTIN\\Administrators"] + subject.run_action(:create) + share = get_installed_share + expect(share["ConcurrentUserLimit"]).to eq(8) + expect(get_installed_share_access["AccountName"]).to eq("BUILTIN\\Administrators") + end + + end + + context "delete a share" do + it "deletes an existing share" do + subject.run_action(:create) + subject.run_action(:delete) + expect(get_installed_share).to be_empty + end + + it "does not delete share if it does not exist" do + subject.run_action(:delete) + expect(subject).not_to be_updated_by_last_action + end + end + + def get_installed_share + powershell_exec!("Get-SmbShare -Name #{share_name} -ErrorAction SilentlyContinue").result + end + + def get_installed_share_access + powershell_exec!("Get-SmbShareAccess -Name #{share_name} -ErrorAction SilentlyContinue").result + end + + def delete_share + rule_to_remove = Chef::Resource::WindowsShare.new(share_name, run_context) + rule_to_remove.run_action(:delete) + end +end diff --git a/spec/support/platform_helpers.rb b/spec/support/platform_helpers.rb index 60990f73a5..b29c860f30 100644 --- a/spec/support/platform_helpers.rb +++ b/spec/support/platform_helpers.rb @@ -2,11 +2,9 @@ require "fcntl" require "chef/mixin/shell_out" require "ohai/mixin/http_helper" require "ohai/mixin/gce_metadata" -require "chef/mixin/powershell_out" class ShellHelpers extend Chef::Mixin::ShellOut - extend Chef::Mixin::PowershellOut end # magic stolen from bundler/spec/support/less_than_proc.rb @@ -242,11 +240,15 @@ def ifconfig? end def choco_installed? - result = ShellHelpers.powershell_out("choco --version") + result = ShellHelpers.shell_out("choco --version") result.stderr.empty? +rescue + false end def pwsh_installed? - result = ShellHelpers.powershell_out("pwsh.exe --version") + result = ShellHelpers.shell_out("pwsh.exe --version") result.stderr.empty? +rescue + false end diff --git a/spec/unit/provider/package/chocolatey_spec.rb b/spec/unit/provider/package/chocolatey_spec.rb index 96b17d90f2..ba5739fe55 100644 --- a/spec/unit/provider/package/chocolatey_spec.rb +++ b/spec/unit/provider/package/chocolatey_spec.rb @@ -501,8 +501,7 @@ describe "behavior when Chocolatey is not installed" do before do # the shellout sometimes returns "", but test nil to be safe. - allow(provider).to receive(:choco_install_path).and_return(nil) - provider.instance_variable_set("@choco_install_path", nil) + allow(provider).to receive(:choco_install_path).and_return("") # we don't care what this returns, but we have to let it be called. allow(provider).to receive(:shell_out_compacted!).and_return(double(stdout: "")) diff --git a/spec/unit/resource/powershell_package_source_spec.rb b/spec/unit/resource/powershell_package_source_spec.rb index 2640d9f3c5..1032902a0f 100644 --- a/spec/unit/resource/powershell_package_source_spec.rb +++ b/spec/unit/resource/powershell_package_source_spec.rb @@ -87,58 +87,58 @@ describe Chef::Resource::PowershellPackageSource do context "#register" do it "builds a minimal command" do - expect(provider.build_ps_repository_command("Register", resource)).to eql("Register-PSRepository -Name 'MyGallery' -SourceLocation 'https://mygallery.company.co/api/v2/' -InstallationPolicy 'Untrusted'") + expect(provider.build_ps_repository_command("Register", resource)).to eql("Register-PSRepository -Name 'MyGallery' -SourceLocation 'https://mygallery.company.co/api/v2/' -InstallationPolicy 'Untrusted' | Out-Null") end it "builds a command with trusted set to true" do resource.trusted(true) - expect(provider.build_ps_repository_command("Register", resource)).to eql("Register-PSRepository -Name 'MyGallery' -SourceLocation 'https://mygallery.company.co/api/v2/' -InstallationPolicy 'Trusted'") + expect(provider.build_ps_repository_command("Register", resource)).to eql("Register-PSRepository -Name 'MyGallery' -SourceLocation 'https://mygallery.company.co/api/v2/' -InstallationPolicy 'Trusted' | Out-Null") end it "builds a command with a publish location" do resource.publish_location("https://mygallery.company.co/api/v2/package") - expect(provider.build_ps_repository_command("Register", resource)).to eql("Register-PSRepository -Name 'MyGallery' -SourceLocation 'https://mygallery.company.co/api/v2/' -InstallationPolicy 'Untrusted' -PublishLocation 'https://mygallery.company.co/api/v2/package'") + expect(provider.build_ps_repository_command("Register", resource)).to eql("Register-PSRepository -Name 'MyGallery' -SourceLocation 'https://mygallery.company.co/api/v2/' -InstallationPolicy 'Untrusted' -PublishLocation 'https://mygallery.company.co/api/v2/package' | Out-Null") end it "builds a command with a script source location" do resource.script_source_location("https://mygallery.company.co/api/v2/scripts") - expect(provider.build_ps_repository_command("Register", resource)).to eql("Register-PSRepository -Name 'MyGallery' -SourceLocation 'https://mygallery.company.co/api/v2/' -InstallationPolicy 'Untrusted' -ScriptSourceLocation 'https://mygallery.company.co/api/v2/scripts'") + expect(provider.build_ps_repository_command("Register", resource)).to eql("Register-PSRepository -Name 'MyGallery' -SourceLocation 'https://mygallery.company.co/api/v2/' -InstallationPolicy 'Untrusted' -ScriptSourceLocation 'https://mygallery.company.co/api/v2/scripts' | Out-Null") end it "builds a command with a script publish location" do resource.script_publish_location("https://mygallery.company.co/api/v2/scripts/package") - expect(provider.build_ps_repository_command("Register", resource)).to eql("Register-PSRepository -Name 'MyGallery' -SourceLocation 'https://mygallery.company.co/api/v2/' -InstallationPolicy 'Untrusted' -ScriptPublishLocation 'https://mygallery.company.co/api/v2/scripts/package'") + expect(provider.build_ps_repository_command("Register", resource)).to eql("Register-PSRepository -Name 'MyGallery' -SourceLocation 'https://mygallery.company.co/api/v2/' -InstallationPolicy 'Untrusted' -ScriptPublishLocation 'https://mygallery.company.co/api/v2/scripts/package' | Out-Null") end end context "#set" do it "builds a minimal command" do - expect(provider.build_ps_repository_command("Set", resource)).to eql("Set-PSRepository -Name 'MyGallery' -SourceLocation 'https://mygallery.company.co/api/v2/' -InstallationPolicy 'Untrusted'") + expect(provider.build_ps_repository_command("Set", resource)).to eql("Set-PSRepository -Name 'MyGallery' -SourceLocation 'https://mygallery.company.co/api/v2/' -InstallationPolicy 'Untrusted' | Out-Null") end it "builds a command to change the url" do resource.url("https://othergallery.company.co/api/v2/") - expect(provider.build_ps_repository_command("Set", resource)).to eql("Set-PSRepository -Name 'MyGallery' -SourceLocation 'https://othergallery.company.co/api/v2/' -InstallationPolicy 'Untrusted'") + expect(provider.build_ps_repository_command("Set", resource)).to eql("Set-PSRepository -Name 'MyGallery' -SourceLocation 'https://othergallery.company.co/api/v2/' -InstallationPolicy 'Untrusted' | Out-Null") end it "builds a command with trusted set to true" do resource.trusted(true) - expect(provider.build_ps_repository_command("Set", resource)).to eql("Set-PSRepository -Name 'MyGallery' -SourceLocation 'https://mygallery.company.co/api/v2/' -InstallationPolicy 'Trusted'") + expect(provider.build_ps_repository_command("Set", resource)).to eql("Set-PSRepository -Name 'MyGallery' -SourceLocation 'https://mygallery.company.co/api/v2/' -InstallationPolicy 'Trusted' | Out-Null") end it "builds a command with a publish location" do resource.publish_location("https://mygallery.company.co/api/v2/package") - expect(provider.build_ps_repository_command("Set", resource)).to eql("Set-PSRepository -Name 'MyGallery' -SourceLocation 'https://mygallery.company.co/api/v2/' -InstallationPolicy 'Untrusted' -PublishLocation 'https://mygallery.company.co/api/v2/package'") + expect(provider.build_ps_repository_command("Set", resource)).to eql("Set-PSRepository -Name 'MyGallery' -SourceLocation 'https://mygallery.company.co/api/v2/' -InstallationPolicy 'Untrusted' -PublishLocation 'https://mygallery.company.co/api/v2/package' | Out-Null") end it "builds a command with a script source location" do resource.script_source_location("https://mygallery.company.co/api/v2/scripts") - expect(provider.build_ps_repository_command("Set", resource)).to eql("Set-PSRepository -Name 'MyGallery' -SourceLocation 'https://mygallery.company.co/api/v2/' -InstallationPolicy 'Untrusted' -ScriptSourceLocation 'https://mygallery.company.co/api/v2/scripts'") + expect(provider.build_ps_repository_command("Set", resource)).to eql("Set-PSRepository -Name 'MyGallery' -SourceLocation 'https://mygallery.company.co/api/v2/' -InstallationPolicy 'Untrusted' -ScriptSourceLocation 'https://mygallery.company.co/api/v2/scripts' | Out-Null") end it "builds a command with a script publish location" do resource.script_publish_location("https://mygallery.company.co/api/v2/scripts/package") - expect(provider.build_ps_repository_command("Set", resource)).to eql("Set-PSRepository -Name 'MyGallery' -SourceLocation 'https://mygallery.company.co/api/v2/' -InstallationPolicy 'Untrusted' -ScriptPublishLocation 'https://mygallery.company.co/api/v2/scripts/package'") + expect(provider.build_ps_repository_command("Set", resource)).to eql("Set-PSRepository -Name 'MyGallery' -SourceLocation 'https://mygallery.company.co/api/v2/' -InstallationPolicy 'Untrusted' -ScriptPublishLocation 'https://mygallery.company.co/api/v2/scripts/package' | Out-Null") end end end @@ -151,42 +151,42 @@ describe Chef::Resource::PowershellPackageSource do context "#register" do it "builds a minimal command" do - expect(provider.build_package_source_command("Register", resource)).to eql("Register-PackageSource -Name 'NuGet' -Location 'http://nuget.org/api/v2/' -Trusted:$false -ProviderName 'NuGet'") + expect(provider.build_package_source_command("Register", resource)).to eql("Register-PackageSource -Name 'NuGet' -Location 'http://nuget.org/api/v2/' -Trusted:$false -ProviderName 'NuGet' | Out-Null") end it "builds a command with trusted set to true" do resource.trusted(true) - expect(provider.build_package_source_command("Register", resource)).to eql("Register-PackageSource -Name 'NuGet' -Location 'http://nuget.org/api/v2/' -Trusted:$true -ProviderName 'NuGet'") + expect(provider.build_package_source_command("Register", resource)).to eql("Register-PackageSource -Name 'NuGet' -Location 'http://nuget.org/api/v2/' -Trusted:$true -ProviderName 'NuGet' | Out-Null") end it "builds a command with a different provider" do resource.source_name("choco") resource.url("https://chocolatey.org/api/v2/") resource.provider_name("chocolatey") - expect(provider.build_package_source_command("Register", resource)).to eql("Register-PackageSource -Name 'choco' -Location 'https://chocolatey.org/api/v2/' -Trusted:$false -ProviderName 'chocolatey'") + expect(provider.build_package_source_command("Register", resource)).to eql("Register-PackageSource -Name 'choco' -Location 'https://chocolatey.org/api/v2/' -Trusted:$false -ProviderName 'chocolatey' | Out-Null") end end context "#set" do it "builds a minimal command" do - expect(provider.build_package_source_command("Set", resource)).to eql("Set-PackageSource -Name 'NuGet' -Location 'http://nuget.org/api/v2/' -Trusted:$false -ProviderName 'NuGet'") + expect(provider.build_package_source_command("Set", resource)).to eql("Set-PackageSource -Name 'NuGet' -Location 'http://nuget.org/api/v2/' -Trusted:$false -ProviderName 'NuGet' | Out-Null") end it "builds a command to change the url" do resource.url("https://nuget.company.co/api/v2/") - expect(provider.build_package_source_command("Set", resource)).to eql("Set-PackageSource -Name 'NuGet' -Location 'https://nuget.company.co/api/v2/' -Trusted:$false -ProviderName 'NuGet'") + expect(provider.build_package_source_command("Set", resource)).to eql("Set-PackageSource -Name 'NuGet' -Location 'https://nuget.company.co/api/v2/' -Trusted:$false -ProviderName 'NuGet' | Out-Null") end it "builds a command with trusted set to true" do resource.trusted(true) - expect(provider.build_package_source_command("Set", resource)).to eql("Set-PackageSource -Name 'NuGet' -Location 'http://nuget.org/api/v2/' -Trusted:$true -ProviderName 'NuGet'") + expect(provider.build_package_source_command("Set", resource)).to eql("Set-PackageSource -Name 'NuGet' -Location 'http://nuget.org/api/v2/' -Trusted:$true -ProviderName 'NuGet' | Out-Null") end it "builds a command with a different provider" do resource.source_name("choco") resource.url("https://chocolatey.org/api/v2/") resource.provider_name("chocolatey") - expect(provider.build_package_source_command("Set", resource)).to eql("Set-PackageSource -Name 'choco' -Location 'https://chocolatey.org/api/v2/' -Trusted:$false -ProviderName 'chocolatey'") + expect(provider.build_package_source_command("Set", resource)).to eql("Set-PackageSource -Name 'choco' -Location 'https://chocolatey.org/api/v2/' -Trusted:$false -ProviderName 'chocolatey' | Out-Null") end end end @@ -205,13 +205,13 @@ describe Chef::Resource::PowershellPackageSource do describe "#package_source_exists?" do it "returns true if it exists" do - allow(provider).to receive(:powershell_out!).with("(Get-PackageSource -Name 'MyGallery' -WarningAction SilentlyContinue).Name").and_return(double("powershell_out!", stdout: "MyGallery\r\n")) + allow(provider).to receive(:powershell_exec!).with("(Get-PackageSource -Name 'MyGallery' -ErrorAction SilentlyContinue).Name").and_return(double("powershell_exec!", result: "MyGallery\r\n")) resource.source_name("MyGallery") expect(provider.package_source_exists?).to eql(true) end it "returns false if it doesn't exist" do - allow(provider).to receive(:powershell_out!).with("(Get-PackageSource -Name 'MyGallery' -WarningAction SilentlyContinue).Name").and_return(double("powershell_out!", stdout: "")) + allow(provider).to receive(:powershell_exec!).with("(Get-PackageSource -Name 'MyGallery' -ErrorAction SilentlyContinue).Name").and_return(double("powershell_exec!", result: "")) resource.source_name("MyGallery") expect(provider.package_source_exists?).to eql(false) end -- cgit v1.2.1 From b5eab58d40da1c69178aa6f59d05b49fd2b44300 Mon Sep 17 00:00:00 2001 From: mwrock Date: Wed, 28 Oct 2020 16:31:25 -0700 Subject: extend windows plan build to an hour Signed-off-by: mwrock --- .expeditor/verify.pipeline.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.expeditor/verify.pipeline.yml b/.expeditor/verify.pipeline.yml index 3f6f45be6e..5c58574cb3 100644 --- a/.expeditor/verify.pipeline.yml +++ b/.expeditor/verify.pipeline.yml @@ -620,6 +620,7 @@ steps: - label: ":habicat: Windows plan" commands: - ./scripts/ci/verify-plan.ps1 + timeout_in_minutes: 60 expeditor: executor: windows: -- cgit v1.2.1 From 31e13be0222e96d3f9b194b2530d6a0a1892a117 Mon Sep 17 00:00:00 2001 From: mwrock Date: Fri, 30 Oct 2020 13:54:16 -0700 Subject: fix habitat adembly resolution failures Signed-off-by: mwrock --- lib/chef/powershell.rb | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/lib/chef/powershell.rb b/lib/chef/powershell.rb index 905b92ebfb..4800708dfc 100644 --- a/lib/chef/powershell.rb +++ b/lib/chef/powershell.rb @@ -63,7 +63,15 @@ class Chef def exec(script) FFI.ffi_lib @dll FFI.attach_function :execute_powershell, :ExecuteScript, [:string], :pointer - execution = FFI.execute_powershell(script).read_utf16string + # This is a temporary fix for running in a Habitat environment + # In habitat we set CHEF_POWERSHELL_BIN so that .Net resolves our + # managed shim assembly from the correct location. + # It seems that that is preventing .Net from successfully loading GAC assemblies + # and can break all sorts of edge (and not so edge) scenarios. Once we are actually + # inside the powershell run space, we know our shim was loaded and can unset + # CHEF_POWERSHELL_BIN which will bypass our custom resolver logic. The real fix is + # to fix our resolver. Oh and OH MY GOD this was a pain to track down. + execution = FFI.execute_powershell("$ENV:CHEF_POWERSHELL_BIN=$NULL;#{script}").read_utf16string hashed_outcome = Chef::JSONCompat.parse(execution) @result = Chef::JSONCompat.parse(hashed_outcome["result"]) @errors = hashed_outcome["errors"] -- cgit v1.2.1