From aebf6c8c926719dbe743c2d4b11da62838d70ff8 Mon Sep 17 00:00:00 2001 From: Dag Wieers Date: Fri, 24 Feb 2017 08:08:19 +0100 Subject: [PATCH] powershell.ps1: Ensure Fail-Json() works with Hashtables (#21697) Without this change a dictionary $result object would be emptied if it is anything but a PSCustomObject. Now we also support Hashtables. --- lib/ansible/module_utils/powershell.ps1 | 42 +++++++++---------- .../win_async_wrapper/library/async_test.ps1 | 20 +++++---- .../targets/win_async_wrapper/tasks/main.yml | 2 +- 3 files changed, 34 insertions(+), 30 deletions(-) diff --git a/lib/ansible/module_utils/powershell.ps1 b/lib/ansible/module_utils/powershell.ps1 index ae8b10d221..bc0caefd83 100644 --- a/lib/ansible/module_utils/powershell.ps1 +++ b/lib/ansible/module_utils/powershell.ps1 @@ -38,7 +38,7 @@ Function Set-Attr($obj, $name, $value) # If the provided $obj is undefined, define one to be nice If (-not $obj.GetType) { - $obj = New-Object psobject + $obj = @{ } } Try @@ -59,7 +59,7 @@ Function Exit-Json($obj) # If the provided $obj is undefined, define one to be nice If (-not $obj.GetType) { - $obj = New-Object psobject + $obj = @{ } } echo $obj | ConvertTo-Json -Compress -Depth 99 @@ -67,25 +67,27 @@ Function Exit-Json($obj) } # Helper function to add the "msg" property and "failed" property, convert the -# powershell object to JSON and echo it, exiting the script +# powershell Hashtable to JSON and echo it, exiting the script # Example: Fail-Json $result "This is the failure message" Function Fail-Json($obj, $message = $null) { - # If we weren't given 2 args, and the only arg was a string, create a new - # psobject and use the arg as the failure message - If ($message -eq $null -and $obj.GetType().Name -eq "String") - { + if ($obj -is [hashtable] -or $obj -is [psobject]) { + # Nothing to do + } elseif ($obj -is [string] -and $message -eq $null) { + # If we weren't given 2 args, and the only arg was a string, + # create a new Hashtable and use the arg as the failure message $message = $obj - $obj = New-Object psobject - } - # If the first args is undefined or not an object, make it an object - ElseIf (-not $obj -or -not $obj.GetType -or $obj.GetType().Name -ne "PSCustomObject") - { - $obj = New-Object psobject + $obj = @{ } + } else { + # If the first argument is undefined or a different type, + # make it a Hashtable + $obj = @{ } } + # Still using Set-Attr for PSObject compatibility Set-Attr $obj "msg" $message Set-Attr $obj "failed" $true + echo $obj | ConvertTo-Json -Compress -Depth 99 Exit 1 } @@ -96,7 +98,7 @@ Function Fail-Json($obj, $message = $null) Function Add-Warning($obj, $message) { if (Get-Member -InputObject $obj -Name "warnings") { - if ($obj.warnings -is [System.Array]) { + if ($obj.warnings -is [array]) { $obj.warnings += $message } else { throw "warnings attribute is not an array" @@ -112,7 +114,7 @@ Function Add-Warning($obj, $message) Function Add-DeprecationWarning($obj, $message, $version = $null) { if (Get-Member -InputObject $obj -Name "deprecations") { - if ($obj.deprecations -is [System.Array]) { + if ($obj.deprecations -is [array]) { $obj.deprecations += @{ msg = $message version = $version @@ -238,12 +240,9 @@ Function ConvertTo-Bool $boolean_strings = "yes", "on", "1", "true", 1 $obj_string = [string]$obj - if (($obj.GetType().Name -eq "Boolean" -and $obj) -or $boolean_strings -contains $obj_string.ToLower()) - { + if (($obj -is [boolean] -and $obj) -or $boolean_strings -contains $obj_string.ToLower()) { return $true - } - Else - { + } else { return $false } } @@ -327,4 +326,5 @@ Function Get-PendingRebootStatus } # this line must stay at the bottom to ensure all defined module parts are exported -Export-ModuleMember -Alias * -Function * -Cmdlet * \ No newline at end of file +Export-ModuleMember -Alias * -Function * -Cmdlet * + diff --git a/test/integration/targets/win_async_wrapper/library/async_test.ps1 b/test/integration/targets/win_async_wrapper/library/async_test.ps1 index 3b891b9fac..63dbf86ca9 100644 --- a/test/integration/targets/win_async_wrapper/library/async_test.ps1 +++ b/test/integration/targets/win_async_wrapper/library/async_test.ps1 @@ -19,14 +19,18 @@ $parsed_args = Parse-Args $args -$sleep_delay_sec = Get-AnsibleParam $parsed_args "sleep_delay_sec" -default 0 -$fail_mode = Get-AnsibleParam $parsed_args "fail_mode" -default "success" -validateset "success","graceful","exception" +$sleep_delay_sec = Get-AnsibleParam -obj $parsed_args -name "sleep_delay_sec" -type "int" -default 0 +$fail_mode = Get-AnsibleParam -obj $parsed_args -name "fail_mode" -type "str" -default "success" -validateset "success","graceful","exception" If($fail_mode -isnot [array]) { $fail_mode = @($fail_mode) } -$result = @{changed=$true; module_pid=$pid; module_tempdir=$PSScriptRoot} +$result = @{ + changed = $true + module_pid = $pid + module_tempdir = $PSScriptRoot +} If($sleep_delay_sec -gt 0) { Sleep -Seconds $sleep_delay_sec @@ -37,13 +41,13 @@ If($fail_mode -contains "leading_junk") { Write-Output "leading junk before module output" } +If($fail_mode -contains "graceful") { + Fail-Json $result "failed gracefully" +} + Try { - If($fail_mode -contains "graceful") { - Fail-Json $result "failed gracefully" - } - - If($fail_mode -eq "exception") { + If($fail_mode -contains "exception") { Throw "failing via exception" } diff --git a/test/integration/targets/win_async_wrapper/tasks/main.yml b/test/integration/targets/win_async_wrapper/tasks/main.yml index 582197a4dd..8a2fd351ab 100644 --- a/test/integration/targets/win_async_wrapper/tasks/main.yml +++ b/test/integration/targets/win_async_wrapper/tasks/main.yml @@ -116,7 +116,7 @@ that: - asyncresult.ansible_job_id is match('\d+\.\d+') - asyncresult.finished == 1 - - asyncresult.changed == false + - asyncresult.changed == true - asyncresult | failed == true - asyncresult.msg == 'failed gracefully'