Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Fix connection-manager and discovery workers #59

Merged
merged 1 commit into from
Sep 13, 2024
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
Fix connection-manager and discovery workers
- Connection-manager - Pydantic cannot correctly handle combination of aliases and unions.
- Discovery - Fixed renamed elements.
jaro0149 committed Sep 13, 2024
commit 809df54d28ac2857f1f581d23f3343702bf6413b
5 changes: 5 additions & 0 deletions uniconfig/python/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -59,3 +59,8 @@
- Upgrade UniConfig API to v2.0.0 (server version 7.0.0).
- Removed temporary workaround related to unwrapping of choice nodes in the Device Discovery and Install Node RPC.
- Integrated new key-value escaping mechanism into workers.

# 3.0.1
- Fix connection-manager and discovery workers.
- Connection-manager - Pydantic cannot correctly handle combination of aliases and unions.
- Discovery - Fixed renamed elements.
30 changes: 25 additions & 5 deletions uniconfig/python/frinx_worker/uniconfig/connection_manager.py
Original file line number Diff line number Diff line change
@@ -40,6 +40,9 @@ class WorkerInput(TaskInput):
connection_type: Literal["netconf", "cli", "gnmi"]
install_params: DictAny
uniconfig_url_base: str = UNICONFIG_URL_BASE
# todo: remove this flag after low-quality Pydantic code is fixed
# (hint: there are issues with unions and aliases)
validate_install_params: bool = True

class WorkerOutput(TaskOutput):
output: DictAny
@@ -48,10 +51,8 @@ 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,
data=class_to_json(
if worker_input.validate_install_params:
data = class_to_json(
self.UniconfigApi.request(
input=installnode.Input(
node_id=worker_input.node_id,
@@ -66,7 +67,26 @@ def execute(self, worker_input: WorkerInput) -> TaskResult[WorkerOutput]:
else None,
),
),
),
)
else:
data = {
"input": {
"node-id": worker_input.node_id
}
}
if worker_input.connection_type == "cli":
data["input"]["cli"] = worker_input.install_params
elif worker_input.connection_type == "netconf":
data["input"]["netconf"] = worker_input.install_params
elif worker_input.connection_type == "gnmi":
data["input"]["gnmi"] = worker_input.install_params
import json
data = json.dumps(data)

response = requests.request(
url=worker_input.uniconfig_url_base + self.UniconfigApi.uri,
method=self.UniconfigApi.method,
data=data,
headers=dict(UNICONFIG_HEADERS),
params=UNICONFIG_REQUEST_PARAMS,
)
33 changes: 16 additions & 17 deletions uniconfig/python/frinx_worker/uniconfig/device_discovery.py
Original file line number Diff line number Diff line change
@@ -14,6 +14,7 @@
from frinx.common.worker.task_def import TaskInput
from frinx.common.worker.task_def import TaskOutput
from frinx.common.worker.task_result import TaskResult
from frinx_api.uniconfig import OperationsDiscoverPostRequest
from frinx_api.uniconfig import OperationsDiscoverPostResponse
from frinx_api.uniconfig.device.discovery.discover import Address
from frinx_api.uniconfig.device.discovery.discover import DeviceDiscoveryTypeOfAddressModel
@@ -58,27 +59,27 @@ def validate_ip(cls, ip: str) -> list[Address]:
if len(ip_list) == 1:
if "/" in ip_list[0]:
address = Address(
type_of_address=DeviceDiscoveryTypeOfAddressModel3(
device_discovery_type_of_address=DeviceDiscoveryTypeOfAddressModel3(
network=str(IPvAnyNetwork(ip_list[0]))
)
)
else:
address = Address(
type_of_address=DeviceDiscoveryTypeOfAddressModel(
device_discovery_type_of_address=DeviceDiscoveryTypeOfAddressModel(
ip_address=str(IPvAnyAddress(ip_list[0]))
)
)
else:
try:
address = Address(
type_of_address=DeviceDiscoveryTypeOfAddressModel1(
device_discovery_type_of_address=DeviceDiscoveryTypeOfAddressModel1(
start_ipv4_address=str(IPv4Address(ip_list[0])),
end_ipv4_address=str(IPv4Address(ip_list[1]))
)
)
except ValueError:
address = Address(
type_of_address=DeviceDiscoveryTypeOfAddressModel2(
device_discovery_type_of_address=DeviceDiscoveryTypeOfAddressModel2(
start_ipv6_address=str(IPv6Address(ip_list[0])),
end_ipv6_address=str(IPv6Address(ip_list[1]))
)
@@ -90,21 +91,17 @@ def validate_ip(cls, ip: str) -> list[Address]:
def validate_tcp(cls, tcp_port: str) -> list[TcpPortItem] | None:
if tcp_port:
return [TcpPortItem(
type_of_port=DeviceDiscoveryTypeOfPortModel(
port=p
)
) for p in parse_ranges(tcp_port.split(","))]
device_discovery_type_of_port=DeviceDiscoveryTypeOfPortModel(port=p)
) for p in parse_ranges(tcp_port.split(","))]
else:
return None

@pydantic.field_validator("udp_port", mode="before")
def validate_udp(cls, udp_port: str) -> list[UdpPortItem] | None:
if udp_port:
return [UdpPortItem(
type_of_port=DeviceDiscoveryTypeOfPortModel2(
port=p
)
) for p in parse_ranges(udp_port.split(","))]
device_discovery_type_of_port=DeviceDiscoveryTypeOfPortModel2(port=p)
) for p in parse_ranges(udp_port.split(","))]
else:
return None

@@ -118,10 +115,12 @@ def execute(self, worker_input: WorkerInput) -> TaskResult[WorkerOutput]:
if Discover.response is None:
raise Exception(f"Failed to create request {Discover.response}")

template = Input(
address=worker_input.ip,
tcp_port=worker_input.tcp_port or None,
udp_port=worker_input.udp_port or None,
rpc_input = OperationsDiscoverPostRequest(
input=Input(
address=worker_input.ip,
tcp_port=worker_input.tcp_port or None,
udp_port=worker_input.udp_port or None,
)
)

response = requests.request(
@@ -130,7 +129,7 @@ def execute(self, worker_input: WorkerInput) -> TaskResult[WorkerOutput]:
params=UNICONFIG_REQUEST_PARAMS,
method=Discover.method,
data=class_to_json(
template,
rpc_input,
),
)

2 changes: 1 addition & 1 deletion uniconfig/python/pyproject.toml
Original file line number Diff line number Diff line change
@@ -21,7 +21,7 @@ packages = [{ include = "frinx_worker" }]
name = "frinx-uniconfig-worker"
description = "Conductor worker for Frinx Uniconfig"
authors = ["Jozef Volak <jozef.volak@elisapolystar.com>"]
version = "3.0.0"
version = "3.0.1"
readme = ["README.md", "CHANGELOG.md", "RELEASE.md"]
keywords = ["frinx-machine", "uniconfig", "worker"]
license = "Apache 2.0"
56 changes: 28 additions & 28 deletions uniconfig/python/tests/test_device_discovery.py
Original file line number Diff line number Diff line change
@@ -18,61 +18,61 @@
class TestDeviceDiscovery(unittest.TestCase):
def test_tcp_validation_list(self) -> None:
tcp_port = "21,22,23"
expected = [TcpPortItem(type_of_port=DeviceDiscoveryTypeOfPortModel(port=21)),
TcpPortItem(type_of_port=DeviceDiscoveryTypeOfPortModel(port=22)),
TcpPortItem(type_of_port=DeviceDiscoveryTypeOfPortModel(port=23))
expected = [TcpPortItem(device_discovery_type_of_port=DeviceDiscoveryTypeOfPortModel(port=21)),
TcpPortItem(device_discovery_type_of_port=DeviceDiscoveryTypeOfPortModel(port=22)),
TcpPortItem(device_discovery_type_of_port=DeviceDiscoveryTypeOfPortModel(port=23))
]
result = DeviceDiscoveryWorkers.DeviceDiscoveryWorker.WorkerInput.validate_tcp(tcp_port=tcp_port) # type: ignore
assert expected == result
assert isinstance(result, list)

def test_tcp_validation_range(self) -> None:
tcp_port = "21-23"
expected = [TcpPortItem(type_of_port=DeviceDiscoveryTypeOfPortModel(port=21)),
TcpPortItem(type_of_port=DeviceDiscoveryTypeOfPortModel(port=22)),
TcpPortItem(type_of_port=DeviceDiscoveryTypeOfPortModel(port=23))
expected = [TcpPortItem(device_discovery_type_of_port=DeviceDiscoveryTypeOfPortModel(port=21)),
TcpPortItem(device_discovery_type_of_port=DeviceDiscoveryTypeOfPortModel(port=22)),
TcpPortItem(device_discovery_type_of_port=DeviceDiscoveryTypeOfPortModel(port=23))
]
result = DeviceDiscoveryWorkers.DeviceDiscoveryWorker.WorkerInput.validate_tcp(tcp_port=tcp_port) # type: ignore
assert expected == result
assert isinstance(result, list)

def test_tcp_validation_list_range(self) -> None:
tcp_port = "21-23,25"
expected = [TcpPortItem(type_of_port=DeviceDiscoveryTypeOfPortModel(port=21)),
TcpPortItem(type_of_port=DeviceDiscoveryTypeOfPortModel(port=22)),
TcpPortItem(type_of_port=DeviceDiscoveryTypeOfPortModel(port=23)),
TcpPortItem(type_of_port=DeviceDiscoveryTypeOfPortModel(port=25))
expected = [TcpPortItem(device_discovery_type_of_port=DeviceDiscoveryTypeOfPortModel(port=21)),
TcpPortItem(device_discovery_type_of_port=DeviceDiscoveryTypeOfPortModel(port=22)),
TcpPortItem(device_discovery_type_of_port=DeviceDiscoveryTypeOfPortModel(port=23)),
TcpPortItem(device_discovery_type_of_port=DeviceDiscoveryTypeOfPortModel(port=25))
]
result = DeviceDiscoveryWorkers.DeviceDiscoveryWorker.WorkerInput.validate_tcp(tcp_port=tcp_port) # type: ignore
assert expected == result
assert isinstance(result, list)

def test_udp_validation_list(self) -> None:
udp_port = "21,22,23"
expected = [UdpPortItem(type_of_port=DeviceDiscoveryTypeOfPortModel2(port=21)),
UdpPortItem(type_of_port=DeviceDiscoveryTypeOfPortModel2(port=22)),
UdpPortItem(type_of_port=DeviceDiscoveryTypeOfPortModel2(port=23))
expected = [UdpPortItem(device_discovery_type_of_port=DeviceDiscoveryTypeOfPortModel2(port=21)),
UdpPortItem(device_discovery_type_of_port=DeviceDiscoveryTypeOfPortModel2(port=22)),
UdpPortItem(device_discovery_type_of_port=DeviceDiscoveryTypeOfPortModel2(port=23))
]
result = DeviceDiscoveryWorkers.DeviceDiscoveryWorker.WorkerInput.validate_udp(udp_port=udp_port) # type: ignore
assert expected == result
assert isinstance(result, list)

def test_udp_validation_range(self) -> None:
udp_port = "21-23"
expected = [UdpPortItem(type_of_port=DeviceDiscoveryTypeOfPortModel2(port=21)),
UdpPortItem(type_of_port=DeviceDiscoveryTypeOfPortModel2(port=22)),
UdpPortItem(type_of_port=DeviceDiscoveryTypeOfPortModel2(port=23))
expected = [UdpPortItem(device_discovery_type_of_port=DeviceDiscoveryTypeOfPortModel2(port=21)),
UdpPortItem(device_discovery_type_of_port=DeviceDiscoveryTypeOfPortModel2(port=22)),
UdpPortItem(device_discovery_type_of_port=DeviceDiscoveryTypeOfPortModel2(port=23))
]
result = DeviceDiscoveryWorkers.DeviceDiscoveryWorker.WorkerInput.validate_udp(udp_port=udp_port) # type: ignore
assert expected == result
assert isinstance(result, list)

def test_udp_validation_list_range(self) -> None:
udp_port = "21-23,25"
expected = [UdpPortItem(type_of_port=DeviceDiscoveryTypeOfPortModel2(port=21)),
UdpPortItem(type_of_port=DeviceDiscoveryTypeOfPortModel2(port=22)),
UdpPortItem(type_of_port=DeviceDiscoveryTypeOfPortModel2(port=23)),
UdpPortItem(type_of_port=DeviceDiscoveryTypeOfPortModel2(port=25))
expected = [UdpPortItem(device_discovery_type_of_port=DeviceDiscoveryTypeOfPortModel2(port=21)),
UdpPortItem(device_discovery_type_of_port=DeviceDiscoveryTypeOfPortModel2(port=22)),
UdpPortItem(device_discovery_type_of_port=DeviceDiscoveryTypeOfPortModel2(port=23)),
UdpPortItem(device_discovery_type_of_port=DeviceDiscoveryTypeOfPortModel2(port=25))
]
result = DeviceDiscoveryWorkers.DeviceDiscoveryWorker.WorkerInput.validate_udp(udp_port=udp_port) # type: ignore
assert expected == result
@@ -81,7 +81,7 @@ def test_udp_validation_list_range(self) -> None:
def test_validate_ip_single_ip_v4(self) -> None:
ip = "192.168.0.59"
expected = [
Address(type_of_address=DeviceDiscoveryTypeOfAddressModel(ip_address="192.168.0.59"))
Address(device_discovery_type_of_address=DeviceDiscoveryTypeOfAddressModel(ip_address="192.168.0.59"))
]
result = DeviceDiscoveryWorkers.DeviceDiscoveryWorker.WorkerInput.validate_ip(ip=ip) # type: ignore
assert expected == result
@@ -90,7 +90,7 @@ def test_validate_ip_single_ip_v4(self) -> None:
def test_validate_ip_range_ip_v4(self) -> None:
ip = "192.168.0.59-192.168.0.90"
expected = [
Address(type_of_address=DeviceDiscoveryTypeOfAddressModel1(
Address(device_discovery_type_of_address=DeviceDiscoveryTypeOfAddressModel1(
start_ipv4_address="192.168.0.59",
end_ipv4_address="192.168.0.90",
)
@@ -103,7 +103,7 @@ def test_validate_ip_range_ip_v4(self) -> None:
def test_validate_ip_network_v4(self) -> None:
ip = "192.168.0.0/24"
expected = [
Address(type_of_address=DeviceDiscoveryTypeOfAddressModel3(network="192.168.0.0/24"))
Address(device_discovery_type_of_address=DeviceDiscoveryTypeOfAddressModel3(network="192.168.0.0/24"))
]
result = DeviceDiscoveryWorkers.DeviceDiscoveryWorker.WorkerInput.validate_ip(ip=ip) # type: ignore
assert expected == result
@@ -112,15 +112,15 @@ def test_validate_ip_network_v4(self) -> None:
def test_validate_ip_single_ip_v6(self) -> None:
ip = "0000:0000:0000:0000:0000:ffff:c0a8:003b"
expected = [
Address(type_of_address=DeviceDiscoveryTypeOfAddressModel(ip_address="::ffff:c0a8:3b"))
Address(device_discovery_type_of_address=DeviceDiscoveryTypeOfAddressModel(ip_address="::ffff:c0a8:3b"))
]
result = DeviceDiscoveryWorkers.DeviceDiscoveryWorker.WorkerInput.validate_ip(ip=ip) # type: ignore
assert expected == result
assert isinstance(result, list)

ip = "::ffff:c0a8:3b"
expected = [
Address(type_of_address=DeviceDiscoveryTypeOfAddressModel(ip_address="::ffff:c0a8:3b"))
Address(device_discovery_type_of_address=DeviceDiscoveryTypeOfAddressModel(ip_address="::ffff:c0a8:3b"))
]
result = DeviceDiscoveryWorkers.DeviceDiscoveryWorker.WorkerInput.validate_ip(ip=ip) # type: ignore
assert expected == result
@@ -130,7 +130,7 @@ def test_validate_ip_range_ip_v6(self) -> None:
ip = "0000:0000:0000:0000:0000:ffff:c0a8:003b-0000:0000:0000:0000:0000:ffff:c0a8:005a"
expected = [
Address(
type_of_address=DeviceDiscoveryTypeOfAddressModel2(
device_discovery_type_of_address=DeviceDiscoveryTypeOfAddressModel2(
start_ipv6_address="::ffff:c0a8:3b",
end_ipv6_address="::ffff:c0a8:5a"
)
@@ -143,7 +143,7 @@ def test_validate_ip_range_ip_v6(self) -> None:
ip = "::ffff:c0a8:3b-::ffff:c0a8:5a"
expected = [
Address(
type_of_address=DeviceDiscoveryTypeOfAddressModel2(
device_discovery_type_of_address=DeviceDiscoveryTypeOfAddressModel2(
start_ipv6_address="::ffff:c0a8:3b",
end_ipv6_address="::ffff:c0a8:5a"
)
@@ -156,7 +156,7 @@ def test_validate_ip_range_ip_v6(self) -> None:
def test_validate_ip_network_v6(self) -> None:
ip = "::ffff:c0a8:0/128"
expected = [
Address(type_of_address=DeviceDiscoveryTypeOfAddressModel3(network="::ffff:c0a8:0/128"))
Address(device_discovery_type_of_address=DeviceDiscoveryTypeOfAddressModel3(network="::ffff:c0a8:0/128"))
]
result = DeviceDiscoveryWorkers.DeviceDiscoveryWorker.WorkerInput.validate_ip(ip) # type: ignore
assert expected == result