diff --git a/lib/ansible/modules/network/cloudengine/ce_link_status.py b/lib/ansible/modules/network/cloudengine/ce_link_status.py new file mode 100644 index 0000000000..61e00afaf7 --- /dev/null +++ b/lib/ansible/modules/network/cloudengine/ce_link_status.py @@ -0,0 +1,567 @@ +#!/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 . +# + +ANSIBLE_METADATA = {'status': ['preview'], + 'supported_by': 'community', + 'metadata_version': '1.0'} + +DOCUMENTATION = ''' +--- + +module: ce_link_status +version_added: "2.4" +short_description: Get interface link status on HUAWEI CloudEngine switches. +description: + - Get interface link status on HUAWEI CloudEngine switches. +author: + - Zhijin Zhou (@CloudEngine-Ansible) +notes: + - Current physical state shows an interface's physical status. + - Current link state shows an interface's link layer protocol status. + - Current IPv4 state shows an interface's IPv4 protocol status. + - Current IPv6 state shows an interface's IPv6 protocol status. + - Inbound octets(bytes) shows the number of bytes that an interface received. + - Inbound unicast(pkts) shows the number of unicast packets that an interface received. + - Inbound multicast(pkts) shows the number of multicast packets that an interface received. + - Inbound broadcast(pkts) shows the number of broadcast packets that an interface received. + - Inbound error(pkts) shows the number of error packets that an interface received. + - Inbound drop(pkts) shows the total number of packets that were sent to the interface but dropped by an interface. + - Inbound rate(byte/sec) shows the rate at which an interface receives bytes within an interval. + - Inbound rate(pkts/sec) shows the rate at which an interface receives packets within an interval. + - Outbound octets(bytes) shows the number of the bytes that an interface sent. + - Outbound unicast(pkts) shows the number of unicast packets that an interface sent. + - Outbound multicast(pkts) shows the number of multicast packets that an interface sent. + - Outbound broadcast(pkts) shows the number of broadcast packets that an interface sent. + - Outbound error(pkts) shows the total number of packets that an interface sent but dropped by the remote interface. + - Outbound drop(pkts) shows the number of dropped packets that an interface sent. + - Outbound rate(byte/sec) shows the rate at which an interface sends bytes within an interval. + - Outbound rate(pkts/sec) shows the rate at which an interface sends packets within an interval. + - Speed shows the rate for an Ethernet interface. +options: + interface: + description: + - For the interface parameter, you can enter C(all) to display information about all interface, + an interface type such as C(40GE) to display information about interfaces of the specified type, + or full name of an interface such as C(40GE1/0/22) or C(vlanif10) + to display information about the specific interface. + required: true +''' + +EXAMPLES = ''' + +- name: Link status 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: Get specified interface link status information + ce_link_status: + interface: 40GE1/0/1 + provider: "{{ cli }}" + + - name: Get specified interface type link status information + ce_link_status: + interface: 40GE + provider: "{{ cli }}" + + - name: Get all interface link status information + ce_link_status: + interface: all + provider: "{{ cli }}" +''' + +RETURN = ''' +result: + description: Interface link status information + returned: always + type: dict + sample: { + "40ge2/0/8": { + "Current IPv4 state": "down", + "Current IPv6 state": "down", + "Current link state": "up", + "Current physical state": "up", + "Inbound broadcast(pkts)": "0", + "Inbound drop(pkts)": "0", + "Inbound error(pkts)": "0", + "Inbound multicast(pkts)": "20151", + "Inbound octets(bytes)": "7314813", + "Inbound rate(byte/sec)": "11", + "Inbound rate(pkts/sec)": "0", + "Inbound unicast(pkts)": "0", + "Outbound broadcast(pkts)": "1", + "Outbound drop(pkts)": "0", + "Outbound error(pkts)": "0", + "Outbound multicast(pkts)": "20152", + "Outbound octets(bytes)": "7235021", + "Outbound rate(byte/sec)": "11", + "Outbound rate(pkts/sec)": "0", + "Outbound unicast(pkts)": "0", + "Speed": "40GE" + } + } +''' + +from xml.etree import ElementTree +from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.ce import ce_argument_spec, get_nc_config + +CE_NC_GET_PORT_SPEED = """ + + + + + %s + + + + + + + +""" + +CE_NC_GET_INT_STATISTICS = """ + + + + + %s + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +""" + +INTERFACE_ALL = 1 +INTERFACE_TYPE = 2 +INTERFACE_FULL_NAME = 3 + + +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_ethernet_port(interface): + """Judge whether it is ethernet port""" + + ethernet_port = ['ge', '10ge', '25ge', '4x10ge', '40ge', '100ge', 'meth'] + if_type = get_interface_type(interface) + if if_type in ethernet_port: + return True + return False + + +class LinkStatus(object): + """Get interface link status information""" + + def __init__(self, argument_spec): + self.spec = argument_spec + self.module = None + self.init_module() + + # interface name + self.interface = self.module.params['interface'] + self.interface = self.interface.replace(' ', '').lower() + self.param_type = None + self.if_type = None + + # state + self.results = dict() + self.result = dict() + + def check_params(self): + """Check all input params""" + + if not self.interface: + self.module.fail_json(msg='Error: Interface name cannot be empty.') + + if self.interface and self.interface != 'all': + if not self.if_type: + self.module.fail_json( + msg='Error: Interface name of %s is error.' % self.interface) + + def init_module(self): + """Init module object""" + + self.module = AnsibleModule( + argument_spec=self.spec, supports_check_mode=True) + + def show_result(self): + """Show result""" + + self.results['result'] = self.result + + self.module.exit_json(**self.results) + + def get_intf_dynamic_info(self, dyn_info, intf_name): + """Get interface dynamic information""" + + if not intf_name: + return + + if dyn_info: + for eles in dyn_info: + if eles.tag in ["ifPhyStatus", "ifV4State", "ifV6State", "ifLinkStatus"]: + if eles.tag == "ifPhyStatus": + self.result[intf_name][ + 'Current physical state'] = eles.text + elif eles.tag == "ifLinkStatus": + self.result[intf_name][ + 'Current link state'] = eles.text + elif eles.tag == "ifV4State": + self.result[intf_name][ + 'Current IPv4 state'] = eles.text + elif eles.tag == "ifV6State": + self.result[intf_name][ + 'Current IPv6 state'] = eles.text + + def get_intf_statistics_info(self, stat_info, intf_name): + """Get interface statistics information""" + + if not intf_name: + return + + if_type = get_interface_type(intf_name) + if if_type == 'fcoe-port' or if_type == 'nve' or if_type == 'tunnel' or \ + if_type == 'vbdif' or if_type == 'vlanif': + return + + if stat_info: + for eles in stat_info: + if eles.tag in ["receiveByte", "sendByte", "rcvUniPacket", "rcvMutiPacket", "rcvBroadPacket", + "sendUniPacket", "sendMutiPacket", "sendBroadPacket", "rcvErrorPacket", + "rcvDropPacket", "sendErrorPacket", "sendDropPacket"]: + if eles.tag == "receiveByte": + self.result[intf_name][ + 'Inbound octets(bytes)'] = eles.text + elif eles.tag == "rcvUniPacket": + self.result[intf_name][ + 'Inbound unicast(pkts)'] = eles.text + elif eles.tag == "rcvMutiPacket": + self.result[intf_name][ + 'Inbound multicast(pkts)'] = eles.text + elif eles.tag == "rcvBroadPacket": + self.result[intf_name][ + 'Inbound broadcast(pkts)'] = eles.text + elif eles.tag == "rcvErrorPacket": + self.result[intf_name][ + 'Inbound error(pkts)'] = eles.text + elif eles.tag == "rcvDropPacket": + self.result[intf_name][ + 'Inbound drop(pkts)'] = eles.text + elif eles.tag == "sendByte": + self.result[intf_name][ + 'Outbound octets(bytes)'] = eles.text + elif eles.tag == "sendUniPacket": + self.result[intf_name][ + 'Outbound unicast(pkts)'] = eles.text + elif eles.tag == "sendMutiPacket": + self.result[intf_name][ + 'Outbound multicast(pkts)'] = eles.text + elif eles.tag == "sendBroadPacket": + self.result[intf_name][ + 'Outbound broadcast(pkts)'] = eles.text + elif eles.tag == "sendErrorPacket": + self.result[intf_name][ + 'Outbound error(pkts)'] = eles.text + elif eles.tag == "sendDropPacket": + self.result[intf_name][ + 'Outbound drop(pkts)'] = eles.text + + def get_intf_cleared_stat(self, clr_stat, intf_name): + """Get interface cleared state information""" + + if not intf_name: + return + + if_type = get_interface_type(intf_name) + if if_type == 'fcoe-port' or if_type == 'nve' or if_type == 'tunnel' or \ + if_type == 'vbdif' or if_type == 'vlanif': + return + + if clr_stat: + for eles in clr_stat: + if eles.tag in ["inByteRate", "inPacketRate", "outByteRate", "outPacketRate"]: + if eles.tag == "inByteRate": + self.result[intf_name][ + 'Inbound rate(byte/sec)'] = eles.text + elif eles.tag == "inPacketRate": + self.result[intf_name][ + 'Inbound rate(pkts/sec)'] = eles.text + elif eles.tag == "outByteRate": + self.result[intf_name][ + 'Outbound rate(byte/sec)'] = eles.text + elif eles.tag == "outPacketRate": + self.result[intf_name][ + 'Outbound rate(pkts/sec)'] = eles.text + + def get_all_interface_info(self, intf_type=None): + """Get interface information all or by interface type""" + + xml_str = CE_NC_GET_INT_STATISTICS % '' + con_obj = get_nc_config(self.module, xml_str) + if "" in con_obj: + return + + xml_str = con_obj.replace('\r', '').replace('\n', '').\ + replace('xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"', "").\ + replace('xmlns="http://www.huawei.com/netconf/vrp"', "") + + # get link status information + root = ElementTree.fromstring(xml_str) + intfs_info = root.find("data/ifm/interfaces") + if not intfs_info: + return + + intf_name = '' + flag = False + for eles in intfs_info: + if eles.tag == "interface": + for ele in eles: + if ele.tag in ["ifName", "ifDynamicInfo", "ifStatistics", "ifClearedStat"]: + if ele.tag == "ifName": + intf_name = ele.text.lower() + if intf_type: + if get_interface_type(intf_name) != intf_type.lower(): + break + else: + flag = True + self.init_interface_data(intf_name) + if is_ethernet_port(intf_name): + self.get_port_info(intf_name) + if ele.tag == "ifDynamicInfo": + self.get_intf_dynamic_info(ele, intf_name) + elif ele.tag == "ifStatistics": + self.get_intf_statistics_info(ele, intf_name) + elif ele.tag == "ifClearedStat": + self.get_intf_cleared_stat(ele, intf_name) + if intf_type and not flag: + self.module.fail_json( + msg='Error: %s interface type does not exist.' % intf_type.upper()) + + def get_interface_info(self): + """Get interface information""" + + xml_str = CE_NC_GET_INT_STATISTICS % self.interface.upper() + con_obj = get_nc_config(self.module, xml_str) + if "" in con_obj: + self.module.fail_json( + msg='Error: %s interface does not exist.' % self.interface.upper()) + return + + xml_str = con_obj.replace('\r', '').replace('\n', '').\ + replace('xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"', "").\ + replace('xmlns="http://www.huawei.com/netconf/vrp"', "") + + # get link status information + root = ElementTree.fromstring(xml_str) + intf_info = root.find("data/ifm/interfaces/interface") + if intf_info: + for eles in intf_info: + if eles.tag in ["ifDynamicInfo", "ifStatistics", "ifClearedStat"]: + if eles.tag == "ifDynamicInfo": + self.get_intf_dynamic_info(eles, self.interface) + elif eles.tag == "ifStatistics": + self.get_intf_statistics_info(eles, self.interface) + elif eles.tag == "ifClearedStat": + self.get_intf_cleared_stat(eles, self.interface) + + def init_interface_data(self, intf_name): + """Init interface data""" + + # init link status data + self.result[intf_name] = dict() + self.result[intf_name]['Current physical state'] = 'down' + self.result[intf_name]['Current link state'] = 'down' + self.result[intf_name]['Current IPv4 state'] = 'down' + self.result[intf_name]['Current IPv6 state'] = 'down' + self.result[intf_name]['Inbound octets(bytes)'] = '--' + self.result[intf_name]['Inbound unicast(pkts)'] = '--' + self.result[intf_name]['Inbound multicast(pkts)'] = '--' + self.result[intf_name]['Inbound broadcast(pkts)'] = '--' + self.result[intf_name]['Inbound error(pkts)'] = '--' + self.result[intf_name]['Inbound drop(pkts)'] = '--' + self.result[intf_name]['Inbound rate(byte/sec)'] = '--' + self.result[intf_name]['Inbound rate(pkts/sec)'] = '--' + self.result[intf_name]['Outbound octets(bytes)'] = '--' + self.result[intf_name]['Outbound unicast(pkts)'] = '--' + self.result[intf_name]['Outbound multicast(pkts)'] = '--' + self.result[intf_name]['Outbound broadcast(pkts)'] = '--' + self.result[intf_name]['Outbound error(pkts)'] = '--' + self.result[intf_name]['Outbound drop(pkts)'] = '--' + self.result[intf_name]['Outbound rate(byte/sec)'] = '--' + self.result[intf_name]['Outbound rate(pkts/sec)'] = '--' + self.result[intf_name]['Speed'] = '--' + + def get_port_info(self, interface): + """Get port information""" + + if_type = get_interface_type(interface) + if if_type == 'meth': + xml_str = CE_NC_GET_PORT_SPEED % interface.lower().replace('meth', 'MEth') + else: + xml_str = CE_NC_GET_PORT_SPEED % interface.upper() + con_obj = get_nc_config(self.module, xml_str) + if "" in con_obj: + return + + xml_str = con_obj.replace('\r', '').replace('\n', '').\ + replace('xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"', "").\ + replace('xmlns="http://www.huawei.com/netconf/vrp"', "") + + # get link status information + root = ElementTree.fromstring(xml_str) + port_info = root.find("data/devm/ports/port") + if port_info: + for eles in port_info: + if eles.tag == "ethernetPort": + for ele in eles: + if ele.tag == 'speed': + self.result[interface]['Speed'] = ele.text + + def get_link_status(self): + """Get link status information""" + + if self.param_type == INTERFACE_FULL_NAME: + self.init_interface_data(self.interface) + self.get_interface_info() + if is_ethernet_port(self.interface): + self.get_port_info(self.interface) + elif self.param_type == INTERFACE_TYPE: + self.get_all_interface_info(self.interface) + else: + self.get_all_interface_info() + + def get_intf_param_type(self): + """Get the type of input interface parameter""" + + if self.interface == 'all': + self.param_type = INTERFACE_ALL + return + + if self.if_type == self.interface: + self.param_type = INTERFACE_TYPE + return + + self.param_type = INTERFACE_FULL_NAME + + def work(self): + """Worker""" + + self.if_type = get_interface_type(self.interface) + self.check_params() + self.get_intf_param_type() + self.get_link_status() + self.show_result() + + +def main(): + """Main function entry""" + + argument_spec = dict( + interface=dict(required=True, type='str'), + ) + argument_spec.update(ce_argument_spec) + linkstatus_obj = LinkStatus(argument_spec) + linkstatus_obj.work() + + +if __name__ == '__main__': + main()