wip - should change the name of manufacturers, maybe other classes than Server etc

This commit is contained in:
Solvik Blum 2019-08-02 18:39:05 +02:00
parent a598c3a68a
commit 81302915eb
No known key found for this signature in database
GPG key ID: CC12B3DC262B6C47
9 changed files with 280 additions and 0 deletions

6
netbox_agent/__init__.py Normal file
View file

@ -0,0 +1,6 @@
from pkg_resources import get_distribution, DistributionNotFound
try:
__version__ = get_distribution(__name__).version
except DistributionNotFound:
pass

3
netbox_agent/config.py Normal file
View file

@ -0,0 +1,3 @@
import pynetbox
netbox_instance = pynetbox.api(url='http://netbox-01.adm.dc3.dailymotion.com:8000', token='Baeree0yahloich4ohl2ohtheigoong6Cuph4Lah')

View file

86
netbox_agent/dell/dell.py Normal file
View file

@ -0,0 +1,86 @@
import socket
from pprint import pprint
from netbox_agent.server import ServerBase
from netbox_agent.config import netbox_instance as nb
class DellHost(ServerBase):
def is_blade(self):
return self.get_product_name().startswith('PowerEdge M')
def get_blade_slot(self):
'''
Return blade slot
dmidecode output is:
` Location In Chassis: Slot 03`
'''
if self.is_blade():
return int(self.dmi.get('base board')[0].get('Location In Chassis').split()[1])
return None
def get_chassis(self):
if self.is_blade():
return self.dmi.get('chassis')[0]['Version']
return self.get_product_name()
def get_chassis_service_tag(self):
if self.is_blade():
return self.dmi.get('chassis')[0]['Serial Number']
return self.get_service_tag
def netbox_create(self):
if self.is_blade():
# let's find the bblade
blade = nb.dcim.devices.get(serial=self.get_service_tag())
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
if not chassis:
device_type = nb.dcim.device_types.get(
model=self.get_chassis(),
)
device_role = nb.dcim.device_roles.get(
name='Server Chassis',
)
datacenter = nb.dcim.sites.get(
name='DC3'
)
new_chassis = nb.dcim.devices.create(
name=''.format(),
device_type=device_type.id,
serial=self.get_chassis_service_tag(),
device_role=device_role.id,
site=datacenter.id,
)
chassis = new_chassis
device_role = nb.dcim.device_roles.get(
name='Blade',
)
device_type = nb.dcim.device_types.get(
model=self.get_product_name(),
)
new_blade = nb.dcim.devices.create(
name='{}'.format(socket.gethostname()),
serial=self.get_service_tag(),
device_role=device_role.id,
device_type=device_type.id,
parent_device=chassis.id,
site='1',
)
blade = new_blade
# 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 = blade
device_bay.save()
else:
# FIXME : handle pizza box

96
netbox_agent/dmidecode.py Normal file
View file

@ -0,0 +1,96 @@
import subprocess
class Dmidecode():
def __init__(self):
self.types = {
0: 'bios',
1: 'system',
2: 'base board',
3: 'chassis',
4: 'processor',
7: 'cache',
8: 'port connector',
9: 'system slot',
10: 'on board device',
11: 'OEM strings',
#13: 'bios language',
15: 'system event log',
16: 'physical memory array',
17: 'memory device',
19: 'memory array mapped address',
24: 'hardware security',
25: 'system power controls',
27: 'cooling device',
32: 'system boot',
41: 'onboard device',
}
self.content = self._get_output()
self.info = self.parse_dmi()
def parse_dmi(self):
"""
Parse the whole dmidecode output.
Returns a list of tuples of (type int, value dict).
"""
self.info = []
lines = iter(self.content.strip().splitlines())
while True:
try:
line = next(lines)
except StopIteration:
break
if line.startswith('Handle 0x'):
typ = int(line.split(',', 2)[1].strip()[len('DMI type'):])
if typ in self.types:
self.info.append(
(self.types[typ], self._parse_handle_section(lines))
)
return self.info
def _parse_handle_section(self, lines):
"""
Parse a section of dmidecode output
* 1st line contains address, type and size
* 2nd line is title
* line started with one tab is one option and its value
* line started with two tabs is a member of list
"""
data = {
'_title': next(lines).rstrip(),
}
for line in lines:
line = line.rstrip()
if line.startswith('\t\t'):
if isinstance(data[k], list):
data[k].append(line.lstrip())
elif line.startswith('\t'):
k, v = [i.strip() for i in line.lstrip().split(':', 1)]
if v:
data[k] = v
else:
data[k] = []
else:
break
return data
def _get_output(self):
try:
output = subprocess.check_output(
'PATH=$PATH:/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin '
'sudo dmidecode', shell=True)
except Exception as e:
print(e, file=sys.stderr)
if str(e).find("command not found") == -1:
print("please install dmidecode", file=sys.stderr)
print("e.g. sudo apt install dmidecode",file=sys.stderr)
sys.exit(1)
return output.decode()
def get(self, i):
return [v for j, v in self.info if j == i]

View file

4
netbox_agent/hp/hp.py Normal file
View file

@ -0,0 +1,4 @@
from netbox_agent.server import ServerBase
class HPHost():
pass

22
netbox_agent/main.py Normal file
View file

@ -0,0 +1,22 @@
from netbox_agent.dmidecode import Dmidecode
from netbox_agent.dell.dell import DellHost
from netbox_agent.hp.hp import HPHost
MANUFACTURERS = {
'Dell Inc.': DellHost,
'HP': HPHost,
'HPE': HPHost,
}
def main():
dmi = Dmidecode()
manufacturer = dmi.get('chassis')[0].get('Manufacturer')
server = MANUFACTURERS[manufacturer](dmi)
print(server.get_chassis())
print(server.get_service_tag())
print(server.get_chassis_service_tag())
server.netbox_create()
print(server.get_network_cards())
if __name__ == '__main__':
main()

63
netbox_agent/server.py Normal file
View file

@ -0,0 +1,63 @@
import re
import os
from netbox_agent.dmidecode import Dmidecode
# 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])$')
class ServerBase():
def __init__(self, dmi=None):
if dmi:
self.dmi = dmi
else:
self.dmi = Dmidecode()
self.system = self.dmi.get('system')
self.bios = self.dmi.get('bios')
self.network_cards = []
def get_product_name(self):
'''
Return the Chassis Name from dmidecode info
'''
return self.system[0]['Product Name']
def get_service_tag(self):
'''
Return the Service Tag from dmidecode info
'''
return self.system[0]['Serial Number']
def is_blade(self):
raise NotImplementedError
def get_blade_slot(self):
raise NotImplementedError
def get_chassis(self):
raise NotImplementedError
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
def get_network_cards(self):
nics = []
for interface in os.listdir('/sys/class/net/'):
if re.match(INTERFACE_REGEX, interface):
nic = {
'name': interface,
'mac': open('/sys/class/net/{}/address'.format(interface), 'r').read().strip(),
'ip': None, #FIXME
}
nics.append(nic)
return nics