Refactoring cnos_vlan in line with ios, eos etc. (#48924)

* Refactoring cnos_vlan in line with ios, eos etc.
This commit is contained in:
Anil Kumar Muraleedharan 2018-11-28 23:21:39 +05:30 committed by Nathaniel Case
parent ca918def18
commit 7a81d859c5
13 changed files with 837 additions and 676 deletions

View file

@ -1,10 +1,8 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
from __future__ import (absolute_import, division, print_function)
__metaclass__ = type
#
# Copyright (C) 2017 Lenovo, Inc.
#
# (c) 2017, Ansible by Red Hat, inc
# This file is part of Ansible
#
# Ansible is free software: you can redistribute it and/or modify
@ -23,532 +21,398 @@ __metaclass__ = type
# Module to send VLAN commands to Lenovo Switches
# Overloading aspect of vlan creation in a range is pending
# Lenovo Networking
#
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'}
DOCUMENTATION = '''
DOCUMENTATION = """
---
module: cnos_vlan
author: "Anil Kumar Muraleedharan (@amuraleedhar)"
short_description: Manage VLAN resources and attributes on devices running
Lenovo CNOS
description:
- This module allows you to work with VLAN related configurations. The
operators used are overloaded to ensure control over switch VLAN
configurations. The first level of VLAN configuration allows to set up the
VLAN range, the VLAN tag persistence, a VLAN access map and access map
filter. After passing this level, there are five VLAN arguments that will
perform further configurations. They are vlanArg1, vlanArg2, vlanArg3,
vlanArg4, and vlanArg5. The value of vlanArg1 will determine the way
following arguments will be evaluated. This module uses SSH to manage
network device configuration. The results of the operation will be placed
in a directory named 'results' that must be created by the user in their
local directory to where the playbook is run.
version_added: "2.3"
extends_documentation_fragment: cnos
author: "Anil Kumar Mureleedharan(@amuraleedhar)"
short_description: Manage VLANs on CNOS network devices
description:
- This module provides declarative management of VLANs
on Lenovo CNOS network devices.
notes:
- Tested against CNOS 10.8.1
options:
vlanArg1:
name:
description:
- This is an overloaded vlan first argument. Usage of this argument can
be found is the User Guide referenced above.
- Name of the VLAN.
version_added: "2.8"
vlan_id:
description:
- ID of the VLAN. Range 1-4094.
required: true
choices: [access-map, dot1q, filter, <1-3999> VLAN ID 1-3999 or range]
vlanArg2:
version_added: "2.8"
interfaces:
description:
- This is an overloaded vlan second argument. Usage of this argument can
be found is the User Guide referenced above.
choices: [VLAN Access Map name,egress-only,name, flood,state, ip]
vlanArg3:
- List of interfaces that should be associated to the VLAN.
required: true
version_added: "2.8"
associated_interfaces:
description:
- This is an overloaded vlan third argument. Usage of this argument can
be found is the User Guide referenced above.
choices: [action, match, statistics, enter VLAN id or range of vlan,
ascii name for the VLAN, ipv4 or ipv6, active or suspend,
fast-leave, last-member-query-interval, mrouter, querier,
querier-timeout, query-interval, query-max-response-time,
report-suppression, robustness-variable, startup-query-count,
startup-query-interval, static-group]
vlanArg4:
- This is a intent option and checks the operational state of the for
given vlan C(name) for associated interfaces. If the value in the
C(associated_interfaces) does not match with the operational state of
vlan interfaces on device it will result in failure.
version_added: "2.8"
delay:
description:
- This is an overloaded vlan fourth argument. Usage of this argument can
be found is the User Guide referenced above.
choices: [drop or forward or redirect, ip or mac,Interval in seconds,
ethernet, port-aggregation, Querier IP address,
Querier Timeout in seconds, Query Interval in seconds,
Query Max Response Time in seconds, Robustness Variable value,
Number of queries sent at startup, Query Interval at startup]
vlanArg5:
- Delay the play should wait to check for declarative intent params
values.
default: 10
version_added: "2.8"
aggregate:
description: List of VLANs definitions.
version_added: "2.8"
purge:
description:
- This is an overloaded vlan fifth argument. Usage of this argument can
be found is the User Guide referenced above.
choices: [access-list name, Slot/chassis number, Port Aggregation Number]
- Purge VLANs not defined in the I(aggregate) parameter.
default: no
type: bool
version_added: "2.8"
state:
description:
- State of the VLAN configuration.
default: present
version_added: "2.8"
choices: ['present', 'absent', 'active', 'suspend']
provider:
description:
- B(Deprecated)
- "Starting with Ansible 2.5 we recommend using C(connection: network_cli)."
- For more information please see the L(IOS Platform Options guide, ../network/user_guide/platform_ios.html).
- HORIZONTALLINE
- A dict object containing connection details.
version_added: "2.8"
suboptions:
host:
description:
- Specifies the DNS host name or address for connecting to the remote
device over the specified transport. The value of host is used as
the destination address for the transport.
required: true
port:
description:
- Specifies the port to use when building the connection to the remote device.
default: 22
username:
description:
- Configures the username to use to authenticate the connection to
the remote device. This value is used to authenticate
the SSH session. If the value is not specified in the task, the
value of environment variable C(ANSIBLE_NET_USERNAME) will be used instead.
password:
description:
- Specifies the password to use to authenticate the connection to
the remote device. This value is used to authenticate
the SSH session. If the value is not specified in the task, the
value of environment variable C(ANSIBLE_NET_PASSWORD) will be used instead.
timeout:
description:
- Specifies the timeout in seconds for communicating with the network device
for either connecting or sending commands. If the timeout is
exceeded before the operation is completed, the module will error.
default: 10
ssh_keyfile:
description:
- Specifies the SSH key to use to authenticate the connection to
the remote device. This value is the path to the
key used to authenticate the SSH session. If the value is not specified
in the task, the value of environment variable C(ANSIBLE_NET_SSH_KEYFILE)
will be used instead.
authorize:
description:
- Instructs the module to enter privileged mode on the remote device
before sending any commands. If not specified, the device will
attempt to execute all commands in non-privileged mode. If the value
is not specified in the task, the value of environment variable
C(ANSIBLE_NET_AUTHORIZE) will be used instead.
type: bool
default: 'no'
auth_pass:
description:
- Specifies the password to use if required to enter privileged mode
on the remote device. If I(authorize) is false, then this argument
does nothing. If the value is not specified in the task, the value of
environment variable C(ANSIBLE_NET_AUTH_PASS) will be used instead.
"""
'''
EXAMPLES = '''
Tasks: The following are examples of using the module cnos_vlan. These are
written in the main.yml file of the tasks directory.
---
- name: Test Vlan - Create a vlan, name it
EXAMPLES = """
- name: Create vlan
cnos_vlan:
deviceType: "{{ hostvars[inventory_hostname]['deviceType'] }}"
outputfile: "./results/test_vlan_{{ inventory_hostname }}_output.txt"
vlanArg1: 13
vlanArg2: "name"
vlanArg3: "Anil"
vlan_id: 100
name: test-vlan
state: present
- name: Test Vlan - Create a vlan, Flood configuration
- name: Add interfaces to VLAN
cnos_vlan:
deviceType: "{{ hostvars[inventory_hostname]['deviceType'] }}"
outputfile: "./results/test_vlan_{{ inventory_hostname }}_output.txt"
vlanArg1: 13
vlanArg2: "flood"
vlanArg3: "ipv4"
vlan_id: 100
interfaces:
- Ethernet1/33
- Ethernet1/44
- name: Test Vlan - Create a vlan, State configuration
- name: Check if interfaces is assigned to VLAN
cnos_vlan:
deviceType: "{{ hostvars[inventory_hostname]['deviceType'] }}"
outputfile: "./results/test_vlan_{{ inventory_hostname }}_output.txt"
vlanArg1: 13
vlanArg2: "state"
vlanArg3: "active"
vlan_id: 100
associated_interfaces:
- Ethernet1/33
- Ethernet1/44
- name: Test Vlan - VLAN Access map1
- name: Delete vlan
cnos_vlan:
deviceType: "{{ hostvars[inventory_hostname]['deviceType'] }}"
outputfile: "./results/test_vlan_{{ inventory_hostname }}_output.txt"
vlanArg1: "access-map"
vlanArg2: "Anil"
vlanArg3: "statistics"
vlan_id: 100
state: absent
"""
- name: Test Vlan - VLAN Accep Map2
cnos_vlan:
deviceType: "{{ hostvars[inventory_hostname]['deviceType'] }}"
outputfile: "./results/test_vlan_{{ inventory_hostname }}_output.txt"
vlanArg1: "access-map"
vlanArg2: "Anil"
vlanArg3: "action"
vlanArg4: "forward"
- name: Test Vlan - ip igmp snooping query interval
cnos_vlan:
deviceType: "{{ hostvars[inventory_hostname]['deviceType'] }}"
outputfile: "./results/test_vlan_{{ inventory_hostname }}_output.txt"
vlanArg1: 13
vlanArg2: "ip"
vlanArg3: "query-interval"
vlanArg4: 1313
- name: Test Vlan - ip igmp snooping mrouter interface port-aggregation 23
cnos_vlan:
deviceType: "{{ hostvars[inventory_hostname]['deviceType'] }}"
outputfile: "./results/test_vlan_{{ inventory_hostname }}_output.txt"
vlanArg1: 13
vlanArg2: "ip"
vlanArg3: "mrouter"
vlanArg4: "port-aggregation"
vlanArg5: 23
'''
RETURN = '''
msg:
description: Success or failure message
RETURN = """
commands:
description: The list of configuration mode commands to send to the device
returned: always
type: string
sample: "VLAN configuration is accomplished"
'''
type: list
sample:
- vlan 100
- name test-vlan
"""
import sys
import time
import socket
import array
import json
import time
import re
try:
from ansible.module_utils.network.cnos import cnos
HAS_LIB = True
except:
HAS_LIB = False
import time
from copy import deepcopy
from ansible.module_utils.basic import AnsibleModule
from collections import defaultdict
from ansible.module_utils.network.common.utils import remove_default_spec
from ansible.module_utils.network.cnos.cnos import load_config, run_commands
from ansible.module_utils.network.cnos.cnos import debugOutput, check_args
from ansible.module_utils.network.cnos.cnos import cnos_argument_spec
from ansible.module_utils._text import to_text
def vlanAccessMapConfig(module, cmd):
retVal = ''
# Wait time to get response from server
command = ''
vlanArg3 = module.params['vlanArg3']
vlanArg4 = module.params['vlanArg4']
vlanArg5 = module.params['vlanArg5']
deviceType = module.params['deviceType']
if(vlanArg3 == "action"):
command = command + vlanArg3 + ' '
value = cnos.checkSanityofVariable(
deviceType, "vlan_accessmap_action", vlanArg4)
if(value == "ok"):
command = command + vlanArg4
else:
retVal = "Error-135"
return retVal
elif(vlanArg3 == "match"):
command = command + vlanArg3 + ' '
if(vlanArg4 == "ip" or vlanArg4 == "mac"):
command = command + vlanArg4 + ' address '
value = cnos.checkSanityofVariable(
deviceType, "vlan_access_map_name", vlanArg5)
if(value == "ok"):
command = command + vlanArg5
else:
retVal = "Error-136"
return retVal
else:
retVal = "Error-137"
return retVal
elif(vlanArg3 == "statistics"):
command = vlanArg3 + " per-entry"
else:
retVal = "Error-138"
return retVal
inner_cmd = [{'command': command, 'prompt': None, 'answer': None}]
cmd.extend(inner_cmd)
retVal = retVal + str(cnos.run_cnos_commands(module, cmd))
# debugOutput(command)
return retVal
# EOM
def search_obj_in_list(vlan_id, lst):
obj = list()
for o in lst:
if o['vlan_id'] == vlan_id:
return o
def checkVlanNameNotAssigned(module, prompt, answer):
retVal = "ok"
vlanId = module.params['vlanArg1']
vlanName = module.params['vlanArg3']
command = "show vlan id " + vlanId
cmd = [{'command': command, 'prompt': None, 'answer': None}]
retVal = str(cnos.run_cnos_commands(module, cmd))
if(retVal.find('Error') != -1):
command = "display vlan id " + vlanId
retVal = str(cnos.run_cnos_commands(module, cmd))
if(retVal.find(vlanName) != -1):
return "Nok"
else:
return "ok"
# EOM
def map_obj_to_commands(updates, module):
commands = list()
want, have = updates
purge = module.params['purge']
for w in want:
vlan_id = w['vlan_id']
name = w['name']
interfaces = w['interfaces']
state = w['state']
# Utility Method to create vlan
def createVlan(module, prompt, answer):
obj_in_have = search_obj_in_list(vlan_id, have)
# vlan config command happens here. It creates if not present
vlanArg1 = module.params['vlanArg1']
vlanArg2 = module.params['vlanArg2']
vlanArg3 = module.params['vlanArg3']
vlanArg4 = module.params['vlanArg4']
vlanArg5 = module.params['vlanArg5']
deviceType = module.params['deviceType']
retVal = ''
command = 'vlan ' + vlanArg1
# debugOutput(command)
cmd = [{'command': command, 'prompt': None, 'answer': None}]
command = ""
if(vlanArg2 == "name"):
# debugOutput("name")
command = vlanArg2 + " "
value = cnos.checkSanityofVariable(deviceType, "vlan_name", vlanArg3)
if(value == "ok"):
value = checkVlanNameNotAssigned(module, prompt, answer)
if(value == "ok"):
command = command + vlanArg3
else:
retVal = retVal + 'VLAN Name is already assigned \n'
command = "\n"
else:
retVal = "Error-139"
return retVal
elif (vlanArg2 == "flood"):
# debugOutput("flood")
command = vlanArg2 + " "
value = cnos.checkSanityofVariable(deviceType, "vlan_flood", vlanArg3)
if(value == "ok"):
command = command + vlanArg3
else:
retVal = "Error-140"
return retVal
if state == 'absent':
if obj_in_have:
commands.append('no vlan {0}'.format(vlan_id))
elif(vlanArg2 == "state"):
# debugOutput("state")
command = vlanArg2 + " "
value = cnos.checkSanityofVariable(deviceType, "vlan_state", vlanArg3)
if(value == "ok"):
command = command + vlanArg3
else:
retVal = "Error-141"
return retVal
elif state == 'present':
if not obj_in_have:
commands.append('vlan {0}'.format(vlan_id))
if name:
commands.append('name {0}'.format(name))
elif(vlanArg2 == "ip"):
# debugOutput("ip")
command = vlanArg2 + " igmp snooping "
# debugOutput("vlanArg3")
if(vlanArg3 is None or vlanArg3 == ""):
# debugOutput("None or empty")
command = command.strip()
elif(vlanArg3 == "fast-leave"):
# debugOutput("fast-leave")
command = command + vlanArg3
elif (vlanArg3 == "last-member-query-interval"):
# debugOutput("last-member-query-interval")
command = command + vlanArg3 + " "
value = cnos.checkSanityofVariable(
deviceType, "vlan_last_member_query_interval", vlanArg4)
if(value == "ok"):
command = command + vlanArg4
else:
retVal = "Error-142"
return retVal
elif (vlanArg3 == "querier"):
# debugOutput("querier")
command = command + vlanArg3 + " "
value = cnos.checkSanityofVariable(deviceType,
"vlan_querier", vlanArg4)
if(value == "ok"):
command = command + vlanArg4
else:
retVal = "Error-143"
return retVal
elif (vlanArg3 == "querier-timeout"):
# debugOutput("querier-timeout")
command = command + vlanArg3 + " "
value = cnos.checkSanityofVariable(
deviceType, "vlan_querier_timeout", vlanArg4)
if(value == "ok"):
command = command + vlanArg4
else:
retVal = "Error-144"
return retVal
elif (vlanArg3 == "query-interval"):
# debugOutput("query-interval")
command = command + vlanArg3 + " "
value = cnos.checkSanityofVariable(
deviceType, "vlan_query_interval", vlanArg4)
if(value == "ok"):
command = command + vlanArg4
else:
retVal = "Error-145"
return retVal
elif (vlanArg3 == "query-max-response-time"):
# debugOutput("query-max-response-time")
command = command + vlanArg3 + " "
value = cnos.checkSanityofVariable(
deviceType, "vlan_query_max_response_time", vlanArg4)
if(value == "ok"):
command = command + vlanArg4
else:
retVal = "Error-146"
return retVal
elif (vlanArg3 == "report-suppression"):
# debugOutput("report-suppression")
command = command + vlanArg3
elif (vlanArg3 == "robustness-variable"):
# debugOutput("robustness-variable")
command = command + vlanArg3 + " "
value = cnos.checkSanityofVariable(
deviceType, "vlan_startup_query_count", vlanArg4)
if(value == "ok"):
command = command + vlanArg4
else:
retVal = "Error-148"
return retVal
elif (vlanArg3 == "startup-query-interval"):
# debugOutput("startup-query-interval")
command = command + vlanArg3 + " "
value = cnos.checkSanityofVariable(
deviceType, "vlan_startup_query_interval", vlanArg4)
if(value == "ok"):
command = command + vlanArg4
else:
retVal = "Error-149"
return retVal
elif (vlanArg3 == "static-group"):
retVal = "Error-102"
return retVal
elif (vlanArg3 == "version"):
# debugOutput("version")
command = command + vlanArg3 + " "
value = cnos.checkSanityofVariable(
deviceType, "vlan_snooping_version", vlanArg4)
if(value == "ok"):
command = command + vlanArg4
else:
retVal = "Error-150"
return retVal
elif (vlanArg3 == "mrouter"):
# debugOutput("mrouter")
command = command + vlanArg3 + " interface "
if(vlanArg4 == "ethernet"):
command = command + vlanArg4 + " "
value = cnos.checkSanityofVariable(
deviceType, "vlan_ethernet_interface", vlanArg5)
if(value == "ok"):
command = command + vlanArg5
else:
retVal = "Error-151"
return retVal
elif(vlanArg4 == "port-aggregation"):
command = command + vlanArg4 + " "
value = cnos.checkSanityofVariable(
deviceType, "vlan_portagg_number", vlanArg5)
if(value == "ok"):
command = command + vlanArg5
else:
retVal = "Error-152"
return retVal
else:
retVal = "Error-153"
return retVal
else:
command = command + vlanArg3
if interfaces:
for i in interfaces:
commands.append('interface {0}'.format(i))
commands.append('switchport mode access')
commands.append('switchport access vlan {0}'.format(vlan_id))
else:
retVal = "Error-154"
return retVal
inner_cmd = [{'command': command, 'prompt': None, 'answer': None}]
cmd.extend(inner_cmd)
retVal = retVal + str(cnos.run_cnos_commands(module, cmd))
# debugOutput(command)
return retVal
# EOM
if name:
if name != obj_in_have['name']:
commands.append('vlan {0}'.format(vlan_id))
commands.append('name {0}'.format(name))
if interfaces:
if not obj_in_have['interfaces']:
for i in interfaces:
commands.append('vlan {0}'.format(vlan_id))
commands.append('interface {0}'.format(i))
commands.append('switchport mode access')
commands.append('switchport access vlan {0}'.format(vlan_id))
def vlanConfig(module, prompt, answer):
elif set(interfaces) != set(obj_in_have['interfaces']):
missing_interfaces = list(set(interfaces) - set(obj_in_have['interfaces']))
for i in missing_interfaces:
commands.append('vlan {0}'.format(vlan_id))
commands.append('interface {0}'.format(i))
commands.append('switchport mode access')
commands.append('switchport access vlan {0}'.format(vlan_id))
retVal = ''
# Wait time to get response from server
vlanArg1 = module.params['vlanArg1']
vlanArg2 = module.params['vlanArg2']
vlanArg3 = module.params['vlanArg3']
vlanArg4 = module.params['vlanArg4']
vlanArg5 = module.params['vlanArg5']
deviceType = module.params['deviceType']
# vlan config command happens here.
command = 'vlan '
if(vlanArg1 == "access-map"):
# debugOutput("access-map ")
command = command + vlanArg1 + ' '
value = cnos.checkSanityofVariable(
deviceType, "vlan_access_map_name", vlanArg2)
if(value == "ok"):
command = command + vlanArg2
# debugOutput(command)
cmd = [{'command': command, 'prompt': None, 'answer': None}]
retVal = retVal + vlanAccessMapConfig(module, cmd)
return retVal
superfluous_interfaces = list(set(obj_in_have['interfaces']) - set(interfaces))
for i in superfluous_interfaces:
commands.append('vlan {0}'.format(vlan_id))
commands.append('interface {0}'.format(i))
commands.append('switchport mode access')
commands.append('no switchport access vlan')
else:
retVal = "Error-130"
return retVal
commands.append('vlan {0}'.format(vlan_id))
if name:
commands.append('name {0}'.format(name))
commands.append('state {0}'.format(state))
elif(vlanArg1 == "dot1q"):
# debugOutput("dot1q")
command = command + vlanArg1 + " tag native "
if(vlanArg2 is not None):
value = cnos.checkSanityofVariable(
deviceType, "vlan_dot1q_tag", vlanArg2)
if(value == "ok"):
command = command + vlanArg2
else:
retVal = "Error-131"
return retVal
if purge:
for h in have:
obj_in_want = search_obj_in_list(h['vlan_id'], want)
if not obj_in_want and h['vlan_id'] != '1':
commands.append('no vlan {0}'.format(h['vlan_id']))
elif(vlanArg1 == "filter"):
# debugOutput( "filter")
command = command + vlanArg1 + " "
if(vlanArg2 is not None):
value = cnos.checkSanityofVariable(
deviceType, "vlan_filter_name", vlanArg2)
if(value == "ok"):
command = command + vlanArg2 + " vlan-list "
value = cnos.checkSanityofVariable(deviceType, "vlan_id",
vlanArg3)
if(value == "ok"):
command = command + vlanArg3
else:
value = cnos.checkSanityofVariable(
deviceType, "vlan_id_range", vlanArg3)
if(value == "ok"):
command = command + vlanArg3
else:
retVal = "Error-133"
return retVal
else:
retVal = "Error-132"
return retVal
return commands
else:
value = cnos.checkSanityofVariable(deviceType, "vlan_id", vlanArg1)
if(value == "ok"):
retVal = createVlan(module, '(config-vlan)#', None)
return retVal
else:
value = cnos.checkSanityofVariable(
deviceType, "vlan_id_range", vlanArg1)
if(value == "ok"):
retVal = createVlan(module, '(config-vlan)#', None)
return retVal
retVal = "Error-133"
return retVal
# debugOutput(command)
cmd = [{'command': command, 'prompt': None, 'answer': None}]
retVal = retVal + str(cnos.run_cnos_commands(module, cmd))
return retVal
# EOM
def map_params_to_obj(module):
obj = []
aggregate = module.params.get('aggregate')
if aggregate:
for item in aggregate:
for key in item:
if item.get(key) is None:
item[key] = module.params[key]
d = item.copy()
d['vlan_id'] = str(d['vlan_id'])
obj.append(d)
else:
obj.append({
'vlan_id': str(module.params['vlan_id']),
'name': module.params['name'],
'interfaces': module.params['interfaces'],
# 'associated_interfaces': module.params['associated_interfaces'],
'state': module.params['state']
})
return obj
def parse_to_logical_rows(out):
relevant_data = False
cur_row = []
for line in out.splitlines():
if not line:
"""Skip empty lines."""
continue
if '0' < line[0] <= '9':
"""Line starting with a number."""
if len(cur_row) > 0:
yield cur_row
cur_row = [] # Reset it to hold a next chunk
relevant_data = True
if relevant_data:
data = line.strip().split('(')
cur_row.append(data[0])
yield cur_row
def parse_to_obj(logical_rows):
first_row = logical_rows[0]
rest_rows = logical_rows[1:]
vlan_data = first_row.split()
obj = {}
obj['vlan_id'] = vlan_data[0]
obj['name'] = vlan_data[1]
obj['state'] = vlan_data[2]
obj['interfaces'] = rest_rows
return obj
def parse_vlan_brief(vlan_out):
return [parse_to_obj(r) for r in parse_to_logical_rows(vlan_out)]
def map_config_to_obj(module):
return parse_vlan_brief(run_commands(module, ['show vlan brief'])[0])
def check_declarative_intent_params(want, module, result):
have = None
is_delay = False
for w in want:
if w.get('associated_interfaces') is None:
continue
if result['changed'] and not is_delay:
time.sleep(module.params['delay'])
is_delay = True
if have is None:
have = map_config_to_obj(module)
for i in w['associated_interfaces']:
obj_in_have = search_obj_in_list(w['vlan_id'], have)
if obj_in_have and 'interfaces' in obj_in_have and i not in obj_in_have['interfaces']:
module.fail_json(msg="Interface %s not configured on vlan %s" % (i, w['vlan_id']))
def main():
#
# Define parameters for vlan creation entry
#
module = AnsibleModule(
argument_spec=dict(
outputfile=dict(required=True),
host=dict(required=False),
username=dict(required=False),
password=dict(required=False, no_log=True),
enablePassword=dict(required=False, no_log=True),
deviceType=dict(required=True),
vlanArg1=dict(required=True),
vlanArg2=dict(required=False),
vlanArg3=dict(required=False),
vlanArg4=dict(required=False),
vlanArg5=dict(required=False),),
supports_check_mode=False)
""" main entry point for module execution
"""
element_spec = dict(
vlan_id=dict(type='int'),
name=dict(),
interfaces=dict(type='list'),
associated_interfaces=dict(type='list'),
delay=dict(default=10, type='int'),
state=dict(default='present',
choices=['present', 'absent', 'active', 'suspend'])
)
outputfile = module.params['outputfile']
aggregate_spec = deepcopy(element_spec)
aggregate_spec['vlan_id'] = dict(required=True)
output = ""
# remove default in aggregate spec, to handle common arguments
remove_default_spec(aggregate_spec)
# Send the CLi command
output = output + str(vlanConfig(module, "(config)#", None))
argument_spec = dict(
aggregate=dict(type='list', elements='dict', options=aggregate_spec),
purge=dict(default=False, type='bool')
)
# Save it operation details into the file
file = open(outputfile, "a")
file.write(output)
file.close()
argument_spec.update(element_spec)
argument_spec.update(cnos_argument_spec)
# need to add logic to check when changes occur or not
errorMsg = cnos.checkOutputForError(output)
if(errorMsg is None):
module.exit_json(changed=True,
msg="VLAN configuration is accomplished")
else:
module.fail_json(msg=errorMsg)
required_one_of = [['vlan_id', 'aggregate']]
mutually_exclusive = [['vlan_id', 'aggregate']]
module = AnsibleModule(argument_spec=argument_spec,
required_one_of=required_one_of,
mutually_exclusive=mutually_exclusive,
supports_check_mode=True)
warnings = list()
result = {'changed': False}
if warnings:
result['warnings'] = warnings
want = map_params_to_obj(module)
have = map_config_to_obj(module)
commands = map_obj_to_commands((want, have), module)
result['commands'] = commands
if commands:
if not module.check_mode:
load_config(module, commands)
result['changed'] = True
check_declarative_intent_params(want, module, result)
module.exit_json(**result)
if __name__ == '__main__':

View file

@ -1,116 +0,0 @@
# Ansible Role: cnos_vlan_sample - Switch VLAN configuration
---
<add role description below>
This role is an example of using the *cnos_vlan.py* Lenovo module in the context of CNOS switch configuration. This module allows you to work with VLAN related configurations. The operators used are overloaded to ensure control over switch VLAN configurations.
The first level of VLAN configuration allows to set up the VLAN range, the VLAN tag persistence, a VLAN access map and access map filter. After passing this level, there are five VLAN arguments that will perform further configurations. They are *vlanArg1*, *vlanArg2*, *vlanArg3*, *vlanArg4*, and *vlanArg5*. The value of *vlanArg1* will determine the way following arguments will be evaluated.
The results of the operation can be viewed in *results* directory.
For more details, see [Lenovo modules for Ansible: cnos_vlan](http://systemx.lenovofiles.com/help/index.jsp?topic=%2Fcom.lenovo.switchmgt.ansible.doc%2Fcnos_vlan.html&cp=0_3_1_0_4_14).
## Requirements
---
<add role requirements information below>
- Ansible version 2.2 or later ([Ansible installation documentation](http://docs.ansible.com/ansible/intro_installation.html))
- Lenovo switches running CNOS version 10.2.1.0 or later
- an SSH connection to the Lenovo switch (SSH must be enabled on the network device)
## Role Variables
---
<add role variables information below>
Available variables are listed below, along with description.
The following are mandatory inventory variables:
Variable | Description
--- | ---
`ansible_connection` | Has to be `network_cli`
`ansible_network_os` | Has to be `cnos`
`ansible_ssh_user` | Specifies the username used to log into the switch
`ansible_ssh_pass` | Specifies the password used to log into the switch
`enablePassword` | Configures the password used to enter Global Configuration command mode on the switch (this is an optional parameter)
`hostname` | Searches the hosts file at */etc/ansible/hosts* and identifies the IP address of the switch on which the role is going to be applied
`deviceType` | Specifies the type of device from where the configuration will be backed up (**g8272_cnos** - G8272, **g8296_cnos** - G8296, **g8332_cnos** - G8332, **NE10032** - NE10032, **NE1072T** - NE1072T, **NE1032** - NE1032, **NE1032T** - NE1032T, **NE2572** - NE2572, **NE0152T** - NE0152T)
The values of the variables used need to be modified to fit the specific scenario in which you are deploying the solution. To change the values of the variables, you need to visits the *vars* directory of each role and edit the *main.yml* file located there. The values stored in this file will be used by Ansible when the template is executed.
The syntax of *main.yml* file for variables is the following:
```
<template variable>:<value>
```
You will need to replace the `<value>` field with the value that suits your topology. The `<template variable>` fields are taken from the template and it is recommended that you leave them unchanged.
Variable | Description
--- | ---
`vlanArg1` | This is an overloaded BGP variable. Please refer to the [cnos_vlan module documentation](http://ralfss28.labs.lenovo.com:5555/help/topic/com.lenovo.switchmgt.ansible.doc/cnos_vlan.html?cp=0_3_1_0_2_16) for detailed information on usage. The values of these variables depend on the configuration context and the choices are the following: **access-map**, **dot1q**, **filter**, specify VLAN.
`vlanArg2` | This is an overloaded BGP variable. Please refer to the [cnos_vlan module documentation](http://ralfss28.labs.lenovo.com:5555/help/topic/com.lenovo.switchmgt.ansible.doc/cnos_vlan.html?cp=0_3_1_0_2_16) for detailed information on usage. The values of these variables depend on the configuration context and the choices are the following: VLAN access map name, **egress-only**, **name**, **flood**, **state**, **ip**.
`vlanArg3` | This is an overloaded BGP variable. Please refer to the [cnos_vlan module documentation](http://ralfss28.labs.lenovo.com:5555/help/topic/com.lenovo.switchmgt.ansible.doc/cnos_vlan.html?cp=0_3_1_0_2_16) for detailed information on usage. The values of these variables depend on the configuration context and the choices are the following: **action**, **match**, **statistics**, specify VLAN, name of the VLAN, **ipv4**, **ipv6**, **active**, **suspend**, **fast-leave**, **last-member-query-interval**, **mrouter**, **querier**, **querier-timeout**, **query-interval**, **query-max-response-time**, **report-suppression**, **robustness-variable**, **startup-query-count**, **startup-query-interval**.
`vlanArg4` | This is an overloaded BGP variable. Please refer to the [cnos_vlan module documentation](http://ralfss28.labs.lenovo.com:5555/help/topic/com.lenovo.switchmgt.ansible.doc/cnos_vlan.html?cp=0_3_1_0_2_16) for detailed information on usage. The values of these variables depend on the configuration context and the choices are the following: **drop**, **forward**, **redirect**, **ip**, **mac**, last member query interval, **ethernet**, **port-aggregation**, querier IP address, querier timeout interval, query interval, query maximum response interval, robustness variable value, numbers of queries sent at startup, startup query interval.
`vlanArg5` | This is an overloaded BGP variable. Please refer to the [cnos_vlan module documentation](http://ralfss28.labs.lenovo.com:5555/help/topic/com.lenovo.switchmgt.ansible.doc/cnos_vlan.html?cp=0_3_1_0_2_16) for detailed information on usage. The values of these variables depend on the configuration context and the choices are the following: ACL name, specify ethernet port, LAG number.
## Dependencies
---
<add dependencies information below>
- username.iptables - Configures the firewall and blocks all ports except those needed for web server and SSH access.
- username.common - Performs common server configuration.
- cnos_vlan.py - This modules needs to be present in the *library* directory of the role.
- cnos.py - This module needs to be present in the PYTHONPATH environment variable set in the Ansible system.
- /etc/ansible/hosts - You must edit the */etc/ansible/hosts* file with the device information of the switches designated as leaf switches. You may refer to *cnos_vlan_sample_hosts* for a sample configuration.
Ansible keeps track of all network elements that it manages through a hosts file. Before the execution of a playbook, the hosts file must be set up.
Open the */etc/ansible/hosts* file with root privileges. Most of the file is commented out by using **#**. You can also comment out the entries you will be adding by using **#**. You need to copy the content of the hosts file for the role into the */etc/ansible/hosts* file. The sample hosts file for the role is located in the main directory.
```
[cnos_vlan_sample]
10.241.107.39 ansible_network_os=cnos ansible_ssh_user=<username> ansible_ssh_pass=<password> deviceType=g8272_cnos
10.241.107.40 ansible_network_os=cnos ansible_ssh_user=<username> ansible_ssh_pass=<password> deviceType=g8272_cnos
```
**Note:** You need to change the IP addresses to fit your specific topology. You also need to change the `<username>` and `<password>` to the appropriate values used to log into the specific Lenovo network devices.
## Example Playbook
---
<add playbook samples below>
To execute an Ansible playbook, use the following command:
```
ansible-playbook cnos_vlan_sample.yml -vvv
```
`-vvv` is an optional verbos command that helps identify what is happening during playbook execution. The playbook for each role is located in the main directory of the solution.
```
- name: Module to do VLAN configurations
hosts: cnos_vlan_sample
gather_facts: no
connection: local
roles:
- cnos_vlan_sample
```
## License
---
<add license information below>
Copyright (C) 2017 Lenovo, Inc.
This file is part of Ansible
Ansible is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
Ansible is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with Ansible. If not, see <http://www.gnu.org/licenses/>.

View file

@ -10,5 +10,5 @@
# Following you should specify IP Adresses details
# Please change <username> and <password> with appropriate value for your switch.
[cnos_vlan_sample]
10.241.107.39 ansible_network_os=cnos ansible_ssh_user=<username> ansible_ssh_pass=<password> deviceType=g8272_cnos
[cnos]
10.241.107.39 ansible_network_os=cnos ansible_ssh_user=<username> ansible_ssh_pass=<password>

View file

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

View file

@ -0,0 +1,22 @@
---
- name: collect all cli test cases
find:
paths: "{{ role_path }}/tests/cli"
patterns: "{{ testcase }}.yaml"
register: test_cases
delegate_to: localhost
- name: set test_items
set_fact: test_items="{{ test_cases.files | map(attribute='path') | list }}"
- name: run test cases (connection=network_cli)
include: "{{ test_case_to_run }}"
with_items: "{{ test_items }}"
loop_control:
loop_var: test_case_to_run
- name: run test case (connection=local)
include: "{{ test_case_to_run }} ansible_connection=local"
with_first_found: "{{ test_items }}"
loop_control:
loop_var: test_case_to_run

View file

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

View file

@ -1,35 +0,0 @@
# This contain sample template execution task
---
- name: Test Vlan - Create a vlan, name it
cnos_vlan: host={{ inventory_hostname }} username={{ hostvars[inventory_hostname]['ansible_ssh_user']}} password={{ hostvars[inventory_hostname]['ansible_ssh_pass']}} deviceType={{ hostvars[inventory_hostname]['deviceType']}} outputfile=./results/cnos_vlan_{{ inventory_hostname }}_output.txt vlanArg1='{{item.vlanArg1}}' vlanArg2='{{item.vlanArg2}}' vlanArg3='{{item.vlanArg3}}'
with_items: "{{cnos_vlan_data1}}"
- name: Test Vlan - Create a vlan, Flood configuration
cnos_vlan: host={{ inventory_hostname }} username={{ hostvars[inventory_hostname]['ansible_ssh_user']}} password={{ hostvars[inventory_hostname]['ansible_ssh_pass']}} deviceType={{ hostvars[inventory_hostname]['deviceType']}} outputfile=./results/cnos_vlan_{{ inventory_hostname }}_output.txt vlanArg1='{{item.vlanArg1}}' vlanArg2='{{item.vlanArg2}}' vlanArg3='{{item.vlanArg3}}'
with_items: "{{cnos_vlan_data2}}"
- name: Test Vlan - Create a vlan, State configuration
cnos_vlan: host={{ inventory_hostname }} username={{ hostvars[inventory_hostname]['ansible_ssh_user']}} password={{ hostvars[inventory_hostname]['ansible_ssh_pass']}} deviceType={{ hostvars[inventory_hostname]['deviceType']}} outputfile=./results/cnos_vlan_{{ inventory_hostname }}_output.txt vlanArg1='{{item.vlanArg1}}' vlanArg2='{{item.vlanArg2}}' vlanArg3='{{item.vlanArg3}}'
with_items: "{{cnos_vlan_data3}}"
- name: Test Vlan - VLAN Access map1
cnos_vlan: host={{ inventory_hostname }} username={{ hostvars[inventory_hostname]['ansible_ssh_user']}} password={{ hostvars[inventory_hostname]['ansible_ssh_pass']}} deviceType={{ hostvars[inventory_hostname]['deviceType']}} outputfile=./results/cnos_vlan_{{ inventory_hostname }}_output.txt vlanArg1='{{item.vlanArg1}}' vlanArg2='{{item.vlanArg2}}' vlanArg3='{{item.vlanArg3}}'
with_items: "{{cnos_vlan_data4}}"
- name: Test Vlan - VLAN Accep Map2
cnos_vlan: host={{ inventory_hostname }} username={{ hostvars[inventory_hostname]['ansible_ssh_user']}} password={{ hostvars[inventory_hostname]['ansible_ssh_pass']}} deviceType={{ hostvars[inventory_hostname]['deviceType']}} outputfile=./results/cnos_vlan_{{ inventory_hostname }}_output.txt vlanArg1='{{item.vlanArg1}}' vlanArg2='{{item.vlanArg2}}' vlanArg3='{{item.vlanArg3}}' vlanArg4='{{item.vlanArg4}}'
with_items: "{{cnos_vlan_data5}}"
- name: Test Vlan - ip igmp snooping query interval
cnos_vlan: host={{ inventory_hostname }} username={{ hostvars[inventory_hostname]['ansible_ssh_user']}} password={{ hostvars[inventory_hostname]['ansible_ssh_pass']}} deviceType={{ hostvars[inventory_hostname]['deviceType']}} outputfile=./results/cnos_vlan_{{ inventory_hostname }}_output.txt vlanArg1='{{item.vlanArg1}}' vlanArg2='{{item.vlanArg2}}' vlanArg3='{{item.vlanArg3}}' vlanArg4='{{item.vlanArg4}}'
with_items: "{{cnos_vlan_data6}}"
- name: Test Vlan - ip igmp snooping last member query interval
cnos_vlan: host={{ inventory_hostname }} username={{ hostvars[inventory_hostname]['ansible_ssh_user']}} password={{ hostvars[inventory_hostname]['ansible_ssh_pass']}} deviceType={{ hostvars[inventory_hostname]['deviceType']}} outputfile=./results/cnos_vlan_{{ inventory_hostname }}_output.txt vlanArg1='{{item.vlanArg1}}' vlanArg2='{{item.vlanArg2}}' vlanArg3='{{item.vlanArg3}}' vlanArg4='{{item.vlanArg4}}'
with_items: "{{cnos_vlan_data7}}"
- name: Test Vlan - ip igmp snooping mrouter interface port-aggregation
cnos_vlan: host={{ inventory_hostname }} username={{ hostvars[inventory_hostname]['ansible_ssh_user']}} password={{ hostvars[inventory_hostname]['ansible_ssh_pass']}} deviceType={{ hostvars[inventory_hostname]['deviceType']}} outputfile=./results/cnos_vlan_{{ inventory_hostname }}_output.txt vlanArg1='{{item.vlanArg1}}' vlanArg2='{{item.vlanArg2}}' vlanArg3='{{item.vlanArg3}}' vlanArg4='{{item.vlanArg4}}' vlanArg5='{{item.vlanArg5}}'
with_items: "{{cnos_vlan_data8}}"
# Completed file

View file

@ -0,0 +1,213 @@
---
- debug: msg="START cli/basic.yaml on connection={{ ansible_connection }}"
#- set_fact: switch_type="{{ switch_type }}"
- block:
- name: setup - remove vlan used in test
cnos_config:
lines:
- no vlan 100
- no vlan 200
- no vlan 300
provider: "{{ cli }}"
- name: setup - remove switchport settings on interfaces used in test
cnos_config:
lines:
- switchport mode access
- no switchport access vlan
provider: "{{ cli }}"
parents: "{{ item }}"
loop:
- interface ethernet1/33
- interface ethernet1/44
- name: create vlan
cnos_vlan: &create
vlan_id: 100
name: test-vlan
provider: "{{ cli }}"
register: result
- assert:
that:
- "result.changed == true"
- "'vlan 100' in result.commands"
- "'name test-vlan' in result.commands"
- name: create vlan(idempotence)
cnos_vlan: *create
register: result
- assert:
that:
- "result.changed == false"
- name: Add interfaces to vlan
cnos_vlan: &interfaces
vlan_id: 100
interfaces:
- Ethernet1/33
- Ethernet1/44
provider: "{{ cli }}"
register: result
- assert:
that:
- "result.changed == true"
- "'interface Ethernet1/33' in result.commands"
- "'switchport mode access' in result.commands"
- "'switchport access vlan 100' in result.commands"
- "'interface Ethernet1/44' in result.commands"
- "'switchport mode access' in result.commands"
- "'switchport access vlan 100' in result.commands"
- name: Add interfaces to vlan(idempotence)
cnos_vlan: *interfaces
register: result
- assert:
that:
- "result.changed == false"
- name: Remove interface from vlan
cnos_vlan: &single_int
vlan_id: 100
interfaces:
- Ethernet1/33
provider: "{{ cli }}"
register: result
- assert:
that:
- "result.changed == true"
- "'vlan 100' in result.commands"
# - "'interface Ethernet1/33' in result.commands"
- "'switchport mode access' in result.commands"
- "'no switchport access vlan' in result.commands"
- name: Remove interface from vlan(idempotence)
cnos_vlan: *single_int
register: result
- assert:
that:
- "result.changed == false"
- name: Suspend vlan
cnos_vlan:
vlan_id: 100
state: suspend
provider: "{{ cli }}"
register: result
- assert:
that:
- "result.changed == true"
- "'vlan 100' in result.commands"
- "'state suspend' in result.commands"
- name: Unsuspend vlan
cnos_vlan:
vlan_id: 100
state: active
provider: "{{ cli }}"
register: result
- assert:
that:
- "result.changed == true"
- "'vlan 100' in result.commands"
- "'state active' in result.commands"
- name: delete vlan
cnos_vlan: &delete
vlan_id: 100
provider: "{{ cli }}"
state: absent
register: result
- assert:
that:
- "result.changed == true"
- "'no vlan 100' in result.commands"
- name: delete vlan(idempotence)
cnos_vlan: *delete
register: result
- assert:
that:
- "result.changed == false"
- name: create vlans using aggregate
cnos_vlan: &create_aggregate
aggregate:
- { vlan_id: 200, name: vlan-200 }
- { vlan_id: 300, name: vlan-300 }
provider: "{{ cli }}"
register: result
- assert:
that:
- "result.changed == true"
- "'vlan 200' in result.commands"
- "'name vlan-200' in result.commands"
- "'vlan 300' in result.commands"
- "'name vlan-300' in result.commands"
- name: create vlans using aggregate(idempotence)
cnos_vlan: *create_aggregate
register: result
- assert:
that:
- "result.changed == false"
- name: delete vlans using aggregate
cnos_vlan: &delete_aggregate
aggregate:
- { vlan_id: 200, name: vlan-200 }
- { vlan_id: 300, name: vlan-300 }
state: absent
provider: "{{ cli }}"
register: result
- assert:
that:
- "result.changed == true"
- "'no vlan 200' in result.commands"
- "'no vlan 300' in result.commands"
- name: delete vlans using aggregate(idempotence)
cnos_vlan: *delete_aggregate
register: result
- assert:
that:
- "result.changed == false"
- name: teardown(part1)
cnos_config:
lines:
- no vlan 100
- no vlan 200
- no vlan 300
provider: "{{ cli }}"
- name: teardown(part2)
cnos_config:
lines:
- switchport mode access
- no switchport access vlan
provider: "{{ cli }}"
parents: "{{ item }}"
loop:
- interface Ethernet1/33
- interface Ethernet1/44
# when: switch_type == 'L2'
- debug: msg="END cli/basic.yaml on connection={{ ansible_connection }}"

View file

@ -0,0 +1,9 @@
---
cli:
host: "{{ inventory_hostname }}"
port: 22
username: admin
password: admin
timeout: 30
authorize: True
auth_pass:

View file

@ -1,19 +0,0 @@
---
cnos_vlan_data1:
- {vlanArg1: 13, vlanArg2: "name", vlanArg3: "anil"}
cnos_vlan_data2:
- {vlanArg1: 13, vlanArg2: "flood", vlanArg3: "ipv4"}
cnos_vlan_data3:
- {vlanArg1: 13, vlanArg2: "state", vlanArg3: "active"}
cnos_vlan_data4:
- {vlanArg1: "access-map", vlanArg2: "anil", vlanArg3: "statistics"}
cnos_vlan_data5:
- {vlanArg1: "access-map", vlanArg2: "anil", vlanArg3: "action", vlanArg4: "forward"}
cnos_vlan_data6:
- {vlanArg1: 13, vlanArg2: "ip", vlanArg3: "query-interval", vlanArg4: 1313}
cnos_vlan_data7:
- {vlanArg1: 13, vlanArg2: "ip", vlanArg3: "last-member-query-interval", vlanArg4: 23}
cnos_vlan_data8:
- {vlanArg1: 13, vlanArg2: "ip", vlanArg3: "mrouter", vlanArg4: "port-aggregation", vlanArg5: 23}
cnos_vlan_data9:
- {clicommand: "no vlan 13"}

View file

@ -592,7 +592,6 @@ lib/ansible/modules/network/cnos/cnos_save.py E326
lib/ansible/modules/network/cnos/cnos_showrun.py E323
lib/ansible/modules/network/cnos/cnos_template.py E326
lib/ansible/modules/network/cnos/cnos_vlag.py E326
lib/ansible/modules/network/cnos/cnos_vlan.py E326
lib/ansible/modules/network/enos/enos_command.py E323
lib/ansible/modules/network/enos/enos_config.py E323
lib/ansible/modules/network/enos/enos_facts.py E323

View file

@ -1,21 +1,77 @@
Flags:
u - untagged egress traffic for this VLAN
t - tagged egress traffic for this VLAN
d - auto-provisioned VLAN
h - static and auto-provisioned VLAN
VLAN Name Status IPMC FLOOD Ports
======== ================================ ======= ========== ===================
1 default ACTIVE IPv6
po1(u)
po2(u)
po11(u)
po12(u)
po13(u)
po14(u)
po15(u)
po17(u)
po20(u)
po100(u)
po1001(u)
po1002(u)
po1003(u)
po1004(u)
Ethernet1/2(u)
Ethernet1/3(t)
Ethernet1/4(t)
Ethernet1/3(u)
Ethernet1/4(u)
Ethernet1/9(u)
Ethernet1/10(u)
Ethernet1/11(u)
Ethernet1/14(u)
Ethernet1/15(u)
Ethernet1/16(u)
Ethernet1/17(u)
Ethernet1/18(u)
Ethernet1/19(u)
Ethernet1/20(u)
Ethernet1/21(u)
Ethernet1/22(u)
Ethernet1/23(u)
Ethernet1/24(u)
Ethernet1/25(u)
Ethernet1/26(u)
Ethernet1/27(u)
Ethernet1/28(u)
Ethernet1/29(u)
Ethernet1/30(u)
Ethernet1/31(u)
Ethernet1/32(u)
Ethernet1/33(u)
Ethernet1/34(u)
Ethernet1/35(u)
Ethernet1/36(u)
Ethernet1/37(u)
Ethernet1/38(u)
Ethernet1/39(u)
Ethernet1/40(u)
Ethernet1/41(u)
Ethernet1/42(u)
Ethernet1/43(u)
Ethernet1/44(u)
Ethernet1/45(u)
Ethernet1/46(u)
Ethernet1/47(u)
Ethernet1/48(u)
Ethernet1/49(u)
Ethernet1/50(u)
Ethernet1/51(u)
Ethernet1/52(u)
Ethernet1/53(u)
Ethernet1/54(u)
2 VLAN0002 ACTIVE IPv6
3 VLAN0003 ACTIVE IPv4,IPv6
5 VLAN0005 ACTIVE IPv4,IPv6
12 VLAN0012 ACTIVE IPv4,IPv6
13 anil ACTIVE IPv4,IPv6
po13(t)
po17(t)
po100(t)
po1003(t)
po1004(t)
Ethernet1/3(t)
Ethernet1/4(t)

View file

@ -1,10 +1,29 @@
# (c) 2018 Red Hat Inc.
#
# This file is part of Ansible
#
# Ansible is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Ansible is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
# Make coding more python3-ish
from __future__ import (absolute_import, division, print_function)
__metaclass__ = type
import json
import os
from units.compat.mock import patch
from ansible.modules.network.cnos import cnos_vlan
from ansible.modules.network.cnos.cnos_vlan import parse_vlan_brief
from units.modules.utils import set_module_args
from .cnos_module import TestCnosModule, load_fixture
@ -16,30 +35,174 @@ class TestCnosVlanModule(TestCnosModule):
def setUp(self):
super(TestCnosVlanModule, self).setUp()
self.mock_run_cnos_commands = patch('ansible.module_utils.network.cnos.cnos.run_cnos_commands')
self.run_cnos_commands = self.mock_run_cnos_commands.start()
self.mock_run_commands = patch('ansible.modules.network.cnos.cnos_vlan.run_commands')
self.run_commands = self.mock_run_commands.start()
self.mock_load_config = patch('ansible.modules.network.cnos.cnos_vlan.load_config')
self.load_config = self.mock_load_config.start()
def tearDown(self):
super(TestCnosVlanModule, self).tearDown()
self.mock_run_cnos_commands.stop()
self.mock_run_commands.stop()
self.mock_load_config.stop()
def load_fixtures(self, commands=None, transport='cli'):
self.run_cnos_commands.return_value = [load_fixture('cnos_vlan_config.cfg')]
self.run_commands.return_value = [load_fixture('cnos_vlan_config.cfg')]
self.load_config.return_value = {'diff': None, 'session': 'session'}
def test_cnos_vlan_create(self):
set_module_args({'username': 'admin', 'password': 'pass',
'host': '10.241.107.39', 'deviceType': 'g8272_cnos',
'outputfile': self.test_log, 'vlanArg1': '13',
'vlanArg2': 'name', 'vlanArg3': 'anil'})
set_module_args({'vlan_id': '3', 'name': 'test', 'state': 'present'})
result = self.execute_module(changed=True)
expected_result = 'VLAN configuration is accomplished'
self.assertEqual(result['msg'], expected_result)
expected_commands = [
'vlan 3',
'name test',
]
self.assertEqual(result['commands'], expected_commands)
def test_cnos_vlan_state(self):
set_module_args({'username': 'admin', 'password': 'pass',
'host': '10.241.107.39', 'deviceType': 'g8272_cnos',
'outputfile': self.test_log, 'vlanArg1': '13',
'vlanArg2': 'state', 'vlanArg3': 'active'})
def test_cnos_vlan_id_startwith_9(self):
set_module_args({'vlan_id': '13', 'name': 'anil', 'state': 'present'})
result = self.execute_module(changed=False)
expected_commands = []
self.assertEqual(result['commands'], expected_commands)
def test_cnos_vlan_rename(self):
set_module_args({'vlan_id': '2', 'name': 'test', 'state': 'present'})
result = self.execute_module(changed=True)
expected_result = 'VLAN configuration is accomplished'
self.assertEqual(result['msg'], expected_result)
expected_commands = [
'vlan 2',
'name test',
]
self.assertEqual(result['commands'], expected_commands)
def test_cnos_vlan_with_interfaces(self):
set_module_args({'vlan_id': '2', 'name': 'vlan2', 'state': 'present',
'interfaces': ['Ethernet1/33', 'Ethernet1/44']})
result = self.execute_module(changed=True)
expected_commands = [
'vlan 2',
'name vlan2',
'vlan 2',
'interface Ethernet1/33',
'switchport mode access',
'switchport access vlan 2',
'vlan 2',
'interface Ethernet1/44',
'switchport mode access',
'switchport access vlan 2',
]
self.assertEqual(result['commands'], expected_commands)
def test_cnos_vlan_with_interfaces_and_newvlan(self):
set_module_args({'vlan_id': '3',
'name': 'vlan3', 'state': 'present',
'interfaces': ['Ethernet1/33', 'Ethernet1/44']})
result = self.execute_module(changed=True)
expected_commands = [
'vlan 3',
'name vlan3',
'vlan 3',
'interface Ethernet1/33',
'switchport mode access',
'switchport access vlan 3',
'vlan 3',
'interface Ethernet1/44',
'switchport mode access',
'switchport access vlan 3',
]
self.assertEqual(result['commands'], expected_commands)
def test_parse_vlan_brief(self):
result = parse_vlan_brief(load_fixture('cnos_vlan_config.cfg'))
obj = [
{
'interfaces': [
'po1',
'po2',
'po11',
'po12',
'po13',
'po14',
'po15',
'po17',
'po20',
'po100',
'po1001',
'po1002',
'po1003',
'po1004',
'Ethernet1/2',
'Ethernet1/3',
'Ethernet1/4',
'Ethernet1/9',
'Ethernet1/10',
'Ethernet1/11',
'Ethernet1/14',
'Ethernet1/15',
'Ethernet1/16',
'Ethernet1/17',
'Ethernet1/18',
'Ethernet1/19',
'Ethernet1/20',
'Ethernet1/21',
'Ethernet1/22',
'Ethernet1/23',
'Ethernet1/24',
'Ethernet1/25',
'Ethernet1/26',
'Ethernet1/27',
'Ethernet1/28',
'Ethernet1/29',
'Ethernet1/30',
'Ethernet1/31',
'Ethernet1/32',
'Ethernet1/33',
'Ethernet1/34',
'Ethernet1/35',
'Ethernet1/36',
'Ethernet1/37',
'Ethernet1/38',
'Ethernet1/39',
'Ethernet1/40',
'Ethernet1/41',
'Ethernet1/42',
'Ethernet1/43',
'Ethernet1/44',
'Ethernet1/45',
'Ethernet1/46',
'Ethernet1/47',
'Ethernet1/48',
'Ethernet1/49',
'Ethernet1/50',
'Ethernet1/51',
'Ethernet1/52',
'Ethernet1/53',
'Ethernet1/54'],
'state': 'ACTIVE',
'name': 'default',
'vlan_id': '1'},
{
'interfaces': [],
'state': 'ACTIVE',
'name': 'VLAN0002',
'vlan_id': '2'},
{
'interfaces': [],
'state': 'ACTIVE',
'name': 'VLAN0003',
'vlan_id': '3'},
{
'interfaces': [],
'state': 'ACTIVE',
'name': 'VLAN0005',
'vlan_id': '5'},
{
'interfaces': [],
'state': 'ACTIVE',
'name': 'VLAN0012',
'vlan_id': '12'},
{
'interfaces': [],
'state': 'ACTIVE',
'name': 'anil',
'vlan_id': '13'}]
self.assertEqual(result, obj)