wait_for: PEP8, imports, cosmetics (#24634)

- Make PEP8 compliant
- Ensure imports are specific
- Few cosmetic changes (sort lists, casing, punctuation)

This fixes #19781
This commit is contained in:
Dag Wieers 2017-06-08 11:06:11 +02:00 committed by René Moser
parent 36082e32b4
commit 6e98dbbfd7
2 changed files with 90 additions and 98 deletions

View file

@ -22,11 +22,10 @@ ANSIBLE_METADATA = {'metadata_version': '1.0',
'status': ['stableinterface'], 'status': ['stableinterface'],
'supported_by': 'core'} 'supported_by': 'core'}
DOCUMENTATION = r'''
DOCUMENTATION = '''
--- ---
module: wait_for module: wait_for
short_description: Waits for a condition before continuing. short_description: Waits for a condition before continuing
description: description:
- You can wait for a set amount of time C(timeout), this is the default if nothing is specified. - You can wait for a set amount of time C(timeout), this is the default if nothing is specified.
- Waiting for a port to become available is useful for when services - Waiting for a port to become available is useful for when services
@ -44,64 +43,51 @@ version_added: "0.7"
options: options:
host: host:
description: description:
- A resolvable hostname or IP address to wait for - A resolvable hostname or IP address to wait for.
required: false
default: "127.0.0.1" default: "127.0.0.1"
timeout: timeout:
description: description:
- maximum number of seconds to wait for - Maximum number of seconds to wait for.
required: false
default: 300 default: 300
connect_timeout: connect_timeout:
description: description:
- maximum number of seconds to wait for a connection to happen before closing and retrying - Maximum number of seconds to wait for a connection to happen before closing and retrying.
required: false
default: 5 default: 5
delay: delay:
description: description:
- number of seconds to wait before starting to poll - Number of seconds to wait before starting to poll.
required: false
default: 0 default: 0
port: port:
description: description:
- port number to poll - Port number to poll.
required: false
default: null
active_connection_states: active_connection_states:
description: description:
- The list of tcp connection states which are counted as active connections - The list of TCP connection states which are counted as active connections.
default: ['ESTABLISHED','SYN_SENT','SYN_RECV','FIN_WAIT1','FIN_WAIT2','TIME_WAIT'] default: [ ESTABLISHED, FIN_WAIT1, FIN_WAIT2, SYN_RECV, SYN_SENT, TIME_WAIT ]
version_added: "2.3" version_added: "2.3"
state: state:
description: description:
- either C(present), C(started), or C(stopped), C(absent), or C(drained) - Either C(present), C(started), or C(stopped), C(absent), or C(drained).
- When checking a port C(started) will ensure the port is open, C(stopped) will check that it is closed, C(drained) will check for active connections - When checking a port C(started) will ensure the port is open, C(stopped) will check that it is closed, C(drained) will check for active connections.
- When checking for a file or a search string C(present) or C(started) will ensure that the file or string is present before continuing, - When checking for a file or a search string C(present) or C(started) will ensure that the file or string is present before continuing,
C(absent) will check that file is absent or removed C(absent) will check that file is absent or removed.
choices: [ "present", "started", "stopped", "absent", "drained" ] choices: [ absent, drained, present, started, stopped ]
required: False default: started
default: "started"
path: path:
version_added: "1.4" version_added: "1.4"
required: false
default: null
description: description:
- path to a file on the filesytem that must exist before continuing - Path to a file on the filesytem that must exist before continuing.
search_regex: search_regex:
version_added: "1.4" version_added: "1.4"
required: false
default: null
description: description:
- Can be used to match a string in either a file or a socket connection. Defaults to a multiline regex. - Can be used to match a string in either a file or a socket connection.
- Defaults to a multiline regex.
exclude_hosts: exclude_hosts:
version_added: "1.8" version_added: "1.8"
required: false
default: null
description: description:
- list of hosts or IPs to ignore when looking for active TCP connections for C(drained) state - List of hosts or IPs to ignore when looking for active TCP connections for C(drained) state.
sleep: sleep:
version_added: "2.3" version_added: "2.3"
required: false
default: 1 default: 1
description: description:
- Number of seconds to sleep between checks, before 2.3 this was hardcoded to 1 second. - Number of seconds to sleep between checks, before 2.3 this was hardcoded to 1 second.
@ -113,63 +99,66 @@ options:
- This overrides the normal error message from a failure to meet the required conditions. - This overrides the normal error message from a failure to meet the required conditions.
notes: notes:
- The ability to use search_regex with a port connection was added in 1.7. - The ability to use search_regex with a port connection was added in 1.7.
requirements: []
author: author:
- "Jeroen Hoekx (@jhoekx)" - Jeroen Hoekx (@jhoekx)
- "John Jarvis (@jarv)" - John Jarvis (@jarv)
- "Andrii Radyk (@AnderEnder)" - Andrii Radyk (@AnderEnder)
''' '''
EXAMPLES = ''' EXAMPLES = r'''
# wait 300 seconds for port 8000 to become open on the host, don't start checking for 10 seconds - name: Wait 300 seconds for port 8000 to become open on the host, don't start checking for 10 seconds
- wait_for: wait_for:
port: 8000 port: 8000
delay: 10 delay: 10
# wait 300 seconds for port 8000 of any IP to close active connections, don't start checking for 10 seconds - name: Wait 300 seconds for port 8000 of any IP to close active connections, don't start checking for 10 seconds
- wait_for: wait_for:
host: 0.0.0.0 host: 0.0.0.0
port: 8000 port: 8000
delay: 10 delay: 10
state: drained state: drained
# wait 300 seconds for port 8000 of any IP to close active connections, ignoring connections for specified hosts - name: Wait 300 seconds for port 8000 of any IP to close active connections, ignoring connections for specified hosts
- wait_for: wait_for:
host: 0.0.0.0 host: 0.0.0.0
port: 8000 port: 8000
state: drained state: drained
exclude_hosts: 10.2.1.2,10.2.1.3 exclude_hosts: 10.2.1.2,10.2.1.3
# wait until the file /tmp/foo is present before continuing - name: Wait until the file /tmp/foo is present before continuing
- wait_for: wait_for:
path: /tmp/foo path: /tmp/foo
# wait until the string "completed" is in the file /tmp/foo before continuing - name: Wait until the string "completed" is in the file /tmp/foo before continuing
- wait_for: wait_for:
path: /tmp/foo path: /tmp/foo
search_regex: completed search_regex: completed
# wait until the lock file is removed - name: Wait until the lock file is removed
- wait_for: wait_for:
path: /var/lock/file.lock path: /var/lock/file.lock
state: absent state: absent
# wait until the process is finished and pid was destroyed - name: Wait until the process is finished and pid was destroyed
- wait_for: wait_for:
path: /proc/3466/status path: /proc/3466/status
state: absent state: absent
# output customized message when failed - name: Output customized message when failed
- wait_for: wait_for:
path: /tmp/foo path: /tmp/foo
state: present state: present
msg: Timeout to find file /tmp/foo msg: Timeout to find file /tmp/foo
# wait 300 seconds for port 22 to become open and contain "OpenSSH", # Don't assume the inventory_hostname is resolvable and delay 10 seconds at start
# don't assume the inventory_hostname is resolvable and don't start checking for 10 seconds - name: Wait 300 seconds for port 22 to become open and contain "OpenSSH"
- wait_for: port=22 host="{{ ansible_host|default(ansible_ssh_host|default(inventory_hostname)) }}" search_regex=OpenSSH delay=10 wait_for:
connection: local port: 22
host: '{{ ansible_ssh_host | default(inventory_hostname) }}'
search_regex: OpenSSH
delay: 10
delegate_to: localhost
''' '''
import binascii import binascii
@ -181,8 +170,10 @@ import socket
import sys import sys
import time import time
from ansible.module_utils.basic import AnsibleModule, load_platform_subclass
from ansible.module_utils._text import to_native from ansible.module_utils._text import to_native
HAS_PSUTIL = False HAS_PSUTIL = False
try: try:
import psutil import psutil
@ -347,6 +338,7 @@ def _convert_host_to_ip(host):
ips.append((socket.AF_INET6, "::ffff:" + ip)) ips.append((socket.AF_INET6, "::ffff:" + ip))
return ips return ips
def _convert_host_to_hex(host): def _convert_host_to_hex(host):
""" """
Convert the provided host to the format in /proc/net/tcp* Convert the provided host to the format in /proc/net/tcp*
@ -367,12 +359,13 @@ def _convert_host_to_hex(host):
hexip_nf = binascii.b2a_hex(socket.inet_pton(family, ip)) hexip_nf = binascii.b2a_hex(socket.inet_pton(family, ip))
hexip_hf = "" hexip_hf = ""
for i in range(0, len(hexip_nf), 8): for i in range(0, len(hexip_nf), 8):
ipgroup_nf = hexip_nf[i:i+8] ipgroup_nf = hexip_nf[i:i + 8]
ipgroup_hf = socket.ntohl(int(ipgroup_nf, base=16)) ipgroup_hf = socket.ntohl(int(ipgroup_nf, base=16))
hexip_hf = "%s%08X" % (hexip_hf, ipgroup_hf) hexip_hf = "%s%08X" % (hexip_hf, ipgroup_hf)
ips.append((family, hexip_hf)) ips.append((family, hexip_hf))
return ips return ips
def _create_connection(host, port, connect_timeout): def _create_connection(host, port, connect_timeout):
""" """
Connect to a 2-tuple (host, port) and return Connect to a 2-tuple (host, port) and return
@ -387,16 +380,18 @@ def _create_connection(host, port, connect_timeout):
(family, _) = (_convert_host_to_ip(host))[0] (family, _) = (_convert_host_to_ip(host))[0]
connect_socket = socket.socket(family, socket.SOCK_STREAM) connect_socket = socket.socket(family, socket.SOCK_STREAM)
connect_socket.settimeout(connect_timeout) connect_socket.settimeout(connect_timeout)
connect_socket.connect( (host, port) ) connect_socket.connect((host, port))
else: else:
connect_socket = socket.create_connection( (host, port), connect_timeout) connect_socket = socket.create_connection((host, port), connect_timeout)
return connect_socket return connect_socket
def _timedelta_total_seconds(timedelta): def _timedelta_total_seconds(timedelta):
return ( return (
timedelta.microseconds + 0.0 + timedelta.microseconds + 0.0 +
(timedelta.seconds + timedelta.days * 24 * 3600) * 10 ** 6) / 10 ** 6 (timedelta.seconds + timedelta.days * 24 * 3600) * 10 ** 6) / 10 ** 6
def get_connection_state_id(state): def get_connection_state_id(state):
connection_state_id = { connection_state_id = {
'ESTABLISHED': '01', 'ESTABLISHED': '01',
@ -408,35 +403,36 @@ def get_connection_state_id(state):
} }
return connection_state_id[state] return connection_state_id[state]
def main(): def main():
module = AnsibleModule( module = AnsibleModule(
argument_spec = dict( argument_spec=dict(
host=dict(default='127.0.0.1'), host=dict(type='str', default='127.0.0.1'),
timeout=dict(default=300, type='int'), timeout=dict(type='int', default=300),
connect_timeout=dict(default=5, type='int'), connect_timeout=dict(type='int', default=5),
delay=dict(default=0, type='int'), delay=dict(type='int', default=0),
port=dict(default=None, type='int'), port=dict(type='int'),
active_connection_states=dict(default=['ESTABLISHED','SYN_SENT','SYN_RECV','FIN_WAIT1','FIN_WAIT2','TIME_WAIT'], type='list'), active_connection_states=dict(type='list', default=['ESTABLISHED', 'FIN_WAIT1', 'FIN_WAIT2', 'SYN_RECV', 'SYN_SENT', 'TIME_WAIT']),
path=dict(default=None, type='path'), path=dict(type='path'),
search_regex=dict(default=None), search_regex=dict(type='str'),
state=dict(default='started', choices=['started', 'stopped', 'present', 'absent', 'drained']), state=dict(type='str', default='started', choices=['absent', 'drained', 'present', 'started', 'stopped']),
exclude_hosts=dict(default=None, type='list'), exclude_hosts=dict(type='list'),
sleep=dict(default=1, type='int'), sleep=dict(type='int', default=1),
msg=dict(default=None, type='str') msg=dict(type='str'),
), ),
) )
params = module.params host = module.params['host']
timeout = module.params['timeout']
connect_timeout = module.params['connect_timeout']
delay = module.params['delay']
port = module.params['port']
state = module.params['state']
path = module.params['path']
search_regex = module.params['search_regex']
msg = module.params['msg']
host = params['host']
timeout = params['timeout']
connect_timeout = params['connect_timeout']
delay = params['delay']
port = params['port']
state = params['state']
path = params['path']
search_regex = params['search_regex']
if search_regex is not None: if search_regex is not None:
compiled_search_re = re.compile(search_regex, re.MULTILINE) compiled_search_re = re.compile(search_regex, re.MULTILINE)
else: else:
@ -448,15 +444,13 @@ def main():
module.fail_json(msg="state=stopped should only be used for checking a port in the wait_for module") module.fail_json(msg="state=stopped should only be used for checking a port in the wait_for module")
if path and state == 'drained': if path and state == 'drained':
module.fail_json(msg="state=drained should only be used for checking a port in the wait_for module") module.fail_json(msg="state=drained should only be used for checking a port in the wait_for module")
if params['exclude_hosts'] is not None and state != 'drained': if module.params['exclude_hosts'] is not None and state != 'drained':
module.fail_json(msg="exclude_hosts should only be with state=drained") module.fail_json(msg="exclude_hosts should only be with state=drained")
for _connection_state in params['active_connection_states']: for _connection_state in module.params['active_connection_states']:
try: try:
get_connection_state_id(_connection_state) get_connection_state_id(_connection_state)
except: except:
module.fail_json(msg="unknown active_connection_state ("+_connection_state+") defined") module.fail_json(msg="unknown active_connection_state (%s) defined" % _connection_state)
msg = params['msg']
start = datetime.datetime.utcnow() start = datetime.datetime.utcnow()
@ -465,8 +459,8 @@ def main():
if not port and not path and state != 'drained': if not port and not path and state != 'drained':
time.sleep(timeout) time.sleep(timeout)
elif state in [ 'stopped', 'absent' ]: elif state in ['absent', 'stopped']:
### first wait for the stop condition # first wait for the stop condition
end = start + datetime.timedelta(seconds=timeout) end = start + datetime.timedelta(seconds=timeout)
while datetime.datetime.utcnow() < end: while datetime.datetime.utcnow() < end:
@ -484,7 +478,7 @@ def main():
except: except:
break break
# Conditions not yet met, wait and try again # Conditions not yet met, wait and try again
time.sleep(params['sleep']) time.sleep(module.params['sleep'])
else: else:
elapsed = datetime.datetime.utcnow() - start elapsed = datetime.datetime.utcnow() - start
if port: if port:
@ -493,7 +487,7 @@ def main():
module.fail_json(msg=msg or "Timeout when waiting for %s to be absent." % (path), elapsed=elapsed.seconds) module.fail_json(msg=msg or "Timeout when waiting for %s to be absent." % (path), elapsed=elapsed.seconds)
elif state in ['started', 'present']: elif state in ['started', 'present']:
### wait for start condition # wait for start condition
end = start + datetime.timedelta(seconds=timeout) end = start + datetime.timedelta(seconds=timeout)
while datetime.datetime.utcnow() < end: while datetime.datetime.utcnow() < end:
if path: if path:
@ -562,7 +556,7 @@ def main():
break break
# Conditions not yet met, wait and try again # Conditions not yet met, wait and try again
time.sleep(params['sleep']) time.sleep(module.params['sleep'])
else: # while-else else: # while-else
# Timeout expired # Timeout expired
@ -571,7 +565,7 @@ def main():
if search_regex: if search_regex:
module.fail_json(msg=msg or "Timeout when waiting for search string %s in %s:%s" % (search_regex, host, port), elapsed=elapsed.seconds) module.fail_json(msg=msg or "Timeout when waiting for search string %s in %s:%s" % (search_regex, host, port), elapsed=elapsed.seconds)
else: else:
module.fail_json(msg= msg or "Timeout when waiting for %s:%s" % (host, port), elapsed=elapsed.seconds) module.fail_json(msg=msg or "Timeout when waiting for %s:%s" % (host, port), elapsed=elapsed.seconds)
elif path: elif path:
if search_regex: if search_regex:
module.fail_json(msg=msg or "Timeout when waiting for search string %s in %s" % (search_regex, path), elapsed=elapsed.seconds) module.fail_json(msg=msg or "Timeout when waiting for search string %s in %s" % (search_regex, path), elapsed=elapsed.seconds)
@ -579,7 +573,7 @@ def main():
module.fail_json(msg=msg or "Timeout when waiting for file %s" % (path), elapsed=elapsed.seconds) module.fail_json(msg=msg or "Timeout when waiting for file %s" % (path), elapsed=elapsed.seconds)
elif state == 'drained': elif state == 'drained':
### wait until all active connections are gone # wait until all active connections are gone
end = start + datetime.timedelta(seconds=timeout) end = start + datetime.timedelta(seconds=timeout)
tcpconns = TCPConnectionInfo(module) tcpconns = TCPConnectionInfo(module)
while datetime.datetime.utcnow() < end: while datetime.datetime.utcnow() < end:
@ -589,7 +583,7 @@ def main():
except IOError: except IOError:
pass pass
# Conditions not yet met, wait and try again # Conditions not yet met, wait and try again
time.sleep(params['sleep']) time.sleep(module.params['sleep'])
else: else:
elapsed = datetime.datetime.utcnow() - start elapsed = datetime.datetime.utcnow() - start
module.fail_json(msg=msg or "Timeout when waiting for %s:%s to drain" % (host, port), elapsed=elapsed.seconds) module.fail_json(msg=msg or "Timeout when waiting for %s:%s to drain" % (host, port), elapsed=elapsed.seconds)
@ -597,7 +591,6 @@ def main():
elapsed = datetime.datetime.utcnow() - start 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, path=path, elapsed=elapsed.seconds)
# import module snippets
from ansible.module_utils.basic import *
if __name__ == '__main__': if __name__ == '__main__':
main() main()

View file

@ -565,4 +565,3 @@ lib/ansible/modules/system/user.py
lib/ansible/modules/utilities/helper/_accelerate.py lib/ansible/modules/utilities/helper/_accelerate.py
lib/ansible/modules/utilities/logic/async_status.py lib/ansible/modules/utilities/logic/async_status.py
lib/ansible/modules/utilities/logic/async_wrapper.py lib/ansible/modules/utilities/logic/async_wrapper.py
lib/ansible/modules/utilities/logic/wait_for.py