Repository: ansible/ansible-modules-core

Issue:
[regression] junos_command returns parsed XML
##### ISSUE TYPE

<!--- Pick one below and delete the rest: -->
- Bug Report
##### COMPONENT NAME

junos_command
##### ANSIBLE VERSION

<!--- Paste verbatim output from “ansible --version” between quotes below -->

```
ansible-playbook 2.2.0 (devel 9d5dff5596) last updated 2016/09/25 19:32:29 (GMT +000)
  lib/ansible/modules/core: (detached HEAD edf361a5d4) last updated 2016/09/25 19:32:37 (GMT +000)
  lib/ansible/modules/extras: (detached HEAD 8aa338ddfa) last updated 2016/09/25 19:32:44 (GMT +000)
  config file = /vagrant/Ansible/Networking/ansible.cfg
  configured module search path = Default w/o overrides
```
##### OS / ENVIRONMENT

<!---
Mention the OS you are running Ansible from, and the OS you are
managing, or say “N/A” for anything that is not platform-specific.
-->

Ansible: Ubuntu
Junos: vSRX 12.1X47
##### SUMMARY

<!--- Explain the problem briefly -->

junos_command returned an object parsed from Junos XML output in stdout (and stdout_lines) in Ansible 2.1. Ansible 2.2 returns XML string (or individual lines from the XML string) breaking backward compatibility and forcing the playbook developed to insert a few unnecessary extra tasks to parse XML results.
##### STEPS TO REPRODUCE

<!---
For bugs, show exactly how to reproduce the problem.
For new features, show how the feature would be used.
-->

<!--- Paste example playbooks or commands between quotes below -->

```

---
- hosts: junos
  tasks:
  - junos_command:
      commands: "show arp"
      provider: "{{netconf}}"
    register: result
```

<!--- You can also paste gist.github.com links for larger files -->
##### EXPECTED RESULTS

```
TASK [junos_command] ***********************************************************
ok: [srx.lab.local] => {"changed": false, "stdout": [{"arp-table-information": {"arp-entry-count": "5", "arp-table-entry": [{"arp-table-entry-flags": {"none": ""}, "hostname": "172.16.1.1", "interface-name": "ge-0/0/1.0", "ip-address": "172.16.1.1", "mac-address": "00:50:56:c0:00:02"}, {"arp-table-entry-flags": {"none": ""}, "hostname": "172.16.1.12", "interface-name": "ge-0/0/1.0", "ip-address": "172.16.1.12", "mac-address": "00:0c:29:20:90:a9"}, {"arp-table-entry-flags": {"none": ""}, "hostname": "192.168.178.1", "interface-name": "ge-0/0/0.0", "ip-address": "192.168.178.1", "mac-address": "00:50:56:c0:00:08"}, {"arp-table-entry-flags": {"none": ""}, "hostname": "192.168.178.2", "interface-name": "ge-0/0/0.0", "ip-address": "192.168.178.2", "mac-address": "00:50:56:f9:6f:b1"}, {"arp-table-entry-flags": {"none": ""}, "hostname": "192.168.178.254", "interface-name": "ge-0/0/0.0", "ip-address": "192.168.178.254", "mac-address": "00:50:56:fb:d5:d8"}]}}], "stdout_lines": [{"arp-table-information": {"arp-entry-count": "5", "arp-table-entry": [{"arp-table-entry-flags": {"none": ""}, "hostname": "172.16.1.1", "interface-name": "ge-0/0/1.0", "ip-address": "172.16.1.1", "mac-address": "00:50:56:c0:00:02"}, {"arp-table-entry-flags": {"none": ""}, "hostname": "172.16.1.12", "interface-name": "ge-0/0/1.0", "ip-address": "172.16.1.12", "mac-address": "00:0c:29:20:90:a9"}, {"arp-table-entry-flags": {"none": ""}, "hostname": "192.168.178.1", "interface-name": "ge-0/0/0.0", "ip-address": "192.168.178.1", "mac-address": "00:50:56:c0:00:08"}, {"arp-table-entry-flags": {"none": ""}, "hostname": "192.168.178.2", "interface-name": "ge-0/0/0.0", "ip-address": "192.168.178.2", "mac-address": "00:50:56:f9:6f:b1"}, {"arp-table-entry-flags": {"none": ""}, "hostname": "192.168.178.254", "interface-name": "ge-0/0/0.0", "ip-address": "192.168.178.254", "mac-address": "00:50:56:fb:d5:d8"}]}}], "xml": ["<arp-table-information style=\"normal\">\n<arp-table-entry>\n<mac-address>\n00:50:56:c0:00:02\n</mac-address>\n<ip-address>\n172.16.1.1\n</ip-address>\n<hostname>\n172.16.1.1\n</hostname>\n<interface-name>\nge-0/0/1.0\n</interface-name>\n<arp-table-entry-flags>\n<none/>\n</arp-table-entry-flags>\n</arp-table-entry>\n<arp-table-entry>\n<mac-address>\n00:0c:29:20:90:a9\n</mac-address>\n<ip-address>\n172.16.1.12\n</ip-address>\n<hostname>\n172.16.1.12\n</hostname>\n<interface-name>\nge-0/0/1.0\n</interface-name>\n<arp-table-entry-flags>\n<none/>\n</arp-table-entry-flags>\n</arp-table-entry>\n<arp-table-entry>\n<mac-address>\n00:50:56:c0:00:08\n</mac-address>\n<ip-address>\n192.168.178.1\n</ip-address>\n<hostname>\n192.168.178.1\n</hostname>\n<interface-name>\nge-0/0/0.0\n</interface-name>\n<arp-table-entry-flags>\n<none/>\n</arp-table-entry-flags>\n</arp-table-entry>\n<arp-table-entry>\n<mac-address>\n00:50:56:f9:6f:b1\n</mac-address>\n<ip-address>\n192.168.178.2\n</ip-address>\n<hostname>\n192.168.178.2\n</hostname>\n<interface-name>\nge-0/0/0.0\n</interface-name>\n<arp-table-entry-flags>\n<none/>\n</arp-table-entry-flags>\n</arp-table-entry>\n<arp-table-entry>\n<mac-address>\n00:50:56:fb:d5:d8\n</mac-address>\n<ip-address>\n192.168.178.254\n</ip-address>\n<hostname>\n192.168.178.254\n</hostname>\n<interface-name>\nge-0/0/0.0\n</interface-name>\n<arp-table-entry-flags>\n<none/>\n</arp-table-entry-flags>\n</arp-table-entry>\n<arp-entry-count>\n5\n</arp-entry-count>\n</arp-table-information>\n"]}
```
##### ACTUAL RESULTS

```
TASK [junos_command] ***********************************************************
ok: [srx.lab.local] => {"changed": false, "stdout": ["<arp-table-information style=\"normal\">\n<arp-table-entry>\n<mac-address>\n00:50:56:c0:00:02\n</mac-address>\n<ip-address>\n172.16.1.1\n</ip-address>\n<hostname>\n172.16.1.1\n</hostname>\n<interface-name>\nge-0/0/1.0\n</interface-name>\n<arp-table-entry-flags>\n<none/>\n</arp-table-entry-flags>\n</arp-table-entry>\n<arp-table-entry>\n<mac-address>\n00:0c:29:20:90:a9\n</mac-address>\n<ip-address>\n172.16.1.12\n</ip-address>\n<hostname>\n172.16.1.12\n</hostname>\n<interface-name>\nge-0/0/1.0\n</interface-name>\n<arp-table-entry-flags>\n<none/>\n</arp-table-entry-flags>\n</arp-table-entry>\n<arp-table-entry>\n<mac-address>\n00:50:56:c0:00:08\n</mac-address>\n<ip-address>\n192.168.178.1\n</ip-address>\n<hostname>\n192.168.178.1\n</hostname>\n<interface-name>\nge-0/0/0.0\n</interface-name>\n<arp-table-entry-flags>\n<none/>\n</arp-table-entry-flags>\n</arp-table-entry>\n<arp-table-entry>\n<mac-address>\n00:50:56:f9:6f:b1\n</mac-address>\n<ip-address>\n192.168.178.2\n</ip-address>\n<hostname>\n192.168.178.2\n</hostname>\n<interface-name>\nge-0/0/0.0\n</interface-name>\n<arp-table-entry-flags>\n<none/>\n</arp-table-entry-flags>\n</arp-table-entry>\n<arp-table-entry>\n<mac-address>\n00:50:56:fb:d5:d8\n</mac-address>\n<ip-address>\n192.168.178.254\n</ip-address>\n<hostname>\n192.168.178.254\n</hostname>\n<interface-name>\nge-0/0/0.0\n</interface-name>\n<arp-table-entry-flags>\n<none/>\n</arp-table-entry-flags>\n</arp-table-entry>\n<arp-entry-count>\n5\n</arp-entry-count>\n</arp-table-information>\n"], "stdout_lines": [["<arp-table-information style=\"normal\">", "<arp-table-entry>", "<mac-address>", "00:50:56:c0:00:02", "</mac-address>", "<ip-address>", "172.16.1.1", "</ip-address>", "<hostname>", "172.16.1.1", "</hostname>", "<interface-name>", "ge-0/0/1.0", "</interface-name>", "<arp-table-entry-flags>", "<none/>", "</arp-table-entry-flags>", "</arp-table-entry>", "<arp-table-entry>", "<mac-address>", "00:0c:29:20:90:a9", "</mac-address>", "<ip-address>", "172.16.1.12", "</ip-address>", "<hostname>", "172.16.1.12", "</hostname>", "<interface-name>", "ge-0/0/1.0", "</interface-name>", "<arp-table-entry-flags>", "<none/>", "</arp-table-entry-flags>", "</arp-table-entry>", "<arp-table-entry>", "<mac-address>", "00:50:56:c0:00:08", "</mac-address>", "<ip-address>", "192.168.178.1", "</ip-address>", "<hostname>", "192.168.178.1", "</hostname>", "<interface-name>", "ge-0/0/0.0", "</interface-name>", "<arp-table-entry-flags>", "<none/>", "</arp-table-entry-flags>", "</arp-table-entry>", "<arp-table-entry>", "<mac-address>", "00:50:56:f9:6f:b1", "</mac-address>", "<ip-address>", "192.168.178.2", "</ip-address>", "<hostname>", "192.168.178.2", "</hostname>", "<interface-name>", "ge-0/0/0.0", "</interface-name>", "<arp-table-entry-flags>", "<none/>", "</arp-table-entry-flags>", "</arp-table-entry>", "<arp-table-entry>", "<mac-address>", "00:50:56:fb:d5:d8", "</mac-address>", "<ip-address>", "192.168.178.254", "</ip-address>", "<hostname>", "192.168.178.254", "</hostname>", "<interface-name>", "ge-0/0/0.0", "</interface-name>", "<arp-table-entry-flags>", "<none/>", "</arp-table-entry-flags>", "</arp-table-entry>", "<arp-entry-count>", "5", "</arp-entry-count>", "</arp-table-information>", ""]], "warnings": []}
```



Discussion:
<!-- @ipspace: Thanks for filing this bug report! -->

@privateip, @gundalow, ping. This issue is waiting on your response.
[click here for bot help](https://github.com/ansible/ansibullbot/blob/master/ISSUE_HELP.md)

<!--- boilerplate: issue_bug_new --->


Resolving patch:
diff --git a/network/junos/junos_command.py b/network/junos/junos_command.py
--- a/network/junos/junos_command.py
+++ b/network/junos/junos_command.py
@@ -151,15 +151,23 @@
   retured: failed
   type: list
   sample: ['...', '...']
+
+xml:
+  description: The raw XML reply from the device
+  returned: when format is xml
+  type: list
+  sample: [['...', '...'], ['...', '...']]
 """
 import re
 
 import ansible.module_utils.junos
 
+
 from ansible.module_utils.basic import get_exception
 from ansible.module_utils.network import NetworkModule, NetworkError
 from ansible.module_utils.netcli import CommandRunner
 from ansible.module_utils.netcli import AddCommandError, FailedConditionsError
+from ansible.module_utils.junos import xml_to_json
 
 VALID_KEYS = {
     'cli': frozenset(['command', 'output', 'prompt', 'response']),
@@ -270,15 +278,19 @@ def main():
         module.fail_json(msg=str(exc))
 
     result = dict(changed=False, stdout=list())
+    xmlout = list()
 
     for cmd in commands:
         try:
             output = runner.get_command(cmd['command'], cmd.get('output'))
+            xmlout.append(output)
+            output = xml_to_json(output)
         except ValueError:
             output = 'command not executed due to check_mode, see warnings'
         result['stdout'].append(output)
 
     result['warnings'] = warnings
+    result['xml'] = xmlout
     result['stdout_lines'] = list(to_lines(result['stdout']))
 
     module.exit_json(**result)


Test patch: