diff --git a/netbox_agent/ethtool.py b/netbox_agent/ethtool.py index 46b55ad..ae78fda 100644 --- a/netbox_agent/ethtool.py +++ b/netbox_agent/ethtool.py @@ -1,7 +1,8 @@ # 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', +field_map = { + 'Supported ports': 'ports', 'Supported link modes': 'sup_link_modes', 'Supports auto-negotiation': 'sup_autoneg', 'Advertised link modes': 'adv_link_modes', @@ -13,28 +14,29 @@ field_map = { 'Supported ports': 'ports', 'Link detected': 'link', } + def parse_ethtool_output(data): - """parse ethtool output""" + """ + parse ethtool output + """ fields = {} - field = "" - fields['speed'] = "-" - fields['link'] = "-" + field = '' + fields['speed'] = '-' + fields['link'] = '-' fields['duplex'] = '-' for line in data.split('\n')[1:]: line = line.rstrip() - r = line.find(':') - #verbose(" line=|%s|", line) + r = line.find(':') if r > 0: field = line[:r].strip() if field not in field_map: continue field = field_map[field] - data = line[r+1:].strip() + 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() + fields[field] += ' ' + line.strip() return fields diff --git a/netbox_agent/network.py b/netbox_agent/network.py index e26888e..c9ffd14 100644 --- a/netbox_agent/network.py +++ b/netbox_agent/network.py @@ -1,21 +1,31 @@ import os import re -import socket import subprocess +from netaddr import IPAddress import netifaces -from netbox_agent.ethtool import parse_ethtool_output from netbox_agent.config import netbox_instance as nb +from netbox_agent.ethtool import parse_ethtool_output # 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])$') +# FIXME: finish mapping tabble +ETHTOOL_TO_NETBOX_TYPE = { + 1200: 'SFP+ (10GE)', + 1150: '10g baseT', + 1000: '1G cuivre', + 1400: '40G', + } + + class Network(): - def __init__(self, *args, **kwargs): + def __init__(self, server, *args, **kwargs): self.nics = [] + self.server = server self.scan() def _ethtool_for_interface(self, interface): @@ -30,7 +40,10 @@ class Network(): 'name': interface, 'mac': open('/sys/class/net/{}/address'.format(interface), 'r').read().strip(), 'ip': [ - x['addr'] for x in ip_addr + '{}/{}'.format( + x['addr'], + IPAddress(x['netmask']).netmask_bits() + ) for x in ip_addr ] if ip_addr else None, # FIXME: handle IPv6 addresses 'ethtool': self._ethtool_for_interface(interface) } @@ -39,13 +52,40 @@ class Network(): 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 + device = self.server.get_netbox_server() + for nic in self.nics: + interface = nb.dcim.interfaces.get( + device=device, + mac_address=nic['mac'], + ) + # if network doesn't exist we create it + if not interface: + new_interface = nb.dcim.interfaces.create( + device=device.id, + name=nic['name'], + mac_address=nic['mac'], + ) + if nic['ip']: + # for each ip, we try to find it + # assign the device's interface to it + # or simply create it + for ip in nic['ip']: + netbox_ip = nb.ipam.ip_addresses.get( + address=ip, + ) + if netbox_ip: + netbox_ip.interface = new_interface + netbox_ip.save() + else: + netbox_ip = nb.ipam.ip_addresses.create( + address=ip, + interface=new_interface.id, + status=1, + ) + # or we check if it needs update + else: + # FIXME: implement update + # update name or ip + # see https://github.com/Solvik/netbox_agent/issues/9 + pass diff --git a/netbox_agent/server.py b/netbox_agent/server.py index bce9e62..fb67bb8 100644 --- a/netbox_agent/server.py +++ b/netbox_agent/server.py @@ -1,9 +1,11 @@ from pprint import pprint +import socket from netbox_agent.config import netbox_instance as nb import netbox_agent.dmidecode as dmidecode from netbox_agent.network import Network + class ServerBase(): def __init__(self, dmi=None): if dmi: @@ -13,7 +15,7 @@ class ServerBase(): self.system = self.dmi.get_by_type('System') self.bios = self.dmi.get_by_type('BIOS') - self.network = Network(service_tag=self.get_service_tag()) + self.network = Network(server=self) def get_product_name(self): """ @@ -110,6 +112,9 @@ class ServerBase(): ) return new_server + def get_netbox_server(self): + return nb.dcim.devices.get(serial=self.get_service_tag()) + def netbox_create(self): if self.is_blade(): # let's find the blade @@ -139,6 +144,8 @@ class ServerBase(): if not server: self._netbox_create_server() + self.network.update_netbox_network_cards() + def print_debug(self): # FIXME: do something more generic by looping on every get_* methods print('Datacenter:', self.get_datacenter()) diff --git a/requirements.txt b/requirements.txt index 0e602b2..6b76e04 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1 +1,3 @@ pynetbox >= 4.0 +netaddr >= 0.7 +netifaces >= 0.10