Contributing lib/ansible/modules/network/cloudengine/ce_link_status.py module to manage HUAWEI data center CloudEngine (#22053)

* add ce_link_status

add ce_link_status

* upgrade ce LinkStatus

* fix CI issues
This commit is contained in:
QijunPan 2017-05-26 00:31:17 +08:00 committed by John R Barker
parent 1359d39f9a
commit f89d12f26e

View file

@ -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 <http://www.gnu.org/licenses/>.
#
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 = """
<filter type="subtree">
<devm xmlns="http://www.huawei.com/netconf/vrp" content-version="1.0" format-version="1.0">
<ports>
<port>
<position>%s</position>
<ethernetPort>
<speed></speed>
</ethernetPort>
</port>
</ports>
</devm>
</filter>
"""
CE_NC_GET_INT_STATISTICS = """
<filter type="subtree">
<ifm xmlns="http://www.huawei.com/netconf/vrp" content-version="1.0" format-version="1.0">
<interfaces>
<interface>
<ifName>%s</ifName>
<ifDynamicInfo>
<ifPhyStatus></ifPhyStatus>
<ifLinkStatus></ifLinkStatus>
<ifV4State></ifV4State>
<ifV6State></ifV6State>
</ifDynamicInfo>
<ifStatistics>
<receiveByte></receiveByte>
<sendByte></sendByte>
<rcvUniPacket></rcvUniPacket>
<rcvMutiPacket></rcvMutiPacket>
<rcvBroadPacket></rcvBroadPacket>
<sendUniPacket></sendUniPacket>
<sendMutiPacket></sendMutiPacket>
<sendBroadPacket></sendBroadPacket>
<rcvErrorPacket></rcvErrorPacket>
<rcvDropPacket></rcvDropPacket>
<sendErrorPacket></sendErrorPacket>
<sendDropPacket></sendDropPacket>
</ifStatistics>
<ifClearedStat>
<inByteRate></inByteRate>
<inPacketRate></inPacketRate>
<outByteRate></outByteRate>
<outPacketRate></outPacketRate>
</ifClearedStat>
</interface>
</interfaces>
</ifm>
</filter>
"""
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 "<data/>" 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 "<data/>" 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 "<data/>" 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()