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
Show file tree
Hide file tree
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
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
Loading