Adds support for:

* sets the datacenter for vlans
* sets the tenant for IP addresses and Devices.
* setting device tags
* setting the blade, chassis, and server roles.
This commit is contained in:
Thomas Davis 2020-02-03 20:02:53 -08:00
commit 96a87c6835
4 changed files with 82 additions and 14 deletions

View file

@ -32,6 +32,20 @@ def get_config():
p.add_argument('--netbox.token', help='Netbox API Token') p.add_argument('--netbox.token', help='Netbox API Token')
p.add_argument('--hostname_cmd', default=None, p.add_argument('--hostname_cmd', default=None,
help="Command to output hostname, used as Device's name in netbox") help="Command to output hostname, used as Device's name in netbox")
p.add_argument('--device.tags', default=r'',
help='tags to use for a host')
p.add_argument('--device.blade_role', default=r'Blade',
help='role to use for a blade server')
p.add_argument('--device.chassis_role', default=r'Server Chassis',
help='role to use for a chassis')
p.add_argument('--device.server_role', default=r'Server',
help='role to use for a server')
p.add_argument('--tenant.driver',
help='tenant driver, ie cmd, file')
p.add_argument('--tenant.driver_file',
help='tenant driver custom driver file path')
p.add_argument('--tenant.regex',
help='tenant regex to extract Netbox tenant slug')
p.add_argument('--datacenter_location.driver', p.add_argument('--datacenter_location.driver',
help='Datacenter location driver, ie: cmd, file') help='Datacenter location driver, ie: cmd, file')
p.add_argument('--datacenter_location.driver_file', p.add_argument('--datacenter_location.driver_file',

View file

@ -50,6 +50,17 @@ class LocationBase():
return getattr(self.driver, 'get')(self.driver_value, self.regex) return getattr(self.driver, 'get')(self.driver_value, self.regex)
class Tenant(LocationBase):
def __init_(self):
driver = config.tenant.driver.split(':')[0] if \
config.tenant.driver else None
driver_value = ':'.join(config.tenant.driver.split(':')[1:]) if \
config.tenant.driver else None
driver_file = config.tenant.driver_file
regex = config.tenant.regex
super().__init__(driver, driver_value, driver_file, regex)
class Datacenter(LocationBase): class Datacenter(LocationBase):
def __init__(self): def __init__(self):
driver = config.datacenter_location.driver.split(':')[0] if \ driver = config.datacenter_location.driver.split(':')[0] if \

View file

@ -19,6 +19,8 @@ class Network():
self.server = server self.server = server
self.device = self.server.get_netbox_server() self.device = self.server.get_netbox_server()
self.datacenter = self.server.get_datacenter()
self.tenant = self.server.get_netbox_tenant()
self.lldp = LLDP() if config.network.lldp else None self.lldp = LLDP() if config.network.lldp else None
self.scan() self.scan()
@ -181,6 +183,7 @@ class Network():
# since users may have same vlan id in multiple dc # since users may have same vlan id in multiple dc
vlan = nb.ipam.vlans.get( vlan = nb.ipam.vlans.get(
vid=vlan_id, vid=vlan_id,
site=self.datacenter
) )
if vlan is None: if vlan is None:
vlan = nb.ipam.vlans.create( vlan = nb.ipam.vlans.create(
@ -359,6 +362,7 @@ class Network():
interface=interface.id, interface=interface.id,
status=1, status=1,
role=self.ipam_choices['ip-address:role']['Anycast'], role=self.ipam_choices['ip-address:role']['Anycast'],
tenant=self.tenant.id if self.tenant else None,
) )
return netbox_ip return netbox_ip
else: else:

View file

@ -7,7 +7,7 @@ import netbox_agent.dmidecode as dmidecode
from netbox_agent.config import config from netbox_agent.config import config
from netbox_agent.config import netbox_instance as nb from netbox_agent.config import netbox_instance as nb
from netbox_agent.inventory import Inventory from netbox_agent.inventory import Inventory
from netbox_agent.location import Datacenter, Rack from netbox_agent.location import Datacenter, Rack, Tenant
from netbox_agent.network import Network from netbox_agent.network import Network
from netbox_agent.power import PowerSupply from netbox_agent.power import PowerSupply
@ -44,6 +44,28 @@ class ServerBase():
self.network = None self.network = None
def create_netbox_tags(self, tags):
for tag in tags:
nb_tag = nb.extras.tags.get(
name=tag
)
if not nb_tag:
nb_tag = nb.extras.tags.create(
name=tag,
slug=tag,
)
def get_tenant(self):
tenant = Tenant()
return tenant.get()
def get_netbox_tenant(self):
tenant = nb.tenancy.tenants.get(
slug=self.get_tenant()
)
return tenant
def get_datacenter(self): def get_datacenter(self):
dc = Datacenter() dc = Datacenter()
return dc.get() return dc.get()
@ -136,9 +158,12 @@ class ServerBase():
def get_power_consumption(self): def get_power_consumption(self):
raise NotImplementedError raise NotImplementedError
def _netbox_create_blade_chassis(self, datacenter, rack): def _netbox_create_blade_chassis(self, datacenter, tenant, rack):
tags = config.device.tags.split(",")
self.create_netbox_tags(tags)
device_type = get_device_type(self.get_chassis()) device_type = get_device_type(self.get_chassis())
device_role = get_device_role('Server Chassis') device_role = get_device_role(config.device.chassis_role)
serial = self.get_chassis_service_tag() serial = self.get_chassis_service_tag()
logging.info('Creating chassis blade (serial: {serial})'.format( logging.info('Creating chassis blade (serial: {serial})'.format(
serial=serial)) serial=serial))
@ -148,12 +173,17 @@ class ServerBase():
serial=serial, serial=serial,
device_role=device_role.id, device_role=device_role.id,
site=datacenter.id if datacenter else None, site=datacenter.id if datacenter else None,
tenant=tenant.id if tenant else None,
rack=rack.id if rack else None, rack=rack.id if rack else None,
tags=tags,
) )
return new_chassis return new_chassis
def _netbox_create_blade(self, chassis, datacenter, rack): def _netbox_create_blade(self, chassis, datacenter, tenant, rack):
device_role = get_device_role('Blade') tags = config.device.tags.split(',')
self.create_netbox_tags(tags)
device_role = get_device_role(config.device.blade_role)
device_type = get_device_type(self.get_product_name()) device_type = get_device_type(self.get_product_name())
serial = self.get_service_tag() serial = self.get_service_tag()
hostname = self.get_hostname() hostname = self.get_hostname()
@ -168,7 +198,9 @@ class ServerBase():
device_type=device_type.id, device_type=device_type.id,
parent_device=chassis.id, parent_device=chassis.id,
site=datacenter.id if datacenter else None, site=datacenter.id if datacenter else None,
tenant=tenant.id if tenant else None,
rack=rack.id if rack else None, rack=rack.id if rack else None,
tags=tags,
) )
return new_blade return new_blade
@ -193,8 +225,11 @@ class ServerBase():
slot=slot slot=slot
)) ))
def _netbox_create_server(self, datacenter, rack): def _netbox_create_server(self, datacenter, tenant, rack):
device_role = get_device_role('Server') tags = config.device.tags.split(",")
self.create_netbox_tags(tags)
device_role = get_device_role(config.device.server_role)
device_type = get_device_type(self.get_product_name()) device_type = get_device_type(self.get_product_name())
if not device_type: if not device_type:
raise Exception('Chassis "{}" doesn\'t exist'.format(self.get_chassis())) raise Exception('Chassis "{}" doesn\'t exist'.format(self.get_chassis()))
@ -208,7 +243,9 @@ class ServerBase():
device_role=device_role.id, device_role=device_role.id,
device_type=device_type.id, device_type=device_type.id,
site=datacenter.id if datacenter else None, site=datacenter.id if datacenter else None,
tenant=tenant.id if tenant else None,
rack=rack.id if rack else None, rack=rack.id if rack else None,
tags=tags,
) )
return new_server return new_server
@ -218,6 +255,7 @@ class ServerBase():
def netbox_create(self, config): def netbox_create(self, config):
logging.debug('Creating Server..') logging.debug('Creating Server..')
datacenter = self.get_netbox_datacenter() datacenter = self.get_netbox_datacenter()
tenant = self.get_netbox_tenant()
rack = self.get_netbox_rack() rack = self.get_netbox_rack()
if self.is_blade(): if self.is_blade():
# let's find the blade # let's find the blade
@ -232,16 +270,16 @@ class ServerBase():
serial=self.get_chassis_service_tag() serial=self.get_chassis_service_tag()
) )
if not chassis: if not chassis:
chassis = self._netbox_create_blade_chassis(datacenter, rack) chassis = self._netbox_create_blade_chassis(datacenter, tenant, rack)
blade = self._netbox_create_blade(chassis, datacenter, rack) blade = self._netbox_create_blade(chassis, datacenter, tenant, rack)
# Set slot for blade # Set slot for blade
self._netbox_set_blade_slot(chassis, blade) self._netbox_set_blade_slot(chassis, blade)
else: else:
server = nb.dcim.devices.get(serial=self.get_service_tag()) server = nb.dcim.devices.get(serial=self.get_service_tag())
if not server: if not server:
self._netbox_create_server(datacenter, rack) self._netbox_create_server(datacenter, tenant, rack)
self.network = Network(server=self) self.network = Network(server=self)
self.network.create_netbox_network_cards() self.network.create_netbox_network_cards()
@ -254,7 +292,7 @@ class ServerBase():
self.inventory.create() self.inventory.create()
logging.debug('Server created!') logging.debug('Server created!')
def _netbox_update_chassis_for_blade(self, server, datacenter): def _netbox_update_chassis_for_blade(self, server, datacenter, tenant):
chassis = server.parent_device.device_bay.device chassis = server.parent_device.device_bay.device
device_bay = nb.dcim.device_bays.get( device_bay = nb.dcim.device_bays.get(
server.parent_device.device_bay.id server.parent_device.device_bay.id
@ -275,7 +313,7 @@ class ServerBase():
serial=self.get_chassis_service_tag() serial=self.get_chassis_service_tag()
) )
if not chassis: if not chassis:
chassis = self._netbox_create_blade_chassis(datacenter) chassis = self._netbox_create_blade_chassis(datacenter, tenant)
if move_device_bay or device_bay.name != self.get_blade_slot(): if move_device_bay or device_bay.name != self.get_blade_slot():
logging.info('Device ({serial}) seems to have moved, reseting old slot..'.format( logging.info('Device ({serial}) seems to have moved, reseting old slot..'.format(
serial=server.serial)) serial=server.serial))
@ -304,16 +342,17 @@ class ServerBase():
update = 0 update = 0
if self.is_blade(): if self.is_blade():
datacenter = self.get_netbox_datacenter() datacenter = self.get_netbox_datacenter()
tenant = self.get_netbox_tenant()
# if it's already linked to a chassis # if it's already linked to a chassis
if server.parent_device: if server.parent_device:
self._netbox_update_chassis_for_blade(server, datacenter) self._netbox_update_chassis_for_blade(server, datacenter, tenant)
else: else:
logging.info('Blade is not in a chassis, fixing...') logging.info('Blade is not in a chassis, fixing...')
chassis = nb.dcim.devices.get( chassis = nb.dcim.devices.get(
serial=self.get_chassis_service_tag() serial=self.get_chassis_service_tag()
) )
if not chassis: if not chassis:
chassis = self._netbox_create_blade_chassis(datacenter) chassis = self._netbox_create_blade_chassis(datacenter, tenant)
# Set slot for blade # Set slot for blade
self._netbox_set_blade_slot(chassis, server) self._netbox_set_blade_slot(chassis, server)