From 622592c4133f8bf66442f695f43d36ce4213e2f7 Mon Sep 17 00:00:00 2001 From: Peter Sprygada Date: Sun, 5 Jun 2016 20:34:31 -0400 Subject: [PATCH] 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 --- .../modules/network/eos/eos_command.py | 99 ++++++++++--------- 1 file changed, 50 insertions(+), 49 deletions(-) diff --git a/lib/ansible/modules/network/eos/eos_command.py b/lib/ansible/modules/network/eos/eos_command.py index 956bf8f1017..3e788357350 100644 --- a/lib/ansible/modules/network/eos/eos_command.py +++ b/lib/ansible/modules/network/eos/eos_command.py @@ -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()