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
pull/57401/head
JayalakshmiV 5 years ago committed by ansibot
parent eca33b80f0
commit 45acdb41d2

@ -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

@ -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

@ -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,
)

@ -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)

@ -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

@ -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()

@ -0,0 +1,3 @@
---
testcase: "[^_].*"
test_items: []

@ -0,0 +1,19 @@
---
- name: Collect all httpapi test cases
find:
paths: "{{ role_path }}/tests/httpapi"
patterns: "{{ testcase }}.yaml"
use_regex: true
register: test_cases
delegate_to: localhost
- name: Set test_items
set_fact: test_items="{{ test_cases.files | map(attribute='path') | list }}"
- name: Run test case (connection=httpapi)
include: "{{ test_case_to_run }}"
vars:
ansible_connection: httpapi
with_items: "{{ test_items }}"
loop_control:
loop_var: test_case_to_run

@ -0,0 +1,2 @@
---
- { include: httpapi.yaml, tags: ['httpapi'] }

@ -0,0 +1,7 @@
---
- name: Populate config
exos_config:
lines:
- create vlan vlan_10 tag 10
- create vlan vlan_20 tag 20
- disable vlan_20

@ -0,0 +1,6 @@
---
- name: Restore initial config
exos_config:
lines:
- delete vlan 2-4094
ignore_errors: yes

@ -0,0 +1,44 @@
---
- debug:
msg: "Start exos_vlan deleted integration tests ansible_connection={{ ansible_connection }}"
- include_tasks: _reset_config.yaml
- include_tasks: _populate_config.yaml
- block:
- name: Delete VLAN
exos_vlans: &deleted
config:
state: deleted
register: result
- name: Assert that the before dicts were correctly generated
assert:
that:
- "{{ initial_state == result['before']}}"
- name: Assert that correct set of requests were correctly generated
assert:
that:
- "{{deleted['requests'] == result['requests']}}"
- name: Assert that the after dicts were correctly generated
assert:
that:
- "{{deleted['after'] == result['after']}}"
- name: Delete attributes of all configured VLANs (IDEMPOTENT)
exos_vlans: *deleted
register: result
- name: Assert that the previous task was idempotent
assert:
that:
- "result.changed == false"
- name: Assert that the before dicts were correctly generated
assert:
that:
- "{{deleted['after'] == result['before']}}"

@ -0,0 +1,49 @@
---
- debug:
msg: "START exos_vlans merged integration tests on connection = {{ ansible_connection }}"
- include_tasks: _reset_config.yaml
- include_tasks: _populate_config.yaml
- block:
- name: Merge the provided configuration with the existing running configuration
exos_vlans: &merged
config:
- name: vlan_30
vlan_id: 30
state: active
- vlan_id: 10
name: vlan_10
state: suspend
state: merged
register: result
- name: Assert that before dicts were correctly generated
assert:
that:
- "{{ initial_state == result['before'] }}"
- name: Assert that correct set of requests were generated
assert:
that:
- "{{ merged['requests'] == result['requests'] }}"
- name: Assert that after dicts were correctly generated
assert:
that:
- "{{ merged['after'] == result['after'] }}"
- name: Merge the provided configuration with the existing configuration (IDEMPOTENT)
exos_vlans: *merged
register: result
- name: Assert that the previous task was idempotent
assert:
that:
- "result.changed == false"
- name: Assert that before dict was correctly generated
assert:
that:
- "{{ merged['after'] == result['before'] }}"

@ -0,0 +1,46 @@
---
- debug:
msg: "START exos_vlans overridden integration tests on connection={{ ansible_connection }}"
- include_tasks: _reset_config.yaml
- include_tasks: _populate_config.yaml
- block:
- name: Override existing VLAN configuration with provided configuration
exos_vlans: &overridden
config:
- name: TEST_VLAN10
vlan_id: 10
state: suspend
state: overridden
register: result
- name: Assert that correct set of requests were generated
assert:
that:
- "{{ overridden['requests'] == result['requests'] }}"
- name: Assert that before dicts were correctly generated
assert:
that:
- "{{ initial_state == result['before'] }}"
- name: Assert that after dicts were correctly generated
assert:
that:
- "{{ overridden['after'] == result['after'] }}"
- name: Override existing VLAN configuration with provided configuration (IDEMPOTENT)
exos_vlans: *overridden
register: result
- name: Assert that task was idempotent
assert:
that:
- "result.changed == false"
- name: Assert that before dicts were correctly generated
assert:
that:
- "{{ overridden['after'] == result['before'] }}"

@ -0,0 +1,49 @@
---
- debug:
msg: "START exos_vlans replaced integration tests on connection={{ ansible_connection }}"
- include_tasks: _reset_config.yaml
- include_tasks: _populate_config.yaml
- block:
- name: Replace existing VLAN configurations with provided configurations
exos_vlans: &replaced
config:
- name: Test_VLAN20
vlan_id: 20
state: active
- name: vlan_40
vlan_id: 40
state: suspend
state: replaced
register: result
- name: Assert that correct set of requests are correctly generated
assert:
that:
- "{{ replaced['requests'] == result['requests'] }}"
- name: Assert that before dicts were correctly generated
assert:
that:
- "{{ initial_state == result['before'] }}"
- name: Assert that after dicts were correctly generated
assert:
that:
- "{{ replaced['after'] == result['after'] }}"
- name: Replace existing VLAN configuration with provided configurations (IDEMPOTENT)
exos_vlans: *replaced
register: result
- name: Assert that task was idempotent
assert:
that:
- "result.changed == false"
- name: Assert that before dict was correctly generated
assert:
that:
- "{{ replaced['after'] == result['before'] }}"

@ -0,0 +1,88 @@
---
initial_state:
- name: "Default"
state: "active"
vlan_id: 1
- name: "vlan_10"
state: "active"
vlan_id: 10
- name: "vlan_20"
state: "suspend"
vlan_id: 20
merged:
requests:
- data: '{"openconfig-vlan:vlans": [{"config": {"status": "ACTIVE", "vlan-id": 30, "name": "vlan_30", "tpid": "oc-vlan-types:TPID_0x8100"}}]}'
method: POST
path: /rest/restconf/data/openconfig-vlan:vlans/
- data: '{"openconfig-vlan:vlans": {"vlan": [{"config": {"status": "SUSPENDED", "vlan-id": 10, "name": "vlan_10", "tpid": "oc-vlan-types:TPID_0x8100"}}]}}'
method: PATCH
path: /rest/restconf/data/openconfig-vlan:vlans/
after:
- name: "Default"
state: "active"
vlan_id: 1
- name: "vlan_10"
state: "suspend"
vlan_id: 10
- name: "vlan_20"
state: "suspend"
vlan_id: 20
- name: "vlan_30"
state: "active"
vlan_id: 30
replaced:
requests:
- data: '{"openconfig-vlan:vlans": [{"config": {"status": "SUSPENDED", "vlan-id": 40, "name": "vlan_40", "tpid": "oc-vlan-types:TPID_0x8100"}}]}'
method: POST
path: /rest/restconf/data/openconfig-vlan:vlans/
- data: '{"openconfig-vlan:vlans": {"vlan": [{"config": {"status": "ACTIVE", "vlan-id": 20, "name": "Test_VLAN20", "tpid": "oc-vlan-types:TPID_0x8100"}}]}}'
method: PATCH
path: /rest/restconf/data/openconfig-vlan:vlans/
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: "vlan_40"
state: "suspend"
vlan_id: 40
overridden:
requests:
- data: null
method: DELETE
path: /rest/restconf/data/openconfig-vlan:vlans/vlan=20
- data: '{"openconfig-vlan:vlans": {"vlan": [{"config": {"status": "SUSPENDED", "vlan-id": 10, "name": "TEST_VLAN10", "tpid": "oc-vlan-types:TPID_0x8100"}}]}}'
method: PATCH
path: /rest/restconf/data/openconfig-vlan:vlans/
after:
- name: "Default"
state: "active"
vlan_id: 1
- name: "TEST_VLAN10"
state: "suspend"
vlan_id: 10
deleted:
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
after:
- name: "Default"
state: "active"
vlan_id: 1
Loading…
Cancel
Save