Project cleanup (#6)

* add requirements.txt

* Create LICENSE

* add test directory

* code cleanup

* flake8 fixes and code cleanup

* setup.py and tox.ini

* more fixes
This commit is contained in:
Solvik 2019-08-04 00:00:22 +02:00 committed by GitHub
commit 396c4b5d10
13 changed files with 385 additions and 59 deletions

View file

@ -1,4 +1,4 @@
from pkg_resources import get_distribution, DistributionNotFound
from pkg_resources import DistributionNotFound, get_distribution
try:
__version__ = get_distribution(__name__).version

36
netbox_agent/cli.py Normal file
View file

@ -0,0 +1,36 @@
import argparse
from netbox_agent.dell.dell import DellHost
import netbox_agent.dmidecode as dmidecode
from netbox_agent.hp.hp import HPHost
MANUFACTURERS = {
'Dell Inc.': DellHost,
'HP': HPHost,
'HPE': HPHost,
}
def run(args):
manufacturer = dmidecode.get_by_type('Chassis')[0].get('Manufacturer')
server = MANUFACTURERS[manufacturer](dmidecode)
if args.debug:
server.print_debug()
if args.register:
server.netbox_create()
return True
def main():
parser = argparse.ArgumentParser(description='Netbox agent command line')
parser.add_argument('--register', action='store_true',
help='Register server in Netbox')
parser.add_argument('--debug', action='store_true',
help='Print debug informations')
args = parser.parse_args()
return run(args)
if __name__ == '__main__':
main()

View file

@ -1,18 +1,16 @@
import socket
from pprint import pprint
from netbox_agent.server import ServerBase
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:
dmidecode output is:
` Location In Chassis: Slot 03`
'''
"""
if self.is_blade():
return int(self.dmi.get_by_type('Baseboard')[0].get('Location In Chassis').split()[1])
return None
@ -26,4 +24,3 @@ class DellHost(ServerBase):
if self.is_blade():
return self.dmi.get_by_type('chassis')[0]['Serial Number']
return self.get_service_tag()

View file

@ -2,10 +2,10 @@ import re as _re
import subprocess as _subprocess
_handle_re = _re.compile("^Handle\\s+(.+),\\s+DMI\\s+type\\s+(\\d+),\\s+(\\d+)\\s+bytes$")
_in_block_re = _re.compile("^\\t\\t(.+)$")
_record_re = _re.compile("\\t(.+):\\s+(.+)$")
_record2_re = _re.compile("\\t(.+):$")
_handle_re = _re.compile('^Handle\\s+(.+),\\s+DMI\\s+type\\s+(\\d+),\\s+(\\d+)\\s+bytes$')
_in_block_re = _re.compile('^\\t\\t(.+)$')
_record_re = _re.compile('\\t(.+):\\s+(.+)$')
_record2_re = _re.compile('\\t(.+):$')
_type2str = {
0: 'BIOS',
@ -129,7 +129,7 @@ def get_by_type(type_id):
def _execute_cmd():
return _subprocess.check_output("dmidecode", stderr=_subprocess.PIPE)
return _subprocess.check_output('dmidecode', stderr=_subprocess.PIPE)
def _parse(buffer):
@ -153,21 +153,21 @@ def _parse(buffer):
dmi_handle = handle_data[0]
output_data[dmi_handle] = {}
output_data[dmi_handle]["DMIType"] = int(handle_data[1])
output_data[dmi_handle]["DMISize"] = int(handle_data[2])
output_data[dmi_handle]['DMIType'] = int(handle_data[1])
output_data[dmi_handle]['DMISize'] = int(handle_data[2])
# Okay, we know 2nd line == name
output_data[dmi_handle]["DMIName"] = record_element[1]
output_data[dmi_handle]['DMIName'] = record_element[1]
in_block_elemet = ""
in_block_list = ""
in_block_elemet = ''
in_block_list = ''
# Loop over the rest of the record, gathering values
for i in range(2, len(record_element), 1):
if i >= len(record_element):
break
# Check whether we are inside a \t\t block
if in_block_elemet != "":
if in_block_elemet != '':
in_block_data = _in_block_re.findall(record_element[1])
@ -175,14 +175,14 @@ def _parse(buffer):
if not in_block_list:
in_block_list = in_block_data[0][0]
else:
in_block_list = in_block_list + "\t\t" + in_block_data[0][1]
in_block_list = in_block_list + '\t\t' + in_block_data[0][1]
output_data[dmi_handle][in_block_elemet] = in_block_list
continue
else:
# We are out of the \t\t block; reset it again, and let
# the parsing continue
in_block_elemet = ""
in_block_elemet = ''
record_data = _record_re.findall(record_element[i])

View file

@ -1,5 +1,6 @@
from netbox_agent.server import ServerBase
class HPHost(ServerBase):
def __init__(self, *args, **kwargs):
super(HPHost, self).__init__(*args, **kwargs)
@ -10,11 +11,11 @@ class HPHost(ServerBase):
return self.get_product_name().startswith('ProLiant BL')
def _find_rack_locator(self):
'''
"""
Depending on the server, the type of the `HP ProLiant System/Rack Locator`
can change.
So we need to find it every time
'''
"""
# FIXME: make a dmidecode function get_by_dminame() ?
if self.is_blade():
for key, value in self.dmi.parse().items():

View file

@ -1,25 +0,0 @@
import sys
from pprint import pprint
import netbox_agent.dmidecode as 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():
manufacturer = dmidecode.get_by_type('Chassis')[0].get('Manufacturer')
print(manufacturer)
server = MANUFACTURERS[manufacturer](dmidecode)
print(server.get_product_name())
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()

View file

@ -1,13 +1,15 @@
import re
import os
import re
import socket
import netbox_agent.dmidecode as dmidecode
from netbox_agent.config import netbox_instance as nb
import netbox_agent.dmidecode as 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:
@ -20,15 +22,15 @@ class ServerBase():
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):
@ -59,7 +61,7 @@ class ServerBase():
nic = {
'name': interface,
'mac': open('/sys/class/net/{}/address'.format(interface), 'r').read().strip(),
'ip': None, #FIXME
'ip': None, # FIXME
}
nics.append(nic)
return nics
@ -74,7 +76,7 @@ class ServerBase():
name='Server Chassis',
)
datacenter = nb.dcim.sites.get(
name='DC3' # FIXME: datacenter support
name='DC3', # FIXME: datacenter support
)
new_chassis = nb.dcim.devices.create(
name=''.format(),
@ -93,7 +95,7 @@ class ServerBase():
model=self.get_product_name(),
)
datacenter = nb.dcim.sites.get(
name='DC3' # FIXME: datacenter support
name='DC3', # FIXME: datacenter support
)
new_blade = nb.dcim.devices.create(
name='{}'.format(socket.gethostname()),
@ -115,7 +117,7 @@ class ServerBase():
if not device_type:
raise Exception('Chassis "{}" doesn\'t exist'.format(self.get_chassis()))
datacenter = nb.dcim.sites.get(
name='DC3' # FIXME: datacenter support
name='DC3' # FIXME: datacenter support
)
new_server = nb.dcim.devices.create(
name='{}'.format(socket.gethostname()),
@ -126,7 +128,6 @@ class ServerBase():
)
return new_server
def netbox_create(self):
if self.is_blade():
# let's find the blade
@ -155,3 +156,13 @@ class ServerBase():
server = nb.dcim.devices.get(serial=self.get_service_tag())
if not server:
self._netbox_create_server()
def print_debug(self):
# FIXME: do something more generic by looping on every get_* methods
print('Datacenter:', self.get_datacenter())
print('Netbox Datacenter:', self.get_netbox_datacenter())
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())