From 6f74df6a100165bd86874161b491395602549512 Mon Sep 17 00:00:00 2001 From: Emerson Felipe Date: Fri, 11 Oct 2024 15:13:04 +0000 Subject: [PATCH] Adding VM Interfaces and ignoring duplicate Virtual Machines and VM Interfaces. --- Pipfile.lock | 0 .../backend/routes/netbox/generic.py | 149 +++++++++++++++++- .../routes/netbox/ipam/ip_addresses.py | 1 + .../netbox/virtualization/interfaces.py | 2 + .../routes/proxbox/clusters/__init__.py | 23 +-- poetry.lock | 0 pyproject.toml | 0 standalone/package-lock.json | 0 8 files changed, 157 insertions(+), 18 deletions(-) mode change 100644 => 100755 Pipfile.lock mode change 100644 => 100755 poetry.lock mode change 100644 => 100755 pyproject.toml mode change 100644 => 100755 standalone/package-lock.json diff --git a/Pipfile.lock b/Pipfile.lock old mode 100644 new mode 100755 diff --git a/netbox_proxbox/backend/routes/netbox/generic.py b/netbox_proxbox/backend/routes/netbox/generic.py index 44bc0bc..222f37c 100755 --- a/netbox_proxbox/backend/routes/netbox/generic.py +++ b/netbox_proxbox/backend/routes/netbox/generic.py @@ -189,8 +189,27 @@ async def _get_by_kwargs(self, **kwargs): logger.info(f"[GET] Searching '{self.object_name}' by kwargs {kwargs}.") try: - response = await asyncio.to_thread(self.pynetbox_path.get, **kwargs) - return response + try: + response = await asyncio.to_thread(self.pynetbox_path.get, **kwargs) + return response + except Exception as error: + if "get() returned more than one result." in f"{error}": + logger.info(f"[CHECK DUPLICATE] Object '{self.object_name}' with the same name already found. Checking with '.filter' method") + + if self.endpoint == "interfaces" and self.primary_field == "device": + + logger.info("[CHECK DUPLICATE] Checking duplicate device using as PRIMARY FIELD the DEVICE.") + result_by_primary = await asyncio.to_thread(self.pynetbox_path.get, virtual_machine=self.primary_field_value) + + if result_by_primary: + if result_by_primary.virtual_machine == self.primary_field_value: + logger.info("[CHECK DUPLICATE] Interface with the same Device found. Duplicated object, returning it.") + return result_by_primary + + else: + logger.info("[CHECK DUPLICATE] If interface equal, but different devices, return as NOT duplicated.") + return None + except ProxboxException as error: raise error @@ -337,8 +356,28 @@ async def post( data["tags"] = [self.nb.tag.id] else: data["tags"].append(self.nb.tag.id) + + try: + logger.info(f"[POST] Trying to create {self.object_name} object on Netbox.") + + response = await asyncio.to_thread(self.pynetbox_path.create, data) + - response = await asyncio.to_thread(self.pynetbox_path.create, data) + except Exception as error: + + if "['The fields virtual_machine, name must make a unique set.']}" in f"{error}": + logger.error(f"Error trying to create 'Virtual Machine Interface' because the same 'virtual_machine' name already exists.\nPayload: {data}") + return None + + if "['Virtual machine name must be unique per cluster.']" in f"{error}": + logger.error(f"Error trying to create 'Virtual Machine' because Virtual Machine Name must be unique.\nPayload: {data}") + return None + + else: + raise ProxboxException( + message=f"[POST] Error trying to create '{self.object_name}' object on Netbox.", + python_exception=error + ) if response: logger.info(f"[POST] '{self.object_name}' object created successfully. {self.object_name} ID: {response.id}") @@ -350,7 +389,7 @@ async def post( logger.info(f"[POST] '{self.object_name}' object already exists on Netbox. Returning it.") return check_duplicate_result - except ProxboxException as error: raise error + #except ProxboxException as error: raise error except Exception as error: raise ProxboxException( @@ -419,11 +458,99 @@ async def _check_duplicate(self, search_params: dict = None, object: dict = None logger.info("[CHECK DUPLICATE] (0.5) Checking object using only custom PRIMARY FIELD and Proxbox TAG provided by the class attribute.") print(f"primary field: {self.primary_field} - primary_field_value: {self.primary_field_value}") + + print(f'self.primary_field = {self.primary_field} / {self.endpoint}') + if self.primary_field == "address": + logger.info("[CHECK DUPLICATE] Checking duplicate device using as PRIMARY FIELD the ADDRESS.") - result_by_primary = await asyncio.to_thread(self.pynetbox_path.get, address=self.primary_field_value) + try: + result_by_primary = await asyncio.to_thread(self.pynetbox_path.get, address=self.primary_field_value) + + except Exception as error: + if "get() returned more than one result" in f"{error}": + try: + result_by_primary = await asyncio.to_thread(self.pynetbox_path.filter, address=self.primary_field_value) + + if result_by_primary: + for address in result_by_primary: + print(f"ADDRESS OBJECT: {address}") + + except Exception as error: + raise ProxboxException( + message="Error trying to filter IP ADDRESS objects.", + python_exception=error, + ) + print(f"self.primary_field_value = {self.primary_field_value}") + if result_by_primary: + logger.info("[CHECK DUPLICATE] IP Address with the same network found. Returning it.") + return result_by_primary + + if self.primary_field == "virtual_machine" and self.endpoint == "interfaces": + logger.info("[CHECK DUPLICATE] Checking duplicate device using as PRIMARY FIELD the DEVICE.") + + result_by_primary = None + + try: + # + # THE ERROR IS HERE. + # + # GET + logger.error("THE ERROR IS HERE.") + result_by_primary = await asyncio.to_thread( + self.pynetbox_path.get, + virtual_machine=self.primary_field_value, + name=object.get("name") + ) + logger.error(f"result_by_primary: {result_by_primary}") + + if result_by_primary: + for interface in result_by_primary: + print(f"INTERFACE OBJECT: {interface} | {interface.virtual_machine}") + + print(f"interface.virtual_machine: {interface.virtual_mchine} | primary_field_value: {self.primary_field_value}") + if interface.virtual_machine == self.primary_field_value: + return interface + else: + return None + + except Exception as error: + logger.info(f"[CHECK DUPLICATE] Error trying to get interface using only 'virtual_machine' field as parameter.\n >{error}") + if "get() returned more than one result" in f"{error}": + # FILTER + logger.info("[CHECK DUPLICATE] Found more than one VM INTERFACE object with the same 'virtual_machine' field. Trying to use '.filter' pynetbox method now.") + + + try: + result_by_primary = await asyncio.to_thread( + self.pynetbox_path.filter, + virtual_machine=self.primary_field_value, + name=object.get("name") + ) + + if result_by_primary: + for interface in result_by_primary: + print(f"INTERFACE OBJECT: {interface} | {interface.virtual_machine}") + + print(f"interface.virtual_machine: {interface.virtual_mchine} | primary_field_value: {self.primary_field_value}") + if interface.virtual_machine == self.primary_field_value: + return interface + else: + return None + + except Exception as error: + raise ProxboxException( + message="Error trying to get 'VM Interface' object using 'virtual_machine' and 'name' fields.", + python_exception=f"{error}" + ) + + + + + + else: result_by_primary = await asyncio.to_thread(self.pynetbox_path.get, { @@ -433,6 +560,16 @@ async def _check_duplicate(self, search_params: dict = None, object: dict = None print(f"result_by_primary: {result_by_primary}") if result_by_primary: + + if self.endpoint == "interfaces": + logger.info("[CHECK DUPLICATE] If duplicate interface found, check if the devices are the same.") + if result_by_primary.device == self.primary_field_value: + logger.info("[CHECK DUPLICATE] Interface with the same Device found. Duplicated object, returning it.") + return result_by_primary + else: + logger.info("[CHECK DUPLICATE] If interface equal, but different devices, return as NOT duplicated.") + return None + logger.info(f"[CHECK_DUPLICATE] Object found on Netbox. Returning it.") print(f'result_by_primary: {result_by_primary}') return result_by_primary @@ -469,8 +606,6 @@ async def _check_duplicate(self, search_params: dict = None, object: dict = None result_by_device = await asyncio.to_thread(self.pynetbox_path.get, name=object.get("name"), - device__id=device_obj.id, - #device=device_obj, tag=[self.nb.tag.slug] ) diff --git a/netbox_proxbox/backend/routes/netbox/ipam/ip_addresses.py b/netbox_proxbox/backend/routes/netbox/ipam/ip_addresses.py index 473ea3c..144e371 100755 --- a/netbox_proxbox/backend/routes/netbox/ipam/ip_addresses.py +++ b/netbox_proxbox/backend/routes/netbox/ipam/ip_addresses.py @@ -7,6 +7,7 @@ class IPAddress(NetboxBase): app: str = "ipam" endpoint: str = "ip_addresses" object_name: str = "IP Address" + primary_field: str = "address" async def get_base_dict(self): diff --git a/netbox_proxbox/backend/routes/netbox/virtualization/interfaces.py b/netbox_proxbox/backend/routes/netbox/virtualization/interfaces.py index a02e228..8f033b2 100755 --- a/netbox_proxbox/backend/routes/netbox/virtualization/interfaces.py +++ b/netbox_proxbox/backend/routes/netbox/virtualization/interfaces.py @@ -11,6 +11,8 @@ class VMInterface(NetboxBase): endpoint = "interfaces" object_name = "Virtual Machine Interface" + primary_field: str = "virtual_machine" + async def get_base_dict(self): virtual_machine = await VirtualMachine(nb = self.nb).get() diff --git a/netbox_proxbox/backend/routes/proxbox/clusters/__init__.py b/netbox_proxbox/backend/routes/proxbox/clusters/__init__.py index c93cf61..d0537ab 100755 --- a/netbox_proxbox/backend/routes/proxbox/clusters/__init__.py +++ b/netbox_proxbox/backend/routes/proxbox/clusters/__init__.py @@ -133,13 +133,9 @@ async def get_nodes( ): """Get Proxmox Nodes from a Cluster""" - result = [] - - await websocket.send_text(data = "Test message") - for px in pxs: # Get Cluster from Netbox based on Proxmox Cluster Name @@ -201,7 +197,7 @@ async def get_nodes( try: await log(websocket, f"Creating Netbox '{interface_name}' Interface on '{current_node.name}' Device...") - create_interface = await Interface(nb=nb).post(data={ + create_interface = await Interface(nb=nb, primary_field_value=current_node.id).post(data={ "device": current_node.id, "name": interface_name, "enabled": enabled, @@ -222,7 +218,7 @@ async def get_nodes( cidr = interface.get("cidr") print(f"cidr: {cidr}") - if cidr: + if create_interface and cidr: try: await log(websocket, "Interface with CIDR/Network. Creating the IP Address object on Netbox...") # If interface with network configured, create IP Address and attach interface to it. @@ -237,7 +233,7 @@ async def get_nodes( message="Error trying to create IP Address of Interface on Netbox.", python_exception=error ) - + if interface_type == "bridge": @@ -253,11 +249,16 @@ async def get_nodes( try: await log(websocket, "Searching children interface of a bridge.") - netbox_port = await Interface(nb=nb).get( - device=current_node.name, + print(f"current_node.id: {current_node.id} / current_node: {current_node} / current_node.name: {current_node.name}") + netbox_port = await Interface(nb=nb, primary_field_value=current_node.id).get( name=port ) - except Exception as error: raise ProxboxException(message="Error trying to search bridge child interface.", python_exception=error) + except Exception as error: + raise ProxboxException( + message="Error trying to search bridge child interface.", + python_exception=f"{error}" + ) + print(f"port: {port}") print(f"netbox_port: {netbox_port}") @@ -280,7 +281,7 @@ async def get_nodes( await log(websocket, f"Creating interface '{port}'...") try: - new_netbox_port = await Interface(nb=nb).post(data={ + new_netbox_port = await Interface(nb=nb, primary_field_value=current_node.id).post(data={ "device": current_node.id, "name": port, "enabled": enabled, diff --git a/poetry.lock b/poetry.lock old mode 100644 new mode 100755 diff --git a/pyproject.toml b/pyproject.toml old mode 100644 new mode 100755 diff --git a/standalone/package-lock.json b/standalone/package-lock.json old mode 100644 new mode 100755