142 lines
5.8 KiB
Python
142 lines
5.8 KiB
Python
from dcim.models import Device
|
|
from django.contrib import messages
|
|
from django.shortcuts import get_object_or_404, redirect
|
|
from django.views import View
|
|
from virtualization.models import VirtualMachine
|
|
|
|
from netbox_librenms_plugin.forms import AddToLIbreSNMPV1V2, AddToLIbreSNMPV3
|
|
from netbox_librenms_plugin.views.mixins import LibreNMSAPIMixin, LibreNMSPermissionMixin
|
|
|
|
|
|
class AddDeviceToLibreNMSView(LibreNMSPermissionMixin, LibreNMSAPIMixin, View):
|
|
"""Add a NetBox device or VM to LibreNMS via the API."""
|
|
|
|
def get_form_class(self):
|
|
"""Return the appropriate SNMP form class based on the SNMP version."""
|
|
snmp_version = self.request.POST.get("snmp_version")
|
|
if not snmp_version:
|
|
snmp_version = self.request.POST.get("v1v2-snmp_version") or self.request.POST.get("v3-snmp_version")
|
|
|
|
if snmp_version in ("v1", "v2c"):
|
|
return AddToLIbreSNMPV1V2
|
|
return AddToLIbreSNMPV3
|
|
|
|
def get_object(self, object_id, object_type=None):
|
|
"""
|
|
Return the Device or VirtualMachine for the given ID.
|
|
|
|
Uses object_type hint when provided to avoid PK collision ambiguity
|
|
(Device and VirtualMachine share independent PK sequences).
|
|
"""
|
|
if object_type == "virtualmachine":
|
|
return get_object_or_404(VirtualMachine, pk=object_id)
|
|
try:
|
|
return Device.objects.get(pk=object_id)
|
|
except Device.DoesNotExist:
|
|
return get_object_or_404(VirtualMachine, pk=object_id)
|
|
|
|
def post(self, request, object_id):
|
|
"""Add a device to LibreNMS using the submitted SNMP form."""
|
|
# Check write permission before adding device to LibreNMS
|
|
if error := self.require_write_permission():
|
|
return error
|
|
|
|
self.object = self.get_object(object_id, request.POST.get("object_type"))
|
|
form_class = self.get_form_class()
|
|
|
|
snmp_version = request.POST.get("v1v2-snmp_version") or request.POST.get("v3-snmp_version")
|
|
prefix = "v1v2" if snmp_version in ("v1", "v2c") else "v3"
|
|
|
|
form = form_class(request.POST, prefix=prefix)
|
|
if form.is_valid():
|
|
# Inject snmp_version from toggle into cleaned_data for v1/v2c forms
|
|
if snmp_version in ("v1", "v2c"):
|
|
form.cleaned_data["snmp_version"] = snmp_version
|
|
return self.form_valid(form, snmp_version=snmp_version)
|
|
|
|
for field, errors in form.errors.items():
|
|
for error in errors:
|
|
messages.error(request, f"{field}: {error}")
|
|
return redirect(self.object.get_absolute_url())
|
|
|
|
def form_valid(self, form, snmp_version=None):
|
|
"""Submit the validated SNMP form data to the LibreNMS API."""
|
|
data = form.cleaned_data
|
|
# Use the snmp_version from toggle/form for v1/v2c, or from form data for v3
|
|
version = snmp_version or data.get("snmp_version")
|
|
device_data = {
|
|
"hostname": data.get("hostname"),
|
|
"snmp_version": version,
|
|
"force_add": data.get("force_add", False),
|
|
}
|
|
|
|
if data.get("port"):
|
|
device_data["port"] = data.get("port")
|
|
if data.get("transport"):
|
|
device_data["transport"] = data.get("transport")
|
|
if data.get("port_association_mode"):
|
|
device_data["port_association_mode"] = data.get("port_association_mode")
|
|
if data.get("poller_group"):
|
|
try:
|
|
device_data["poller_group"] = int(data.get("poller_group"))
|
|
except (ValueError, TypeError):
|
|
pass
|
|
|
|
if device_data["snmp_version"] in ("v1", "v2c"):
|
|
device_data["community"] = data.get("community")
|
|
elif device_data["snmp_version"] == "v3":
|
|
device_data.update(
|
|
{
|
|
"authlevel": data.get("authlevel"),
|
|
"authname": data.get("authname"),
|
|
"authpass": data.get("authpass"),
|
|
"authalgo": data.get("authalgo"),
|
|
"cryptopass": data.get("cryptopass"),
|
|
"cryptoalgo": data.get("cryptoalgo"),
|
|
}
|
|
)
|
|
else:
|
|
messages.error(self.request, "Unknown SNMP version.")
|
|
return redirect(self.object.get_absolute_url())
|
|
|
|
success, message = self.librenms_api.add_device(device_data)
|
|
|
|
if success:
|
|
messages.success(self.request, message)
|
|
else:
|
|
messages.error(self.request, message)
|
|
return redirect(self.object.get_absolute_url())
|
|
|
|
|
|
class UpdateDeviceLocationView(LibreNMSPermissionMixin, LibreNMSAPIMixin, View):
|
|
"""Update the LibreNMS site/location based on the NetBox site."""
|
|
|
|
def post(self, request, pk):
|
|
"""Sync the device location to LibreNMS from the NetBox site."""
|
|
# Check write permission before updating location in LibreNMS
|
|
if error := self.require_write_permission():
|
|
return error
|
|
|
|
device = get_object_or_404(Device, pk=pk)
|
|
self.librenms_id = self.librenms_api.get_librenms_id(device)
|
|
|
|
if device.site:
|
|
librenms_api = self.librenms_api
|
|
field_data = {
|
|
"field": ["location", "override_sysLocation"],
|
|
"data": [device.site.name, "1"],
|
|
}
|
|
success, message = librenms_api.update_device_field(self.librenms_id, field_data)
|
|
|
|
if success:
|
|
messages.success(
|
|
request,
|
|
f"Device location updated in LibreNMS to {device.site.name}",
|
|
)
|
|
else:
|
|
messages.error(request, f"Failed to update device location in LibreNMS: {message}")
|
|
else:
|
|
messages.warning(request, "Device has no associated site in NetBox")
|
|
|
|
return redirect("plugins:netbox_librenms_plugin:device_librenms_sync", pk=pk)
|