blob: c2138e35914326c166f319e9dff73c846425099f (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
|
# (c) 2018 Ansible Project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
param(
[Parameter(Mandatory = $true)][System.Collections.IDictionary]$Payload
)
# help with debugging errors as we don't have visibility of this running process
trap {
$watchdog_path = "$($env:TEMP)\ansible-async-watchdog-error-$(Get-Date -Format "yyyy-MM-ddTHH-mm-ss.ffffZ").txt"
$error_msg = "Error while running the async exec wrapper`r`n$(Format-AnsibleException -ErrorRecord $_)"
Set-Content -Path $watchdog_path -Value $error_msg
break
}
$ErrorActionPreference = "Stop"
Write-AnsibleLog "INFO - starting async_watchdog" "async_watchdog"
# pop 0th action as entrypoint
$payload.actions = $payload.actions[1..99]
$actions = $Payload.actions
$entrypoint = $payload.($actions[0])
$entrypoint = [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($entrypoint))
$resultfile_path = $payload.async_results_path
$max_exec_time_sec = $payload.async_timeout_sec
Write-AnsibleLog "INFO - deserializing existing result file args at: '$resultfile_path'" "async_watchdog"
if (-not (Test-Path -Path $resultfile_path)) {
$msg = "result file at '$resultfile_path' does not exist"
Write-AnsibleLog "ERROR - $msg" "async_watchdog"
throw $msg
}
$result_json = Get-Content -Path $resultfile_path -Raw
Write-AnsibleLog "INFO - result file json is: $result_json" "async_watchdog"
$result = ConvertFrom-AnsibleJson -InputObject $result_json
Write-AnsibleLog "INFO - creating async runspace" "async_watchdog"
$rs = [RunspaceFactory]::CreateRunspace()
$rs.Open()
Write-AnsibleLog "INFO - creating async PowerShell pipeline" "async_watchdog"
$ps = [PowerShell]::Create()
$ps.Runspace = $rs
# these functions are set in exec_wrapper
Write-AnsibleLog "INFO - adding global functions to PowerShell pipeline script" "async_watchdog"
$ps.AddScript($script:common_functions).AddStatement() > $null
$ps.AddScript($script:wrapper_functions).AddStatement() > $null
$function_params = @{
Name = "common_functions"
Value = $script:common_functions
Scope = "script"
}
$ps.AddCommand("Set-Variable").AddParameters($function_params).AddStatement() > $null
Write-AnsibleLog "INFO - adding $($actions[0]) to PowerShell pipeline script" "async_watchdog"
$ps.AddScript($entrypoint).AddArgument($payload) > $null
Write-AnsibleLog "INFO - async job start, calling BeginInvoke()" "async_watchdog"
$job_async_result = $ps.BeginInvoke()
Write-AnsibleLog "INFO - waiting '$max_exec_time_sec' seconds for async job to complete" "async_watchdog"
$job_async_result.AsyncWaitHandle.WaitOne($max_exec_time_sec * 1000) > $null
$result.finished = 1
if ($job_async_result.IsCompleted) {
Write-AnsibleLog "INFO - async job completed, calling EndInvoke()" "async_watchdog"
$job_output = $ps.EndInvoke($job_async_result)
$job_error = $ps.Streams.Error
Write-AnsibleLog "INFO - raw module stdout:`r`n$($job_output | Out-String)" "async_watchdog"
if ($job_error) {
Write-AnsibleLog "WARN - raw module stderr:`r`n$($job_error | Out-String)" "async_watchdog"
}
# write success/output/error to result object
# TODO: cleanse leading/trailing junk
try {
Write-AnsibleLog "INFO - deserializing Ansible stdout" "async_watchdog"
$module_result = ConvertFrom-AnsibleJson -InputObject $job_output
# TODO: check for conflicting keys
$result = $result + $module_result
}
catch {
$result.failed = $true
$result.msg = "failed to parse module output: $($_.Exception.Message)"
# return output back to Ansible to help with debugging errors
$result.stdout = $job_output | Out-String
$result.stderr = $job_error | Out-String
}
$result_json = ConvertTo-Json -InputObject $result -Depth 99 -Compress
Set-Content -Path $resultfile_path -Value $result_json
Write-AnsibleLog "INFO - wrote output to $resultfile_path" "async_watchdog"
}
else {
Write-AnsibleLog "ERROR - reached timeout on async job, stopping job" "async_watchdog"
$ps.BeginStop($null, $null) > $null # best effort stop
# write timeout to result object
$result.failed = $true
$result.msg = "timed out waiting for module completion"
$result_json = ConvertTo-Json -InputObject $result -Depth 99 -Compress
Set-Content -Path $resultfile_path -Value $result_json
Write-AnsibleLog "INFO - wrote timeout to '$resultfile_path'" "async_watchdog"
}
# in the case of a hung pipeline, this will cause the process to stay alive until it's un-hung...
#$rs.Close() | Out-Null
Write-AnsibleLog "INFO - ending async_watchdog" "async_watchdog"
|