refactor the eos_command module to use the CommandRunner

* This adds support the CommandRunner to handle executing commands on
the remote device.
* It also changes the waitfor argument to wait_for to remain compatable
with other modules and adds an alias for waitfor.
* Restricts commands to show commands only when check mode is specified.
* add version_added to wait_for doc string
This commit is contained in:
Peter Sprygada 2016-06-05 20:34:31 -04:00 committed by Matt Clay
parent a2e6ac6ca8
commit 622592c413

View file

@ -20,7 +20,7 @@ DOCUMENTATION = """
---
module: eos_command
version_added: "2.1"
author: "Peter sprygada (@privateip)"
author: "Peter Sprygada (@privateip)"
short_description: Run arbitrary command on EOS device
description:
- Sends an aribtrary set of commands to an EOS node and returns the results
@ -37,7 +37,7 @@ options:
module is not returned until the condition is satisfied or
the number of retries has been exceeded.
required: true
waitfor:
wait_for:
description:
- Specifies what to evaluate from the output of the command
and what conditionals to apply. This argument will cause
@ -46,6 +46,8 @@ options:
by the configured retries, the task fails. See examples.
required: false
default: null
aliases: ['waitfor']
version_added: "2.2"
retries:
description:
- Specifies the number of retries a command should be tried
@ -65,9 +67,6 @@ options:
"""
EXAMPLES = """
- eos_command:
commands: "{{ lookup('file', 'commands.txt') }}"
- eos_command:
commands:
- show interface {{ item }}
@ -109,14 +108,12 @@ failed_conditions:
type: list
sample: ['...', '...']
"""
from ansible.module_utils.basic import get_exception
from ansible.module_utils.netcmd import CommandRunner, FailedConditionsError
from ansible.module_utils.network import NetworkError
from ansible.module_utils.eos import get_module
import time
import shlex
import re
INDEX_RE = re.compile(r'(\[\d+\])')
def iterlines(stdout):
def to_lines(stdout):
for item in stdout:
if isinstance(item, basestring):
item = str(item).split('\n')
@ -124,8 +121,8 @@ def iterlines(stdout):
def main():
spec = dict(
commands=dict(type='list'),
waitfor=dict(type='list'),
commands=dict(type='list', required=True),
wait_for=dict(type='list', aliases=['waitfor']),
retries=dict(default=10, type='int'),
interval=dict(default=1, type='int')
)
@ -134,50 +131,54 @@ def main():
supports_check_mode=True)
commands = module.params['commands']
conditionals = module.params['wait_for'] or list()
retries = module.params['retries']
interval = module.params['interval']
warnings = list()
runner = CommandRunner(module)
for cmd in commands:
if module.check_mode and not cmd.startswith('show'):
warnings.append('only show commands are supported when using '
'check mode, not executing `%s`' % cmd)
else:
runner.add_command(cmd)
for item in conditionals:
runner.add_conditional(item)
runner.retries = module.params['retries']
runner.interval = module.params['interval']
try:
queue = set()
for entry in (module.params['waitfor'] or list()):
queue.add(Conditional(entry))
except AttributeError:
runner.run()
except FailedConditionsError:
exc = get_exception()
module.fail_json(msg=exc.message)
module.fail_json(msg=str(exc), failed_conditions=exc.failed_conditions)
except NetworkError:
exc = get_exception()
module.fail_json(msg=str(exc))
result = dict(changed=False)
while retries > 0:
response = module.execute(commands)
result['stdout'] = response
for index, cmd in enumerate(commands):
result['stdout'] = list()
for cmd in commands:
try:
output = runner.get_command(cmd)
if cmd.endswith('json'):
response[index] = module.from_json(response[index])
for item in list(queue):
if item(response):
queue.remove(item)
if not queue:
break
time.sleep(interval)
retries -= 1
else:
failed_conditions = [item.raw for item in queue]
module.fail_json(msg='timeout waiting for value', failed_conditions=failed_conditions)
result['stdout_lines'] = list(iterlines(result['stdout']))
return module.exit_json(**result)
output = module.from_json(output)
except ValueError:
output = 'command not executed due to check_mode, see warnings'
result['stdout'].append(output)
result['warnings'] = warnings
result['connected'] = module.connected
result['stdout_lines'] = list(to_lines(result['stdout']))
module.exit_json(**result)
from ansible.module_utils.basic import *
from ansible.module_utils.urls import *
from ansible.module_utils.shell import *
from ansible.module_utils.netcfg import *
from ansible.module_utils.eos import *
if __name__ == '__main__':
main()
main()