Repository: ansible/ansible

Issue:
onyx_vlan throws exception when using onyx version 3.6.6000
<!---
Verify first that your issue/request is not already reported on GitHub.
Also test if the latest release, and devel branch are affected too.
-->

##### ISSUE TYPE
<!--- Pick one below and delete the rest -->
 - Bug Report

##### COMPONENT NAME
<!---
Name of the module, plugin, task or feature
Do not include extra details here, e.g. "vyos_command" not "the network module vyos_command" or the full path
-->
onyx_vlan.py

##### ANSIBLE VERSION
<!--- Paste verbatim output from "ansible --version" between quotes below -->
```
ansible 2.6.0 (devel c1008d693c) last updated 2018/03/12 15:51:01 (GMT +000)
  python version = 2.7.5 (default, Nov  6 2016, 00:28:07) [GCC 4.8.5 20150623 (Red Hat 4.8.5-11)]
```

##### CONFIGURATION
<!---
If using Ansible 2.4 or above, paste the results of "ansible-config dump --only-changed"
Otherwise, mention any settings you have changed/added/removed in ansible.cfg
(or using the ANSIBLE_* environment variables).
-->

##### 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.
Also mention the specific version of what you are trying to control,
e.g. if this is a network bug the version of firmware on the network device.
-->
N/A
##### SUMMARY
<!--- Explain the problem briefly -->
when running command onyx_vlan on onyx network device with version 3.6.6000 or later, there is an exception.

##### STEPS TO REPRODUCE
<!---
For bugs, show exactly how to reproduce the problem, using a minimal test-case.
For new features, show how the feature would be used.
-->
run any playbook with onyx_vlan

<!--- Paste example playbooks or commands between quotes below -->
```yaml
- name: Configure vlan for IPL
  onyx_vlan:
    vlan_id: 4000
    name: IPL
```

<!--- You can also paste gist.github.com links for larger files -->

##### EXPECTED RESULTS
<!--- What did you expect to happen when running the steps above? -->
onyx_vlan will configure vlan on the network device

##### ACTUAL RESULTS
<!--- What actually happened? If possible run with extra verbosity (-vvvv) -->
Command failed with exception

<!--- Paste verbatim command output between quotes below -->
```
fatal: [swi60]: FAILED! => {
    "changed": false,
    "module_stderr": "Traceback (most recent call last):\n  File \"/tmp/ansible_pkMA4U/ansible_module_onyx_vlan.py\", line 201, in <module>\n    main()\n  File \"/tmp/ansible_pkMA4U/ansible_module_onyx_vlan.py\", line 197, in main\n    OnyxVlanModule.main()\n  File \"/tmp/ansible_pkMA4U/ansible_modlib.zip/ansible/module_utils/network/onyx/onyx.py\", line 229, in main\n  File \"/tmp/ansible_pkMA4U/ansible_modlib.zip/ansible/module_utils/network/onyx/onyx.py\", line 207, in run\n  File \"/tmp/ansible_pkMA4U/ansible_module_onyx_vlan.py\", line 161, in load_current_config\n    self._create_vlan_data(vlan_id, vlan_data)\n  File \"/tmp/ansible_pkMA4U/ansible_module_onyx_vlan.py\", line 143, in _create_vlan_data\n    'name': self.get_config_attr(vlan_data, 'Name')\n  File \"/tmp/ansible_pkMA4U/ansible_modlib.zip/ansible/module_utils/network/onyx/onyx.py\", line 183, in get_config_attr\nAttributeError: 'list' object has no attribute 'get'\n",
    "module_stdout": "",
    "msg": "MODULE FAILURE",
    "rc": 1
```



Discussion:
Files identified in the description:
* [lib/ansible/modules/network/onyx/onyx_vlan.py](https://github.com/ansible/ansible/blob/devel/lib/ansible/modules/network/onyx/onyx_vlan.py)

If these files are inaccurate, please update the `component name` section of the description or use the `!component` bot command.

[click here for bot help](https://github.com/ansible/ansibullbot/blob/master/ISSUE_HELP.md)
<!--- boilerplate: components_banner --->
cc @atabachnik
[click here for bot help](https://github.com/ansible/ansibullbot/blob/master/ISSUE_HELP.md)
<!--- boilerplate: notify --->

Resolving patch:
diff --git a/lib/ansible/module_utils/network/onyx/onyx.py b/lib/ansible/module_utils/network/onyx/onyx.py
--- a/lib/ansible/module_utils/network/onyx/onyx.py
+++ b/lib/ansible/module_utils/network/onyx/onyx.py
@@ -140,18 +140,24 @@ def get_interfaces_config(module, interface_type, flags=None, json_fmt=True):
     return show_cmd(module, cmd, json_fmt)
 
 
+def show_version(module):
+    return show_cmd(module, "show version")
+
+
 def get_bgp_summary(module):
     cmd = "show running-config protocol bgp"
     return show_cmd(module, cmd, json_fmt=False, fail_on_error=False)
 
 
 class BaseOnyxModule(object):
+    ONYX_API_VERSION = "3.6.6000"
 
     def __init__(self):
         self._module = None
         self._commands = list()
         self._current_config = None
         self._required_config = None
+        self._os_version = None
 
     def init_module(self):
         pass
@@ -162,6 +168,11 @@ def load_current_config(self):
     def get_required_config(self):
         pass
 
+    def _get_os_version(self):
+        version_data = show_version(self._module)
+        return self.get_config_attr(
+            version_data, "Product release")
+
     # pylint: disable=unused-argument
     def check_declarative_intent_params(self, result):
         return None
diff --git a/lib/ansible/modules/network/onyx/onyx_vlan.py b/lib/ansible/modules/network/onyx/onyx_vlan.py
--- a/lib/ansible/modules/network/onyx/onyx_vlan.py
+++ b/lib/ansible/modules/network/onyx/onyx_vlan.py
@@ -138,6 +138,8 @@ def get_required_config(self):
             self._required_config.append(params)
 
     def _create_vlan_data(self, vlan_id, vlan_data):
+        if self._os_version >= self.ONYX_API_VERSION:
+            vlan_data = vlan_data[0]
         return {
             'vlan_id': vlan_id,
             'name': self.get_config_attr(vlan_data, 'Name')
@@ -148,6 +150,7 @@ def _get_vlan_config(self):
 
     def load_current_config(self):
         # called in base class in run function
+        self._os_version = self._get_os_version()
         self._current_config = dict()
         vlan_config = self._get_vlan_config()
         if not vlan_config:


Test patch:
diff --git a/test/units/modules/network/onyx/test_onyx_vlan.py b/test/units/modules/network/onyx/test_onyx_vlan.py
--- a/test/units/modules/network/onyx/test_onyx_vlan.py
+++ b/test/units/modules/network/onyx/test_onyx_vlan.py
@@ -20,8 +20,6 @@
 from __future__ import (absolute_import, division, print_function)
 __metaclass__ = type
 
-import json
-
 from ansible.compat.tests.mock import patch
 from ansible.modules.network.onyx import onyx_vlan
 from units.modules.utils import set_module_args
@@ -42,15 +40,21 @@ def setUp(self):
             'ansible.module_utils.network.onyx.onyx.load_config')
         self.load_config = self.mock_load_config.start()
 
+        self.mock_get_version = patch.object(
+            onyx_vlan.OnyxVlanModule, "_get_os_version")
+        self.get_version = self.mock_get_version.start()
+
     def tearDown(self):
         super(TestOnyxVlanModule, self).tearDown()
         self.mock_get_config.stop()
         self.mock_load_config.stop()
+        self.mock_get_version.stop()
 
     def load_fixtures(self, commands=None, transport='cli'):
         config_file = 'onyx_vlan_show.cfg'
         self.get_config.return_value = load_fixture(config_file)
         self.load_config.return_value = None
+        self.get_version.return_value = "3.6.5000"
 
     def test_vlan_no_change(self):
         set_module_args(dict(vlan_id=20))