From 7b2c013e5a3cba364137cd3c14687dbb0b512aa9 Mon Sep 17 00:00:00 2001 From: Peter Sprygada Date: Thu, 2 Mar 2017 16:05:20 -0600 Subject: [PATCH] returns xml as a display option to junos_command (#21833) The display option xml as accidentially removed from the display argument. This patch adds xml back as an option. fixes #21823 --- lib/ansible/module_utils/netcli.py | 36 ++------------ .../modules/network/junos/junos_command.py | 47 ++++++++++++++----- lib/ansible/plugins/connection/network_cli.py | 2 +- lib/ansible/plugins/terminal/junos.py | 1 - 4 files changed, 41 insertions(+), 45 deletions(-) diff --git a/lib/ansible/module_utils/netcli.py b/lib/ansible/module_utils/netcli.py index 3771f80888..9e7ed8790b 100644 --- a/lib/ansible/module_utils/netcli.py +++ b/lib/ansible/module_utils/netcli.py @@ -202,7 +202,6 @@ class Conditional(object): def __init__(self, conditional, encoding=None): self.raw = conditional - self.encoding = encoding or 'json' try: key, op, val = shlex.split(conditional) @@ -236,36 +235,11 @@ class Conditional(object): raise AttributeError('unknown operator: %s' % oper) def get_value(self, result): - if self.encoding in ['json', 'text']: - try: - return self.get_json(result) - except (IndexError, TypeError, AttributeError): - msg = 'unable to apply conditional to result' - raise FailedConditionalError(msg, self.raw) - - elif self.encoding == 'xml': - return self.get_xml(result.get('result')) - - def get_xml(self, result): - parts = self.key.split('.') - - value_index = None - match = re.match(r'^\S+(\[)(\d+)\]', parts[-1]) - if match: - start, end = match.regs[1] - parts[-1] = parts[-1][0:start] - value_index = int(match.group(2)) - - path = '/'.join(parts[1:]) - path = '/%s' % path - path += '/text()' - - index = int(re.match(r'result\[(\d+)\]', parts[0]).group(1)) - values = result[index].findall(path) - - if value_index is not None: - return values[value_index].strip() - return [v.strip() for v in values] + try: + return self.get_json(result) + except (IndexError, TypeError, AttributeError): + msg = 'unable to apply conditional to result' + raise FailedConditionalError(msg, self.raw) def get_json(self, result): string = re.sub(r"\[[\'|\"]", ".", self.key) diff --git a/lib/ansible/modules/network/junos/junos_command.py b/lib/ansible/modules/network/junos/junos_command.py index bc22fb8320..524517d946 100644 --- a/lib/ansible/modules/network/junos/junos_command.py +++ b/lib/ansible/modules/network/junos/junos_command.py @@ -128,15 +128,22 @@ failed_conditions: import time from functools import partial +from xml.etree import ElementTree as etree from ansible.module_utils.junos import run_commands from ansible.module_utils.junos import junos_argument_spec from ansible.module_utils.junos import check_args as junos_check_args from ansible.module_utils.basic import AnsibleModule from ansible.module_utils.six import string_types -from ansible.module_utils.netcli import Conditional +from ansible.module_utils.netcli import Conditional, FailedConditionalError from ansible.module_utils.network_common import ComplexList +try: + import jxmlease + HAS_JXMLEASE = True +except ImportError: + HAS_JXMLEASE = False + def check_args(module, warnings): junos_check_args(module, warnings) @@ -155,9 +162,9 @@ def to_lines(stdout): def parse_commands(module, warnings): spec = dict( command=dict(key=True), - output=dict(default=module.params['display'], choices=['text', 'json']), + output=dict(default=module.params['display'], choices=['text', 'json', 'xml']), prompt=dict(), - response=dict() + answer=dict() ) transform = ComplexList(spec, module) @@ -172,9 +179,13 @@ def parse_commands(module, warnings): if item['output'] == 'json' and 'display json' not in item['command']: item['command'] += '| display json' - elif item['output'] == 'text' and 'display json' in item['command']: - item['command'] = item['command'].replace('| display json', '') - + elif item['output'] == 'xml' and 'display xml' not in item['command']: + item['command'] += '| display xml' + else: + if '| display json' in item['command']: + item['command'] = str(item['command']).replace(' | display json', '') + elif '| display xml' in item['command']: + item['command'] = str(item['command']).replace(' | display xml', '') commands[index] = item return commands @@ -184,7 +195,7 @@ def main(): """ argument_spec = dict( commands=dict(type='list', required=True), - display=dict(choices=['text', 'json'], default='text'), + display=dict(choices=['text', 'json', 'xml'], default='text', aliases=['format', 'output']), # deprecated (Ansible 2.3) - use junos_rpc rpcs=dict(type='list'), @@ -208,6 +219,7 @@ def main(): commands = parse_commands(module, warnings) wait_for = module.params['wait_for'] or list() + display = module.params['display'] conditionals = [Conditional(c) for c in wait_for] retries = module.params['retries'] @@ -218,11 +230,22 @@ def main(): responses = run_commands(module, commands) for item in list(conditionals): - if item(responses): - if match == 'any': - conditionals = list() - break - conditionals.remove(item) + + for index, (resp, cmd) in enumerate(zip(responses, commands)): + if cmd['output'] == 'xml': + if not HAS_JXMLEASE: + module.fail_json(msg='jxmlease is required but does not appear to ' + 'be installed. It can be installed using `pip install jxmlease`') + responses[index] = jxmlease.parse(resp) + + try: + if item(responses): + if match == 'any': + conditionals = list() + break + conditionals.remove(item) + except FailedConditionalError: + pass if not conditionals: break diff --git a/lib/ansible/plugins/connection/network_cli.py b/lib/ansible/plugins/connection/network_cli.py index 0724e25026..0bb9ee00ed 100644 --- a/lib/ansible/plugins/connection/network_cli.py +++ b/lib/ansible/plugins/connection/network_cli.py @@ -183,7 +183,7 @@ class Connection(_Connection): cleaned = [] command = obj.get('command') if obj else None for line in resp.splitlines(): - if (command and line.startswith(command.strip())) or self._find_prompt(line): + if (command and line.startswith(command.strip())) or self._matched_prompt.strip() in line: continue cleaned.append(line) return str("\n".join(cleaned)).strip() diff --git a/lib/ansible/plugins/terminal/junos.py b/lib/ansible/plugins/terminal/junos.py index f41bb0e323..a5b539e9f9 100644 --- a/lib/ansible/plugins/terminal/junos.py +++ b/lib/ansible/plugins/terminal/junos.py @@ -36,7 +36,6 @@ class TerminalModule(TerminalBase): terminal_stdout_re = [ re.compile(r"[\r\n]?[\w+\-\.:\/\[\]]+(?:\([^\)]+\)){,3}(?:>|#) ?$"), - re.compile(r"[\r\n]?[\w+\-\.:\/\[\]]+(?:\([^\)]+\)){,3}(?:>|%) ?$"), ] terminal_stderr_re = [