Skip to content

Associate devices to clusters and virtual machines to devices #327

New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Merged
merged 8 commits into from
Jan 7, 2025
Merged
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
9 changes: 9 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -17,6 +17,8 @@ The goal is to generate an existing infrastructure on Netbox and have the abilit
* Automatic cabling (server's interface to switch's interface) using lldp
* Local inventory using `Inventory Item` for CPU, GPU, RAM, RAID cards, physical disks (behind raid cards)
* PSUs creation and power consumption reporting (based on vendor's tools)
* Associate hypervisor devices to the virtualization cluster
* Associate virtual machines to the hypervisor device

# Requirements

@@ -128,6 +130,13 @@ network:
# # see https://netbox.company.com/virtualization/clusters/
# cluster_name: my_vm_cluster

## Enable hypervisor support
# virtual:
# enabled: false
# hypervisor: true
# cluster_name: my_cluster
# list_guests_cmd: command that lists VMs names

# Enable datacenter location feature in Netbox
datacenter_location:
driver: "cmd:cat /etc/qualification | tr [A-Z] [a-z]"
4 changes: 4 additions & 0 deletions netbox_agent/cli.py
Original file line number Diff line number Diff line change
@@ -25,10 +25,14 @@ def run(config):
dmi = dmidecode.parse()

if config.virtual.enabled or is_vm(dmi):
if config.virtual.hypervisor:
raise Exception('This host can\'t be a hypervisor because it\'s a VM')
if not config.virtual.cluster_name:
raise Exception('virtual.cluster_name parameter is mandatory because it\'s a VM')
server = VirtualMachine(dmi=dmi)
else:
if config.virtual.hypervisor and not config.virtual.cluster_name:
raise Exception('virtual.cluster_name parameter is mandatory because it\'s a hypervisor')
manufacturer = dmidecode.get_by_type(dmi, 'Chassis')[0].get('Manufacturer')
try:
server = MANUFACTURERS[manufacturer](dmi=dmi)
4 changes: 4 additions & 0 deletions netbox_agent/config.py
Original file line number Diff line number Diff line change
@@ -28,6 +28,7 @@ def get_config():
p.add_argument('--update-inventory', action='store_true', help='Update inventory')
p.add_argument('--update-location', action='store_true', help='Update location')
p.add_argument('--update-psu', action='store_true', help='Update PSU')
p.add_argument('--update-hypervisor', action='store_true', help='Update virtualization cluster and virtual machines')
p.add_argument('--update-old-devices', action='store_true',
help='Update serial number of existing (old ?) devices having same name but different serial')
p.add_argument('--purge-old-devices', action='store_true',
@@ -43,6 +44,9 @@ def get_config():
help='Disable SSL verification')
p.add_argument('--virtual.enabled', action='store_true', help='Is a virtual machine or not')
p.add_argument('--virtual.cluster_name', help='Cluster name of VM')
p.add_argument('--virtual.hypervisor', action='store_true', help='Is a hypervisor or not')
p.add_argument('--virtual.list_guests_cmd', default=None,
help='Command to output the list of vrtualization guests in the hypervisor separated by whitespace')
p.add_argument('--hostname_cmd', default=None,
help="Command to output hostname, used as Device's name in netbox")
p.add_argument('--device.platform', default=None,
73 changes: 73 additions & 0 deletions netbox_agent/hypervisor.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import shlex
import subprocess

from netbox_agent.config import config
from netbox_agent.config import netbox_instance as nb


class Hypervisor():
def __init__(self, server=None):
self.server = server
self.netbox_server = self.server.get_netbox_server()

def get_netbox_cluster(self, name):
cluster = nb.virtualization.clusters.get(
name=name,
)
return cluster

def create_or_update_device_cluster(self):
cluster = self.get_netbox_cluster(config.virtual.cluster_name)
if self.netbox_server.cluster != cluster:
self.netbox_server.cluster = cluster
self.netbox_server.save()
return True

def get_netbox_virtual_guests(self):
guests = nb.virtualization.virtual_machines.filter(
device=self.netbox_server.name,
)
return guests

def get_netbox_virtual_guest(self, name):
guest = nb.virtualization.virtual_machines.get(
name=name,
)
return guest

def create_netbox_virtual_guest(self, name):
guest = nb.virtualization.virtual_machines.create(
name=name,
device=self.netbox_server.id,
cluster=self.netbox_server.cluster.id,
)
return guest

def get_virtual_guests(self):
output = subprocess.check_output(shlex.split(config.virtual.list_guests_cmd))
return output.decode("utf-8").split()

def create_or_update_device_virtual_machines(self):
nb_guests = self.get_netbox_virtual_guests()
guests = self.get_virtual_guests()

for nb_guest in nb_guests:
# loop over the VMs associated to this hypervisor in Netbox
if nb_guest.name not in guests:
# remove the device property from VMs not found on the hypervisor
nb_guest.device = None
nb_guest.save()

for guest in guests:
# loop over the VMs running in this hypervisor
nb_guest = self.get_netbox_virtual_guest(guest)
if not nb_guest:
# add the VM to Netbox
nb.virtualization.virtual_machines
nb_guest = self.create_netbox_virtual_guest(guest)
if nb_guest.device != self.netbox_server:
# add the device property to VMs found on the hypervisor
nb_guest.device = self.netbox_server
nb_guest.save()

return True
8 changes: 8 additions & 0 deletions netbox_agent/server.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import netbox_agent.dmidecode as dmidecode
from netbox_agent.config import config
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.misc import create_netbox_tags, get_device_role, get_device_type, get_device_platform
@@ -383,6 +384,7 @@ def netbox_create_or_update(self, config):
* Network infos
* Inventory management
* PSU management
* virtualization cluster device
"""
datacenter = self.get_netbox_datacenter()
rack = self.get_netbox_rack()
@@ -429,6 +431,12 @@ def netbox_create_or_update(self, config):
self.power = PowerSupply(server=self)
self.power.create_or_update_power_supply()
self.power.report_power_consumption()
# update virtualization cluster and virtual machines
if config.register or config.update_all or config.update_hypervisor:
self.hypervisor = Hypervisor(server=self)
self.hypervisor.create_or_update_device_cluster()
if config.virtual.list_guests_cmd:
self.hypervisor.create_or_update_device_virtual_machines()

expansion = nb.dcim.devices.get(serial=self.get_expansion_service_tag())
if self.own_expansion_slot() and config.expansion_as_device:
Loading