diff options
Diffstat (limited to 'lib/ansible/modules/network/cloudengine/ce_switchport.py')
-rw-r--r-- | lib/ansible/modules/network/cloudengine/ce_switchport.py | 1006 |
1 files changed, 0 insertions, 1006 deletions
diff --git a/lib/ansible/modules/network/cloudengine/ce_switchport.py b/lib/ansible/modules/network/cloudengine/ce_switchport.py deleted file mode 100644 index fecd6aa33d..0000000000 --- a/lib/ansible/modules/network/cloudengine/ce_switchport.py +++ /dev/null @@ -1,1006 +0,0 @@ -#!/usr/bin/python -# -# 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/>. -# - -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type - -ANSIBLE_METADATA = {'metadata_version': '1.1', - 'status': ['preview'], - 'supported_by': 'community'} - -DOCUMENTATION = ''' ---- -module: ce_switchport -version_added: "2.4" -short_description: Manages Layer 2 switchport interfaces on HUAWEI CloudEngine switches. -description: - - Manages Layer 2 switchport interfaces on HUAWEI CloudEngine switches. -author: QijunPan (@QijunPan) -notes: - - When C(state=absent), VLANs can be added/removed from trunk links and - the existing access VLAN can be 'unconfigured' to just having VLAN 1 on that interface. - - When working with trunks VLANs the keywords add/remove are always sent - in the C(port trunk allow-pass vlan) command. Use verbose mode to see commands sent. - - When C(state=unconfigured), the interface will result with having a default Layer 2 interface, i.e. vlan 1 in access mode. - - This module requires the netconf system service be enabled on the remote device being managed. - - Recommended connection is C(netconf). - - This module also works with C(local) connections for legacy playbooks. -options: - interface: - description: - - Full name of the interface, i.e. 40GE1/0/22. - required: true - mode: - description: - - The link type of an interface. - choices: ['access','trunk', 'hybrid', 'dot1qtunnel'] - default_vlan: - version_added: 2.9 - description: - - If C(mode=access, or mode=dot1qtunnel), used as the access VLAN ID, in the range from 1 to 4094. - pvid_vlan: - version_added: 2.9 - description: - - If C(mode=trunk, or mode=hybrid), used as the trunk native VLAN ID, in the range from 1 to 4094. - trunk_vlans: - description: - - If C(mode=trunk), used as the VLAN range to ADD or REMOVE - from the trunk, such as 2-10 or 2,5,10-15, etc. - untagged_vlans: - version_added: 2.9 - description: - - If C(mode=hybrid), used as the VLAN range to ADD or REMOVE - from the trunk, such as 2-10 or 2,5,10-15, etc. - tagged_vlans: - version_added: 2.9 - description: - - If C(mode=hybrid), used as the VLAN range to ADD or REMOVE - from the trunk, such as 2-10 or 2,5,10-15, etc. - state: - description: - - Manage the state of the resource. - default: present - choices: ['present', 'absent', 'unconfigured'] -''' - -EXAMPLES = ''' -- name: switchport module test - hosts: cloudengine - connection: local - gather_facts: no - vars: - cli: - host: "{{ inventory_hostname }}" - port: "{{ ansible_ssh_port }}" - username: "{{ username }}" - password: "{{ password }}" - transport: cli - - tasks: - - name: Ensure 10GE1/0/22 is in its default switchport state - ce_switchport: - interface: 10GE1/0/22 - state: unconfigured - provider: '{{ cli }}' - - - name: Ensure 10GE1/0/22 is configured for access vlan 20 - ce_switchport: - interface: 10GE1/0/22 - mode: access - default_vlan: 20 - provider: '{{ cli }}' - - - name: Ensure 10GE1/0/22 only has vlans 5-10 as trunk vlans - ce_switchport: - interface: 10GE1/0/22 - mode: trunk - pvid_vlan: 10 - trunk_vlans: 5-10 - provider: '{{ cli }}' - - - name: Ensure 10GE1/0/22 is a trunk port and ensure 2-50 are being tagged (doesn't mean others aren't also being tagged) - ce_switchport: - interface: 10GE1/0/22 - mode: trunk - pvid_vlan: 10 - trunk_vlans: 2-50 - provider: '{{ cli }}' - - - name: Ensure these VLANs are not being tagged on the trunk - ce_switchport: - interface: 10GE1/0/22 - mode: trunk - trunk_vlans: 51-4000 - state: absent - provider: '{{ cli }}' -''' - -RETURN = ''' -proposed: - description: k/v pairs of parameters passed into module - returned: always - type: dict - sample: {"default_vlan": "20", "interface": "10GE1/0/22", "mode": "access"} -existing: - description: k/v pairs of existing switchport - returned: always - type: dict - sample: {"default_vlan": "10", "interface": "10GE1/0/22", - "mode": "access", "switchport": "enable"} -end_state: - description: k/v pairs of switchport after module execution - returned: always - type: dict - sample: {"default_vlan": "20", "interface": "10GE1/0/22", - "mode": "access", "switchport": "enable"} -updates: - description: command string sent to the device - returned: always - type: list - sample: ["10GE1/0/22", "port default vlan 20"] -changed: - description: check to see if a change was made on the device - returned: always - type: bool - sample: true -''' - -import re -from xml.etree import ElementTree as ET -from ansible.module_utils.basic import AnsibleModule -from ansible.module_utils.network.cloudengine.ce import get_nc_config, set_nc_config, ce_argument_spec - - -CE_NC_GET_PORT_ATTR = """ -<filter type="subtree"> - <ethernet xmlns="http://www.huawei.com/netconf/vrp" content-version="1.0" format-version="1.0"> - <ethernetIfs> - <ethernetIf> - <ifName>%s</ifName> - <l2Enable></l2Enable> - <l2Attribute> - <linkType></linkType> - <pvid></pvid> - <trunkVlans></trunkVlans> - <untagVlans></untagVlans> - </l2Attribute> - </ethernetIf> - </ethernetIfs> - </ethernet> -</filter> -""" - -CE_NC_SET_PORT = """ -<ethernet xmlns="http://www.huawei.com/netconf/vrp" content-version="1.0" format-version="1.0"> -<ethernetIfs> - <ethernetIf operation="merge"> - <ifName>%s</ifName> - <l2Attribute> - <linkType>%s</linkType> - <pvid>%s</pvid> - <trunkVlans>%s</trunkVlans> - <untagVlans>%s</untagVlans> - </l2Attribute> - </ethernetIf> -</ethernetIfs> -</ethernet> -""" - -CE_NC_SET_PORT_MODE = """ -<ethernet xmlns="http://www.huawei.com/netconf/vrp" content-version="1.0" format-version="1.0"> -<ethernetIfs> - <ethernetIf operation="merge"> - <ifName>%s</ifName> - <l2Attribute> - <linkType>%s</linkType> - </l2Attribute> - </ethernetIf> -</ethernetIfs> -</ethernet> -""" - -CE_NC_SET_DEFAULT_PORT = """ -<config> - <ethernet xmlns="http://www.huawei.com/netconf/vrp" content-version="1.0" format-version="1.0"> - <ethernetIfs> - <ethernetIf operation="merge"> - <ifName>%s</ifName> - <l2Attribute> - <linkType>access</linkType> - <pvid>1</pvid> - <trunkVlans></trunkVlans> - <untagVlans></untagVlans> - </l2Attribute> - </ethernetIf> - </ethernetIfs> - </ethernet> -</config> -""" - - -SWITCH_PORT_TYPE = ('ge', '10ge', '25ge', - '4x10ge', '40ge', '100ge', 'eth-trunk') - - -def get_interface_type(interface): - """Gets the type of interface, such as 10GE, ETH-TRUNK, VLANIF...""" - - if interface is None: - return None - - iftype = None - - if interface.upper().startswith('GE'): - iftype = 'ge' - elif interface.upper().startswith('10GE'): - iftype = '10ge' - elif interface.upper().startswith('25GE'): - iftype = '25ge' - elif interface.upper().startswith('4X10GE'): - iftype = '4x10ge' - elif interface.upper().startswith('40GE'): - iftype = '40ge' - elif interface.upper().startswith('100GE'): - iftype = '100ge' - elif interface.upper().startswith('VLANIF'): - iftype = 'vlanif' - elif interface.upper().startswith('LOOPBACK'): - iftype = 'loopback' - elif interface.upper().startswith('METH'): - iftype = 'meth' - elif interface.upper().startswith('ETH-TRUNK'): - iftype = 'eth-trunk' - elif interface.upper().startswith('VBDIF'): - iftype = 'vbdif' - elif interface.upper().startswith('NVE'): - iftype = 'nve' - elif interface.upper().startswith('TUNNEL'): - iftype = 'tunnel' - elif interface.upper().startswith('ETHERNET'): - iftype = 'ethernet' - elif interface.upper().startswith('FCOE-PORT'): - iftype = 'fcoe-port' - elif interface.upper().startswith('FABRIC-PORT'): - iftype = 'fabric-port' - elif interface.upper().startswith('STACK-PORT'): - iftype = 'stack-port' - elif interface.upper().startswith('NULL'): - iftype = 'null' - else: - return None - - return iftype.lower() - - -def is_portswitch_enalbed(iftype): - """"[undo] portswitch""" - - return bool(iftype in SWITCH_PORT_TYPE) - - -def vlan_bitmap_undo(bitmap): - """convert vlan bitmap to undo bitmap""" - - vlan_bit = ['F'] * 1024 - - if not bitmap or len(bitmap) == 0: - return ''.join(vlan_bit) - - bit_len = len(bitmap) - for num in range(bit_len): - undo = (~int(bitmap[num], 16)) & 0xF - vlan_bit[num] = hex(undo)[2] - - return ''.join(vlan_bit) - - -def is_vlan_bitmap_empty(bitmap): - """check vlan bitmap empty""" - - if not bitmap or len(bitmap) == 0: - return True - - bit_len = len(bitmap) - for num in range(bit_len): - if bitmap[num] != '0': - return False - - return True - - -class SwitchPort(object): - """ - Manages Layer 2 switchport interfaces. - """ - - def __init__(self, argument_spec): - self.spec = argument_spec - self.module = None - self.init_module() - - # interface and vlan info - self.interface = self.module.params['interface'] - self.mode = self.module.params['mode'] - self.state = self.module.params['state'] - self.default_vlan = self.module.params['default_vlan'] - self.pvid_vlan = self.module.params['pvid_vlan'] - self.trunk_vlans = self.module.params['trunk_vlans'] - self.untagged_vlans = self.module.params['untagged_vlans'] - self.tagged_vlans = self.module.params['tagged_vlans'] - - # host info - self.host = self.module.params['host'] - self.username = self.module.params['username'] - self.port = self.module.params['port'] - - # state - self.changed = False - self.updates_cmd = list() - self.results = dict() - self.proposed = dict() - self.existing = dict() - self.end_state = dict() - self.intf_info = dict() # interface vlan info - self.intf_type = None # loopback tunnel ... - - def init_module(self): - """ init module """ - - required_if = [('state', 'absent', ['mode']), ('state', 'present', ['mode'])] - mutually_exclusive = [['default_vlan', 'trunk_vlans'], - ['default_vlan', 'pvid_vlan'], - ['default_vlan', 'untagged_vlans'], - ['trunk_vlans', 'untagged_vlans'], - ['trunk_vlans', 'tagged_vlans'], - ['default_vlan', 'tagged_vlans']] - - self.module = AnsibleModule( - argument_spec=self.spec, required_if=required_if, supports_check_mode=True, mutually_exclusive=mutually_exclusive) - - def check_response(self, xml_str, xml_name): - """Check if response message is already succeed.""" - - if "<ok/>" not in xml_str: - self.module.fail_json(msg='Error: %s failed.' % xml_name) - - def get_interface_dict(self, ifname): - """ get one interface attributes dict.""" - - intf_info = dict() - conf_str = CE_NC_GET_PORT_ATTR % ifname - xml_str = get_nc_config(self.module, conf_str) - if "<data/>" in xml_str: - return intf_info - xml_str = xml_str.replace('\r', '').replace('\n', '').\ - replace('xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"', "").\ - replace('xmlns="http://www.huawei.com/netconf/vrp"', "") - tree = ET.fromstring(xml_str) - l2Enable = tree.find('ethernet/ethernetIfs/ethernetIf/l2Enable') - intf_info["l2Enable"] = l2Enable.text - port_type = tree.find('ethernet/ethernetIfs/ethernetIf/l2Attribute') - for pre in port_type: - intf_info[pre.tag] = pre.text - intf_info["ifName"] = ifname - if intf_info["trunkVlans"] is None: - intf_info["trunkVlans"] = "" - if intf_info["untagVlans"] is None: - intf_info["untagVlans"] = "" - return intf_info - - def is_l2switchport(self): - """Check layer2 switch port""" - - return bool(self.intf_info["l2Enable"] == "enable") - - def merge_access_vlan(self, ifname, default_vlan): - """Merge access interface vlan""" - - change = False - conf_str = "" - - self.updates_cmd.append("interface %s" % ifname) - if self.state == "present": - if self.intf_info["linkType"] == "access": - if default_vlan and self.intf_info["pvid"] != default_vlan: - self.updates_cmd.append( - "port default vlan %s" % default_vlan) - conf_str = CE_NC_SET_PORT % (ifname, "access", default_vlan, "", "") - change = True - else: # not access - self.updates_cmd.append("port link-type access") - if default_vlan: - self.updates_cmd.append( - "port default vlan %s" % default_vlan) - conf_str = CE_NC_SET_PORT % (ifname, "access", default_vlan, "", "") - else: - conf_str = CE_NC_SET_PORT % (ifname, "access", "1", "", "") - change = True - elif self.state == "absent": - if self.intf_info["linkType"] == "access": - if default_vlan and self.intf_info["pvid"] == default_vlan and default_vlan != "1": - self.updates_cmd.append( - "undo port default vlan %s" % default_vlan) - conf_str = CE_NC_SET_PORT % (ifname, "access", "1", "", "") - change = True - - if not change: - self.updates_cmd.pop() # remove interface - return - conf_str = "<config>" + conf_str + "</config>" - rcv_xml = set_nc_config(self.module, conf_str) - self.check_response(rcv_xml, "MERGE_ACCESS_PORT") - self.changed = True - - def merge_trunk_vlan(self, ifname, pvid_vlan, trunk_vlans): - """Merge trunk interface vlan""" - - change = False - xmlstr = "" - pvid = "" - trunk = "" - self.updates_cmd.append("interface %s" % ifname) - if trunk_vlans: - vlan_list = self.vlan_range_to_list(trunk_vlans) - vlan_map = self.vlan_list_to_bitmap(vlan_list) - if self.state == "present": - if self.intf_info["linkType"] == "trunk": - if pvid_vlan and self.intf_info["pvid"] != pvid_vlan: - self.updates_cmd.append( - "port trunk pvid vlan %s" % pvid_vlan) - pvid = pvid_vlan - change = True - - if trunk_vlans: - add_vlans = self.vlan_bitmap_add( - self.intf_info["trunkVlans"], vlan_map) - if not is_vlan_bitmap_empty(add_vlans): - self.updates_cmd.append( - "port trunk allow-pass %s" - % trunk_vlans.replace(',', ' ').replace('-', ' to ')) - trunk = "%s:%s" % (add_vlans, add_vlans) - change = True - if pvid or trunk: - xmlstr += CE_NC_SET_PORT % (ifname, "trunk", pvid, trunk, "") - if not pvid: - xmlstr = xmlstr.replace("<pvid></pvid>", "") - if not trunk: - xmlstr = xmlstr.replace("<trunkVlans></trunkVlans>", "") - - else: # not trunk - self.updates_cmd.append("port link-type trunk") - change = True - if pvid_vlan: - self.updates_cmd.append( - "port trunk pvid vlan %s" % pvid_vlan) - pvid = pvid_vlan - if trunk_vlans: - self.updates_cmd.append( - "port trunk allow-pass %s" - % trunk_vlans.replace(',', ' ').replace('-', ' to ')) - trunk = "%s:%s" % (vlan_map, vlan_map) - if pvid or trunk: - xmlstr += CE_NC_SET_PORT % (ifname, "trunk", pvid, trunk, "") - if not pvid: - xmlstr = xmlstr.replace("<pvid></pvid>", "") - if not trunk: - xmlstr = xmlstr.replace("<trunkVlans></trunkVlans>", "") - - if not pvid_vlan and not trunk_vlans: - xmlstr += CE_NC_SET_PORT_MODE % (ifname, "trunk") - self.updates_cmd.append( - "undo port trunk allow-pass vlan 1") - elif self.state == "absent": - if self.intf_info["linkType"] == "trunk": - if pvid_vlan and self.intf_info["pvid"] == pvid_vlan and pvid_vlan != '1': - self.updates_cmd.append( - "undo port trunk pvid vlan %s" % pvid_vlan) - pvid = "1" - change = True - if trunk_vlans: - del_vlans = self.vlan_bitmap_del( - self.intf_info["trunkVlans"], vlan_map) - if not is_vlan_bitmap_empty(del_vlans): - self.updates_cmd.append( - "undo port trunk allow-pass %s" - % trunk_vlans.replace(',', ' ').replace('-', ' to ')) - undo_map = vlan_bitmap_undo(del_vlans) - trunk = "%s:%s" % (undo_map, del_vlans) - change = True - if pvid or trunk: - xmlstr += CE_NC_SET_PORT % (ifname, "trunk", pvid, trunk, "") - if not pvid: - xmlstr = xmlstr.replace("<pvid></pvid>", "") - if not trunk: - xmlstr = xmlstr.replace("<trunkVlans></trunkVlans>", "") - - if not change: - self.updates_cmd.pop() - return - conf_str = "<config>" + xmlstr + "</config>" - rcv_xml = set_nc_config(self.module, conf_str) - self.check_response(rcv_xml, "MERGE_TRUNK_PORT") - self.changed = True - - def merge_hybrid_vlan(self, ifname, pvid_vlan, tagged_vlans, untagged_vlans): - """Merge hybrid interface vlan""" - - change = False - xmlstr = "" - pvid = "" - tagged = "" - untagged = "" - self.updates_cmd.append("interface %s" % ifname) - if tagged_vlans: - vlan_targed_list = self.vlan_range_to_list(tagged_vlans) - vlan_targed_map = self.vlan_list_to_bitmap(vlan_targed_list) - if untagged_vlans: - vlan_untarged_list = self.vlan_range_to_list(untagged_vlans) - vlan_untarged_map = self.vlan_list_to_bitmap(vlan_untarged_list) - if self.state == "present": - if self.intf_info["linkType"] == "hybrid": - if pvid_vlan and self.intf_info["pvid"] != pvid_vlan: - self.updates_cmd.append( - "port hybrid pvid vlan %s" % pvid_vlan) - pvid = pvid_vlan - change = True - if tagged_vlans: - add_vlans = self.vlan_bitmap_add( - self.intf_info["trunkVlans"], vlan_targed_map) - if not is_vlan_bitmap_empty(add_vlans): - self.updates_cmd.append( - "port hybrid tagged vlan %s" - % tagged_vlans.replace(',', ' ').replace('-', ' to ')) - tagged = "%s:%s" % (add_vlans, add_vlans) - change = True - if untagged_vlans: - add_vlans = self.vlan_bitmap_add( - self.intf_info["untagVlans"], vlan_untarged_map) - if not is_vlan_bitmap_empty(add_vlans): - self.updates_cmd.append( - "port hybrid untagged vlan %s" - % untagged_vlans.replace(',', ' ').replace('-', ' to ')) - untagged = "%s:%s" % (add_vlans, add_vlans) - change = True - if pvid or tagged or untagged: - xmlstr += CE_NC_SET_PORT % (ifname, "hybrid", pvid, tagged, untagged) - if not pvid: - xmlstr = xmlstr.replace("<pvid></pvid>", "") - if not tagged: - xmlstr = xmlstr.replace("<trunkVlans></trunkVlans>", "") - if not untagged: - xmlstr = xmlstr.replace("<untagVlans></untagVlans>", "") - else: - self.updates_cmd.append("port link-type hybrid") - change = True - if pvid_vlan: - self.updates_cmd.append( - "port hybrid pvid vlan %s" % pvid_vlan) - pvid = pvid_vlan - if tagged_vlans: - self.updates_cmd.append( - "port hybrid tagged vlan %s" - % tagged_vlans.replace(',', ' ').replace('-', ' to ')) - tagged = "%s:%s" % (vlan_targed_map, vlan_targed_map) - if untagged_vlans: - self.updates_cmd.append( - "port hybrid untagged vlan %s" - % untagged_vlans.replace(',', ' ').replace('-', ' to ')) - untagged = "%s:%s" % (vlan_untarged_map, vlan_untarged_map) - if pvid or tagged or untagged: - xmlstr += CE_NC_SET_PORT % (ifname, "hybrid", pvid, tagged, untagged) - if not pvid: - xmlstr = xmlstr.replace("<pvid></pvid>", "") - if not tagged: - xmlstr = xmlstr.replace("<trunkVlans></trunkVlans>", "") - if not untagged: - xmlstr = xmlstr.replace("<untagVlans></untagVlans>", "") - if not pvid_vlan and not tagged_vlans and not untagged_vlans: - xmlstr += CE_NC_SET_PORT_MODE % (ifname, "hybrid") - self.updates_cmd.append( - "undo port hybrid untagged vlan 1") - elif self.state == "absent": - if self.intf_info["linkType"] == "hybrid": - if pvid_vlan and self.intf_info["pvid"] == pvid_vlan and pvid_vlan != '1': - self.updates_cmd.append( - "undo port hybrid pvid vlan %s" % pvid_vlan) - pvid = "1" - change = True - if tagged_vlans: - del_vlans = self.vlan_bitmap_del( - self.intf_info["trunkVlans"], vlan_targed_map) - if not is_vlan_bitmap_empty(del_vlans): - self.updates_cmd.append( - "undo port hybrid tagged vlan %s" - % tagged_vlans.replace(',', ' ').replace('-', ' to ')) - undo_map = vlan_bitmap_undo(del_vlans) - tagged = "%s:%s" % (undo_map, del_vlans) - change = True - if untagged_vlans: - del_vlans = self.vlan_bitmap_del( - self.intf_info["untagVlans"], vlan_untarged_map) - if not is_vlan_bitmap_empty(del_vlans): - self.updates_cmd.append( - "undo port hybrid untagged vlan %s" - % untagged_vlans.replace(',', ' ').replace('-', ' to ')) - undo_map = vlan_bitmap_undo(del_vlans) - untagged = "%s:%s" % (undo_map, del_vlans) - change = True - if pvid or tagged or untagged: - xmlstr += CE_NC_SET_PORT % (ifname, "hybrid", pvid, tagged, untagged) - if not pvid: - xmlstr = xmlstr.replace("<pvid></pvid>", "") - if not tagged: - xmlstr = xmlstr.replace("<trunkVlans></trunkVlans>", "") - if not untagged: - xmlstr = xmlstr.replace("<untagVlans></untagVlans>", "") - - if not change: - self.updates_cmd.pop() - return - - conf_str = "<config>" + xmlstr + "</config>" - rcv_xml = set_nc_config(self.module, conf_str) - self.check_response(rcv_xml, "MERGE_HYBRID_PORT") - self.changed = True - - def merge_dot1qtunnel_vlan(self, ifname, default_vlan): - """Merge dot1qtunnel""" - - change = False - conf_str = "" - - self.updates_cmd.append("interface %s" % ifname) - if self.state == "present": - if self.intf_info["linkType"] == "dot1qtunnel": - if default_vlan and self.intf_info["pvid"] != default_vlan: - self.updates_cmd.append( - "port default vlan %s" % default_vlan) - conf_str = CE_NC_SET_PORT % (ifname, "dot1qtunnel", default_vlan, "", "") - change = True - else: - self.updates_cmd.append("port link-type dot1qtunnel") - if default_vlan: - self.updates_cmd.append( - "port default vlan %s" % default_vlan) - conf_str = CE_NC_SET_PORT % (ifname, "dot1qtunnel", default_vlan, "", "") - else: - conf_str = CE_NC_SET_PORT % (ifname, "dot1qtunnel", "1", "", "") - change = True - elif self.state == "absent": - if self.intf_info["linkType"] == "dot1qtunnel": - if default_vlan and self.intf_info["pvid"] == default_vlan and default_vlan != "1": - self.updates_cmd.append( - "undo port default vlan %s" % default_vlan) - conf_str = CE_NC_SET_PORT % (ifname, "dot1qtunnel", "1", "", "") - change = True - if not change: - self.updates_cmd.pop() # remove interface - return - conf_str = "<config>" + conf_str + "</config>" - rcv_xml = set_nc_config(self.module, conf_str) - self.check_response(rcv_xml, "MERGE_DOT1QTUNNEL_PORT") - self.changed = True - - def default_switchport(self, ifname): - """Set interface default or unconfigured""" - - change = False - if self.intf_info["linkType"] != "access": - self.updates_cmd.append("interface %s" % ifname) - self.updates_cmd.append("port link-type access") - self.updates_cmd.append("port default vlan 1") - change = True - else: - if self.intf_info["pvid"] != "1": - self.updates_cmd.append("interface %s" % ifname) - self.updates_cmd.append("port default vlan 1") - change = True - - if not change: - return - - conf_str = CE_NC_SET_DEFAULT_PORT % ifname - rcv_xml = set_nc_config(self.module, conf_str) - self.check_response(rcv_xml, "DEFAULT_INTF_VLAN") - self.changed = True - - def vlan_series(self, vlanid_s): - """ convert vlan range to vlan list """ - - vlan_list = [] - peerlistlen = len(vlanid_s) - if peerlistlen != 2: - self.module.fail_json(msg='Error: Format of vlanid is invalid.') - for num in range(peerlistlen): - if not vlanid_s[num].isdigit(): - self.module.fail_json( - msg='Error: Format of vlanid is invalid.') - if int(vlanid_s[0]) > int(vlanid_s[1]): - self.module.fail_json(msg='Error: Format of vlanid is invalid.') - elif int(vlanid_s[0]) == int(vlanid_s[1]): - vlan_list.append(str(vlanid_s[0])) - return vlan_list - for num in range(int(vlanid_s[0]), int(vlanid_s[1])): - vlan_list.append(str(num)) - vlan_list.append(vlanid_s[1]) - - return vlan_list - - def vlan_region(self, vlanid_list): - """ convert vlan range to vlan list """ - - vlan_list = [] - peerlistlen = len(vlanid_list) - for num in range(peerlistlen): - if vlanid_list[num].isdigit(): - vlan_list.append(vlanid_list[num]) - else: - vlan_s = self.vlan_series(vlanid_list[num].split('-')) - vlan_list.extend(vlan_s) - - return vlan_list - - def vlan_range_to_list(self, vlan_range): - """ convert vlan range to vlan list """ - - vlan_list = self.vlan_region(vlan_range.split(',')) - - return vlan_list - - def vlan_list_to_bitmap(self, vlanlist): - """ convert vlan list to vlan bitmap """ - - vlan_bit = ['0'] * 1024 - bit_int = [0] * 1024 - - vlan_list_len = len(vlanlist) - for num in range(vlan_list_len): - tagged_vlans = int(vlanlist[num]) - if tagged_vlans <= 0 or tagged_vlans > 4094: - self.module.fail_json( - msg='Error: Vlan id is not in the range from 1 to 4094.') - j = tagged_vlans // 4 - bit_int[j] |= 0x8 >> (tagged_vlans % 4) - vlan_bit[j] = hex(bit_int[j])[2] - - vlan_xml = ''.join(vlan_bit) - - return vlan_xml - - def vlan_bitmap_add(self, oldmap, newmap): - """vlan add bitmap""" - - vlan_bit = ['0'] * 1024 - - if len(newmap) != 1024: - self.module.fail_json(msg='Error: New vlan bitmap is invalid.') - - if len(oldmap) != 1024 and len(oldmap) != 0: - self.module.fail_json(msg='Error: old vlan bitmap is invalid.') - - if len(oldmap) == 0: - return newmap - - for num in range(1024): - new_tmp = int(newmap[num], 16) - old_tmp = int(oldmap[num], 16) - add = (~(new_tmp & old_tmp)) & new_tmp - vlan_bit[num] = hex(add)[2] - - vlan_xml = ''.join(vlan_bit) - - return vlan_xml - - def vlan_bitmap_del(self, oldmap, delmap): - """vlan del bitmap""" - - vlan_bit = ['0'] * 1024 - - if not oldmap or len(oldmap) == 0: - return ''.join(vlan_bit) - - if len(oldmap) != 1024 or len(delmap) != 1024: - self.module.fail_json(msg='Error: vlan bitmap is invalid.') - - for num in range(1024): - tmp = int(delmap[num], 16) & int(oldmap[num], 16) - vlan_bit[num] = hex(tmp)[2] - - vlan_xml = ''.join(vlan_bit) - - return vlan_xml - - def check_params(self): - """Check all input params""" - - # interface type check - if self.interface: - self.intf_type = get_interface_type(self.interface) - if not self.intf_type: - self.module.fail_json( - msg='Error: Interface name of %s is error.' % self.interface) - - if not self.intf_type or not is_portswitch_enalbed(self.intf_type): - self.module.fail_json(msg='Error: Interface %s is error.') - - # check default_vlan - if self.default_vlan: - if not self.default_vlan.isdigit(): - self.module.fail_json(msg='Error: Access vlan id is invalid.') - if int(self.default_vlan) <= 0 or int(self.default_vlan) > 4094: - self.module.fail_json( - msg='Error: Access vlan id is not in the range from 1 to 4094.') - - # check pvid_vlan - if self.pvid_vlan: - if not self.pvid_vlan.isdigit(): - self.module.fail_json(msg='Error: Pvid vlan id is invalid.') - if int(self.pvid_vlan) <= 0 or int(self.pvid_vlan) > 4094: - self.module.fail_json( - msg='Error: Pvid vlan id is not in the range from 1 to 4094.') - - # get interface info - self.intf_info = self.get_interface_dict(self.interface) - if not self.intf_info: - self.module.fail_json(msg='Error: Interface does not exist.') - - if not self.is_l2switchport(): - self.module.fail_json( - msg='Error: Interface is not layer2 switch port.') - if self.state == "unconfigured": - if any([self.mode, self.default_vlan, self.pvid_vlan, self.trunk_vlans, self.untagged_vlans, self.tagged_vlans]): - self.module.fail_json( - msg='Error: When state is unconfigured, only interface name exists.') - else: - if self.mode == "access": - if any([self.pvid_vlan, self.trunk_vlans, self.untagged_vlans, self.tagged_vlans]): - self.module.fail_json( - msg='Error: When mode is access, only default_vlan can be supported.') - elif self.mode == "trunk": - if any([self.default_vlan, self.untagged_vlans, self.tagged_vlans]): - self.module.fail_json( - msg='Error: When mode is trunk, only pvid_vlan and trunk_vlans can exist.') - elif self.mode == "hybrid": - if any([self.default_vlan, self.trunk_vlans]): - self.module.fail_json( - msg='Error: When mode is hybrid, default_vlan and trunk_vlans cannot exist') - else: - if any([self.pvid_vlan, self.trunk_vlans, self.untagged_vlans, self.tagged_vlans]): - self.module.fail_json( - msg='Error: When mode is dot1qtunnel, only default_vlan can be supported.') - - def get_proposed(self): - """get proposed info""" - - self.proposed['state'] = self.state - self.proposed['interface'] = self.interface - self.proposed['mode'] = self.mode - if self.mode: - if self.mode == "access": - self.proposed['access_pvid'] = self.default_vlan - elif self.mode == "trunk": - self.proposed['pvid_vlan'] = self.pvid_vlan - self.proposed['trunk_vlans'] = self.trunk_vlans - elif self.mode == "hybrid": - self.proposed['pvid_vlan'] = self.pvid_vlan - self.proposed['untagged_vlans'] = self.untagged_vlans - self.proposed['tagged_vlans'] = self.tagged_vlans - else: - self.proposed['dot1qtunnel_pvid'] = self.default_vlan - - def get_existing(self): - """get existing info""" - - if self.intf_info: - self.existing["interface"] = self.intf_info["ifName"] - self.existing["switchport"] = self.intf_info["l2Enable"] - self.existing["mode"] = self.intf_info["linkType"] - if self.intf_info["linkType"] == "access": - self.existing['access_pvid'] = self.intf_info["pvid"] - elif self.intf_info["linkType"] == "trunk": - self.existing['trunk_pvid'] = self.intf_info["pvid"] - self.existing['trunk_vlans'] = self.intf_info["trunkVlans"] - elif self.intf_info["linkType"] == "hybrid": - self.existing['hybrid_pvid'] = self.intf_info["pvid"] - self.existing['hybrid_untagged_vlans'] = self.intf_info["untagVlans"] - self.existing['hybrid_tagged_vlans'] = self.intf_info["trunkVlans"] - else: - self.existing['dot1qtunnel_pvid'] = self.intf_info["pvid"] - - def get_end_state(self): - """get end state info""" - - end_info = self.get_interface_dict(self.interface) - if end_info: - self.end_state["interface"] = end_info["ifName"] - self.end_state["switchport"] = end_info["l2Enable"] - self.end_state["mode"] = end_info["linkType"] - if end_info["linkType"] == "access": - self.end_state['access_pvid'] = end_info["pvid"] - elif end_info["linkType"] == "trunk": - self.end_state['trunk_pvid'] = end_info["pvid"] - self.end_state['trunk_vlans'] = end_info["trunkVlans"] - elif end_info["linkType"] == "hybrid": - self.end_state['hybrid_pvid'] = end_info["pvid"] - self.end_state['hybrid_untagged_vlans'] = end_info["untagVlans"] - self.end_state['hybrid_tagged_vlans'] = end_info["trunkVlans"] - else: - self.end_state['dot1qtunnel_pvid'] = end_info["pvid"] - if self.end_state == self.existing: - self.changed = False - - def work(self): - """worker""" - - self.check_params() - if not self.intf_info: - self.module.fail_json(msg='Error: interface does not exist.') - self.get_existing() - self.get_proposed() - - # present or absent - if self.state == "present" or self.state == "absent": - if self.mode == "access": - self.merge_access_vlan(self.interface, self.default_vlan) - elif self.mode == "trunk": - self.merge_trunk_vlan( - self.interface, self.pvid_vlan, self.trunk_vlans) - elif self.mode == "hybrid": - self.merge_hybrid_vlan(self.interface, self.pvid_vlan, self.tagged_vlans, self.untagged_vlans) - else: - self.merge_dot1qtunnel_vlan(self.interface, self.default_vlan) - - # unconfigured - else: - self.default_switchport(self.interface) - - self.get_end_state() - self.results['changed'] = self.changed - self.results['proposed'] = self.proposed - self.results['existing'] = self.existing - self.results['end_state'] = self.end_state - if self.changed: - self.results['updates'] = self.updates_cmd - else: - self.results['updates'] = list() - - self.module.exit_json(**self.results) - - -def main(): - """Module main""" - - argument_spec = dict( - interface=dict(required=True, type='str'), - mode=dict(choices=['access', 'trunk', 'dot1qtunnel', 'hybrid'], required=False), - default_vlan=dict(type='str', required=False), - pvid_vlan=dict(type='str', required=False), - trunk_vlans=dict(type='str', required=False), - untagged_vlans=dict(type='str', required=False), - tagged_vlans=dict(type='str', required=False), - state=dict(choices=['absent', 'present', 'unconfigured'], - default='present') - ) - - argument_spec.update(ce_argument_spec) - switchport = SwitchPort(argument_spec) - switchport.work() - - -if __name__ == '__main__': - main() |