Add power supply support (#56)
This commit is contained in:
parent
1c44ab36fb
commit
8d0168acb5
6 changed files with 160 additions and 2 deletions
|
@ -24,7 +24,7 @@ def run(config):
|
||||||
if config.register:
|
if config.register:
|
||||||
server.netbox_create(config)
|
server.netbox_create(config)
|
||||||
if config.update_all or config.update_network or config.update_location or \
|
if config.update_all or config.update_network or config.update_location or \
|
||||||
config.update_inventory:
|
config.update_inventory or config.update_psu:
|
||||||
server.netbox_update(config)
|
server.netbox_update(config)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
|
@ -22,6 +22,7 @@ def get_config():
|
||||||
p.add_argument('--update-network', action='store_true', help='Update network')
|
p.add_argument('--update-network', action='store_true', help='Update network')
|
||||||
p.add_argument('--update-inventory', action='store_true', help='Update inventory')
|
p.add_argument('--update-inventory', action='store_true', help='Update inventory')
|
||||||
p.add_argument('--update-location', action='store_true', help='Update location')
|
p.add_argument('--update-location', action='store_true', help='Update location')
|
||||||
|
p.add_argument('--update-psu', action='store_true', help='Update PSU')
|
||||||
|
|
||||||
p.add_argument('--log_level', default='debug')
|
p.add_argument('--log_level', default='debug')
|
||||||
p.add_argument('--netbox.url', help='Netbox URL')
|
p.add_argument('--netbox.url', help='Netbox URL')
|
||||||
|
|
|
@ -503,7 +503,6 @@ class Network():
|
||||||
|
|
||||||
def update_netbox_network_cards(self):
|
def update_netbox_network_cards(self):
|
||||||
if config.update_all is None or config.update_network is None:
|
if config.update_all is None or config.update_network is None:
|
||||||
print(config)
|
|
||||||
return None
|
return None
|
||||||
logging.debug('Updating NIC...')
|
logging.debug('Updating NIC...')
|
||||||
|
|
||||||
|
|
111
netbox_agent/power.py
Normal file
111
netbox_agent/power.py
Normal file
|
@ -0,0 +1,111 @@
|
||||||
|
import logging
|
||||||
|
|
||||||
|
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 self.server.dmi.get_by_type(PSU_DMI_TYPE):
|
||||||
|
if 'Present' not in psu['Status']:
|
||||||
|
continue
|
||||||
|
|
||||||
|
max_power = psu.get('Max Power Capacity').split()[0]
|
||||||
|
desc = '{} - {}'.format(
|
||||||
|
psu.get('Manufacturer', 'No Manufacturer').strip(),
|
||||||
|
psu.get('Name', 'No name').strip(),
|
||||||
|
)
|
||||||
|
power_supply.append({
|
||||||
|
'name': psu.get('Serial Number', 'No S/N').strip(),
|
||||||
|
'description': desc,
|
||||||
|
'allocated_draw': None,
|
||||||
|
'maximum_draw': int(max_power),
|
||||||
|
'device': self.device_id,
|
||||||
|
})
|
||||||
|
return power_supply
|
||||||
|
|
||||||
|
def get_netbox_power_supply(self):
|
||||||
|
return nb.dcim.power_ports.filter(
|
||||||
|
device_id=self.device_id
|
||||||
|
)
|
||||||
|
|
||||||
|
def create_or_update_power_supply(self):
|
||||||
|
nb_psus = self.get_netbox_power_supply()
|
||||||
|
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
|
||||||
|
))
|
||||||
|
nb_psu = nb.dcim.power_ports.create(
|
||||||
|
**psu
|
||||||
|
)
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
def report_power_consumption(self):
|
||||||
|
psu_cons = self.server.get_power_consumption()
|
||||||
|
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
|
||||||
|
voltage = None
|
||||||
|
pwr_feeds = None
|
||||||
|
if self.netbox_server.rack:
|
||||||
|
pwr_feeds = nb.dcim.power_feeds.filter(
|
||||||
|
rack=self.netbox_server.rack.id
|
||||||
|
)
|
||||||
|
if pwr_feeds is None or not len(pwr_feeds):
|
||||||
|
logging.info('Could not find power feeds for Rack, defaulting value to 230')
|
||||||
|
voltage = 230
|
||||||
|
|
||||||
|
for i, nb_psu in enumerate(nb_psus):
|
||||||
|
nb_psu.allocated_draw = float(psu_cons[i]) * voltage
|
||||||
|
nb_psu.save()
|
||||||
|
logging.info('Updated power consumption for PSU {}: {}W'.format(
|
||||||
|
nb_psu.name,
|
||||||
|
nb_psu.allocated_draw,
|
||||||
|
))
|
||||||
|
|
||||||
|
return True
|
|
@ -7,6 +7,7 @@ import netbox_agent.dmidecode as dmidecode
|
||||||
from netbox_agent.location import Datacenter, Rack
|
from netbox_agent.location import Datacenter, Rack
|
||||||
from netbox_agent.inventory import Inventory
|
from netbox_agent.inventory import Inventory
|
||||||
from netbox_agent.network import Network
|
from netbox_agent.network import Network
|
||||||
|
from netbox_agent.power import PowerSupply
|
||||||
|
|
||||||
|
|
||||||
class ServerBase():
|
class ServerBase():
|
||||||
|
@ -107,6 +108,9 @@ class ServerBase():
|
||||||
def get_bios_release_date(self):
|
def get_bios_release_date(self):
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
|
def get_power_consumption(self):
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
def _netbox_create_blade_chassis(self, datacenter, rack):
|
def _netbox_create_blade_chassis(self, datacenter, rack):
|
||||||
device_type = nb.dcim.device_types.get(
|
device_type = nb.dcim.device_types.get(
|
||||||
model=self.get_chassis(),
|
model=self.get_chassis(),
|
||||||
|
@ -232,6 +236,10 @@ class ServerBase():
|
||||||
|
|
||||||
self.network = Network(server=self)
|
self.network = Network(server=self)
|
||||||
self.network.create_netbox_network_cards()
|
self.network.create_netbox_network_cards()
|
||||||
|
|
||||||
|
self.power = PowerSupply(server=self)
|
||||||
|
self.power.create_or_update_power_supply()
|
||||||
|
|
||||||
if config.inventory:
|
if config.inventory:
|
||||||
self.inventory = Inventory(server=self)
|
self.inventory = Inventory(server=self)
|
||||||
self.inventory.create()
|
self.inventory.create()
|
||||||
|
@ -313,6 +321,11 @@ class ServerBase():
|
||||||
if config.update_all or config.update_inventory:
|
if config.update_all or config.update_inventory:
|
||||||
self.inventory = Inventory(server=self)
|
self.inventory = Inventory(server=self)
|
||||||
self.inventory.update()
|
self.inventory.update()
|
||||||
|
# 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()
|
||||||
if update:
|
if update:
|
||||||
server.save()
|
server.save()
|
||||||
logging.debug('Finished updating Server!')
|
logging.debug('Finished updating Server!')
|
||||||
|
|
34
netbox_agent/vendors/dell.py
vendored
34
netbox_agent/vendors/dell.py
vendored
|
@ -1,4 +1,8 @@
|
||||||
|
import logging
|
||||||
|
import subprocess
|
||||||
|
|
||||||
from netbox_agent.server import ServerBase
|
from netbox_agent.server import ServerBase
|
||||||
|
from netbox_agent.misc import is_tool
|
||||||
|
|
||||||
|
|
||||||
class DellHost(ServerBase):
|
class DellHost(ServerBase):
|
||||||
|
@ -33,3 +37,33 @@ class DellHost(ServerBase):
|
||||||
if self.is_blade():
|
if self.is_blade():
|
||||||
return self.dmi.get_by_type('Chassis')[0]['Serial Number']
|
return self.dmi.get_by_type('Chassis')[0]['Serial Number']
|
||||||
return self.get_service_tag()
|
return self.get_service_tag()
|
||||||
|
|
||||||
|
def get_power_consumption(self):
|
||||||
|
'''
|
||||||
|
Parse omreport output like this
|
||||||
|
|
||||||
|
Amperage
|
||||||
|
PS1 Current 1 : 1.8 A
|
||||||
|
PS2 Current 2 : 1.4 A
|
||||||
|
'''
|
||||||
|
value = []
|
||||||
|
|
||||||
|
if not is_tool('omreport'):
|
||||||
|
logging.error('omreport does not seem to be installed, please debug')
|
||||||
|
return value
|
||||||
|
|
||||||
|
data = subprocess.getoutput('omreport chassis pwrmonitoring')
|
||||||
|
amperage = False
|
||||||
|
for line in data.splitlines():
|
||||||
|
if line.startswith('Amperage'):
|
||||||
|
amperage = True
|
||||||
|
continue
|
||||||
|
|
||||||
|
if amperage:
|
||||||
|
if line.startswith('PS'):
|
||||||
|
amp_value = line.split(':')[1].split()[0]
|
||||||
|
value.append(amp_value)
|
||||||
|
else:
|
||||||
|
break
|
||||||
|
|
||||||
|
return value
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue