Skip to content
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

Make wait_for return matched groups defined in search_regex. Closes #… #47690

Merged
merged 3 commits into from
Nov 20, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
37 changes: 34 additions & 3 deletions lib/ansible/modules/utilities/logic/wait_for.py
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,14 @@
path: /tmp/foo
search_regex: completed

- name: Wait until regex pattern matches in the file /tmp/foo and print the matched group
wait_for:
path: /tmp/foo
search_regex: completed (?P<task>\w+)
register: waitfor
- debug:
msg: Completed {{ waitfor['groupdict']['task'] }}

- name: Wait until the lock file is removed
wait_for:
path: /var/lock/file.lock
Expand Down Expand Up @@ -176,6 +184,20 @@
returned: always
type: int
sample: 23
match_groups:
description: Tuple containing all the subgroups of the match as returned by U(https://docs.python.org/2/library/re.html#re.MatchObject.groups)
returned: always
type: list
sample: ['match 1', 'match 2']
match_groupdict:
description: Dictionary containing all the named subgroups of the match, keyed by the subgroup name,
as returned by U(https://docs.python.org/2/library/re.html#re.MatchObject.groupdict)
returned: always
type: dict
sample:
{
'group': 'match'
}
'''

import binascii
Expand Down Expand Up @@ -468,6 +490,9 @@ def main():
else:
compiled_search_re = None

match_groupdict = {}
match_groups = ()

if port and path:
module.fail_json(msg="port and path parameter can not both be passed to wait_for", elapsed=0)
if path and state == 'stopped':
Expand Down Expand Up @@ -537,8 +562,13 @@ def main():
try:
f = open(path)
try:
if re.search(compiled_search_re, f.read()):
# String found, success!
search = re.search(compiled_search_re, f.read())
if search:
if search.groupdict():
match_groupdict = search.groupdict()
if search.groups():
match_groups = search.groups()

break
finally:
f.close()
Expand Down Expand Up @@ -630,7 +660,8 @@ def main():
module.fail_json(msg=msg or "Timeout when waiting for %s:%s to drain" % (host, port), elapsed=elapsed.seconds)

elapsed = datetime.datetime.utcnow() - start
module.exit_json(state=state, port=port, search_regex=search_regex, path=path, elapsed=elapsed.seconds)
module.exit_json(state=state, port=port, search_regex=search_regex, match_groups=match_groups, match_groupdict=match_groupdict, path=path,
elapsed=elapsed.seconds)


if __name__ == '__main__':
Expand Down
61 changes: 42 additions & 19 deletions test/integration/targets/wait_for/tasks/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,65 +11,88 @@

- name: setup a path
file:
path: /tmp/wait_for_file
path: "{{ output_dir }}/wait_for_file"
state: touch

- name: setup remove a file after 10s
shell: sleep 10 && rm /tmp/wait_for_file
- name: setup remove a file after 3s
shell: sleep 3 && rm {{ output_dir }}/wait_for_file
async: 20
poll: 0

- name: test for absent path
wait_for:
path: /tmp/wait_for_file
path: "{{ output_dir }}/wait_for_file"
state: absent
timeout: 20
register: waitfor
- name: verify test for absent path
assert:
that:
- waitfor is successful
- "waitfor.path == '/tmp/wait_for_file'"
- waitfor.elapsed >= 5
- waitfor.path == "{{ output_dir | expanduser }}/wait_for_file"
- waitfor.elapsed >= 2
- waitfor.elapsed <= 15

- name: setup create a file after 10s
shell: sleep 10 && touch /tmp/wait_for_file
- name: setup create a file after 3s
shell: sleep 3 && touch {{ output_dir }}/wait_for_file
async: 20
poll: 0

- name: test for present path
wait_for:
path: /tmp/wait_for_file
timeout: 20
path: "{{ output_dir }}/wait_for_file"
timeout: 5
register: waitfor
- name: verify test for absent path
assert:
that:
- waitfor is successful
- "waitfor.path == '/tmp/wait_for_file'"
- waitfor.elapsed >= 5
- waitfor.path == "{{ output_dir | expanduser }}/wait_for_file"
- waitfor.elapsed >= 2
- waitfor.elapsed <= 15

- name: setup write keyword to file after 10s
shell: rm -f /tmp/wait_for_keyword && sleep 10 && echo completed > /tmp/wait_for_keyword
- name: setup write keyword to file after 3s
shell: sleep 3 && echo completed > {{output_dir}}/wait_for_keyword
async: 20
poll: 0

- name: test wait for keyword in file
wait_for:
path: /tmp/wait_for_keyword
path: "{{output_dir}}/wait_for_keyword"
search_regex: completed
timeout: 20
timeout: 5
register: waitfor
- name: verify test wait for port timeout

- name: verify test wait for keyword in file
assert:
that:
- waitfor is successful
- "waitfor.search_regex == 'completed'"
- waitfor.elapsed >= 5
- waitfor.elapsed >= 2
- waitfor.elapsed <= 15

- name: setup write keyword to file after 3s
shell: sleep 3 && echo "completed data 123" > {{output_dir}}/wait_for_keyword
async: 20
poll: 0

- name: test wait for keyword in file with match groups
wait_for:
path: "{{output_dir}}/wait_for_keyword"
search_regex: completed (?P<foo>\w+) ([0-9]+)
timeout: 5
register: waitfor

- name: verify test wait for keyword in file with match groups
assert:
that:
- waitfor is successful
- waitfor.elapsed >= 2
- waitfor.elapsed <= 15
- waitfor['match_groupdict'] | length == 1
- waitfor['match_groupdict']['foo'] == 'data'
- waitfor['match_groups'] == ['data', '123']

- name: test wait for port timeout
wait_for:
port: 12121
Expand Down Expand Up @@ -98,7 +121,7 @@
- "waitfor.msg == 'fail with custom message'"

- name: setup start SimpleHTTPServer
shell: sleep 10 && cd {{ files_dir }} && {{ ansible_python.executable }} {{ output_dir}}/testserver.py {{ http_port }}
shell: sleep 3 && cd {{ files_dir }} && {{ ansible_python.executable }} {{ output_dir}}/testserver.py {{ http_port }}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why change sleep here? It seems like that might have been tuned for timing in CI or similar. If it's just to take less time maybe we should change it in a separate PR.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And the same comment for all the other timing changes.

async: 120 # this test set can take ~1m to run on FreeBSD (via Shippable)
poll: 0

Expand Down