diff options
Diffstat (limited to 'lib/ansible/modules/network/cloudengine/ce_ip_interface.py')
-rw-r--r-- | lib/ansible/modules/network/cloudengine/ce_ip_interface.py | 740 |
1 files changed, 0 insertions, 740 deletions
diff --git a/lib/ansible/modules/network/cloudengine/ce_ip_interface.py b/lib/ansible/modules/network/cloudengine/ce_ip_interface.py deleted file mode 100644 index 2e17469fc2..0000000000 --- a/lib/ansible/modules/network/cloudengine/ce_ip_interface.py +++ /dev/null @@ -1,740 +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_ip_interface -version_added: "2.4" -short_description: Manages L3 attributes for IPv4 and IPv6 interfaces on HUAWEI CloudEngine switches. -description: - - Manages Layer 3 attributes for IPv4 and IPv6 interfaces on HUAWEI CloudEngine switches. -author: QijunPan (@QijunPan) -notes: - - Interface must already be a L3 port when using this module. - - Logical interfaces (loopback, vlanif) must be created first. - - C(mask) must be inserted in decimal format (i.e. 24) for - both IPv6 and IPv4. - - A single interface can have multiple IPv6 configured. - - 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 interface, i.e. 40GE1/0/22, vlanif10. - required: true - addr: - description: - - IPv4 or IPv6 Address. - mask: - description: - - Subnet mask for IPv4 or IPv6 Address in decimal format. - version: - description: - - IP address version. - default: v4 - choices: ['v4','v6'] - ipv4_type: - description: - - Specifies an address type. - The value is an enumerated type. - main, primary IP address. - sub, secondary IP address. - default: main - choices: ['main','sub'] - state: - description: - - Specify desired state of the resource. - default: present - choices: ['present','absent'] -''' - -EXAMPLES = ''' -- name: ip_interface 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 ipv4 address is configured on 10GE1/0/22 - ce_ip_interface: - interface: 10GE1/0/22 - version: v4 - state: present - addr: 20.20.20.20 - mask: 24 - provider: '{{ cli }}' - - - name: Ensure ipv4 secondary address is configured on 10GE1/0/22 - ce_ip_interface: - interface: 10GE1/0/22 - version: v4 - state: present - addr: 30.30.30.30 - mask: 24 - ipv4_type: sub - provider: '{{ cli }}' - - - name: Ensure ipv6 is enabled on 10GE1/0/22 - ce_ip_interface: - interface: 10GE1/0/22 - version: v6 - state: present - provider: '{{ cli }}' - - - name: Ensure ipv6 address is configured on 10GE1/0/22 - ce_ip_interface: - interface: 10GE1/0/22 - version: v6 - state: present - addr: 2001::db8:800:200c:cccb - mask: 64 - provider: '{{ cli }}' -''' - -RETURN = ''' -proposed: - description: k/v pairs of parameters passed into module - returned: always - type: dict - sample: {"addr": "20.20.20.20", "interface": "10GE1/0/22", "mask": "24"} -existing: - description: k/v pairs of existing IP attributes on the interface - returned: always - type: dict - sample: {"ipv4": [{"ifIpAddr": "11.11.11.11", "subnetMask": "255.255.0.0", "addrType": "main"}], - "interface": "10GE1/0/22"} -end_state: - description: k/v pairs of IP attributes after module execution - returned: always - type: dict - sample: {"ipv4": [{"ifIpAddr": "20.20.20.20", "subnetMask": "255.255.255.0", "addrType": "main"}], - "interface": "10GE1/0/22"} -updates: - description: commands sent to the device - returned: always - type: list - sample: ["interface 10GE1/0/22", "ip address 20.20.20.20 24"] -changed: - description: check to see if a change was made on the device - returned: always - type: bool - sample: true -''' - -import re -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_INTF = """ -<filter type="subtree"> - <ifm xmlns="http://www.huawei.com/netconf/vrp" content-version="1.0" format-version="1.0"> - <interfaces> - <interface> - <ifName>%s</ifName> - <isL2SwitchPort></isL2SwitchPort> - <ifmAm4> - </ifmAm4> - <ifmAm6> - </ifmAm6> - </interface> - </interfaces> - </ifm> -</filter> -""" - -CE_NC_ADD_IPV4 = """ -<config> - <ifm xmlns="http://www.huawei.com/netconf/vrp" content-version="1.0" format-version="1.0"> - <interfaces> - <interface> - <ifName>%s</ifName> - <ifmAm4> - <am4CfgAddrs> - <am4CfgAddr operation="merge"> - <ifIpAddr>%s</ifIpAddr> - <subnetMask>%s</subnetMask> - <addrType>%s</addrType> - </am4CfgAddr> - </am4CfgAddrs> - </ifmAm4> - </interface> - </interfaces> - </ifm> -</config> -""" - -CE_NC_MERGE_IPV4 = """ -<config> - <ifm xmlns="http://www.huawei.com/netconf/vrp" content-version="1.0" format-version="1.0"> - <interfaces> - <interface> - <ifName>%s</ifName> - <ifmAm4> - <am4CfgAddrs> - <am4CfgAddr operation="delete"> - <ifIpAddr>%s</ifIpAddr> - <subnetMask>%s</subnetMask> - <addrType>main</addrType> - </am4CfgAddr> - <am4CfgAddr operation="merge"> - <ifIpAddr>%s</ifIpAddr> - <subnetMask>%s</subnetMask> - <addrType>main</addrType> - </am4CfgAddr> - </am4CfgAddrs> - </ifmAm4> - </interface> - </interfaces> - </ifm> -</config> -""" - - -CE_NC_DEL_IPV4 = """ -<config> - <ifm xmlns="http://www.huawei.com/netconf/vrp" content-version="1.0" format-version="1.0"> - <interfaces> - <interface> - <ifName>%s</ifName> - <ifmAm4> - <am4CfgAddrs> - <am4CfgAddr operation="delete"> - <ifIpAddr>%s</ifIpAddr> - <subnetMask>%s</subnetMask> - <addrType>%s</addrType> - </am4CfgAddr> - </am4CfgAddrs> - </ifmAm4> - </interface> - </interfaces> - </ifm> -</config> -""" - -CE_NC_ADD_IPV6 = """ -<config> - <ifm xmlns="http://www.huawei.com/netconf/vrp" content-version="1.0" format-version="1.0"> - <interfaces> - <interface> - <ifName>%s</ifName> - <ifmAm6> - <am6CfgAddrs> - <am6CfgAddr operation="merge"> - <ifIp6Addr>%s</ifIp6Addr> - <addrPrefixLen>%s</addrPrefixLen> - <addrType6>global</addrType6> - </am6CfgAddr> - </am6CfgAddrs> - </ifmAm6> - </interface> - </interfaces> - </ifm> -</config> -""" - -CE_NC_DEL_IPV6 = """ - <config> - <ifm xmlns="http://www.huawei.com/netconf/vrp" content-version="1.0" format-version="1.0"> - <interfaces> - <interface> - <ifName>%s</ifName> - <ifmAm6> - <am6CfgAddrs> - <am6CfgAddr operation="delete"> - <ifIp6Addr>%s</ifIp6Addr> - <addrPrefixLen>%s</addrPrefixLen> - <addrType6>global</addrType6> - </am6CfgAddr> - </am6CfgAddrs> - </ifmAm6> - </interface> - </interfaces> - </ifm> - </config> -""" - -CE_NC_MERGE_IPV6_ENABLE = """ -<config> - <ifm xmlns="http://www.huawei.com/netconf/vrp" content-version="1.0" format-version="1.0"> - <interfaces> - <interface> - <ifName>%s</ifName> - <ifmAm6 operation="merge"> - <enableFlag>%s</enableFlag> - </ifmAm6> - </interface> - </interfaces> - </ifm> -</config> -""" - - -def get_interface_type(interface): - """Gets the type of interface, such as 10GE, ETH-TRUNK, VLANIF...""" - - if interface is None: - return None - - if interface.upper().startswith('GE'): - return 'ge' - elif interface.upper().startswith('10GE'): - return '10ge' - elif interface.upper().startswith('25GE'): - return '25ge' - elif interface.upper().startswith('4X10GE'): - return '4x10ge' - elif interface.upper().startswith('40GE'): - return '40ge' - elif interface.upper().startswith('100GE'): - return '100ge' - elif interface.upper().startswith('VLANIF'): - return 'vlanif' - elif interface.upper().startswith('LOOPBACK'): - return 'loopback' - elif interface.upper().startswith('METH'): - return 'meth' - elif interface.upper().startswith('ETH-TRUNK'): - return 'eth-trunk' - elif interface.upper().startswith('VBDIF'): - return 'vbdif' - elif interface.upper().startswith('NVE'): - return 'nve' - elif interface.upper().startswith('TUNNEL'): - return 'tunnel' - elif interface.upper().startswith('ETHERNET'): - return 'ethernet' - elif interface.upper().startswith('FCOE-PORT'): - return 'fcoe-port' - elif interface.upper().startswith('FABRIC-PORT'): - return 'fabric-port' - elif interface.upper().startswith('STACK-PORT'): - return 'stack-port' - elif interface.upper().startswith('NULL'): - return 'null' - else: - return None - - -def is_valid_v4addr(addr): - """check is ipv4 addr is valid""" - - if not addr: - return False - - if addr.find('.') != -1: - addr_list = addr.split('.') - if len(addr_list) != 4: - return False - for each_num in addr_list: - if not each_num.isdigit(): - return False - if int(each_num) > 255: - return False - return True - - return False - - -class IpInterface(object): - """ - Manages L3 attributes for IPv4 and IPv6 interfaces. - """ - - def __init__(self, argument_spec): - self.spec = argument_spec - self.module = None - self.__init_module__() - - # module input info] - self.interface = self.module.params['interface'] - self.addr = self.module.params['addr'] - self.mask = self.module.params['mask'] - self.version = self.module.params['version'] - self.ipv4_type = self.module.params['ipv4_type'] - self.state = self.module.params['state'] - - # state - self.changed = False - self.updates_cmd = list() - self.results = dict() - self.proposed = dict() - self.existing = dict() - self.end_state = dict() - # interface info - self.intf_info = dict() - self.intf_type = None - - def __init_module__(self): - """ init module """ - - required_if = [("version", "v4", ("addr", "mask"))] - required_together = [("addr", "mask")] - self.module = AnsibleModule( - argument_spec=self.spec, - required_if=required_if, - required_together=required_together, - supports_check_mode=True - ) - - def netconf_set_config(self, xml_str, xml_name): - """ netconf set config """ - - rcv_xml = set_nc_config(self.module, xml_str) - if "<ok/>" not in rcv_xml: - 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_INTF % ifname - rcv_xml = get_nc_config(self.module, conf_str) - - if "<data/>" in rcv_xml: - return intf_info - - # get interface base info - intf = re.findall( - r'.*<ifName>(.*)</ifName>.*\s*' - r'<isL2SwitchPort>(.*)</isL2SwitchPort>.*', rcv_xml) - - if intf: - intf_info = dict(ifName=intf[0][0], - isL2SwitchPort=intf[0][1]) - - # get interface ipv4 address info - ipv4_info = re.findall( - r'.*<ifIpAddr>(.*)</ifIpAddr>.*\s*<subnetMask>(.*)' - r'</subnetMask>.*\s*<addrType>(.*)</addrType>.*', rcv_xml) - intf_info["am4CfgAddr"] = list() - for info in ipv4_info: - intf_info["am4CfgAddr"].append( - dict(ifIpAddr=info[0], subnetMask=info[1], addrType=info[2])) - - # get interface ipv6 address info - ipv6_info = re.findall( - r'.*<ifmAm6>.*\s*<enableFlag>(.*)</enableFlag>.*', rcv_xml) - if not ipv6_info: - self.module.fail_json(msg='Error: Fail to get interface %s IPv6 state.' % self.interface) - else: - intf_info["enableFlag"] = ipv6_info[0] - - # get interface ipv6 enable info - ipv6_info = re.findall( - r'.*<ifIp6Addr>(.*)</ifIp6Addr>.*\s*<addrPrefixLen>(.*)' - r'</addrPrefixLen>.*\s*<addrType6>(.*)</addrType6>.*', rcv_xml) - - intf_info["am6CfgAddr"] = list() - for info in ipv6_info: - intf_info["am6CfgAddr"].append( - dict(ifIp6Addr=info[0], addrPrefixLen=info[1], addrType6=info[2])) - - return intf_info - - def convert_len_to_mask(self, masklen): - """convert mask length to ip address mask, i.e. 24 to 255.255.255.0""" - - mask_int = ["0"] * 4 - length = int(masklen) - - if length > 32: - self.module.fail_json(msg='Error: IPv4 ipaddress mask length is invalid.') - if length < 8: - mask_int[0] = str(int((0xFF << (8 - length % 8)) & 0xFF)) - if length >= 8: - mask_int[0] = '255' - mask_int[1] = str(int((0xFF << (16 - (length % 16))) & 0xFF)) - if length >= 16: - mask_int[1] = '255' - mask_int[2] = str(int((0xFF << (24 - (length % 24))) & 0xFF)) - if length >= 24: - mask_int[2] = '255' - mask_int[3] = str(int((0xFF << (32 - (length % 32))) & 0xFF)) - if length == 32: - mask_int[3] = '255' - - return '.'.join(mask_int) - - def is_ipv4_exist(self, addr, maskstr, ipv4_type): - """"Check IPv4 address exist""" - - addrs = self.intf_info["am4CfgAddr"] - if not addrs: - return False - - for address in addrs: - if address["ifIpAddr"] == addr: - return address["subnetMask"] == maskstr and address["addrType"] == ipv4_type - return False - - def get_ipv4_main_addr(self): - """get IPv4 main address""" - - addrs = self.intf_info["am4CfgAddr"] - if not addrs: - return None - - for address in addrs: - if address["addrType"] == "main": - return address - - return None - - def is_ipv6_exist(self, addr, masklen): - """Check IPv6 address exist""" - - addrs = self.intf_info["am6CfgAddr"] - if not addrs: - return False - - for address in addrs: - if address["ifIp6Addr"] == addr.upper(): - if address["addrPrefixLen"] == masklen and address["addrType6"] == "global": - return True - else: - self.module.fail_json( - msg="Error: Input IPv6 address or mask is invalid.") - - return False - - def set_ipv4_addr(self, ifname, addr, mask, ipv4_type): - """Set interface IPv4 address""" - - if not addr or not mask or not type: - return - - maskstr = self.convert_len_to_mask(mask) - if self.state == "present": - if not self.is_ipv4_exist(addr, maskstr, ipv4_type): - # primary IP address - if ipv4_type == "main": - main_addr = self.get_ipv4_main_addr() - if not main_addr: - # no ipv4 main address in this interface - xml_str = CE_NC_ADD_IPV4 % (ifname, addr, maskstr, ipv4_type) - self.netconf_set_config(xml_str, "ADD_IPV4_ADDR") - else: - # remove old address and set new - xml_str = CE_NC_MERGE_IPV4 % (ifname, main_addr["ifIpAddr"], - main_addr["subnetMask"], - addr, maskstr) - self.netconf_set_config(xml_str, "MERGE_IPV4_ADDR") - # secondary IP address - else: - xml_str = CE_NC_ADD_IPV4 % (ifname, addr, maskstr, ipv4_type) - self.netconf_set_config(xml_str, "ADD_IPV4_ADDR") - - self.updates_cmd.append("interface %s" % ifname) - if ipv4_type == "main": - self.updates_cmd.append("ip address %s %s" % (addr, maskstr)) - else: - self.updates_cmd.append("ip address %s %s sub" % (addr, maskstr)) - self.changed = True - else: - if self.is_ipv4_exist(addr, maskstr, ipv4_type): - xml_str = CE_NC_DEL_IPV4 % (ifname, addr, maskstr, ipv4_type) - self.netconf_set_config(xml_str, "DEL_IPV4_ADDR") - self.updates_cmd.append("interface %s" % ifname) - if ipv4_type == "main": - self.updates_cmd.append("undo ip address %s %s" % (addr, maskstr)) - else: - self.updates_cmd.append("undo ip address %s %s sub" % (addr, maskstr)) - self.changed = True - - def set_ipv6_addr(self, ifname, addr, mask): - """Set interface IPv6 address""" - - if not addr or not mask: - return - - if self.state == "present": - self.updates_cmd.append("interface %s" % ifname) - if self.intf_info["enableFlag"] == "false": - xml_str = CE_NC_MERGE_IPV6_ENABLE % (ifname, "true") - self.netconf_set_config(xml_str, "SET_IPV6_ENABLE") - self.updates_cmd.append("ipv6 enable") - self.changed = True - - if not self.is_ipv6_exist(addr, mask): - xml_str = CE_NC_ADD_IPV6 % (ifname, addr, mask) - self.netconf_set_config(xml_str, "ADD_IPV6_ADDR") - - self.updates_cmd.append("ipv6 address %s %s" % (addr, mask)) - self.changed = True - - if not self.changed: - self.updates_cmd.pop() - else: - if self.is_ipv6_exist(addr, mask): - xml_str = CE_NC_DEL_IPV6 % (ifname, addr, mask) - self.netconf_set_config(xml_str, "DEL_IPV6_ADDR") - self.updates_cmd.append("interface %s" % ifname) - self.updates_cmd.append( - "undo ipv6 address %s %s" % (addr, mask)) - self.changed = True - - def set_ipv6_enable(self, ifname): - """Set interface IPv6 enable""" - - if self.state == "present": - if self.intf_info["enableFlag"] == "false": - xml_str = CE_NC_MERGE_IPV6_ENABLE % (ifname, "true") - self.netconf_set_config(xml_str, "SET_IPV6_ENABLE") - self.updates_cmd.append("interface %s" % ifname) - self.updates_cmd.append("ipv6 enable") - self.changed = True - else: - if self.intf_info["enableFlag"] == "true": - xml_str = CE_NC_MERGE_IPV6_ENABLE % (ifname, "false") - self.netconf_set_config(xml_str, "SET_IPV6_DISABLE") - self.updates_cmd.append("interface %s" % ifname) - self.updates_cmd.append("undo ipv6 enable") - self.changed = True - - def check_params(self): - """Check all input params""" - - # check interface type - 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) - - # ipv4 addr and mask check - if self.version == "v4": - if not is_valid_v4addr(self.addr): - self.module.fail_json( - msg='Error: The %s is not a valid address.' % self.addr) - if not self.mask.isdigit(): - self.module.fail_json(msg='Error: mask is invalid.') - if int(self.mask) > 32 or int(self.mask) < 1: - self.module.fail_json( - msg='Error: mask must be an integer between 1 and 32.') - - # ipv6 mask check - if self.version == "v6": - if self.addr: - if not self.mask.isdigit(): - self.module.fail_json(msg='Error: mask is invalid.') - if int(self.mask) > 128 or int(self.mask) < 1: - self.module.fail_json( - msg='Error: mask must be an integer between 1 and 128.') - - # interface and layer3 check - self.intf_info = self.get_interface_dict(self.interface) - if not self.intf_info: - self.module.fail_json(msg='Error: interface %s does not exist.' % self.interface) - - if self.intf_info["isL2SwitchPort"] == "true": - self.module.fail_json(msg='Error: interface %s is layer2.' % self.interface) - - def get_proposed(self): - """get proposed info""" - - self.proposed["state"] = self.state - self.proposed["addr"] = self.addr - self.proposed["mask"] = self.mask - self.proposed["ipv4_type"] = self.ipv4_type - self.proposed["version"] = self.version - self.proposed["interface"] = self.interface - - def get_existing(self): - """get existing info""" - - self.existing["interface"] = self.interface - self.existing["ipv4addr"] = self.intf_info["am4CfgAddr"] - self.existing["ipv6addr"] = self.intf_info["am6CfgAddr"] - self.existing["ipv6enalbe"] = self.intf_info["enableFlag"] - - def get_end_state(self): - """get end state info""" - - intf_info = self.get_interface_dict(self.interface) - self.end_state["interface"] = self.interface - self.end_state["ipv4addr"] = intf_info["am4CfgAddr"] - self.end_state["ipv6addr"] = intf_info["am6CfgAddr"] - self.end_state["ipv6enalbe"] = intf_info["enableFlag"] - - def work(self): - """worker""" - - self.check_params() - self.get_existing() - self.get_proposed() - - # deal present or absent - if self.version == "v4": - self.set_ipv4_addr(self.interface, self.addr, self.mask, self.ipv4_type) - else: - if not self.addr and not self.mask: - self.set_ipv6_enable(self.interface) - else: - self.set_ipv6_addr(self.interface, self.addr, self.mask) - - 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), - addr=dict(required=False), - version=dict(required=False, choices=['v4', 'v6'], - default='v4'), - mask=dict(type='str', required=False), - ipv4_type=dict(required=False, choices=['main', 'sub'], default='main'), - state=dict(required=False, default='present', - choices=['present', 'absent']) - ) - - argument_spec.update(ce_argument_spec) - module = IpInterface(argument_spec) - module.work() - - -if __name__ == '__main__': - main() |