From 63fbc3896fe01ff846be98e0883dada141cd7a75 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Bogu=C5=A1=C4=8Diak?= Date: Mon, 10 Jun 2024 08:51:29 +0200 Subject: [PATCH 01/17] [unconfig] Adjust device discovery MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jakub Boguščiak --- uniconfig/python/CHANGELOG.md | 5 +++- .../uniconfig/device_discovery.py | 24 ++++++++++++++++++- uniconfig/python/pyproject.toml | 2 +- 3 files changed, 28 insertions(+), 3 deletions(-) diff --git a/uniconfig/python/CHANGELOG.md b/uniconfig/python/CHANGELOG.md index d68c9bb..b1aa5d8 100644 --- a/uniconfig/python/CHANGELOG.md +++ b/uniconfig/python/CHANGELOG.md @@ -47,4 +47,7 @@ - Update Inventory properties and bump Uniconfig API. # 2.3.3 -- Fix Device Discovery RPC based on new OpenAPI model. \ No newline at end of file +- Fix Device Discovery RPC based on new OpenAPI model. + +# 2.3.4 +- Device Discovery RPC workaround caused by choice-nodes in UniConfig Yang models. \ No newline at end of file diff --git a/uniconfig/python/frinx_worker/uniconfig/device_discovery.py b/uniconfig/python/frinx_worker/uniconfig/device_discovery.py index 0855d5c..3cded71 100644 --- a/uniconfig/python/frinx_worker/uniconfig/device_discovery.py +++ b/uniconfig/python/frinx_worker/uniconfig/device_discovery.py @@ -1,5 +1,6 @@ from ipaddress import IPv4Address from ipaddress import IPv6Address +from typing import Any import pydantic import requests @@ -36,6 +37,26 @@ from .util import parse_ranges +def _unwrap_data(discovery_input: Input): + tcp_port: list[dict[str, Any]] | None = [] + udp_port: list[dict[str, Any]] | None = [] + address: list[dict[str, Any]] | None = [] + if discovery_input.tcp_port is not None: + for tcp_port_item in discovery_input.tcp_port: + tcp_port.append(tcp_port_item.type_of_port.model_dump()) + if discovery_input.udp_port is not None: + for udp_port_item in discovery_input.udp_port: + udp_port.append(udp_port_item.type_of_port.model_dump()) + if discovery_input.address is not None: + for address_item in discovery_input.address: + address.append(address_item.type_of_address.model_dump()) + return { + 'address': address, + 'tcp_port': tcp_port, + 'udp_port': udp_port + } + + class DeviceDiscoveryWorkers(ServiceWorkersImpl): class DeviceDiscoveryWorker(WorkerImpl): class ExecutionProperties(TaskExecutionProperties): @@ -129,8 +150,9 @@ def execute(self, worker_input: WorkerInput) -> TaskResult[WorkerOutput]: headers=dict(UNICONFIG_HEADERS), params=UNICONFIG_REQUEST_PARAMS, method=Discover.method, + # temporary workaround until UC adds possibility to accept choice nodes data=class_to_json( - Discover.request(input=template), + _unwrap_data(template), ), ) diff --git a/uniconfig/python/pyproject.toml b/uniconfig/python/pyproject.toml index 896bcc3..9dac6a5 100644 --- a/uniconfig/python/pyproject.toml +++ b/uniconfig/python/pyproject.toml @@ -21,7 +21,7 @@ packages = [{ include = "frinx_worker" }] name = "frinx-uniconfig-worker" description = "Conductor worker for Frinx Uniconfig" authors = ["Jozef Volak "] -version = "2.3.3" +version = "2.3.4" readme = ["README.md", "CHANGELOG.md", "RELEASE.md"] keywords = ["frinx-machine", "uniconfig", "worker"] license = "Apache 2.0" From d61b116730178e4eb2f3c138a6b81c48df703683 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Bogu=C5=A1=C4=8Diak?= Date: Mon, 10 Jun 2024 08:54:35 +0200 Subject: [PATCH 02/17] Formatting (mypy, ruff) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jakub Boguščiak --- .../frinx_worker/uniconfig/device_discovery.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/uniconfig/python/frinx_worker/uniconfig/device_discovery.py b/uniconfig/python/frinx_worker/uniconfig/device_discovery.py index 3cded71..f519598 100644 --- a/uniconfig/python/frinx_worker/uniconfig/device_discovery.py +++ b/uniconfig/python/frinx_worker/uniconfig/device_discovery.py @@ -37,10 +37,10 @@ from .util import parse_ranges -def _unwrap_data(discovery_input: Input): - tcp_port: list[dict[str, Any]] | None = [] - udp_port: list[dict[str, Any]] | None = [] - address: list[dict[str, Any]] | None = [] +def _unwrap_data(discovery_input: Input) -> dict[str, Any]: + tcp_port: list[dict[str, Any]] = [] + udp_port: list[dict[str, Any]] = [] + address: list[dict[str, Any]] = [] if discovery_input.tcp_port is not None: for tcp_port_item in discovery_input.tcp_port: tcp_port.append(tcp_port_item.type_of_port.model_dump()) @@ -51,9 +51,9 @@ def _unwrap_data(discovery_input: Input): for address_item in discovery_input.address: address.append(address_item.type_of_address.model_dump()) return { - 'address': address, - 'tcp_port': tcp_port, - 'udp_port': udp_port + "address": None if not address else address, + "tcp_port": None if not tcp_port else tcp_port, + "udp_port": None if not udp_port else udp_port } From ed33c6adbd2328207959fae2351540c10764a28c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Bogu=C5=A1=C4=8Diak?= Date: Mon, 10 Jun 2024 08:58:47 +0200 Subject: [PATCH 03/17] Formatting (pyright) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jakub Boguščiak --- .../python/frinx_worker/uniconfig/device_discovery.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/uniconfig/python/frinx_worker/uniconfig/device_discovery.py b/uniconfig/python/frinx_worker/uniconfig/device_discovery.py index f519598..92d90dd 100644 --- a/uniconfig/python/frinx_worker/uniconfig/device_discovery.py +++ b/uniconfig/python/frinx_worker/uniconfig/device_discovery.py @@ -43,13 +43,16 @@ def _unwrap_data(discovery_input: Input) -> dict[str, Any]: address: list[dict[str, Any]] = [] if discovery_input.tcp_port is not None: for tcp_port_item in discovery_input.tcp_port: - tcp_port.append(tcp_port_item.type_of_port.model_dump()) + if tcp_port_item.type_of_port is not None: + tcp_port.append(tcp_port_item.type_of_port.model_dump()) if discovery_input.udp_port is not None: for udp_port_item in discovery_input.udp_port: - udp_port.append(udp_port_item.type_of_port.model_dump()) + if udp_port_item.type_of_port is not None: + udp_port.append(udp_port_item.type_of_port.model_dump()) if discovery_input.address is not None: for address_item in discovery_input.address: - address.append(address_item.type_of_address.model_dump()) + if address_item.type_of_address is not None: + address.append(address_item.type_of_address.model_dump()) return { "address": None if not address else address, "tcp_port": None if not tcp_port else tcp_port, From 022f353777c55bfe2b56651a1e378da90acd35f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Bogu=C5=A1=C4=8Diak?= Date: Mon, 10 Jun 2024 10:29:43 +0200 Subject: [PATCH 04/17] Add input container to input data MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jakub Boguščiak --- .../python/frinx_worker/uniconfig/device_discovery.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/uniconfig/python/frinx_worker/uniconfig/device_discovery.py b/uniconfig/python/frinx_worker/uniconfig/device_discovery.py index 92d90dd..ef10765 100644 --- a/uniconfig/python/frinx_worker/uniconfig/device_discovery.py +++ b/uniconfig/python/frinx_worker/uniconfig/device_discovery.py @@ -54,9 +54,11 @@ def _unwrap_data(discovery_input: Input) -> dict[str, Any]: if address_item.type_of_address is not None: address.append(address_item.type_of_address.model_dump()) return { - "address": None if not address else address, - "tcp_port": None if not tcp_port else tcp_port, - "udp_port": None if not udp_port else udp_port + 'input': { + 'address': None if not address else address, + 'tcp_port': None if not tcp_port else tcp_port, + 'udp_port': None if not udp_port else udp_port + } } From f6d4d786c009ea1b246b47846ff522b28bbb0251 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Bogu=C5=A1=C4=8Diak?= Date: Mon, 10 Jun 2024 10:31:41 +0200 Subject: [PATCH 05/17] Formatting (ruff) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jakub Boguščiak --- .../python/frinx_worker/uniconfig/device_discovery.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/uniconfig/python/frinx_worker/uniconfig/device_discovery.py b/uniconfig/python/frinx_worker/uniconfig/device_discovery.py index ef10765..30f1975 100644 --- a/uniconfig/python/frinx_worker/uniconfig/device_discovery.py +++ b/uniconfig/python/frinx_worker/uniconfig/device_discovery.py @@ -54,10 +54,10 @@ def _unwrap_data(discovery_input: Input) -> dict[str, Any]: if address_item.type_of_address is not None: address.append(address_item.type_of_address.model_dump()) return { - 'input': { - 'address': None if not address else address, - 'tcp_port': None if not tcp_port else tcp_port, - 'udp_port': None if not udp_port else udp_port + "input": { + "address": None if not address else address, + "tcp_port": None if not tcp_port else tcp_port, + "udp_port": None if not udp_port else udp_port } } From c313cecf7cdae75de44b14831f629b4f2f66fac9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Bogu=C5=A1=C4=8Diak?= Date: Mon, 10 Jun 2024 14:08:18 +0200 Subject: [PATCH 06/17] Adjust install worker MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jakub Boguščiak --- .../uniconfig/connection_manager.py | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/uniconfig/python/frinx_worker/uniconfig/connection_manager.py b/uniconfig/python/frinx_worker/uniconfig/connection_manager.py index 4c1306b..78c3d84 100644 --- a/uniconfig/python/frinx_worker/uniconfig/connection_manager.py +++ b/uniconfig/python/frinx_worker/uniconfig/connection_manager.py @@ -14,6 +14,9 @@ from frinx.common.worker.task_result import TaskResult from frinx.common.worker.worker import WorkerImpl from frinx_api.uniconfig.connection.manager import MountType +from frinx_api.uniconfig.connection.manager.installnode import Credentials +from frinx_api.uniconfig.connection.manager.installnode import CredentialsModel1 +from frinx_api.uniconfig.connection.manager.installnode import GnmiTopologyCredentials from . import class_to_json from . import handle_response @@ -48,6 +51,9 @@ def execute(self, worker_input: WorkerInput) -> TaskResult[WorkerOutput]: if self.UniconfigApi.request is None: raise Exception(f"Failed to create request {self.UniconfigApi.request}") + # prepare input with credentials + self._prepare_input(worker_input) + response = requests.request( url=worker_input.uniconfig_url_base + self.UniconfigApi.uri, method=self.UniconfigApi.method, @@ -73,6 +79,26 @@ def execute(self, worker_input: WorkerInput) -> TaskResult[WorkerOutput]: return handle_response(response, self.WorkerOutput) + def _prepare_input(self, worker_input: WorkerInput) -> None: + if worker_input.connection_type == "cli": + worker_input.install_params["credentials"] = Credentials( + cli_topology_username=worker_input.install_params.pop("cli-topology:username"), + cli_topology_password=worker_input.install_params.pop("cli-topology:password") + ) + elif worker_input.connection_type == "netconf": + worker_input.install_params["credentials"] = CredentialsModel1( + netconf_node_topology_username=worker_input.install_params.pop("netconf-node-topology:username"), + netconf_node_topology_password=worker_input.install_params.pop("netconf-node-topology:password") + ) + elif worker_input.connection_type == "gnmi": + worker_input.install_params["credentials"] = GnmiTopologyCredentials( + gnmi_topology_username=worker_input.install_params.pop("gnmi-topology:username"), + gnmi_topology_password=worker_input.install_params.pop("gnmi-topology:password") + ) + else: + raise ValueError(f"Unknown connection type '{worker_input.connection_type}'") + + class UninstallNode(WorkerImpl): from frinx_api.uniconfig.connection.manager import ConnectionType from frinx_api.uniconfig.connection.manager.uninstallnode import Input From 213afbcda31fa44f3d18109d62def8270cdbd562 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Bogu=C5=A1=C4=8Diak?= Date: Mon, 10 Jun 2024 14:30:01 +0200 Subject: [PATCH 07/17] Fix credentials MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jakub Boguščiak --- .../python/frinx_worker/uniconfig/connection_manager.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/uniconfig/python/frinx_worker/uniconfig/connection_manager.py b/uniconfig/python/frinx_worker/uniconfig/connection_manager.py index 78c3d84..3d46c90 100644 --- a/uniconfig/python/frinx_worker/uniconfig/connection_manager.py +++ b/uniconfig/python/frinx_worker/uniconfig/connection_manager.py @@ -81,17 +81,17 @@ def execute(self, worker_input: WorkerInput) -> TaskResult[WorkerOutput]: def _prepare_input(self, worker_input: WorkerInput) -> None: if worker_input.connection_type == "cli": - worker_input.install_params["credentials"] = Credentials( + worker_input.install_params["cli-topology:credentials"] = Credentials( cli_topology_username=worker_input.install_params.pop("cli-topology:username"), cli_topology_password=worker_input.install_params.pop("cli-topology:password") ) elif worker_input.connection_type == "netconf": - worker_input.install_params["credentials"] = CredentialsModel1( + worker_input.install_params["netconf-node-topology:credentials"] = CredentialsModel1( netconf_node_topology_username=worker_input.install_params.pop("netconf-node-topology:username"), netconf_node_topology_password=worker_input.install_params.pop("netconf-node-topology:password") ) elif worker_input.connection_type == "gnmi": - worker_input.install_params["credentials"] = GnmiTopologyCredentials( + worker_input.install_params["gnmi-topology:credentials"] = GnmiTopologyCredentials( gnmi_topology_username=worker_input.install_params.pop("gnmi-topology:username"), gnmi_topology_password=worker_input.install_params.pop("gnmi-topology:password") ) From edf48a1140784ba64d06265d3cf842329d7f0f06 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Bogu=C5=A1=C4=8Diak?= Date: Mon, 10 Jun 2024 14:43:45 +0200 Subject: [PATCH 08/17] Adjust install params MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jakub Boguščiak --- .../uniconfig/connection_manager.py | 73 +++++++++++-------- 1 file changed, 44 insertions(+), 29 deletions(-) diff --git a/uniconfig/python/frinx_worker/uniconfig/connection_manager.py b/uniconfig/python/frinx_worker/uniconfig/connection_manager.py index 3d46c90..1f24aaa 100644 --- a/uniconfig/python/frinx_worker/uniconfig/connection_manager.py +++ b/uniconfig/python/frinx_worker/uniconfig/connection_manager.py @@ -14,9 +14,6 @@ from frinx.common.worker.task_result import TaskResult from frinx.common.worker.worker import WorkerImpl from frinx_api.uniconfig.connection.manager import MountType -from frinx_api.uniconfig.connection.manager.installnode import Credentials -from frinx_api.uniconfig.connection.manager.installnode import CredentialsModel1 -from frinx_api.uniconfig.connection.manager.installnode import GnmiTopologyCredentials from . import class_to_json from . import handle_response @@ -26,7 +23,6 @@ class ConnectionManager(ServiceWorkersImpl): class InstallNode(WorkerImpl): from frinx_api.uniconfig.connection.manager.installnode import Cli from frinx_api.uniconfig.connection.manager.installnode import Gnmi - from frinx_api.uniconfig.connection.manager.installnode import Input from frinx_api.uniconfig.connection.manager.installnode import Netconf from frinx_api.uniconfig.rest_api import InstallNode as UniconfigApi @@ -59,18 +55,19 @@ def execute(self, worker_input: WorkerInput) -> TaskResult[WorkerOutput]: method=self.UniconfigApi.method, data=class_to_json( self.UniconfigApi.request( - input=self.Input( - node_id=worker_input.node_id, - cli=self.Cli(**worker_input.install_params) - if worker_input.connection_type == "cli" - else None, - netconf=self.Netconf(**worker_input.install_params) - if worker_input.connection_type == "netconf" - else None, - gnmi=self.Gnmi(**worker_input.install_params) - if worker_input.connection_type == "gnmi" - else None, - ), + self._prepare_input(worker_input) + # input=self.Input( + # node_id=worker_input.node_id, + # cli=self.Cli(**worker_input.install_params) + # if worker_input.connection_type == "cli" + # else None, + # netconf=self.Netconf(**worker_input.install_params) + # if worker_input.connection_type == "netconf" + # else None, + # gnmi=self.Gnmi(**worker_input.install_params) + # if worker_input.connection_type == "gnmi" + # else None, + # ), ), ), headers=dict(UNICONFIG_HEADERS), @@ -79,22 +76,40 @@ def execute(self, worker_input: WorkerInput) -> TaskResult[WorkerOutput]: return handle_response(response, self.WorkerOutput) - def _prepare_input(self, worker_input: WorkerInput) -> None: + def _prepare_input(self, worker_input: WorkerInput) -> DictAny: + install_params: DictAny + username: str + password: str if worker_input.connection_type == "cli": - worker_input.install_params["cli-topology:credentials"] = Credentials( - cli_topology_username=worker_input.install_params.pop("cli-topology:username"), - cli_topology_password=worker_input.install_params.pop("cli-topology:password") - ) + install_params = self.Cli(**worker_input.install_params).model_dump() + install_params["cli-topology:username"] = worker_input.install_params.get("cli-topology:username") + install_params["cli-topology:password"] = worker_input.install_params.get("cli-topology:password") + return { + "input": { + "node_id": worker_input.node_id, + "cli": install_params + } + } elif worker_input.connection_type == "netconf": - worker_input.install_params["netconf-node-topology:credentials"] = CredentialsModel1( - netconf_node_topology_username=worker_input.install_params.pop("netconf-node-topology:username"), - netconf_node_topology_password=worker_input.install_params.pop("netconf-node-topology:password") - ) + install_params = self.Netconf(**worker_input.install_params).model_dump() + install_params["netconf-node-topology:username"] = worker_input.install_params.get("netconf-node-topology:username") + install_params["netconf-node-topology:username"] = worker_input.install_params.get("netconf-node-topology:username") + return { + "input": { + "node_id": worker_input.node_id, + "netconf": install_params + } + } elif worker_input.connection_type == "gnmi": - worker_input.install_params["gnmi-topology:credentials"] = GnmiTopologyCredentials( - gnmi_topology_username=worker_input.install_params.pop("gnmi-topology:username"), - gnmi_topology_password=worker_input.install_params.pop("gnmi-topology:password") - ) + install_params = self.Gnmi(**worker_input.install_params).model_dump() + install_params["gnmi-topology:username"] = worker_input.install_params.get("gnmi-topology:username") + install_params["gnmi-topology:username"] = worker_input.install_params.get("gnmi-topology:username") + return { + "input": { + "node_id": worker_input.node_id, + "gnmi": install_params + } + } else: raise ValueError(f"Unknown connection type '{worker_input.connection_type}'") From bb461098ba42d5e91dffb0bd9deae87870d0e157 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Bogu=C5=A1=C4=8Diak?= Date: Mon, 10 Jun 2024 14:46:59 +0200 Subject: [PATCH 09/17] Add comment and remove redundant use MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jakub Boguščiak --- uniconfig/python/frinx_worker/uniconfig/connection_manager.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/uniconfig/python/frinx_worker/uniconfig/connection_manager.py b/uniconfig/python/frinx_worker/uniconfig/connection_manager.py index 1f24aaa..988155e 100644 --- a/uniconfig/python/frinx_worker/uniconfig/connection_manager.py +++ b/uniconfig/python/frinx_worker/uniconfig/connection_manager.py @@ -47,14 +47,13 @@ def execute(self, worker_input: WorkerInput) -> TaskResult[WorkerOutput]: if self.UniconfigApi.request is None: raise Exception(f"Failed to create request {self.UniconfigApi.request}") - # prepare input with credentials - self._prepare_input(worker_input) response = requests.request( url=worker_input.uniconfig_url_base + self.UniconfigApi.uri, method=self.UniconfigApi.method, data=class_to_json( self.UniconfigApi.request( + # FIXME prepare input with credentials (TEMPORARY SOLUTION) self._prepare_input(worker_input) # input=self.Input( # node_id=worker_input.node_id, From 4b12940ec17b0abfac3418f85255ab666b0d63c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Bogu=C5=A1=C4=8Diak?= Date: Mon, 10 Jun 2024 14:48:19 +0200 Subject: [PATCH 10/17] Formatting (ruff) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jakub Boguščiak --- .../python/frinx_worker/uniconfig/connection_manager.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/uniconfig/python/frinx_worker/uniconfig/connection_manager.py b/uniconfig/python/frinx_worker/uniconfig/connection_manager.py index 988155e..171e0db 100644 --- a/uniconfig/python/frinx_worker/uniconfig/connection_manager.py +++ b/uniconfig/python/frinx_worker/uniconfig/connection_manager.py @@ -47,7 +47,6 @@ def execute(self, worker_input: WorkerInput) -> TaskResult[WorkerOutput]: if self.UniconfigApi.request is None: raise Exception(f"Failed to create request {self.UniconfigApi.request}") - response = requests.request( url=worker_input.uniconfig_url_base + self.UniconfigApi.uri, method=self.UniconfigApi.method, @@ -77,8 +76,6 @@ def execute(self, worker_input: WorkerInput) -> TaskResult[WorkerOutput]: def _prepare_input(self, worker_input: WorkerInput) -> DictAny: install_params: DictAny - username: str - password: str if worker_input.connection_type == "cli": install_params = self.Cli(**worker_input.install_params).model_dump() install_params["cli-topology:username"] = worker_input.install_params.get("cli-topology:username") @@ -91,8 +88,10 @@ def _prepare_input(self, worker_input: WorkerInput) -> DictAny: } elif worker_input.connection_type == "netconf": install_params = self.Netconf(**worker_input.install_params).model_dump() - install_params["netconf-node-topology:username"] = worker_input.install_params.get("netconf-node-topology:username") - install_params["netconf-node-topology:username"] = worker_input.install_params.get("netconf-node-topology:username") + install_params["netconf-node-topology:username"] = (worker_input.install_params + .get("netconf-node-topology:username")) + install_params["netconf-node-topology:username"] = (worker_input.install_params + .get("netconf-node-topology:username")) return { "input": { "node_id": worker_input.node_id, From 3b0694995c52d38afd9c35fcd705fd00fbab8d24 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Bogu=C5=A1=C4=8Diak?= Date: Mon, 10 Jun 2024 15:07:02 +0200 Subject: [PATCH 11/17] Update install params MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jakub Boguščiak --- .../uniconfig/connection_manager.py | 29 +++++-------------- 1 file changed, 7 insertions(+), 22 deletions(-) diff --git a/uniconfig/python/frinx_worker/uniconfig/connection_manager.py b/uniconfig/python/frinx_worker/uniconfig/connection_manager.py index 171e0db..4eb064e 100644 --- a/uniconfig/python/frinx_worker/uniconfig/connection_manager.py +++ b/uniconfig/python/frinx_worker/uniconfig/connection_manager.py @@ -21,9 +21,6 @@ class ConnectionManager(ServiceWorkersImpl): class InstallNode(WorkerImpl): - from frinx_api.uniconfig.connection.manager.installnode import Cli - from frinx_api.uniconfig.connection.manager.installnode import Gnmi - from frinx_api.uniconfig.connection.manager.installnode import Netconf from frinx_api.uniconfig.rest_api import InstallNode as UniconfigApi class ExecutionProperties(TaskExecutionProperties): @@ -51,9 +48,9 @@ def execute(self, worker_input: WorkerInput) -> TaskResult[WorkerOutput]: url=worker_input.uniconfig_url_base + self.UniconfigApi.uri, method=self.UniconfigApi.method, data=class_to_json( - self.UniconfigApi.request( - # FIXME prepare input with credentials (TEMPORARY SOLUTION) - self._prepare_input(worker_input) + # FIXME prepare input with credentials (TEMPORARY SOLUTION) + self._prepare_input(worker_input) + # self.UniconfigApi.request( # input=self.Input( # node_id=worker_input.node_id, # cli=self.Cli(**worker_input.install_params) @@ -66,7 +63,7 @@ def execute(self, worker_input: WorkerInput) -> TaskResult[WorkerOutput]: # if worker_input.connection_type == "gnmi" # else None, # ), - ), + # ), ), headers=dict(UNICONFIG_HEADERS), params=UNICONFIG_REQUEST_PARAMS, @@ -75,37 +72,25 @@ def execute(self, worker_input: WorkerInput) -> TaskResult[WorkerOutput]: return handle_response(response, self.WorkerOutput) def _prepare_input(self, worker_input: WorkerInput) -> DictAny: - install_params: DictAny if worker_input.connection_type == "cli": - install_params = self.Cli(**worker_input.install_params).model_dump() - install_params["cli-topology:username"] = worker_input.install_params.get("cli-topology:username") - install_params["cli-topology:password"] = worker_input.install_params.get("cli-topology:password") return { "input": { "node_id": worker_input.node_id, - "cli": install_params + "cli": worker_input.install_params } } elif worker_input.connection_type == "netconf": - install_params = self.Netconf(**worker_input.install_params).model_dump() - install_params["netconf-node-topology:username"] = (worker_input.install_params - .get("netconf-node-topology:username")) - install_params["netconf-node-topology:username"] = (worker_input.install_params - .get("netconf-node-topology:username")) return { "input": { "node_id": worker_input.node_id, - "netconf": install_params + "netconf": worker_input.install_params } } elif worker_input.connection_type == "gnmi": - install_params = self.Gnmi(**worker_input.install_params).model_dump() - install_params["gnmi-topology:username"] = worker_input.install_params.get("gnmi-topology:username") - install_params["gnmi-topology:username"] = worker_input.install_params.get("gnmi-topology:username") return { "input": { "node_id": worker_input.node_id, - "gnmi": install_params + "gnmi": worker_input.install_params } } else: From 643cdae95a81e74be4b34f153a57e50e73904bc6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Bogu=C5=A1=C4=8Diak?= Date: Tue, 11 Jun 2024 10:03:33 +0200 Subject: [PATCH 12/17] Update python SDK MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jakub Boguščiak --- uniconfig/python/poetry.lock | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/uniconfig/python/poetry.lock b/uniconfig/python/poetry.lock index ae0a784..6856b1a 100644 --- a/uniconfig/python/poetry.lock +++ b/uniconfig/python/poetry.lock @@ -288,13 +288,13 @@ test = ["pytest (>=6)"] [[package]] name = "frinx-python-sdk" -version = "2.1.0" +version = "2.1.1" description = "Python SDK for Frinx Machine Workflow Manager" optional = false python-versions = "<4.0,>=3.10" files = [ - {file = "frinx_python_sdk-2.1.0-py3-none-any.whl", hash = "sha256:49c3eb1098f111eb414331bd9349338bb78aeda8e9177373e5dcbef4e266f6e4"}, - {file = "frinx_python_sdk-2.1.0.tar.gz", hash = "sha256:085c270e83e1686cd715d672a556c27f51eb81c7e8fa6793aa0c756a7873a71b"}, + {file = "frinx_python_sdk-2.1.1-py3-none-any.whl", hash = "sha256:1afe053dd9c9b9a74deafcc61158f46a6080f96e10cfe20792079bfc21cd443a"}, + {file = "frinx_python_sdk-2.1.1.tar.gz", hash = "sha256:e2e1a36856f86b2b78e3fc8c4740d1dd7f2e70a8d76382c2b8ebdf70c0c49516"}, ] [package.dependencies] @@ -601,13 +601,13 @@ files = [ [[package]] name = "packaging" -version = "24.0" +version = "24.1" description = "Core utilities for Python packages" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "packaging-24.0-py3-none-any.whl", hash = "sha256:2ddfb553fdf02fb784c234c7ba6ccc288296ceabec964ad2eae3777778130bc5"}, - {file = "packaging-24.0.tar.gz", hash = "sha256:eb82c5e3e56209074766e6885bb04b8c38a0c015d0a30036ebe7ece34c9989e9"}, + {file = "packaging-24.1-py3-none-any.whl", hash = "sha256:5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124"}, + {file = "packaging-24.1.tar.gz", hash = "sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002"}, ] [[package]] @@ -889,13 +889,13 @@ urllib3 = ">=2" [[package]] name = "typing-extensions" -version = "4.12.1" +version = "4.12.2" description = "Backported and Experimental Type Hints for Python 3.8+" optional = false python-versions = ">=3.8" files = [ - {file = "typing_extensions-4.12.1-py3-none-any.whl", hash = "sha256:6024b58b69089e5a89c347397254e35f1bf02a907728ec7fee9bf0fe837d203a"}, - {file = "typing_extensions-4.12.1.tar.gz", hash = "sha256:915f5e35ff76f56588223f15fdd5938f9a1cf9195c0de25130c627e4d597f6d1"}, + {file = "typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d"}, + {file = "typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8"}, ] [[package]] From e41d09a04f2e6db61b39429c31a262084f9b3e7f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Bogu=C5=A1=C4=8Diak?= Date: Wed, 12 Jun 2024 16:00:10 +0200 Subject: [PATCH 13/17] Update Connection Manager MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jakub Boguščiak --- .../uniconfig/connection_manager.py | 42 ++++++++++--------- 1 file changed, 23 insertions(+), 19 deletions(-) diff --git a/uniconfig/python/frinx_worker/uniconfig/connection_manager.py b/uniconfig/python/frinx_worker/uniconfig/connection_manager.py index 4eb064e..fd77892 100644 --- a/uniconfig/python/frinx_worker/uniconfig/connection_manager.py +++ b/uniconfig/python/frinx_worker/uniconfig/connection_manager.py @@ -15,13 +15,16 @@ from frinx.common.worker.worker import WorkerImpl from frinx_api.uniconfig.connection.manager import MountType -from . import class_to_json +from . import class_to_json, snake_to_kebab_case from . import handle_response class ConnectionManager(ServiceWorkersImpl): class InstallNode(WorkerImpl): from frinx_api.uniconfig.rest_api import InstallNode as UniconfigApi + # from frinx_api.uniconfig.connection.manager.installnode import Cli + # from frinx_api.uniconfig.connection.manager.installnode import Gnmi + # from frinx_api.uniconfig.connection.manager.installnode import Netconf class ExecutionProperties(TaskExecutionProperties): exclude_empty_inputs: bool = True @@ -44,27 +47,28 @@ def execute(self, worker_input: WorkerInput) -> TaskResult[WorkerOutput]: if self.UniconfigApi.request is None: raise Exception(f"Failed to create request {self.UniconfigApi.request}") + import json response = requests.request( url=worker_input.uniconfig_url_base + self.UniconfigApi.uri, method=self.UniconfigApi.method, - data=class_to_json( - # FIXME prepare input with credentials (TEMPORARY SOLUTION) - self._prepare_input(worker_input) - # self.UniconfigApi.request( - # input=self.Input( - # node_id=worker_input.node_id, - # cli=self.Cli(**worker_input.install_params) - # if worker_input.connection_type == "cli" - # else None, - # netconf=self.Netconf(**worker_input.install_params) - # if worker_input.connection_type == "netconf" - # else None, - # gnmi=self.Gnmi(**worker_input.install_params) - # if worker_input.connection_type == "gnmi" - # else None, - # ), - # ), - ), + # FIXME prepare input with credentials (TEMPORARY SOLUTION) + data=json.dumps(snake_to_kebab_case(self._prepare_input(worker_input))), + # data=class_to_json( + # self.UniconfigApi.request( + # input=self.Input( + # node_id=worker_input.node_id, + # cli=self.Cli(**worker_input.install_params) + # if worker_input.connection_type == "cli" + # else None, + # netconf=self.Netconf(**worker_input.install_params) + # if worker_input.connection_type == "netconf" + # else None, + # gnmi=self.Gnmi(**worker_input.install_params) + # if worker_input.connection_type == "gnmi" + # else None, + # ), + # ), + # ), headers=dict(UNICONFIG_HEADERS), params=UNICONFIG_REQUEST_PARAMS, ) From da8293a9a9653a9fcf314671c74049614e4c868b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Bogu=C5=A1=C4=8Diak?= Date: Wed, 12 Jun 2024 16:02:16 +0200 Subject: [PATCH 14/17] Formatting (ruff) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jakub Boguščiak --- uniconfig/python/frinx_worker/uniconfig/connection_manager.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/uniconfig/python/frinx_worker/uniconfig/connection_manager.py b/uniconfig/python/frinx_worker/uniconfig/connection_manager.py index fd77892..10cc8a6 100644 --- a/uniconfig/python/frinx_worker/uniconfig/connection_manager.py +++ b/uniconfig/python/frinx_worker/uniconfig/connection_manager.py @@ -15,8 +15,9 @@ from frinx.common.worker.worker import WorkerImpl from frinx_api.uniconfig.connection.manager import MountType -from . import class_to_json, snake_to_kebab_case +from . import class_to_json from . import handle_response +from . import snake_to_kebab_case class ConnectionManager(ServiceWorkersImpl): From 419edeffd5e477aa8aadd0597f6f246a69d055db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Bogu=C5=A1=C4=8Diak?= Date: Thu, 13 Jun 2024 14:30:50 +0200 Subject: [PATCH 15/17] Update frinx python sdk MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jakub Boguščiak --- uniconfig/python/poetry.lock | 8 ++++---- uniconfig/python/pyproject.toml | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/uniconfig/python/poetry.lock b/uniconfig/python/poetry.lock index 6856b1a..5d1a60c 100644 --- a/uniconfig/python/poetry.lock +++ b/uniconfig/python/poetry.lock @@ -288,13 +288,13 @@ test = ["pytest (>=6)"] [[package]] name = "frinx-python-sdk" -version = "2.1.1" +version = "2.1.2" description = "Python SDK for Frinx Machine Workflow Manager" optional = false python-versions = "<4.0,>=3.10" files = [ - {file = "frinx_python_sdk-2.1.1-py3-none-any.whl", hash = "sha256:1afe053dd9c9b9a74deafcc61158f46a6080f96e10cfe20792079bfc21cd443a"}, - {file = "frinx_python_sdk-2.1.1.tar.gz", hash = "sha256:e2e1a36856f86b2b78e3fc8c4740d1dd7f2e70a8d76382c2b8ebdf70c0c49516"}, + {file = "frinx_python_sdk-2.1.2-py3-none-any.whl", hash = "sha256:98c7ccb048c00e5c5413f445ba631d58798247801427f67a451a2f165e15fa03"}, + {file = "frinx_python_sdk-2.1.2.tar.gz", hash = "sha256:5d41d49b2ee63d4e5ba23410c78612a4b7a1e2dda590188c7977bc8a163450a5"}, ] [package.dependencies] @@ -1102,4 +1102,4 @@ multidict = ">=4.0" [metadata] lock-version = "2.0" python-versions = "^3.10" -content-hash = "55d42176967658b508edf364455021d390d3565a149bd5d3a03c31c1896de745" +content-hash = "f78df47996daaa6e546de7fcdfb2e18f3d121c9def9aae01c8a78b78ff236d3d" diff --git a/uniconfig/python/pyproject.toml b/uniconfig/python/pyproject.toml index 9dac6a5..90addf1 100644 --- a/uniconfig/python/pyproject.toml +++ b/uniconfig/python/pyproject.toml @@ -6,7 +6,7 @@ build-backend = "poetry.core.masonry.api" python = "^3.10" pydantic = "^2" requests = "^2.31.0" -frinx-python-sdk = "^2" +frinx-python-sdk = "2.1.2" frinx-uniconfig-api = { git = "https://github.com/FRINXio/frinx-services-python-api.git", tag = "frinx-uniconfig-api_v1.2.0", subdirectory = "uniconfig/python" } [tool.poetry.group.dev.dependencies] From a868b51789670367306fef51bc25bacfa346bbea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Bogu=C5=A1=C4=8Diak?= Date: Fri, 14 Jun 2024 09:54:43 +0200 Subject: [PATCH 16/17] Bump frinx python SDK MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jakub Boguščiak --- uniconfig/python/poetry.lock | 8 ++++---- uniconfig/python/pyproject.toml | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/uniconfig/python/poetry.lock b/uniconfig/python/poetry.lock index 5d1a60c..e7fc19f 100644 --- a/uniconfig/python/poetry.lock +++ b/uniconfig/python/poetry.lock @@ -288,13 +288,13 @@ test = ["pytest (>=6)"] [[package]] name = "frinx-python-sdk" -version = "2.1.2" +version = "2.1.3" description = "Python SDK for Frinx Machine Workflow Manager" optional = false python-versions = "<4.0,>=3.10" files = [ - {file = "frinx_python_sdk-2.1.2-py3-none-any.whl", hash = "sha256:98c7ccb048c00e5c5413f445ba631d58798247801427f67a451a2f165e15fa03"}, - {file = "frinx_python_sdk-2.1.2.tar.gz", hash = "sha256:5d41d49b2ee63d4e5ba23410c78612a4b7a1e2dda590188c7977bc8a163450a5"}, + {file = "frinx_python_sdk-2.1.3-py3-none-any.whl", hash = "sha256:45f48a0b973a5137e718e48a1cdd031c06dd444aaabd3edf70902c296254f3de"}, + {file = "frinx_python_sdk-2.1.3.tar.gz", hash = "sha256:7a92362f3477a74da6532eadb11818b907386c43ce18ff0e106e444626a6571e"}, ] [package.dependencies] @@ -1102,4 +1102,4 @@ multidict = ">=4.0" [metadata] lock-version = "2.0" python-versions = "^3.10" -content-hash = "f78df47996daaa6e546de7fcdfb2e18f3d121c9def9aae01c8a78b78ff236d3d" +content-hash = "55d42176967658b508edf364455021d390d3565a149bd5d3a03c31c1896de745" diff --git a/uniconfig/python/pyproject.toml b/uniconfig/python/pyproject.toml index 90addf1..9dac6a5 100644 --- a/uniconfig/python/pyproject.toml +++ b/uniconfig/python/pyproject.toml @@ -6,7 +6,7 @@ build-backend = "poetry.core.masonry.api" python = "^3.10" pydantic = "^2" requests = "^2.31.0" -frinx-python-sdk = "2.1.2" +frinx-python-sdk = "^2" frinx-uniconfig-api = { git = "https://github.com/FRINXio/frinx-services-python-api.git", tag = "frinx-uniconfig-api_v1.2.0", subdirectory = "uniconfig/python" } [tool.poetry.group.dev.dependencies] From d5b59ed88f2b36586647e1079179efc0f4d0e4f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Bogu=C5=A1=C4=8Diak?= Date: Fri, 14 Jun 2024 11:01:33 +0200 Subject: [PATCH 17/17] Review changes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jakub Boguščiak --- .../python/frinx_worker/uniconfig/connection_manager.py | 7 +++++++ .../python/frinx_worker/uniconfig/device_discovery.py | 6 ++++++ 2 files changed, 13 insertions(+) diff --git a/uniconfig/python/frinx_worker/uniconfig/connection_manager.py b/uniconfig/python/frinx_worker/uniconfig/connection_manager.py index 10cc8a6..629402b 100644 --- a/uniconfig/python/frinx_worker/uniconfig/connection_manager.py +++ b/uniconfig/python/frinx_worker/uniconfig/connection_manager.py @@ -77,6 +77,13 @@ def execute(self, worker_input: WorkerInput) -> TaskResult[WorkerOutput]: return handle_response(response, self.WorkerOutput) def _prepare_input(self, worker_input: WorkerInput) -> DictAny: + """ + The input now contains multiple choice nodes (keepalive, credentials and other). Until UniConfig can parse + choice nodes, this is a workaround to prepare the input for the installation request correctly. + https://frinxhelpdesk.atlassian.net/browse/UNIC-1764 + :param worker_input: Worker input. + :return: Request input data as dict. + """ if worker_input.connection_type == "cli": return { "input": { diff --git a/uniconfig/python/frinx_worker/uniconfig/device_discovery.py b/uniconfig/python/frinx_worker/uniconfig/device_discovery.py index 30f1975..fc56943 100644 --- a/uniconfig/python/frinx_worker/uniconfig/device_discovery.py +++ b/uniconfig/python/frinx_worker/uniconfig/device_discovery.py @@ -38,6 +38,12 @@ def _unwrap_data(discovery_input: Input) -> dict[str, Any]: + """ + Unwrapping is necessary because of the input now containing choice wrapper nodes which cannot be parsed by + UniConfig yet. https://frinxhelpdesk.atlassian.net/browse/UNIC-1764 + :param discovery_input: Device Discovery input. + :return: Unwrapped data as dict. + """ tcp_port: list[dict[str, Any]] = [] udp_port: list[dict[str, Any]] = [] address: list[dict[str, Any]] = []