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)