From 1063ec63e00bb9d5308d3fcfc226e1b7ba75ea98 Mon Sep 17 00:00:00 2001 From: Solvik Blum Date: Sun, 4 Aug 2019 14:37:51 +0200 Subject: [PATCH] WIP - handle network --- netbox_agent/ethtool.py | 40 ++++++++++++++++++++++++++++++++ netbox_agent/network.py | 51 +++++++++++++++++++++++++++++++++++++++++ netbox_agent/server.py | 27 +++++----------------- 3 files changed, 97 insertions(+), 21 deletions(-) create mode 100644 netbox_agent/ethtool.py create mode 100644 netbox_agent/network.py diff --git a/netbox_agent/ethtool.py b/netbox_agent/ethtool.py new file mode 100644 index 0000000..46b55ad --- /dev/null +++ b/netbox_agent/ethtool.py @@ -0,0 +1,40 @@ +# Originally from https://github.com/opencoff/useful-scripts/blob/master/linktest.py + +# mapping fields from ethtool output to simple names +field_map = { 'Supported ports': 'ports', + 'Supported link modes': 'sup_link_modes', + 'Supports auto-negotiation': 'sup_autoneg', + 'Advertised link modes': 'adv_link_modes', + 'Advertised auto-negotiation': 'adv_autoneg', + 'Speed': 'speed', + 'Duplex': 'duplex', + 'Port': 'port', + 'Auto-negotiation': 'autoneg', + 'Link detected': 'link', +} + +def parse_ethtool_output(data): + """parse ethtool output""" + + fields = {} + field = "" + fields['speed'] = "-" + fields['link'] = "-" + fields['duplex'] = '-' + for line in data.split('\n')[1:]: + line = line.rstrip() + r = line.find(':') + #verbose(" line=|%s|", line) + if r > 0: + field = line[:r].strip() + if field not in field_map: + continue + field = field_map[field] + data = line[r+1:].strip() + fields[field] = data + #verbose(" %s=%s", field, data) + else: + if len(field) > 0 and \ + field in field_map.keys(): + fields[field] += ' ' + line.strip() + return fields diff --git a/netbox_agent/network.py b/netbox_agent/network.py new file mode 100644 index 0000000..e26888e --- /dev/null +++ b/netbox_agent/network.py @@ -0,0 +1,51 @@ +import os +import re +import socket +import subprocess + +import netifaces + +from netbox_agent.ethtool import parse_ethtool_output +from netbox_agent.config import netbox_instance as nb + +# Regex to match base interface name +# Doesn't match vlan interfaces and other loopback etc +INTERFACE_REGEX = re.compile('^(eth[0-9]+|ens[0-9]+|enp[0-9]+s[0-9]f[0-9])$') + +class Network(): + def __init__(self, *args, **kwargs): + self.nics = [] + + self.scan() + + def _ethtool_for_interface(self, interface): + output = subprocess.getoutput('ethtool {}'.format(interface)) + return parse_ethtool_output(output) + + def scan(self): + for interface in os.listdir('/sys/class/net/'): + if re.match(INTERFACE_REGEX, interface): + ip_addr = netifaces.ifaddresses(interface).get(netifaces.AF_INET) + nic = { + 'name': interface, + 'mac': open('/sys/class/net/{}/address'.format(interface), 'r').read().strip(), + 'ip': [ + x['addr'] for x in ip_addr + ] if ip_addr else None, # FIXME: handle IPv6 addresses + 'ethtool': self._ethtool_for_interface(interface) + } + self.nics.append(nic) + + def get_network_cards(self): + return self.nics + + def get_netbox_network_cards(self): + pass + + def update_netbox_network_cards(self): + # if network doesn't exist we create it + if True: + pass + # or we check if it needs update + else: + pass diff --git a/netbox_agent/server.py b/netbox_agent/server.py index 3677ca1..bce9e62 100644 --- a/netbox_agent/server.py +++ b/netbox_agent/server.py @@ -1,14 +1,8 @@ -import os -import re -import socket +from pprint import pprint from netbox_agent.config import netbox_instance as nb import netbox_agent.dmidecode as dmidecode - -# Regex to match base interface name -# Doesn't match vlan interfaces and other loopback etc -INTERFACE_REGEX = re.compile('^(eth[0-9]+|ens[0-9]+|enp[0-9]+s[0-9]f[0-9])$') - +from netbox_agent.network import Network class ServerBase(): def __init__(self, dmi=None): @@ -19,7 +13,7 @@ class ServerBase(): self.system = self.dmi.get_by_type('System') self.bios = self.dmi.get_by_type('BIOS') - self.network_cards = [] + self.network = Network(service_tag=self.get_service_tag()) def get_product_name(self): """ @@ -54,18 +48,6 @@ class ServerBase(): def get_bios_release_date(self): raise NotImplementedError - def get_network_cards(self): - nics = [] - for interface in os.listdir('/sys/class/net/'): - if re.match(INTERFACE_REGEX, interface): - nic = { - 'name': interface, - 'mac': open('/sys/class/net/{}/address'.format(interface), 'r').read().strip(), - 'ip': None, # FIXME - } - nics.append(nic) - return nics - def _netbox_create_blade_chassis(self): device_type = nb.dcim.device_types.get( model=self.get_chassis(), @@ -166,3 +148,6 @@ class ServerBase(): print('Chassis:', self.get_chassis()) print('Chassis service tag:', self.get_chassis_service_tag()) print('Service tag:', self.get_service_tag()) + print('NIC:',) + pprint(self.network.get_network_cards()) + pass