Skip to content

Commit

Permalink
Fix connection-manager and discovery workers
Browse files Browse the repository at this point in the history
- Connection-manager - Pydantic cannot correctly handle combination of aliases and unions.
- Discovery - Fixed renamed elements.
  • Loading branch information
jaro0149 committed Sep 13, 2024
1 parent 0cd0de2 commit 809df54
Show file tree
Hide file tree
Showing 5 changed files with 75 additions and 51 deletions.
5 changes: 5 additions & 0 deletions uniconfig/python/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Up @@ -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
Expand All @@ -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,
Expand All @@ -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,
)
Expand Down
33 changes: 16 additions & 17 deletions uniconfig/python/frinx_worker/uniconfig/device_discovery.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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]))
)
Expand All @@ -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

Expand All @@ -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(
Expand All @@ -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,
),
)

Expand Down
2 changes: 1 addition & 1 deletion uniconfig/python/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ packages = [{ include = "frinx_worker" }]
name = "frinx-uniconfig-worker"
description = "Conductor worker for Frinx Uniconfig"
authors = ["Jozef Volak <[email protected]>"]
version = "3.0.0"
version = "3.0.1"
readme = ["README.md", "CHANGELOG.md", "RELEASE.md"]
keywords = ["frinx-machine", "uniconfig", "worker"]
license = "Apache 2.0"
Expand Down
56 changes: 28 additions & 28 deletions uniconfig/python/tests/test_device_discovery.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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",
)
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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"
)
Expand All @@ -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"
)
Expand All @@ -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
Expand Down

0 comments on commit 809df54

Please sign in to comment.