summaryrefslogtreecommitdiff
path: root/lib/ansible
diff options
context:
space:
mode:
authorJayalakshmiV <53187249+JayalakshmiV@users.noreply.github.com>2019-10-10 06:50:04 -0400
committeransibot <ansibot@users.noreply.github.com>2019-10-10 06:50:04 -0400
commit45acdb41d2ac81216c5d8e26b095c767bc5054d0 (patch)
tree8d4b4e9dfdcedf26718d8ea22372b0a5d2d1d627 /lib/ansible
parenteca33b80f02473d548095b9449eb907573c5770d (diff)
downloadansible-45acdb41d2ac81216c5d8e26b095c767bc5054d0.tar.gz
Added Exos vlan resource module (#61865)
* EXOS_VLAN resource module * EXOS_VLAN resource module * EXOS_VLAN resource module * EXOS_VLAN resource module * EXOS_VLAN resource module * Fix exos_vlans resource module and integration test * Move exos_vlan folder to exos_vlans folder * Fix exos->config->vlans and exos->utils * Fix version_added * Improve exos_vlans module and integration tests * Fix exos_vlans.py * exos_vlan resource module
Diffstat (limited to 'lib/ansible')
-rw-r--r--lib/ansible/module_utils/network/exos/argspec/vlans/__init__.py0
-rw-r--r--lib/ansible/module_utils/network/exos/argspec/vlans/vlans.py53
-rw-r--r--lib/ansible/module_utils/network/exos/config/vlans/__init__.py0
-rw-r--r--lib/ansible/module_utils/network/exos/config/vlans/vlans.py277
-rw-r--r--lib/ansible/module_utils/network/exos/facts/facts.py2
-rw-r--r--lib/ansible/module_utils/network/exos/facts/vlans/__init__.py0
-rw-r--r--lib/ansible/module_utils/network/exos/facts/vlans/vlans.py89
-rw-r--r--lib/ansible/module_utils/network/exos/utils/utils.py13
-rw-r--r--lib/ansible/modules/network/exos/exos_vlans.py759
9 files changed, 1188 insertions, 5 deletions
diff --git a/lib/ansible/module_utils/network/exos/argspec/vlans/__init__.py b/lib/ansible/module_utils/network/exos/argspec/vlans/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/lib/ansible/module_utils/network/exos/argspec/vlans/__init__.py
diff --git a/lib/ansible/module_utils/network/exos/argspec/vlans/vlans.py b/lib/ansible/module_utils/network/exos/argspec/vlans/vlans.py
new file mode 100644
index 0000000000..538a155a7d
--- /dev/null
+++ b/lib/ansible/module_utils/network/exos/argspec/vlans/vlans.py
@@ -0,0 +1,53 @@
+#
+# -*- coding: utf-8 -*-
+# Copyright 2019 Red Hat
+# GNU General Public License v3.0+
+# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+#############################################
+# WARNING #
+#############################################
+#
+# This file is auto generated by the resource
+# module builder playbook.
+#
+# Do not edit this file manually.
+#
+# Changes to this file will be over written
+# by the resource module builder.
+#
+# Changes should be made in the model used to
+# generate this file or in the resource module
+# builder template.
+#
+#############################################
+
+"""
+The arg spec for the exos_vlans module
+"""
+from __future__ import absolute_import, division, print_function
+__metaclass__ = type
+
+
+class VlansArgs(object): # pylint: disable=R0903
+ """The arg spec for the exos_vlans module
+ """
+
+ def __init__(self, **kwargs):
+ pass
+
+ argument_spec = {
+ 'config': {
+ 'elements': 'dict',
+ 'options': {
+ 'name': {'type': 'str'},
+ 'state': {
+ 'choices': ['active', 'suspend'],
+ 'default': 'active',
+ 'type': 'str'},
+ 'vlan_id': {'required': True, 'type': 'int'}},
+ 'type': 'list'},
+ 'state': {
+ 'choices': ['merged', 'replaced', 'overridden', 'deleted'],
+ 'default': 'merged',
+ 'type': 'str'}} # pylint: disable=C0301
diff --git a/lib/ansible/module_utils/network/exos/config/vlans/__init__.py b/lib/ansible/module_utils/network/exos/config/vlans/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/lib/ansible/module_utils/network/exos/config/vlans/__init__.py
diff --git a/lib/ansible/module_utils/network/exos/config/vlans/vlans.py b/lib/ansible/module_utils/network/exos/config/vlans/vlans.py
new file mode 100644
index 0000000000..efe615a19c
--- /dev/null
+++ b/lib/ansible/module_utils/network/exos/config/vlans/vlans.py
@@ -0,0 +1,277 @@
+#
+# -*- coding: utf-8 -*-
+# Copyright 2019 Red Hat
+# GNU General Public License v3.0+
+# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+"""
+The exos_vlans class
+It is in this file where the current configuration (as dict)
+is compared to the provided configuration (as dict) and the command set
+necessary to bring the current configuration to it's desired end-state is
+created
+"""
+from __future__ import absolute_import, division, print_function
+__metaclass__ = type
+
+import json
+from copy import deepcopy
+from ansible.module_utils.network.common.cfg.base import ConfigBase
+from ansible.module_utils.network.common.utils import to_list, dict_diff
+from ansible.module_utils.network.exos.facts.facts import Facts
+from ansible.module_utils.network.exos.exos import send_requests
+from ansible.module_utils.network.exos.utils.utils import search_obj_in_list
+
+
+class Vlans(ConfigBase):
+ """
+ The exos_vlans class
+ """
+
+ gather_subset = [
+ '!all',
+ '!min',
+ ]
+
+ gather_network_resources = [
+ 'vlans',
+ ]
+
+ VLAN_POST = {
+ "data": {"openconfig-vlan:vlans": []},
+ "method": "POST",
+ "path": "/rest/restconf/data/openconfig-vlan:vlans/"
+ }
+
+ VLAN_PATCH = {
+ "data": {"openconfig-vlan:vlans": {"vlan": []}},
+ "method": "PATCH",
+ "path": "/rest/restconf/data/openconfig-vlan:vlans/"
+ }
+
+ VLAN_DELETE = {
+ "method": "DELETE",
+ "path": None
+ }
+
+ DEL_PATH = "/rest/restconf/data/openconfig-vlan:vlans/vlan="
+
+ REQUEST_BODY = {
+ "config": {"name": None, "status": "ACTIVE", "tpid": "oc-vlan-types:TPID_0x8100", "vlan-id": None}
+ }
+
+ def __init__(self, module):
+ super(Vlans, self).__init__(module)
+
+ def get_vlans_facts(self):
+ """ Get the 'facts' (the current configuration)
+
+ :rtype: A dictionary
+ :returns: The current configuration as a dictionary
+ """
+ facts, _warnings = Facts(self._module).get_facts(
+ self.gather_subset, self.gather_network_resources)
+ vlans_facts = facts['ansible_network_resources'].get('vlans')
+ if not vlans_facts:
+ return []
+ return vlans_facts
+
+ def execute_module(self):
+ """ Execute the module
+
+ :rtype: A dictionary
+ :returns: The result from module execution
+ """
+ result = {'changed': False}
+ warnings = list()
+ requests = list()
+
+ existing_vlans_facts = self.get_vlans_facts()
+ requests.extend(self.set_config(existing_vlans_facts))
+ if requests:
+ if not self._module.check_mode:
+ send_requests(self._module, requests=requests)
+ result['changed'] = True
+ result['requests'] = requests
+
+ changed_vlans_facts = self.get_vlans_facts()
+
+ result['before'] = existing_vlans_facts
+ if result['changed']:
+ result['after'] = changed_vlans_facts
+
+ result['warnings'] = warnings
+ return result
+
+ def set_config(self, existing_vlans_facts):
+ """ Collect the configuration from the args passed to the module,
+ collect the current configuration (as a dict from facts)
+
+ :rtype: A list
+ :returns: the requests necessary to migrate the current configuration
+ to the desired configuration
+ """
+ want = self._module.params['config']
+ have = existing_vlans_facts
+ resp = self.set_state(want, have)
+ return to_list(resp)
+
+ def set_state(self, want, have):
+ """ Select the appropriate function based on the state provided
+
+ :param want: the desired configuration as a dictionary
+ :param have: the current configuration as a dictionary
+ :rtype: A list
+ :returns: the requests necessary to migrate the current configuration
+ to the desired configuration
+ """
+ state = self._module.params['state']
+ if state == 'overridden':
+ requests = self._state_overridden(want, have)
+ elif state == 'deleted':
+ requests = self._state_deleted(want, have)
+ elif state == 'merged':
+ requests = self._state_merged(want, have)
+ elif state == 'replaced':
+ requests = self._state_replaced(want, have)
+ return requests
+
+ def _state_replaced(self, want, have):
+ """ The request generator when state is replaced
+
+ :rtype: A list
+ :returns: the requests necessary to migrate the current configuration
+ to the desired configuration
+ """
+ requests = []
+ request_patch = deepcopy(self.VLAN_PATCH)
+
+ for w in want:
+ if w.get('vlan_id'):
+ h = search_obj_in_list(w['vlan_id'], have, 'vlan_id')
+ if h:
+ if dict_diff(w, h):
+ request_body = self._update_patch_request(w)
+ request_patch["data"]["openconfig-vlan:vlans"]["vlan"].append(request_body)
+ else:
+ request_post = self._update_post_request(w)
+ requests.append(request_post)
+
+ if len(request_patch["data"]["openconfig-vlan:vlans"]["vlan"]):
+ request_patch["data"] = json.dumps(request_patch["data"])
+ requests.append(request_patch)
+
+ return requests
+
+ def _state_overridden(self, want, have):
+ """ The request generator when state is overridden
+
+ :rtype: A list
+ :returns: the requests necessary to migrate the current configuration
+ to the desired configuration
+ """
+ requests = []
+ request_patch = deepcopy(self.VLAN_PATCH)
+
+ have_copy = []
+ for w in want:
+ if w.get('vlan_id'):
+ h = search_obj_in_list(w['vlan_id'], have, 'vlan_id')
+ if h:
+ if dict_diff(w, h):
+ request_body = self._update_patch_request(w)
+ request_patch["data"]["openconfig-vlan:vlans"]["vlan"].append(request_body)
+ have_copy.append(h)
+ else:
+ request_post = self._update_post_request(w)
+ requests.append(request_post)
+
+ for h in have:
+ if h not in have_copy and h['vlan_id'] != 1:
+ request_delete = self._update_delete_request(h)
+ requests.append(request_delete)
+
+ if len(request_patch["data"]["openconfig-vlan:vlans"]["vlan"]):
+ request_patch["data"] = json.dumps(request_patch["data"])
+ requests.append(request_patch)
+
+ return requests
+
+ def _state_merged(self, want, have):
+ """ The requests generator when state is merged
+
+ :rtype: A list
+ :returns: the requests necessary to merge the provided into
+ the current configuration
+ """
+ requests = []
+
+ request_patch = deepcopy(self.VLAN_PATCH)
+
+ for w in want:
+ if w.get('vlan_id'):
+ h = search_obj_in_list(w['vlan_id'], have, 'vlan_id')
+ if h:
+ if dict_diff(w, h):
+ request_body = self._update_patch_request(w)
+ request_patch["data"]["openconfig-vlan:vlans"]["vlan"].append(request_body)
+ else:
+ request_post = self._update_post_request(w)
+ requests.append(request_post)
+
+ if len(request_patch["data"]["openconfig-vlan:vlans"]["vlan"]):
+ request_patch["data"] = json.dumps(request_patch["data"])
+ requests.append(request_patch)
+ return requests
+
+ def _state_deleted(self, want, have):
+ """ The requests generator when state is deleted
+
+ :rtype: A list
+ :returns: the requests necessary to remove the current configuration
+ of the provided objects
+ """
+ requests = []
+
+ if want:
+ for w in want:
+ if w.get('vlan_id'):
+ h = search_obj_in_list(w['vlan_id'], have, 'vlan_id')
+ if h:
+ request_delete = self._update_delete_request(h)
+ requests.append(request_delete)
+
+ else:
+ if not have:
+ return requests
+ for h in have:
+ if h['vlan_id'] == 1:
+ continue
+ else:
+ request_delete = self._update_delete_request(h)
+ requests.append(request_delete)
+
+ return requests
+
+ def _update_vlan_config_body(self, want, request):
+ request["config"]["name"] = want["name"]
+ request["config"]["status"] = "SUSPENDED" if want["state"] == "suspend" else want["state"].upper()
+ request["config"]["vlan-id"] = want["vlan_id"]
+ return request
+
+ def _update_patch_request(self, want):
+ request_body = deepcopy(self.REQUEST_BODY)
+ request_body = self._update_vlan_config_body(want, request_body)
+ return request_body
+
+ def _update_post_request(self, want):
+ request_post = deepcopy(self.VLAN_POST)
+ request_body = deepcopy(self.REQUEST_BODY)
+ request_body = self._update_vlan_config_body(want, request_body)
+ request_post["data"]["openconfig-vlan:vlans"].append(request_body)
+ request_post["data"] = json.dumps(request_post["data"])
+ return request_post
+
+ def _update_delete_request(self, have):
+ request_delete = deepcopy(self.VLAN_DELETE)
+ request_delete["path"] = self.DEL_PATH + str(have['vlan_id'])
+ return request_delete
diff --git a/lib/ansible/module_utils/network/exos/facts/facts.py b/lib/ansible/module_utils/network/exos/facts/facts.py
index 04c08ea78d..089407be9f 100644
--- a/lib/ansible/module_utils/network/exos/facts/facts.py
+++ b/lib/ansible/module_utils/network/exos/facts/facts.py
@@ -14,6 +14,7 @@ __metaclass__ = type
from ansible.module_utils.network.exos.argspec.facts.facts import FactsArgs
from ansible.module_utils.network.common.facts.facts import FactsBase
from ansible.module_utils.network.exos.facts.lldp_global.lldp_global import Lldp_globalFacts
+from ansible.module_utils.network.exos.facts.vlans.vlans import VlansFacts
from ansible.module_utils.network.exos.facts.legacy.base import Default, Hardware, Interfaces, Config
FACT_LEGACY_SUBSETS = dict(
@@ -24,6 +25,7 @@ FACT_LEGACY_SUBSETS = dict(
FACT_RESOURCE_SUBSETS = dict(
lldp_global=Lldp_globalFacts,
+ vlans=VlansFacts,
)
diff --git a/lib/ansible/module_utils/network/exos/facts/vlans/__init__.py b/lib/ansible/module_utils/network/exos/facts/vlans/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/lib/ansible/module_utils/network/exos/facts/vlans/__init__.py
diff --git a/lib/ansible/module_utils/network/exos/facts/vlans/vlans.py b/lib/ansible/module_utils/network/exos/facts/vlans/vlans.py
new file mode 100644
index 0000000000..55f211f732
--- /dev/null
+++ b/lib/ansible/module_utils/network/exos/facts/vlans/vlans.py
@@ -0,0 +1,89 @@
+#
+# -*- coding: utf-8 -*-
+# Copyright 2019 Red Hat
+# GNU General Public License v3.0+
+# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+"""
+The exos vlans fact class
+It is in this file the configuration is collected from the device
+for a given resource, parsed, and the facts tree is populated
+based on the configuration.
+"""
+from __future__ import absolute_import, division, print_function
+__metaclass__ = type
+
+import re
+from copy import deepcopy
+
+from ansible.module_utils.network.common import utils
+from ansible.module_utils.network.exos.argspec.vlans.vlans import VlansArgs
+from ansible.module_utils.network.exos.exos import send_requests
+
+
+class VlansFacts(object):
+ """ The exos vlans fact class
+ """
+
+ def __init__(self, module, subspec='config', options='options'):
+ self._module = module
+ self.argument_spec = VlansArgs.argument_spec
+ spec = deepcopy(self.argument_spec)
+ if subspec:
+ if options:
+ facts_argument_spec = spec[subspec][options]
+ else:
+ facts_argument_spec = spec[subspec]
+ else:
+ facts_argument_spec = spec
+
+ self.generated_spec = utils.generate_dict(facts_argument_spec)
+
+ def populate_facts(self, connection, ansible_facts, data=None):
+ """ Populate the facts for vlans
+ :param connection: the device connection
+ :param ansible_facts: Facts dictionary
+ :param data: previously collected conf
+ :rtype: dictionary
+ :returns: facts
+ """
+
+ if not data:
+ request = [{
+ "path": "/rest/restconf/data/openconfig-vlan:vlans?depth=5",
+ "method": "GET"
+ }]
+ data = send_requests(self._module, requests=request)
+
+ objs = []
+ if data:
+ for d in data[0]["openconfig-vlan:vlans"]["vlan"]:
+ obj = self.render_config(self.generated_spec, d["config"])
+ if obj:
+ objs.append(obj)
+
+ ansible_facts['ansible_network_resources'].pop('vlans', None)
+ facts = {}
+ if objs:
+ params = utils.validate_config(self.argument_spec, {'config': objs})
+ facts['vlans'] = params['config']
+
+ ansible_facts['ansible_network_resources'].update(facts)
+ return ansible_facts
+
+ def render_config(self, spec, conf):
+ """
+ Render config as dictionary structure and delete keys
+ from spec for null values
+
+ :param spec: The facts tree, generated from the argspec
+ :param conf: The configuration
+ :rtype: dictionary
+ :returns: The generated config
+ """
+ config = deepcopy(spec)
+
+ config["name"] = conf["name"]
+ config["state"] = "suspend" if conf["status"] == "SUSPENDED" else conf["status"].lower()
+ config["vlan_id"] = conf["vlan-id"]
+
+ return utils.remove_empties(config)
diff --git a/lib/ansible/module_utils/network/exos/utils/utils.py b/lib/ansible/module_utils/network/exos/utils/utils.py
index d3b7c17de0..d40f81714c 100644
--- a/lib/ansible/module_utils/network/exos/utils/utils.py
+++ b/lib/ansible/module_utils/network/exos/utils/utils.py
@@ -1,6 +1,9 @@
-# -*- coding: utf-8 -*-
-# Copyright 2019 Red Hat
-# GNU General Public License v3.0+
-# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+from __future__ import absolute_import, division, print_function
+__metaclass__ = type
-# utils
+
+def search_obj_in_list(item, lst, key):
+ for o in lst:
+ if o[key] == item:
+ return o
+ return None
diff --git a/lib/ansible/modules/network/exos/exos_vlans.py b/lib/ansible/modules/network/exos/exos_vlans.py
new file mode 100644
index 0000000000..eea07ea96c
--- /dev/null
+++ b/lib/ansible/modules/network/exos/exos_vlans.py
@@ -0,0 +1,759 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+# Copyright 2019 Red Hat
+# GNU General Public License v3.0+
+# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+#############################################
+# WARNING #
+#############################################
+#
+# This file is auto generated by the resource
+# module builder playbook.
+#
+# Do not edit this file manually.
+#
+# Changes to this file will be over written
+# by the resource module builder.
+#
+# Changes should be made in the model used to
+# generate this file or in the resource module
+# builder template.
+#
+#############################################
+
+"""
+The module file for exos_vlans
+"""
+
+from __future__ import absolute_import, division, print_function
+__metaclass__ = type
+
+ANSIBLE_METADATA = {
+ 'metadata_version': '1.1',
+ 'status': ['preview'],
+ 'supported_by': 'community'
+}
+
+DOCUMENTATION = """
+---
+module: exos_vlans
+version_added: "2.10"
+short_description: Manage VLANs on Extreme Networks EXOS devices.
+description: This module provides declarative management of VLANs on Extreme Networks EXOS network devices.
+author: Jayalakshmi Viswanathan (@jayalakshmiV)
+notes:
+ - Tested against EXOS 30.2.1.8
+ - This module works with connection C(httpapi).
+ See L(EXOS Platform Options,../network/user_guide/platform_exos.html)
+options:
+ config:
+ description: A dictionary of VLANs options
+ type: list
+ elements: dict
+ suboptions:
+ name:
+ description:
+ - Ascii name of the VLAN.
+ type: str
+ vlan_id:
+ description:
+ - ID of the VLAN. Range 1-4094
+ type: int
+ required: True
+ state:
+ description:
+ - Operational state of the VLAN
+ type: str
+ choices:
+ - active
+ - suspend
+ default: active
+ state:
+ description:
+ - The state the configuration should be left in
+ type: str
+ choices:
+ - merged
+ - replaced
+ - overridden
+ - deleted
+ default: merged
+"""
+EXAMPLES = """
+# Using deleted
+
+# Before state:
+# -------------
+#
+# path: /rest/restconf/data/openconfig-vlan:vlans/
+# method: GET
+# data:
+# {
+# "openconfig-vlan:vlans": {
+# "vlan": [
+# {
+# "config": {
+# "name": "Default",
+# "status": "ACTIVE",
+# "tpid": "oc-vlan-types:TPID_0x8100",
+# "vlan-id": 1
+# },
+# },
+# {
+# "config": {
+# "name": "vlan_10",
+# "status": "ACTIVE",
+# "tpid": "oc-vlan-types:TPID_0x8100",
+# "vlan-id": 10
+# },
+# },
+# {
+# "config": {
+# "name": "vlan_20",
+# "status": "ACTIVE",
+# "tpid": "oc-vlan-types:TPID_0x8100",
+# "vlan-id": 20
+# },
+# },
+# {
+# "config": {
+# "name": "vlan_30",
+# "status": "ACTIVE",
+# "tpid": "oc-vlan-types:TPID_0x8100",
+# "vlan-id": 30
+# },
+# }
+# ]
+# }
+# }
+
+- name: Delete attributes of given VLANs
+ exos_vlans:
+ config:
+ - vlan_id: 10
+ - vlan_id: 20
+ - vlan_id: 30
+ state: deleted
+
+# Module Execution Results:
+# -------------------------
+#
+# "after": [
+# {
+# "name": "Default",
+# "state": "active",
+# "vlan_id": 1
+# }
+# ],
+#
+# "before": [
+# {
+# "name": "Default",
+# "state": "active",
+# "vlan_id": 1
+# },
+# {
+# "name": "vlan_10",
+# "state": "active",
+# "vlan_id": 10
+# },
+# {
+# "name": "vlan_20",
+# "state": "active",
+# "vlan_id": 20
+# }
+# {
+# "name": "vlan_30",
+# "state": "active",
+# "vlan_id": 30
+# }
+# ],
+#
+# "requests": [
+# {
+# "data": null,
+# "method": "DELETE",
+# "path": "/rest/restconf/data/openconfig-vlan:vlans/vlan=10"
+# },
+# {
+# "data": null,
+# "method": "DELETE",
+# "path": "/rest/restconf/data/openconfig-vlan:vlans/vlan=20"
+# },
+# {
+# "data": null,
+# "method": "DELETE",
+# "path": "/rest/restconf/data/openconfig-vlan:vlans/vlan=30"
+# }
+# ]
+#
+#
+# After state:
+# -------------
+#
+# path: /rest/restconf/data/openconfig-vlan:vlans/
+# method: GET
+# data:
+# {
+# "openconfig-vlan:vlans": {
+# "vlan": [
+# {
+# "config": {
+# "name": "Default",
+# "status": "ACTIVE",
+# "tpid": "oc-vlan-types:TPID_0x8100",
+# "vlan-id": 1
+# },
+# }
+# ]
+# }
+# }
+
+
+# Using merged
+
+# Before state:
+# -------------
+# path: /rest/restconf/data/openconfig-vlan:vlans/
+# method: GET
+# data:
+# {
+# "openconfig-vlan:vlans": {
+# "vlan": [
+# {
+# "config": {
+# "name": "Default",
+# "status": "ACTIVE",
+# "tpid": "oc-vlan-types:TPID_0x8100",
+# "vlan-id": 1
+# },
+# }
+# ]
+# }
+# }
+
+- name: Merge provided configuration with device configuration
+ exos_vlans:
+ config:
+ - name: vlan_10
+ vlan_id: 10
+ state: active
+ - name: vlan_20
+ vlan_id: 20
+ state: active
+ - name: vlan_30
+ vlan_id: 30
+ state: active
+ state: merged
+
+# Module Execution Results:
+# -------------------------
+#
+# "after": [
+# {
+# "name": "Default",
+# "state": "active",
+# "vlan_id": 1
+# },
+# {
+# "name": "vlan_10",
+# "state": "active",
+# "vlan_id": 10
+# },
+# {
+# "name": "vlan_20",
+# "state": "active",
+# "vlan_id": 20
+# },
+# {
+# "name": "vlan_30",
+# "state": "active",
+# "vlan_id": 30
+# }
+# ],
+#
+# "before": [
+# {
+# "name": "Default",
+# "state": "active",
+# "vlan_id": 1
+# }
+# ],
+#
+# "requests": [
+# {
+# "data": {
+# "openconfig-vlan:vlan": [
+# {
+# "config": {
+# "name": "vlan_10",
+# "status": "ACTIVE",
+# "tpid": "oc-vlan-types:TPID_0x8100",
+# "vlan-id": 10
+# }
+# }
+# ]
+# },
+# "method": "POST",
+# "path": "/rest/restconf/data/openconfig-vlan:vlans/"
+# },
+# {
+# "data": {
+# "openconfig-vlan:vlan": [
+# {
+# "config": {
+# "name": "vlan_20",
+# "status": "ACTIVE",
+# "tpid": "oc-vlan-types:TPID_0x8100",
+# "vlan-id": 20
+# }
+# }
+# ]
+# },
+# "method": "POST",
+# "path": "/rest/restconf/data/openconfig-vlan:vlans/"
+# },
+# "data": {
+# "openconfig-vlan:vlan": [
+# {
+# "config": {
+# "name": "vlan_30",
+# "status": "ACTIVE",
+# "tpid": "oc-vlan-types:TPID_0x8100",
+# "vlan-id": 30
+# }
+# }
+# ]
+# },
+# "method": "POST",
+# "path": "/rest/restconf/data/openconfig-vlan:vlans/"
+# }
+# ]
+#
+#
+# After state:
+# -------------
+#
+# path: /rest/restconf/data/openconfig-vlan:vlans/
+# method: GET
+# data:
+# {
+# "openconfig-vlan:vlans": {
+# "vlan": [
+# {
+# "config": {
+# "name": "Default",
+# "status": "ACTIVE",
+# "tpid": "oc-vlan-types:TPID_0x8100",
+# "vlan-id": 1
+# },
+# },
+# {
+# "config": {
+# "name": "vlan_10",
+# "status": "ACTIVE",
+# "tpid": "oc-vlan-types:TPID_0x8100",
+# "vlan-id": 10
+# },
+# },
+# {
+# "config": {
+# "name": "vlan_20",
+# "status": "ACTIVE",
+# "tpid": "oc-vlan-types:TPID_0x8100",
+# "vlan-id": 20
+# },
+# },
+# {
+# "config": {
+# "name": "vlan_30",
+# "status": "ACTIVE",
+# "tpid": "oc-vlan-types:TPID_0x8100",
+# "vlan-id": 30
+# },
+# }
+# ]
+# }
+# }
+
+
+# Using overridden
+
+# Before state:
+# -------------
+#
+# path: /rest/restconf/data/openconfig-vlan:vlans/
+# method: GET
+# data:
+# {
+# "openconfig-vlan:vlans": {
+# "vlan": [
+# {
+# "config": {
+# "name": "Default",
+# "status": "ACTIVE",
+# "tpid": "oc-vlan-types:TPID_0x8100",
+# "vlan-id": 1
+# },
+# },
+# {
+# "config": {
+# "name": "vlan_10",
+# "status": "ACTIVE",
+# "tpid": "oc-vlan-types:TPID_0x8100",
+# "vlan-id": 10
+# },
+# },
+# {
+# "config": {
+# "name": "vlan_20",
+# "status": "ACTIVE",
+# "tpid": "oc-vlan-types:TPID_0x8100",
+# "vlan-id": 20
+# },
+# },
+# {
+# "config": {
+# "name": "vlan_30",
+# "status": "ACTIVE",
+# "tpid": "oc-vlan-types:TPID_0x8100",
+# "vlan-id": 30
+# },
+# }
+# ]
+# }
+# }
+
+- name: Override device configuration of all VLANs with provided configuration
+ exos_vlans:
+ config:
+ - name: TEST_VLAN10
+ vlan_id: 10
+ state: overridden
+
+# Module Execution Results:
+# -------------------------
+#
+# "after": [
+# {
+# "name": "Default",
+# "state": "active",
+# "vlan_id": 1
+# },
+# {
+# "name": "TEST_VLAN10",
+# "state": "active",
+# "vlan_id": 10
+# },
+# ],
+#
+# "before": [
+# {
+# "name": "Default",
+# "state": "active",
+# "vlan_id": 1
+# },
+# {
+# "name": "vlan_10",
+# "state": "active",
+# "vlan_id": 10
+# },
+# {
+# "name": "vlan_20",
+# "state": "active",
+# "vlan_id": 20
+# },
+# {
+# "name": "vlan_30",
+# "state": "active",
+# "vlan_id": 30
+# }
+# ],
+#
+# "requests": [
+# {
+# "data": {
+# "openconfig-vlan:vlan": {
+# "vlan": [
+# {
+# "config": {
+# "name": "TEST_VLAN10",
+# "status": "ACTIVE",
+# "tpid": "oc-vlan-types:TPID_0x8100",
+# "vlan-id": 10
+# }
+# }
+# ]
+# }
+# }
+# },
+# "method": "PATCH",
+# "path": "/rest/restconf/data/openconfig-vlan:vlans/"
+# },
+# {
+# "data": null,
+# "method": "DELETE",
+# "path": "/rest/restconf/data/openconfig-vlan:vlans/vlan=20"
+# },
+# {
+# "data": null,
+# "method": "DELETE",
+# "path": "/rest/restconf/data/openconfig-vlan:vlans/vlan=30"
+# }
+# ]
+#
+#
+# After state:
+# -------------
+#
+# path: /rest/restconf/data/openconfig-vlan:vlans/
+# method: GET
+# data:
+# {
+# "openconfig-vlan:vlans": {
+# "vlan": [
+# {
+# "config": {
+# "name": "Default",
+# "status": "ACTIVE",
+# "tpid": "oc-vlan-types:TPID_0x8100",
+# "vlan-id": 1
+# },
+# },
+# {
+# "config": {
+# "name": "TEST_VLAN10",
+# "status": "ACTIVE",
+# "tpid": "oc-vlan-types:TPID_0x8100",
+# "vlan-id": 10
+# },
+# }
+# ]
+# }
+# }
+
+
+# Using replaced
+
+# Before state:
+# -------------
+#
+# path: /rest/restconf/data/openconfig-vlan:vlans/
+# method: GET
+# data:
+# {
+# "openconfig-vlan:vlans": {
+# "vlan": [
+# {
+# "config": {
+# "name": "Default",
+# "status": "ACTIVE",
+# "tpid": "oc-vlan-types:TPID_0x8100",
+# "vlan-id": 1
+# },
+# },
+# {
+# "config": {
+# "name": "vlan_10",
+# "status": "ACTIVE",
+# "tpid": "oc-vlan-types:TPID_0x8100",
+# "vlan-id": 10
+# },
+# },
+# {
+# "config": {
+# "name": "vlan_20",
+# "status": "ACTIVE",
+# "tpid": "oc-vlan-types:TPID_0x8100",
+# "vlan-id": 20
+# },
+# },
+# {
+# "config": {
+# "name": "vlan_30",
+# "status": "ACTIVE",
+# "tpid": "oc-vlan-types:TPID_0x8100",
+# "vlan-id": 30
+# },
+# }
+# ]
+# }
+# }
+
+- name: Replaces device configuration of listed VLANs with provided configuration
+ exos_vlans:
+ config:
+ - name: Test_VLAN20
+ vlan_id: 20
+ - name: Test_VLAN30
+ vlan_id: 30
+ state: replaced
+
+# Module Execution Results:
+# -------------------------
+#
+# "after": [
+# {
+# "name": "Default",
+# "state": "active",
+# "vlan_id": 1
+# },
+# {
+# "name": "vlan_10",
+# "state": "active",
+# "vlan_id": 10
+# },
+# {
+# "name": "TEST_VLAN20",
+# "state": "active",
+# "vlan_id": 20
+# },
+# {
+# "name": "TEST_VLAN30",
+# "state": "active",
+# "vlan_id": 30
+# }
+# ],
+#
+# "before": [
+# {
+# "name": "Default",
+# "state": "active",
+# "vlan_id": 1
+# },
+# {
+# "name": "vlan_10",
+# "state": "active",
+# "vlan_id": 10
+# },
+# {
+# "name": "vlan_20",
+# "state": "active",
+# "vlan_id": 20
+# },
+# {
+# "name": "vlan_30",
+# "state": "active",
+# "vlan_id": 30
+# }
+# ],
+#
+# "requests": [
+# {
+# "data": {
+# "openconfig-vlan:vlan": {
+# "vlan": [
+# {
+# "config": {
+# "name": "TEST_VLAN20",
+# "status": "ACTIVE",
+# "tpid": "oc-vlan-types:TPID_0x8100",
+# "vlan-id": 20
+# }
+# "config": {
+# "name": "TEST_VLAN30",
+# "status": "ACTIVE",
+# "tpid": "oc-vlan-types:TPID_0x8100",
+# "vlan-id": 30
+# }
+# }
+# ]
+# },
+# "method": "PATCH",
+# "path": "/rest/restconf/data/openconfig-vlan:vlans/"
+# }
+# ]
+#
+# After state:
+# -------------
+#
+# path: /rest/restconf/data/openconfig-vlan:vlans/
+# method: GET
+# data:
+# {
+# "openconfig-vlan:vlans": {
+# "vlan": [
+# {
+# "config": {
+# "name": "Default",
+# "status": "ACTIVE",
+# "tpid": "oc-vlan-types:TPID_0x8100",
+# "vlan-id": 1
+# },
+# },
+# {
+# "config": {
+# "name": "vlan_10",
+# "status": "ACTIVE",
+# "tpid": "oc-vlan-types:TPID_0x8100",
+# "vlan-id": 10
+# },
+# },
+# {
+# "config": {
+# "name": "TEST_VLAN20",
+# "status": "ACTIVE",
+# "tpid": "oc-vlan-types:TPID_0x8100",
+# "vlan-id": 20
+# },
+# },
+# {
+# "config": {
+# "name": "TEST_VLAN30",
+# "status": "ACTIVE",
+# "tpid": "oc-vlan-types:TPID_0x8100",
+# "vlan-id": 30
+# },
+# }
+# ]
+# }
+# }
+
+
+"""
+RETURN = """
+before:
+ description: The configuration prior to the model invocation.
+ returned: always
+ sample: >
+ The configuration returned will always be in the same format
+ of the parameters above.
+ type: list
+after:
+ description: The resulting configuration model invocation.
+ returned: when changed
+ sample: >
+ The configuration returned will always be in the same format
+ of the parameters above.
+ type: list
+requests:
+ description: The set of requests pushed to the remote device.
+ returned: always
+ type: list
+ sample: [{"data": "...", "method": "...", "path": "..."}, {"data": "...", "method": "...", "path": "..."}, {"data": "...", "method": "...", "path": "..."}]
+"""
+
+
+from ansible.module_utils.basic import AnsibleModule
+from ansible.module_utils.network.exos.argspec.vlans.vlans import VlansArgs
+from ansible.module_utils.network.exos.config.vlans.vlans import Vlans
+
+
+def main():
+ """
+ Main entry point for module execution
+
+ :returns: the result form module invocation
+ """
+ required_if = [('state', 'merged', ('config',)),
+ ('state', 'replaced', ('config',))]
+ module = AnsibleModule(argument_spec=VlansArgs.argument_spec, required_if=required_if,
+ supports_check_mode=True)
+
+ result = Vlans(module).execute_module()
+ module.exit_json(**result)
+
+
+if __name__ == '__main__':
+ main()