-
Notifications
You must be signed in to change notification settings - Fork 23.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
add win_wait_for_process #40404
Merged
ansibot
merged 9 commits into
ansible:devel
from
crossan007:module/add-win-wait-for-process
Aug 28, 2018
Merged
add win_wait_for_process #40404
Changes from all commits
Commits
Show all changes
9 commits
Select commit
Hold shift + click to select a range
07f8a12
add win_wait_for_process
crossan007 16912b5
try working on additional filter options and fix derps
crossan007 58a9ee6
improve process name matching: support arrays. support pre and post wait
crossan007 927ba22
use CIM instead of WIM. requre exact contain process binary extension
crossan007 736988e
updates to metadata
crossan007 5edb42c
fix errors in waiting for process to start
crossan007 46d0d93
validate process min count for absent state. fix typo
crossan007 46bc8bf
fix bug if only one processes is detected
crossan007 d731fc0
address GitHub comments
crossan007 File filter
Filter by extension
Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,162 @@ | ||
#!powershell | ||
# This file is part of Ansible | ||
|
||
# Copyright (c) 2017 Ansible Project | ||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) | ||
|
||
#Requires -Module Ansible.ModuleUtils.Legacy | ||
#Requires -Module Ansible.ModuleUtils.FileUtil | ||
|
||
$ErrorActionPreference = "Stop" | ||
|
||
$params = Parse-Args -arguments $args -supports_check_mode $true | ||
|
||
$process_name_exact = Get-AnsibleParam -obj $params -name "process_name_exact" -type "list" | ||
$process_name_pattern = Get-AnsibleParam -obj $params -name "process_name_pattern" -type "str" | ||
$process_id = Get-AnsibleParam -obj $params -name "pid" -type "int" -default 0 #pid is a reserved variable in PowerShell. use process_id instead. | ||
$owner = Get-AnsibleParam -obj $params -name "owner" -type "str" | ||
$sleep = Get-AnsibleParam -obj $params -name "sleep" -type "int" -default 1 | ||
$pre_wait_delay = Get-AnsibleParam -obj $params -name "pre_wait_delay" -type "int" -default 0 | ||
$post_wait_delay = Get-AnsibleParam -obj $params -name "post_wait_delay" -type "int" -default 0 | ||
$process_min_count = Get-AnsibleParam -obj $params -name "process_min_count" -type "int" -default 1 | ||
$state = Get-AnsibleParam -obj $params -name "state" -type "str" -default "present" -validateset "present","absent" | ||
$timeout = Get-AnsibleParam -obj $params -name "timeout" -type "int" -default 300 | ||
|
||
$result = @{ | ||
changed = $false | ||
} | ||
|
||
# validate the input | ||
if ($state -eq "absent" -and $sleep -ne 1) | ||
{ | ||
Add-Warning $result "sleep parameter has no effect when waiting for a process to stop." | ||
} | ||
|
||
if ($state -eq "absent" -and $process_min_count -ne 1) | ||
{ | ||
Add-Warning $result "process_min_count parameter has no effect when waiting for a process to stop." | ||
} | ||
|
||
if (($process_name_exact -or $process_name_pattern) -and $process_id) | ||
{ | ||
Fail-json $result "process_id may not be used with process_name_exact or process_name_pattern." | ||
} | ||
if ($process_name_exact -and $process_name_pattern) | ||
{ | ||
Fail-json $result "process_name_exact and process_name_pattern may not be used at the same time." | ||
} | ||
|
||
if (-not ($process_name_exact -or $process_name_pattern -or $process_id -or $owner)) | ||
{ | ||
Fail-json $result "at least one of: process_name_exact, process_name_pattern, process_id, or owner must be supplied." | ||
} | ||
|
||
$module_start = Get-Date | ||
|
||
#Get-Process doesn't actually return a UserName value, so get it from WMI. | ||
Function Get-ProcessMatchesFilter { | ||
[cmdletbinding()] | ||
Param( | ||
[String] | ||
$Owner, | ||
$ProcessNameExact, | ||
$ProcessNamePattern, | ||
[int] | ||
$ProcessId | ||
) | ||
|
||
$CIMProcesses = Get-CimInstance Win32_Process | ||
foreach ($CIMProcess in $CIMProcesses) | ||
{ | ||
$include = $true | ||
if(-not [String]::IsNullOrEmpty($ProcessNamePattern)) | ||
{ | ||
#if a process name was specified in the filter, validate that here. | ||
$include = $include -and ($CIMProcess.ProcessName -match $ProcessNamePattern) | ||
} | ||
if($ProcessNameExact -is [Array] -or (-not [String]::IsNullOrEmpty($ProcessNameExact))) | ||
{ | ||
#if a process name was specified in the filter, validate that here. | ||
if ($ProcessNameExact -is [Array] ) | ||
{ | ||
$include = $include -and ($ProcessNameExact -contains $CIMProcess.ProcessName) | ||
} | ||
else { | ||
$include = $include -and ($ProcessNameExact -eq $CIMProcess.ProcessName) | ||
} | ||
} | ||
if ($ProcessId -and $ProcessId -ne 0) | ||
{ | ||
# if a PID was specified in the filger, validate that here. | ||
$include = $include -and ($CIMProcess.ProcessId -eq $ProcessId) | ||
} | ||
if (-not [String]::IsNullOrEmpty($Owner) ) | ||
{ | ||
# if an owner was specified in the filter, validate that here. | ||
$include = $include -and ($($(Invoke-CimMethod -InputObject $CIMProcess -MethodName GetOwner).User) -eq $Owner) | ||
} | ||
|
||
if ($include) | ||
{ | ||
$CIMProcess | Select-Object -Property ProcessId, ProcessName, @{name="Owner";Expression={$($(Invoke-CimMethod -InputObject $CIMProcess -MethodName GetOwner).User)}} | ||
} | ||
} | ||
} | ||
|
||
Start-Sleep -Seconds $pre_wait_delay | ||
if ($state -eq "present" ) { | ||
#wait for a process to start | ||
$Processes = @() | ||
$attempts = 0 | ||
Do { | ||
if (((Get-Date) - $module_start).TotalSeconds -gt $timeout) | ||
{ | ||
$result.elapsed = ((Get-Date) - $module_start).TotalSeconds | ||
Fail-Json $result "timeout while waiting for $process_name to start. waited $timeout seconds" | ||
} | ||
|
||
$Processes = Get-ProcessMatchesFilter -Owner $owner -ProcessNameExact $process_name_exact -ProcessNamePattern $process_name_pattern -ProcessId $process_id | ||
Start-Sleep -Seconds $sleep | ||
$attempts ++ | ||
$ProcessCount = $null | ||
if ($Processes -is [array]) { | ||
$ProcessCount = $Processes.count | ||
} | ||
elseif ($null -ne $Processes) { | ||
$ProcessCount = 1 | ||
} | ||
else { | ||
$ProcessCount = 0 | ||
} | ||
} While ($ProcessCount -lt $process_min_count) | ||
|
||
if ($attempts -gt 0) | ||
{ | ||
$result.changed = $true | ||
} | ||
$result.matched_processess = $Processes | ||
} | ||
elseif ($state -eq "absent") { | ||
#wait for a process to stop | ||
$Processes = Get-ProcessMatchesFilter -Owner $owner -ProcessNameExact $process_name_exact -ProcessNamePattern $process_name_pattern -ProcessId $process_id | ||
$result.matched_processes = $Processes | ||
$ProcessCount = $(if ($Processes -is [array]) { $Processes.count } elseif ($Processes){ 1 } else {0}) | ||
if ($ProcessCount -gt 0 ) | ||
{ | ||
try { | ||
Wait-Process -Id $($Processes | Select-Object -ExpandProperty ProcessId) -Timeout $timeout -ErrorAction Stop | ||
$result.changed = $true | ||
} | ||
catch { | ||
$result.elapsed = ((Get-Date) - $module_start).TotalSeconds | ||
Fail-Json $result "$($_.Exception.Message). timeout while waiting for $process_name to stop. waited $timeout seconds" | ||
} | ||
} | ||
else{ | ||
$result.changed = $false | ||
|
||
} | ||
} | ||
Start-Sleep -Seconds $post_wait_delay | ||
$result.elapsed = ((Get-Date) - $module_start).TotalSeconds | ||
Exit-Json $result |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,99 @@ | ||
#!/usr/bin/python | ||
# -*- coding: utf-8 -*- | ||
|
||
# Copyright: (c) 2017, Ansible Project | ||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) | ||
|
||
# this is a windows documentation stub, actual code lives in the .ps1 | ||
# file of the same name | ||
|
||
ANSIBLE_METADATA = {'metadata_version': '1.1', | ||
'status': ['preview'], | ||
'supported_by': 'community'} | ||
|
||
DOCUMENTATION = r''' | ||
--- | ||
module: win_wait_for_process | ||
version_added: '2.7' | ||
short_description: Waits for a process to exist or not exist before continuing. | ||
description: | ||
- Waiting for a process to start or stop is useful when Windows services | ||
behave poorly and do not enumerate external dependencies in their | ||
manifest. | ||
options: | ||
process_name_exact: | ||
description: | ||
- The name of the process(es) for which to wait. | ||
- Must inclue the file extension of the process binary (.exe) | ||
process_name_pattern: | ||
description: | ||
- RegEx pattern matching desired process(es) | ||
sleep: | ||
description: | ||
- Number of seconds to sleep between checks. | ||
- Only applies when waiting for a process to start. Waiting for a process to start | ||
does not have a native non-polling mechanism. Waiting for a stop uses native PowerShell | ||
and does not require polling. | ||
default: 1 | ||
process_min_count: | ||
description: | ||
- Minimum number of process matching the supplied pattern to satisfy C(present) condition. | ||
- Only applies to C(present). | ||
default: 1 | ||
state: | ||
description: | ||
- When checking for a running process C(present) will block execution | ||
until the process exists, or until the timeout has been reached. | ||
C(absent) will block execution untile the processs no longer exists, | ||
or until the timeout has been reached. | ||
- When waiting for C(present), the module will return changed only if | ||
the process was not present on the initial check but became present on | ||
subsequent checks. | ||
- If, while waiting for C(absent), new processes matching the supplied | ||
pattern are started, these new processes will not be included in the | ||
action. | ||
default: present | ||
choices: [ absent, present ] | ||
timeout: | ||
description: | ||
- The maximum number of seconds to wait for a for a process to start or stop | ||
before erroring out. | ||
default: 300 | ||
author: | ||
- Charles Crossan (@crossan007) | ||
''' | ||
|
||
EXAMPLES = r''' | ||
- name: Wait 300 seconds for all Oracle VirtualBox processes to stop. (VBoxHeadless, VirtualBox, VBoxSVC) | ||
win_wait_for_process: | ||
process_name: "v(irtual)?box(headless|svc)?" | ||
state: absent | ||
timeout: 500 | ||
|
||
|
||
- name: Wait 300 seconds for 3 instances of cmd to start, waiting 5 seconds between each check | ||
win_wait_for_process: | ||
process_name: "cmd\\.exe" | ||
state: present | ||
timeout: 500 | ||
sleep: 5 | ||
process_min_count: 3 | ||
|
||
''' | ||
|
||
RETURN = r''' | ||
elapsed: | ||
description: The elapsed seconds between the start of poll and the end of the | ||
module. | ||
returned: always | ||
type: float | ||
sample: 3.14159265 | ||
changed: | ||
description: True if a process was started or stopped during the module execution. | ||
returned: always | ||
type: bool | ||
matched_processes: | ||
description: Count of processes stopped or started. | ||
returned: always | ||
type: int | ||
''' |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is support_check_mode true intended here?
I suggest looking at other wait_for module code to see how it behaves in check mode.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure about this. This module doesn't actually change anything, so check_mode is almost irrelevant; however, I suspect module users may still wish for a process change or presence check to occur if they're running a
--check
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To be honest, since this module does not make a change, it should simply work in check-mode identically to normal mode. So I agree with @crossan007