2019-08-07 10:32:23 +02:00
|
|
|
import logging
|
2019-08-04 14:37:51 +02:00
|
|
|
from pprint import pprint
|
2019-08-04 15:14:36 +02:00
|
|
|
import socket
|
2019-09-12 11:15:12 +02:00
|
|
|
import subprocess
|
2019-08-04 00:00:22 +02:00
|
|
|
|
2019-09-12 11:15:12 +02:00
|
|
|
from netbox_agent.config import netbox_instance as nb, config
|
2019-08-04 00:00:22 +02:00
|
|
|
import netbox_agent.dmidecode as dmidecode
|
2019-08-05 11:54:06 +02:00
|
|
|
from netbox_agent.location import Datacenter, Rack
|
2019-08-26 16:54:48 +02:00
|
|
|
from netbox_agent.inventory import Inventory
|
2019-08-04 14:37:51 +02:00
|
|
|
from netbox_agent.network import Network
|
2019-09-05 13:47:10 +02:00
|
|
|
from netbox_agent.power import PowerSupply
|
2019-08-04 00:00:22 +02:00
|
|
|
|
2019-08-04 15:14:36 +02:00
|
|
|
|
2019-08-02 18:39:05 +02:00
|
|
|
class ServerBase():
|
|
|
|
def __init__(self, dmi=None):
|
|
|
|
if dmi:
|
|
|
|
self.dmi = dmi
|
|
|
|
else:
|
2019-08-03 15:46:21 +02:00
|
|
|
self.dmi = dmidecode.parse()
|
2019-09-05 15:13:36 +02:00
|
|
|
|
|
|
|
self.baseboard = self.dmi.get_by_type('Baseboard')
|
2019-08-03 15:46:21 +02:00
|
|
|
self.bios = self.dmi.get_by_type('BIOS')
|
2019-09-05 15:13:36 +02:00
|
|
|
self.chassis = self.dmi.get_by_type('Chassis')
|
|
|
|
self.system = self.dmi.get_by_type('System')
|
2019-08-02 18:39:05 +02:00
|
|
|
|
2019-08-09 12:08:11 +02:00
|
|
|
self.network = None
|
2019-08-02 18:39:05 +02:00
|
|
|
|
2019-08-04 01:11:53 +02:00
|
|
|
def get_datacenter(self):
|
|
|
|
dc = Datacenter()
|
2019-08-04 19:33:09 +02:00
|
|
|
return dc.get()
|
2019-08-04 01:11:53 +02:00
|
|
|
|
|
|
|
def get_netbox_datacenter(self):
|
|
|
|
datacenter = nb.dcim.sites.get(
|
2019-08-04 19:33:09 +02:00
|
|
|
slug=self.get_datacenter()
|
2019-08-04 01:11:53 +02:00
|
|
|
)
|
|
|
|
return datacenter
|
|
|
|
|
2019-09-03 13:16:37 +02:00
|
|
|
def update_netbox_location(self, server):
|
|
|
|
dc = self.get_datacenter()
|
|
|
|
rack = self.get_rack()
|
|
|
|
nb_rack = self.get_netbox_rack()
|
|
|
|
nb_dc = self.get_netbox_datacenter()
|
|
|
|
|
|
|
|
update = False
|
2019-09-12 17:47:41 +02:00
|
|
|
if dc and server.site and server.site.slug != nb_dc.slug:
|
2019-09-03 13:16:37 +02:00
|
|
|
logging.info('Datacenter location has changed from {} to {}, updating'.format(
|
|
|
|
server.site.slug,
|
|
|
|
nb_dc.slug,
|
|
|
|
))
|
|
|
|
update = True
|
|
|
|
server.site = nb_dc.id
|
|
|
|
|
2019-09-12 17:47:41 +02:00
|
|
|
if rack and server.rack and server.rack.id != nb_rack.id:
|
2019-09-03 13:16:37 +02:00
|
|
|
logging.info('Rack location has changed from {} to {}, updating'.format(
|
|
|
|
server.rack,
|
|
|
|
nb_rack,
|
|
|
|
))
|
|
|
|
update = True
|
|
|
|
server.rack = nb_rack
|
|
|
|
if nb_rack is None:
|
|
|
|
server.face = None
|
|
|
|
server.position = None
|
|
|
|
return update, server
|
|
|
|
|
2019-08-05 11:54:06 +02:00
|
|
|
def get_rack(self):
|
|
|
|
rack = Rack()
|
|
|
|
return rack.get()
|
|
|
|
|
|
|
|
def get_netbox_rack(self):
|
|
|
|
rack = nb.dcim.racks.get(
|
|
|
|
name=self.get_rack(),
|
2019-09-11 17:35:27 +02:00
|
|
|
site_id=self.get_netbox_datacenter().id,
|
2019-08-05 11:54:06 +02:00
|
|
|
)
|
|
|
|
return rack
|
|
|
|
|
2019-08-02 18:39:05 +02:00
|
|
|
def get_product_name(self):
|
2019-08-04 00:00:22 +02:00
|
|
|
"""
|
2019-08-02 18:39:05 +02:00
|
|
|
Return the Chassis Name from dmidecode info
|
2019-08-04 00:00:22 +02:00
|
|
|
"""
|
2019-09-10 14:46:04 +02:00
|
|
|
return self.system[0]['Product Name'].strip()
|
2019-08-02 18:39:05 +02:00
|
|
|
|
|
|
|
def get_service_tag(self):
|
2019-08-04 00:00:22 +02:00
|
|
|
"""
|
2019-08-02 18:39:05 +02:00
|
|
|
Return the Service Tag from dmidecode info
|
2019-08-04 00:00:22 +02:00
|
|
|
"""
|
2019-08-14 11:17:24 +02:00
|
|
|
return self.system[0]['Serial Number'].strip()
|
2019-08-02 18:39:05 +02:00
|
|
|
|
2019-08-05 16:03:35 +02:00
|
|
|
def get_hostname(self):
|
2019-09-12 11:15:12 +02:00
|
|
|
if config.hostname_cmd is None:
|
|
|
|
return '{}'.format(socket.gethostname())
|
|
|
|
return subprocess.getoutput(config.hostname_cmd)
|
2019-08-05 16:03:35 +02:00
|
|
|
|
2019-08-02 18:39:05 +02:00
|
|
|
def is_blade(self):
|
|
|
|
raise NotImplementedError
|
|
|
|
|
|
|
|
def get_blade_slot(self):
|
|
|
|
raise NotImplementedError
|
|
|
|
|
|
|
|
def get_chassis(self):
|
|
|
|
raise NotImplementedError
|
|
|
|
|
2019-08-08 14:37:02 +02:00
|
|
|
def get_chassis_name(self):
|
|
|
|
raise NotImplementedError
|
|
|
|
|
2019-08-02 18:39:05 +02:00
|
|
|
def get_chassis_service_tag(self):
|
|
|
|
raise NotImplementedError
|
|
|
|
|
|
|
|
def get_bios_version(self):
|
|
|
|
raise NotImplementedError
|
|
|
|
|
|
|
|
def get_bios_version_attr(self):
|
|
|
|
raise NotImplementedError
|
|
|
|
|
|
|
|
def get_bios_release_date(self):
|
|
|
|
raise NotImplementedError
|
|
|
|
|
2019-09-05 13:47:10 +02:00
|
|
|
def get_power_consumption(self):
|
|
|
|
raise NotImplementedError
|
|
|
|
|
2019-08-14 11:17:24 +02:00
|
|
|
def _netbox_create_blade_chassis(self, datacenter, rack):
|
2019-08-03 15:46:21 +02:00
|
|
|
device_type = nb.dcim.device_types.get(
|
|
|
|
model=self.get_chassis(),
|
|
|
|
)
|
|
|
|
if not device_type:
|
2019-08-06 17:59:46 +02:00
|
|
|
error_msg = 'Chassis "{}" doesn\'t exist'.format(self.get_chassis())
|
2019-08-07 10:32:23 +02:00
|
|
|
logging.error(error_msg)
|
2019-08-06 17:59:46 +02:00
|
|
|
raise Exception(error_msg)
|
2019-08-03 15:46:21 +02:00
|
|
|
device_role = nb.dcim.device_roles.get(
|
|
|
|
name='Server Chassis',
|
|
|
|
)
|
2019-08-06 17:59:46 +02:00
|
|
|
serial = self.get_chassis_service_tag()
|
2019-08-07 10:32:23 +02:00
|
|
|
logging.info('Creating chassis blade (serial: {serial})'.format(
|
2019-08-06 17:59:46 +02:00
|
|
|
serial=serial))
|
2019-08-03 15:46:21 +02:00
|
|
|
new_chassis = nb.dcim.devices.create(
|
2019-08-08 14:37:02 +02:00
|
|
|
name=self.get_chassis_name(),
|
2019-08-03 15:46:21 +02:00
|
|
|
device_type=device_type.id,
|
2019-08-06 17:59:46 +02:00
|
|
|
serial=serial,
|
2019-08-03 15:46:21 +02:00
|
|
|
device_role=device_role.id,
|
2019-08-04 01:11:53 +02:00
|
|
|
site=datacenter.id if datacenter else None,
|
2019-08-14 11:17:24 +02:00
|
|
|
rack=rack.id if rack else None,
|
2019-08-03 15:46:21 +02:00
|
|
|
)
|
|
|
|
return new_chassis
|
|
|
|
|
2019-08-14 11:17:24 +02:00
|
|
|
def _netbox_create_blade(self, chassis, datacenter, rack):
|
2019-08-03 15:46:21 +02:00
|
|
|
device_role = nb.dcim.device_roles.get(
|
|
|
|
name='Blade',
|
|
|
|
)
|
|
|
|
device_type = nb.dcim.device_types.get(
|
|
|
|
model=self.get_product_name(),
|
|
|
|
)
|
2019-08-06 17:59:46 +02:00
|
|
|
serial = self.get_service_tag()
|
|
|
|
hostname = self.get_hostname()
|
2019-08-07 10:32:23 +02:00
|
|
|
logging.info(
|
2019-08-06 17:59:46 +02:00
|
|
|
'Creating blade (serial: {serial}) {hostname} on chassis {chassis_serial}'.format(
|
|
|
|
serial=serial, hostname=hostname, chassis_serial=chassis.serial
|
|
|
|
))
|
2019-08-03 15:46:21 +02:00
|
|
|
new_blade = nb.dcim.devices.create(
|
2019-08-06 17:59:46 +02:00
|
|
|
name=hostname,
|
|
|
|
serial=serial,
|
2019-08-03 15:46:21 +02:00
|
|
|
device_role=device_role.id,
|
|
|
|
device_type=device_type.id,
|
|
|
|
parent_device=chassis.id,
|
2019-08-04 01:11:53 +02:00
|
|
|
site=datacenter.id if datacenter else None,
|
2019-08-14 11:17:24 +02:00
|
|
|
rack=rack.id if rack else None,
|
2019-08-03 15:46:21 +02:00
|
|
|
)
|
|
|
|
return new_blade
|
|
|
|
|
2019-08-08 14:37:02 +02:00
|
|
|
def _netbox_set_blade_slot(self, chassis, server):
|
|
|
|
slot = self.get_blade_slot()
|
|
|
|
# Find the slot and update it with our blade
|
|
|
|
device_bays = nb.dcim.device_bays.filter(
|
|
|
|
device_id=chassis.id,
|
|
|
|
name=slot,
|
|
|
|
)
|
|
|
|
if len(device_bays) > 0:
|
|
|
|
logging.info(
|
|
|
|
'Setting device ({serial}) new slot on {slot} '
|
|
|
|
'(Chassis {chassis_serial})..'.format(
|
|
|
|
serial=server.serial, slot=slot, chassis_serial=chassis.serial
|
|
|
|
))
|
|
|
|
device_bay = device_bays[0]
|
|
|
|
device_bay.installed_device = server
|
|
|
|
device_bay.save()
|
|
|
|
else:
|
|
|
|
logging.error('Could not find slot {slot} for chassis'.format(
|
|
|
|
slot=slot
|
|
|
|
))
|
|
|
|
|
2019-08-14 11:17:24 +02:00
|
|
|
def _netbox_create_server(self, datacenter, rack):
|
2019-08-03 15:57:06 +02:00
|
|
|
device_role = nb.dcim.device_roles.get(
|
|
|
|
name='Server',
|
|
|
|
)
|
|
|
|
device_type = nb.dcim.device_types.get(
|
|
|
|
model=self.get_product_name(),
|
|
|
|
)
|
|
|
|
if not device_type:
|
|
|
|
raise Exception('Chassis "{}" doesn\'t exist'.format(self.get_chassis()))
|
2019-08-06 17:59:46 +02:00
|
|
|
serial = self.get_service_tag()
|
|
|
|
hostname = self.get_hostname()
|
2019-08-07 10:32:23 +02:00
|
|
|
logging.info('Creating server (serial: {serial}) {hostname}'.format(
|
2019-08-06 17:59:46 +02:00
|
|
|
serial=serial, hostname=hostname))
|
2019-08-03 15:57:06 +02:00
|
|
|
new_server = nb.dcim.devices.create(
|
2019-08-06 17:59:46 +02:00
|
|
|
name=hostname,
|
|
|
|
serial=serial,
|
2019-08-03 15:57:06 +02:00
|
|
|
device_role=device_role.id,
|
|
|
|
device_type=device_type.id,
|
2019-08-04 01:11:53 +02:00
|
|
|
site=datacenter.id if datacenter else None,
|
2019-08-14 11:17:24 +02:00
|
|
|
rack=rack.id if rack else None,
|
2019-08-03 15:57:06 +02:00
|
|
|
)
|
|
|
|
return new_server
|
|
|
|
|
2019-08-04 15:14:36 +02:00
|
|
|
def get_netbox_server(self):
|
|
|
|
return nb.dcim.devices.get(serial=self.get_service_tag())
|
|
|
|
|
2019-09-03 13:16:37 +02:00
|
|
|
def netbox_create(self, config):
|
2019-08-07 10:32:23 +02:00
|
|
|
logging.debug('Creating Server..')
|
2019-08-04 01:11:53 +02:00
|
|
|
datacenter = self.get_netbox_datacenter()
|
2019-08-14 11:17:24 +02:00
|
|
|
rack = self.get_netbox_rack()
|
2019-08-03 15:46:21 +02:00
|
|
|
if self.is_blade():
|
|
|
|
# let's find the blade
|
2019-08-06 17:59:46 +02:00
|
|
|
serial = self.get_service_tag()
|
|
|
|
blade = nb.dcim.devices.get(serial=serial)
|
2019-08-03 15:46:21 +02:00
|
|
|
chassis = nb.dcim.devices.get(serial=self.get_chassis_service_tag())
|
|
|
|
# if it doesn't exist, create it
|
|
|
|
if not blade:
|
|
|
|
# check if the chassis exist before
|
|
|
|
# if it doesn't exist, create it
|
2019-08-05 16:03:35 +02:00
|
|
|
chassis = nb.dcim.devices.get(
|
|
|
|
serial=self.get_chassis_service_tag()
|
|
|
|
)
|
2019-08-03 15:46:21 +02:00
|
|
|
if not chassis:
|
2019-08-14 11:17:24 +02:00
|
|
|
chassis = self._netbox_create_blade_chassis(datacenter, rack)
|
2019-08-03 15:46:21 +02:00
|
|
|
|
2019-08-14 11:17:24 +02:00
|
|
|
blade = self._netbox_create_blade(chassis, datacenter, rack)
|
2019-08-03 15:46:21 +02:00
|
|
|
|
2019-08-08 14:37:02 +02:00
|
|
|
# Set slot for blade
|
2019-08-08 14:46:06 +02:00
|
|
|
self._netbox_set_blade_slot(chassis, blade)
|
2019-08-03 15:46:21 +02:00
|
|
|
else:
|
2019-08-03 15:57:06 +02:00
|
|
|
server = nb.dcim.devices.get(serial=self.get_service_tag())
|
|
|
|
if not server:
|
2019-08-14 11:17:24 +02:00
|
|
|
self._netbox_create_server(datacenter, rack)
|
2019-08-04 00:00:22 +02:00
|
|
|
|
2019-08-09 12:08:11 +02:00
|
|
|
self.network = Network(server=self)
|
2019-08-05 16:51:01 +02:00
|
|
|
self.network.create_netbox_network_cards()
|
2019-09-05 13:47:10 +02:00
|
|
|
|
|
|
|
self.power = PowerSupply(server=self)
|
|
|
|
self.power.create_or_update_power_supply()
|
|
|
|
|
2019-09-03 13:16:37 +02:00
|
|
|
if config.inventory:
|
|
|
|
self.inventory = Inventory(server=self)
|
|
|
|
self.inventory.create()
|
2019-08-07 10:32:23 +02:00
|
|
|
logging.debug('Server created!')
|
2019-08-04 15:14:36 +02:00
|
|
|
|
2019-08-08 14:37:02 +02:00
|
|
|
def _netbox_update_chassis_for_blade(self, server, datacenter):
|
|
|
|
chassis = server.parent_device.device_bay.device
|
|
|
|
device_bay = nb.dcim.device_bays.get(
|
|
|
|
server.parent_device.device_bay.id
|
|
|
|
)
|
|
|
|
netbox_chassis_serial = server.parent_device.device_bay.device.serial
|
2019-08-08 14:46:06 +02:00
|
|
|
move_device_bay = False
|
2019-08-08 14:37:02 +02:00
|
|
|
|
|
|
|
# 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()
|
|
|
|
)
|
|
|
|
if not chassis:
|
|
|
|
chassis = self._netbox_create_blade_chassis(datacenter)
|
|
|
|
if move_device_bay or device_bay.name != self.get_blade_slot():
|
|
|
|
logging.info('Device ({serial}) seems to have moved, reseting old slot..'.format(
|
|
|
|
serial=server.serial))
|
|
|
|
device_bay.installed_device = None
|
|
|
|
device_bay.save()
|
|
|
|
|
|
|
|
# Set slot for blade
|
|
|
|
self._netbox_set_blade_slot(chassis, server)
|
|
|
|
|
2019-09-03 13:16:37 +02:00
|
|
|
def netbox_update(self, config):
|
2019-08-05 16:03:35 +02:00
|
|
|
"""
|
|
|
|
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
|
|
|
|
"""
|
2019-08-07 10:32:23 +02:00
|
|
|
logging.debug('Updating Server...')
|
2019-09-03 13:16:37 +02:00
|
|
|
|
2019-08-05 12:02:42 +02:00
|
|
|
server = nb.dcim.devices.get(serial=self.get_service_tag())
|
2019-08-05 16:03:35 +02:00
|
|
|
if not server:
|
|
|
|
raise Exception("The server (Serial: {}) isn't yet registered in Netbox, register"
|
2019-08-05 16:55:22 +02:00
|
|
|
'it before updating it'.format(self.get_service_tag()))
|
2019-09-03 13:16:37 +02:00
|
|
|
update = 0
|
2019-08-05 12:02:42 +02:00
|
|
|
if self.is_blade():
|
2019-08-08 14:37:02 +02:00
|
|
|
datacenter = self.get_netbox_datacenter()
|
|
|
|
# if it's already linked to a chassis
|
|
|
|
if server.parent_device:
|
|
|
|
self._netbox_update_chassis_for_blade(server, datacenter)
|
|
|
|
else:
|
|
|
|
logging.info('Blade is not in a chassis, fixing...')
|
2019-08-05 16:03:35 +02:00
|
|
|
chassis = nb.dcim.devices.get(
|
|
|
|
serial=self.get_chassis_service_tag()
|
|
|
|
)
|
|
|
|
if not chassis:
|
|
|
|
chassis = self._netbox_create_blade_chassis(datacenter)
|
2019-08-08 14:37:02 +02:00
|
|
|
# Set slot for blade
|
|
|
|
self._netbox_set_blade_slot(chassis, server)
|
2019-08-05 16:03:35 +02:00
|
|
|
|
2019-08-05 12:02:42 +02:00
|
|
|
# for every other specs
|
|
|
|
# check hostname
|
2019-08-05 16:03:35 +02:00
|
|
|
if server.name != self.get_hostname():
|
2019-09-03 13:16:37 +02:00
|
|
|
update += 1
|
2019-09-12 11:15:12 +02:00
|
|
|
server.name = self.get_hostname()
|
2019-09-03 13:16:37 +02:00
|
|
|
|
|
|
|
if config.update_all or config.update_location:
|
|
|
|
ret, server = self.update_netbox_location(server)
|
|
|
|
update += ret
|
|
|
|
|
2019-08-05 12:02:42 +02:00
|
|
|
# check network cards
|
2019-09-03 13:16:37 +02:00
|
|
|
if config.update_all or config.update_network:
|
|
|
|
self.network = Network(server=self)
|
|
|
|
self.network.update_netbox_network_cards()
|
2019-08-26 16:54:48 +02:00
|
|
|
# update inventory
|
2019-09-03 13:16:37 +02:00
|
|
|
if config.update_all or config.update_inventory:
|
|
|
|
self.inventory = Inventory(server=self)
|
|
|
|
self.inventory.update()
|
2019-09-05 13:47:10 +02:00
|
|
|
# update psu
|
|
|
|
if config.update_all or config.update_psu:
|
|
|
|
self.power = PowerSupply(server=self)
|
|
|
|
self.power.create_or_update_power_supply()
|
|
|
|
self.power.report_power_consumption()
|
2019-08-05 16:03:35 +02:00
|
|
|
if update:
|
|
|
|
server.save()
|
2019-08-07 10:32:23 +02:00
|
|
|
logging.debug('Finished updating Server!')
|
2019-08-04 15:14:36 +02:00
|
|
|
|
2019-08-04 00:00:22 +02:00
|
|
|
def print_debug(self):
|
2019-08-26 16:54:48 +02:00
|
|
|
self.network = Network(server=self)
|
2019-08-04 00:00:22 +02:00
|
|
|
print('Datacenter:', self.get_datacenter())
|
|
|
|
print('Netbox Datacenter:', self.get_netbox_datacenter())
|
2019-08-05 11:54:06 +02:00
|
|
|
print('Rack:', self.get_rack())
|
|
|
|
print('Netbox Rack:', self.get_netbox_rack())
|
2019-08-04 00:00:22 +02:00
|
|
|
print('Is blade:', self.is_blade())
|
|
|
|
print('Product Name:', self.get_product_name())
|
|
|
|
print('Chassis:', self.get_chassis())
|
|
|
|
print('Chassis service tag:', self.get_chassis_service_tag())
|
|
|
|
print('Service tag:', self.get_service_tag())
|
2019-08-04 14:37:51 +02:00
|
|
|
print('NIC:',)
|
|
|
|
pprint(self.network.get_network_cards())
|
|
|
|
pass
|