diff --git a/netbox_agent/cli.py b/netbox_agent/cli.py index c0498bf..6b29d80 100644 --- a/netbox_agent/cli.py +++ b/netbox_agent/cli.py @@ -18,14 +18,18 @@ def run(args): server.print_debug() if args.register: server.netbox_create() + if args.update: + server.netbox_update() return True def main(): parser = argparse.ArgumentParser(description='Netbox agent command line') - parser.add_argument('--register', action='store_true', + parser.add_argument('-r', '--register', action='store_true', help='Register server in Netbox') - parser.add_argument('--debug', action='store_true', + parser.add_argument('-u', '--update', action='store_true', + help='Update server in Netbox') + parser.add_argument('-d', '--debug', action='store_true', help='Print debug informations') args = parser.parse_args() diff --git a/netbox_agent/network.py b/netbox_agent/network.py index 38855ca..44e6efc 100644 --- a/netbox_agent/network.py +++ b/netbox_agent/network.py @@ -1,3 +1,4 @@ +from itertools import chain import os import re @@ -86,7 +87,7 @@ class Network(): type=self.get_netbox_type_for_nic(nic), ) - def update_netbox_network_cards(self): + def create_netbox_network_cards(self): device = self.server.get_netbox_server() for nic in self.nics: interface = nb.dcim.interfaces.get( @@ -112,9 +113,49 @@ class Network(): 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 + + def update_netbox_network_cards(self): + device = self.server.get_netbox_server() + + # delete IP on netbox that are not known on this server + netbox_ips = nb.ipam.ip_addresses.filter( + device=device + ) + all_local_ips = list(chain.from_iterable([ + x['ip'] for x in self.nics if x['ip'] is not None + ])) + for netbox_ip in netbox_ips: + if netbox_ip.address not in all_local_ips: + netbox_ip.interface = None + netbox_ip.save() + + # update each nic + for nic in self.nics: + interface = nb.dcim.interfaces.get( + mac_address=nic['mac'], + ) + + nic_update = False + if nic['name'] != interface.name: + nic_update = True + interface.name = nic['name'] + + if nic['ip']: + # sync local IPs + for ip in nic['ip']: + netbox_ip = nb.ipam.ip_addresses.get( + address=ip, + ) + if not netbox_ip: + # create netbbox_ip on device + netbox_ip = nb.ipam.ip_addresses.create( + address=ip, + interface=interface.id, + status=1, + ) + else: + if netbox_ip.device != device: + netbox_ip.device = device + netbox_ip.save() + if nic_update: + interface.save() diff --git a/netbox_agent/server.py b/netbox_agent/server.py index dabf866..b445664 100644 --- a/netbox_agent/server.py +++ b/netbox_agent/server.py @@ -2,6 +2,7 @@ from pprint import pprint import socket from netbox_agent.config import netbox_instance as nb + import netbox_agent.dmidecode as dmidecode from netbox_agent.location import Datacenter, Rack from netbox_agent.network import Network @@ -51,6 +52,9 @@ class ServerBase(): """ return self.system[0]['Serial Number'] + def get_hostname(self): + return '{}'.format(socket.gethostname()) + def is_blade(self): raise NotImplementedError @@ -98,7 +102,7 @@ class ServerBase(): model=self.get_product_name(), ) new_blade = nb.dcim.devices.create( - name='{}'.format(socket.gethostname()), + name=self.get_hostname(), serial=self.get_service_tag(), device_role=device_role.id, device_type=device_type.id, @@ -117,7 +121,7 @@ class ServerBase(): if not device_type: raise Exception('Chassis "{}" doesn\'t exist'.format(self.get_chassis())) new_server = nb.dcim.devices.create( - name='{}'.format(socket.gethostname()), + name=self.get_hostname(), serial=self.get_service_tag(), device_role=device_role.id, device_type=device_type.id, @@ -138,6 +142,9 @@ class ServerBase(): if not blade: # check if the chassis exist before # if it doesn't exist, create it + chassis = nb.dcim.devices.get( + serial=self.get_chassis_service_tag() + ) if not chassis: chassis = self._netbox_create_blade_chassis(datacenter) @@ -157,7 +164,66 @@ class ServerBase(): if not server: self._netbox_create_server() + self.network.create_netbox_network_cards() + + def netbox_update(self): + """ + Netbox method to update info about our server/blade + + Handle: + * new chasis for a blade + * new slot for a bblade + * hostname update + * new network infos + """ + server = nb.dcim.devices.get(serial=self.get_service_tag()) + if not server: + raise Exception("The server (Serial: {}) isn't yet registered in Netbox, register" + 'it before updating it'.format(self.get_service_tag())) + update = False + if self.is_blade(): + # get current chassis device bay + device_bay = nb.dcim.device_bays.get( + server.parent_device.device_bay.id + ) + netbox_chassis_serial = server.parent_device.device_bay.device.serial + chassis = server.parent_device.device_bay.device + move_device_bay = False + + # check chassis serial with dmidecode + if netbox_chassis_serial != self.get_chassis_service_tag(): + move_device_bay = True + # try to find the new netbox chassis + chassis = nb.dcim.devices.get( + serial=self.get_chassis_service_tag() + ) + # create the new chassis if it doesn't exist + if not chassis: + datacenter = self.get_netbox_datacenter() + chassis = self._netbox_create_blade_chassis(datacenter) + + if move_device_bay or device_bay.name != 'Blade {}'.format(self.get_blade_slot()): + device_bay.installed_device = None + device_bay.save() + # Find the slot and update it with our blade + device_bays = nb.dcim.device_bays.filter( + device_id=chassis.id, + name='Blade {}'.format(self.get_blade_slot()), + ) + if len(device_bays) > 0: + device_bay = device_bays[0] + device_bay.installed_device = server + device_bay.save() + + # for every other specs + # check hostname + if server.name != self.get_hostname(): + update = True + server.hostname = self.get_hostname() + # check network cards self.network.update_netbox_network_cards() + if update: + server.save() def print_debug(self): # FIXME: do something more generic by looping on every get_* methods