Merge branch 'master' into feature/network

This commit is contained in:
Solvik 2019-08-04 20:27:58 +02:00 committed by GitHub
commit 4ddbb89c18
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 135 additions and 23 deletions

16
netbox_agent/config.py Normal file
View file

@ -0,0 +1,16 @@
import pynetbox
import yaml
with open('/etc/netbox_agent.yaml', 'r') as ymlfile:
# FIXME: validate configuration file
config = yaml.load(ymlfile)
netbox_instance = pynetbox.api(
url=config['netbox']['url'],
token=config['netbox']['token']
)
DATACENTER_LOCATION_DRIVER_FILE = config.get('datacenter_location').get('driver_file')
DATACENTER_LOCATION = config.get('datacenter_location').get('driver')
DATACENTER_LOCATION_REGEX = config.get('datacenter_location').get('regex')

View file

@ -0,0 +1,46 @@
import importlib
import importlib.machinery
from netbox_agent.config import DATACENTER_LOCATION, DATACENTER_LOCATION_DRIVER_FILE, \
DATACENTER_LOCATION_REGEX
class Datacenter():
"""
This class is used to guess the datacenter in order to push the information
in Netbox for a `Device`
A driver takes a `value` and evaluates a regex with a `capture group`.
There's embeded drivers such as `file` or `cmd` which read a file or return the
output of a file.
There's also a support for an external driver file outside of this project in case
the logic isn't supported here.
"""
def __init__(self, *args, **kwargs):
self.driver = DATACENTER_LOCATION.split(':')[0]
self.driver_value = ':'.join(DATACENTER_LOCATION.split(':')[1:])
self.driver_file = DATACENTER_LOCATION_DRIVER_FILE
if self.driver_file:
try:
# FIXME: Works with Python 3.3+, support older version?
loader = importlib.machinery.SourceFileLoader('driver_file', self.driver_file)
self.driver = loader.load_module()
except ImportError:
raise ImportError("Couldn't import {} as a module".format(self.driver_file))
else:
try:
self.driver = importlib.import_module(
'netbox_agent.drivers.datacenter_{}'.format(self.driver)
)
except ImportError:
raise ImportError("Driver {} doesn't exists".format(self.driver))
def get(self):
if not hasattr(self.driver, 'get'):
raise Exception(
"Your driver {} doesn't have a get() function, please fix it".format(self.driver)
)
return getattr(self.driver, 'get')(self.driver_value, DATACENTER_LOCATION_REGEX)

View file

View file

@ -0,0 +1,10 @@
import re
import subprocess
def get(value, regex):
output = subprocess.getoutput(value)
r = re.search(regex, output)
if r and len(r.groups()) > 0:
return r.groups()[0]
return None

View file

@ -0,0 +1,9 @@
import re
def get(value, regex):
for line in open(value, 'r'):
r = re.search(regex, line)
if r and len(r.groups()) > 0:
return r.groups()[0]
return None

View file

@ -2,6 +2,7 @@ from pprint import pprint
import socket
from netbox_agent.config import netbox_instance as nb
from netbox_agent.datacenter import Datacenter
import netbox_agent.dmidecode as dmidecode
from netbox_agent.network import Network
@ -17,6 +18,16 @@ class ServerBase():
self.network = Network(server=self)
def get_datacenter(self):
dc = Datacenter()
return dc.get()
def get_netbox_datacenter(self):
datacenter = nb.dcim.sites.get(
slug=self.get_datacenter()
)
return datacenter
def get_product_name(self):
"""
Return the Chassis Name from dmidecode info
@ -59,39 +70,33 @@ class ServerBase():
device_role = nb.dcim.device_roles.get(
name='Server Chassis',
)
datacenter = nb.dcim.sites.get(
name='DC3', # FIXME: datacenter support
)
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,
site=datacenter.id if datacenter else None,
)
return new_chassis
def _netbox_create_blade(self, chassis):
def _netbox_create_blade(self, chassis, datacenter):
device_role = nb.dcim.device_roles.get(
name='Blade',
)
device_type = nb.dcim.device_types.get(
model=self.get_product_name(),
)
datacenter = nb.dcim.sites.get(
name='DC3', # FIXME: datacenter support
)
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=datacenter.id,
site=datacenter.id if datacenter else None,
)
return new_blade
def _netbox_create_server(self):
def _netbox_create_server(self, datacenter):
device_role = nb.dcim.device_roles.get(
name='Server',
)
@ -100,15 +105,12 @@ 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
)
new_server = nb.dcim.devices.create(
name='{}'.format(socket.gethostname()),
serial=self.get_service_tag(),
device_role=device_role.id,
device_type=device_type.id,
site=datacenter.id,
site=datacenter.id if datacenter else None,
)
return new_server
@ -116,6 +118,7 @@ class ServerBase():
return nb.dcim.devices.get(serial=self.get_service_tag())
def netbox_create(self):
datacenter = self.get_netbox_datacenter()
if self.is_blade():
# let's find the blade
blade = nb.dcim.devices.get(serial=self.get_service_tag())
@ -125,9 +128,9 @@ class ServerBase():
# check if the chassis exist before
# if it doesn't exist, create it
if not chassis:
chassis = self._netbox_create_blade_chassis()
chassis = self._netbox_create_blade_chassis(datacenter)
blade = self._netbox_create_blade(chassis)
blade = self._netbox_create_blade(chassis, datacenter)
# Find the slot and update it with our blade
device_bays = nb.dcim.device_bays.filter(
@ -139,7 +142,6 @@ class ServerBase():
device_bay.installed_device = blade
device_bay.save()
else:
# FIXME : handle pizza box
server = nb.dcim.devices.get(serial=self.get_service_tag())
if not server:
self._netbox_create_server()