Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions netbox_agent.yaml.example
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,10 @@ rack_location:
#
# driver: "file:/tmp/datacenter"
# regex: "(.*)"
#position_location:
# driver: 'cmd:lldpctl -f keyvalue'
# match SysName: G1-8-U24-S1-E1
# regex: 'lldp.eno[0-3].port.descr=[GEFH][0-9]-[0-9]-U([0-9]+)[-E0-9]+'

# Some servers dont report the slot, since most people put it in the hostname
# here's a way to extract it and maintain correct slot location in Netbox
Expand Down
3 changes: 3 additions & 0 deletions netbox_agent/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,9 @@ def get_config():
p.add_argument("--rack_location.driver", help="Rack location driver, ie: cmd, file")
p.add_argument("--rack_location.driver_file", help="Rack location custom driver file path")
p.add_argument("--rack_location.regex", help="Rack location regex to extract Rack name")
p.add_argument("--position_location.driver", help="position location driver, ie: cmd, file")
p.add_argument("--position_location.driver_file", help="position location custom driver file path")
p.add_argument("--position_location.regex", help="position location regex to extract Rack name")
p.add_argument("--slot_location.driver", help="Slot location driver, ie: cmd, file")
p.add_argument("--slot_location.driver_file", help="Slot location custom driver file path")
p.add_argument("--slot_location.regex", help="Slot location regex to extract slot name")
Expand Down
12 changes: 12 additions & 0 deletions netbox_agent/location.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,18 @@ def __init__(self):
regex = config.rack_location.regex
super().__init__(driver, driver_value, driver_file, regex)

class Position(LocationBase):
def __init__(self):
driver = config.position_location.driver.split(":")[0] if config.position_location.driver else None
driver_value = (
":".join(config.position_location.driver.split(":")[1:])
if config.position_location.driver
else None
)
Comment on lines +96 to +100
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just nitpicking on style but you could use maxsplit

Suggested change
driver_value = (
":".join(config.position_location.driver.split(":")[1:])
if config.position_location.driver
else None
)
driver_value = (
config.position_location.driver.split(":", maxsplit=1)[1]
if config.position_location.driver
else None
)

driver_file = config.position_location.driver_file
regex = config.position_location.regex
super().__init__(driver, driver_value, driver_file, regex)


class Slot(LocationBase):
def __init__(self):
Expand Down
37 changes: 29 additions & 8 deletions netbox_agent/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from netbox_agent.config import netbox_instance as nb
from netbox_agent.hypervisor import Hypervisor
from netbox_agent.inventory import Inventory
from netbox_agent.location import Datacenter, Rack, Tenant
from netbox_agent.location import Datacenter, Rack, Position, Tenant
from netbox_agent.misc import (
create_netbox_tags,
get_device_role,
Expand Down Expand Up @@ -123,6 +123,10 @@ def get_rack(self):
rack = Rack()
return rack.get()

def get_position(self):
position = Position()
return position.get()

def get_netbox_rack(self):
rack = self.get_rack()
datacenter = self.get_netbox_datacenter()
Expand All @@ -136,6 +140,17 @@ def get_netbox_rack(self):
name=rack,
site_id=datacenter.id,
)
def get_netbox_position(self):
position = self.get_position()
logging.debug("Get_position: {position}".format(position=position))
datacenter = self.get_netbox_datacenter()
if not position:
return None
if position and not datacenter:
logging.error("Can't get position if no datacenter is configured or found")
sys.exit(1)

return position
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function is supposed to return the position currently set in Netbox, rather than the actual, expected one, to be used in the diff checks around lines 480-530.


def get_product_name(self):
"""
Expand Down Expand Up @@ -191,7 +206,7 @@ def get_power_consumption(self):
def get_expansion_product(self):
raise NotImplementedError

def _netbox_create_chassis(self, datacenter, tenant, rack):
def _netbox_create_chassis(self, datacenter, tenant, rack, position):
device_type = get_device_type(self.get_chassis())
device_role = get_device_role(config.device.chassis_role)
serial = self.get_chassis_service_tag()
Expand All @@ -204,12 +219,13 @@ def _netbox_create_chassis(self, datacenter, tenant, rack):
site=datacenter.id if datacenter else None,
tenant=tenant.id if tenant else None,
rack=rack.id if rack else None,
position=position.id if position else None,
tags=[{"name": x} for x in self.tags],
custom_fields=self.custom_fields,
)
return new_chassis

def _netbox_create_blade(self, chassis, datacenter, tenant, rack):
def _netbox_create_blade(self, chassis, datacenter, tenant, rack, position):
device_role = get_device_role(config.device.blade_role)
device_type = get_device_type(self.get_product_name())
serial = self.get_service_tag()
Expand Down Expand Up @@ -267,7 +283,7 @@ def _netbox_deduplicate_server(self, purge):
server.serial = serial
server.save()

def _netbox_create_server(self, datacenter, tenant, rack):
def _netbox_create_server(self, datacenter, tenant, rack, position):
device_role = get_device_role(config.device.server_role)
device_type = get_device_type(self.get_product_name())
if not device_type:
Expand All @@ -288,6 +304,8 @@ def _netbox_create_server(self, datacenter, tenant, rack):
site=datacenter.id if datacenter else None,
tenant=tenant.id if tenant else None,
rack=rack.id if rack else None,
position=position if position else None,
face=face if face else "front",
tags=[{"name": x} for x in self.tags],
)
return new_server
Expand Down Expand Up @@ -393,6 +411,7 @@ def netbox_create_or_update(self, config):
datacenter = self.get_netbox_datacenter()
rack = self.get_netbox_rack()
tenant = self.get_netbox_tenant()
position = self.get_netbox_position()

if config.update_old_devices:
self._netbox_deduplicate_server(purge=False)
Expand All @@ -404,18 +423,18 @@ def netbox_create_or_update(self, config):
chassis = nb.dcim.devices.get(serial=self.get_chassis_service_tag())
# Chassis does not exist
if not chassis:
chassis = self._netbox_create_chassis(datacenter, tenant, rack)
chassis = self._netbox_create_chassis(datacenter, tenant, rack, position)

server = nb.dcim.devices.get(serial=self.get_service_tag())
if not server:
server = self._netbox_create_blade(chassis, datacenter, tenant, rack)
server = self._netbox_create_blade(chassis, datacenter, tenant, rack, position)

# Set slot for blade
self._netbox_set_or_update_blade_slot(server, chassis, datacenter)
else:
server = nb.dcim.devices.get(serial=self.get_service_tag())
if not server:
server = self._netbox_create_server(datacenter, tenant, rack)
server = self._netbox_create_server(datacenter, tenant, rack, position)

logging.debug("Updating Server...")
# check network cards
Expand Down Expand Up @@ -522,9 +541,11 @@ def print_debug(self):
print("Datacenter:", self.get_datacenter())
print("Netbox Datacenter:", self.get_netbox_datacenter())
print("Rack:", self.get_rack())
print("Netbox Rack:", self.get_netbox_rack())
print("Position:", self.get_position())
print("Is blade:", self.is_blade())
print("Got expansion:", self.own_expansion_slot())
print("Netbox Rack:", self.get_netbox_rack())
print("Netbox Position:", self.get_netbox_position())
print("Product Name:", self.get_product_name())
print("Platform:", self.device_platform)
print("Chassis:", self.get_chassis())
Expand Down