netbox-agent/netbox_agent/power.py

132 lines
4.4 KiB
Python
Raw Normal View History

2019-09-05 13:47:10 +02:00
import logging
import netbox_agent.dmidecode as dmidecode
2019-09-05 13:47:10 +02:00
from netbox_agent.config import netbox_instance as nb
PSU_DMI_TYPE = 39
class PowerSupply():
def __init__(self, server=None):
self.server = server
self.netbox_server = self.server.get_netbox_server()
if self.server.is_blade():
self.device_id = self.netbox_server.parent_device.id if self.netbox_server else None
else:
self.device_id = self.netbox_server.id if self.netbox_server else None
def get_power_supply(self):
power_supply = []
for psu in dmidecode.get_by_type(self.server.dmi, PSU_DMI_TYPE):
2019-09-11 10:37:31 +02:00
if 'Present' not in psu['Status'] or psu['Status'] == 'Not Present':
2019-09-05 13:47:10 +02:00
continue
2019-09-10 14:48:16 +02:00
try:
max_power = int(psu.get('Max Power Capacity').split()[0])
except ValueError:
max_power = None
2019-09-05 13:47:10 +02:00
desc = '{} - {}'.format(
psu.get('Manufacturer', 'No Manufacturer').strip(),
psu.get('Name', 'No name').strip(),
)
2020-05-20 16:12:47 +02:00
sn = psu.get('Serial Number', '').strip()
# Let's assume that if no serial and no power reported we skip it
2020-06-15 15:46:09 +02:00
if sn == '' and max_power is None:
2020-05-20 16:12:47 +02:00
continue
if sn == '':
sn = 'N/A'
2019-09-05 13:47:10 +02:00
power_supply.append({
2020-05-20 16:12:47 +02:00
'name': sn,
2019-09-05 13:47:10 +02:00
'description': desc,
'allocated_draw': None,
2019-09-10 14:48:16 +02:00
'maximum_draw': max_power,
2019-09-05 13:47:10 +02:00
'device': self.device_id,
2020-02-02 20:08:56 +01:00
})
2019-09-05 13:47:10 +02:00
return power_supply
def get_netbox_power_supply(self):
return nb.dcim.power_ports.filter(
device_id=self.device_id
2020-02-02 20:08:56 +01:00
)
2019-09-05 13:47:10 +02:00
def create_or_update_power_supply(self):
nb_psus = list(self.get_netbox_power_supply())
2019-09-05 13:47:10 +02:00
psus = self.get_power_supply()
# Delete unknown PSU
delete = False
for nb_psu in nb_psus:
if nb_psu.name not in [x['name'] for x in psus]:
logging.info('Deleting unknown locally PSU {name}'.format(
name=nb_psu.name
))
nb_psu.delete()
delete = True
if delete:
nb_psus = self.get_netbox_power_supply()
# sync existing Netbox PSU with local infos
for nb_psu in nb_psus:
local_psu = next(
item for item in psus if item['name'] == nb_psu.name
)
update = False
if nb_psu.description != local_psu['description']:
update = True
nb_psu.description = local_psu['description']
if nb_psu.maximum_draw != local_psu['maximum_draw']:
update = True
nb_psu.maximum_draw = local_psu['maximum_draw']
if update:
nb_psu.save()
for psu in psus:
if psu['name'] not in [x.name for x in nb_psus]:
logging.info('Creating PSU {name} ({description}), {maximum_draw}W'.format(
**psu
2020-02-02 20:08:56 +01:00
))
2019-09-05 13:47:10 +02:00
nb_psu = nb.dcim.power_ports.create(
**psu
2020-02-02 20:08:56 +01:00
)
2019-09-05 13:47:10 +02:00
return True
def report_power_consumption(self):
2019-09-11 10:37:31 +02:00
try:
psu_cons = self.server.get_power_consumption()
except NotImplementedError:
logging.error('Cannot report power consumption for this vendor')
return False
2019-09-05 13:47:10 +02:00
nb_psus = self.get_netbox_power_supply()
if not len(nb_psus) or not len(psu_cons):
return False
# find power feeds for rack or dc
pwr_feeds = None
if self.netbox_server.rack:
pwr_feeds = nb.dcim.power_feeds.filter(
rack=self.netbox_server.rack.id
)
if pwr_feeds:
voltage = [p['voltage'] for p in pwr_feeds]
else:
2019-09-05 13:47:10 +02:00
logging.info('Could not find power feeds for Rack, defaulting value to 230')
Added disks extended attributes This patch brings some of the physical and virtual drive attributes as `custom_fields` to the disks inventory. The goal is to have this information present to ease disks maintenance when a drive becomes unavailable and its attributes can't be read anymore from the RAID controller. It also helps to standardize the extended disk attributes across the different manufacturers. As the disk physical identifers were not available under the correct format (hexadecimal format using the `xml` output as opposed as `X:Y:Z` format using the default `list` format), the command line parser has been refactored to read the `list` format, rather than `xml` one in the `omreport` raid controller parser. As the custom fields have to be created prior being able to register the disks extended attributes, this feature is only activated using the `--process-virtual-drives` command line parameter, or by setting `process_virtual_drives` to `true` in the configuration file. The custom fields to create as `DCIM > inventory item` `Text` are described below. NAME LABEL DESCRIPTION mount_point Mount point Device mount point(s) pd_identifier Physical disk identifier Physical disk identifier in the RAID controller vd_array Virtual drive array Virtual drive array the disk is member of vd_consistency Virtual drive consistency Virtual disk array consistency vd_device Virtual drive device Virtual drive system device vd_raid_type Virtual drive RAID Virtual drive array RAID type vd_size Virtual drive size Virtual drive array size In the current implementation, the disks attributes ore not updated: if a disk with the correct serial number is found, it's sufficient to consider it as up to date. To force the reprocessing of the disks extended attributes, the `--force-disk-refresh` command line option can be used: it removes all existing disks to before populating them with the correct parsing. Unless this option is specified, the extended attributes won't be modified unless a disk is replaced. It is possible to dump the physical/virtual disks map on the filesystem under the JSON notation to ease or automate disks management. The file path has to be provided using the `--dump-disks-map` command line parameter.
2022-02-25 18:43:09 +01:00
voltage = [230 for _ in nb_psus]
2019-09-05 13:47:10 +02:00
for i, nb_psu in enumerate(nb_psus):
nb_psu.allocated_draw = int(float(psu_cons[i]) * voltage[i])
if nb_psu.allocated_draw < 1:
logging.info('PSU is not connected or in standby mode')
continue
2019-09-05 13:47:10 +02:00
nb_psu.save()
logging.info('Updated power consumption for PSU {}: {}W'.format(
nb_psu.name,
nb_psu.allocated_draw,
))
return True