feat(system): manage compute contour network profile

This commit is contained in:
DCCONSTRUCTIONS
2026-07-29 12:32:41 +03:00
parent 1eba7c82ba
commit d8ccc9345a
8 changed files with 1139 additions and 9 deletions
+10
View File
@@ -41,6 +41,7 @@ def test_contour_store_migrates_worker_006_as_first_configuration(
assert contours[0].telemetry_mode == "agent-mqtt"
assert contours[0].telemetry_poll_interval_seconds == 3
assert contours[0].mqtt_publish_interval_seconds == 2
assert contours[0].mqtt_bind_address == "127.0.0.1"
assert not store.path.exists()
@@ -53,6 +54,7 @@ def test_contour_store_creates_and_updates_private_catalog(tmp_path: Path) -> No
platform="linux",
address="192.0.2.25",
mqtt_host="192.0.2.5",
mqtt_bind_address="192.168.10.5",
)
)
updated = store.update(
@@ -67,6 +69,7 @@ def test_contour_store_creates_and_updates_private_catalog(tmp_path: Path) -> No
ssh_port=22,
mqtt_host="192.0.2.5",
mqtt_port=1883,
mqtt_bind_address="192.168.10.5",
telemetry_poll_interval_seconds=1,
mqtt_publish_interval_seconds=4,
),
@@ -91,6 +94,7 @@ def test_contour_store_creates_and_updates_private_catalog(tmp_path: Path) -> No
ssh_port=22,
mqtt_host="127.0.0.1",
mqtt_port=1883,
mqtt_bind_address="127.0.0.1",
telemetry_poll_interval_seconds=3,
mqtt_publish_interval_seconds=2,
),
@@ -119,6 +123,12 @@ def test_contour_router_exposes_catalog_and_safe_install_contract(
assert "password" not in document["agent"]["environment"]
assert document["agent"]["environment"]["MISSIONCORE_TELEMETRY_INTERVAL"] == "2s"
assert document["ready"] is False
network = _endpoint(
router,
"/api/v1/system/contours/{contour_id}/network",
"GET",
)
assert callable(network)
def test_contour_router_returns_404_for_unknown_contour(tmp_path: Path) -> None:
+137
View File
@@ -0,0 +1,137 @@
from __future__ import annotations
import stat
from pathlib import Path
from typing import Any
import pytest
from k1link.web import compute_contour_network as network
from k1link.web.compute_contour_network import (
ComputeContourNetworkTarget,
NetworkOperationError,
)
def _target(**updates: object) -> ComputeContourNetworkTarget:
values: dict[str, object] = {
"contour_id": "worker-006",
"expected_node_id": "DESKTOP-OPJ8J04",
"platform": "windows",
"worker_address": "",
"ssh_port": 22,
"mqtt_host": "mission-core.local",
"mqtt_port": 1883,
"mqtt_bind_address": "192.168.68.56",
"mqtt_publish_interval_seconds": 2,
}
values.update(updates)
return ComputeContourNetworkTarget(**values) # type: ignore[arg-type]
def test_broker_apply_preserves_private_environment_and_changes_only_bind(
tmp_path: Path,
monkeypatch: pytest.MonkeyPatch,
) -> None:
root = tmp_path / "telemetry-plane"
root.mkdir()
environment = root / ".env"
environment.write_text(
"MISSIONCORE_MQTT_BIND_ADDRESS=192.168.1.5\n"
"MISSIONCORE_MQTT_PASSWORD=do-not-copy\n",
encoding="utf-8",
)
environment.chmod(0o600)
(root / "compose.yaml").write_text("services: {}\n", encoding="utf-8")
compose_calls: list[Path] = []
monkeypatch.setattr(network, "_address_belongs_to_host", lambda _value: True)
monkeypatch.setattr(network, "_tcp_reachable", lambda *_args, **_kwargs: True)
monkeypatch.setattr(
network,
"_run_compose_broker",
lambda path: compose_calls.append(path),
)
result = network.apply_broker_network(_target(), root)
document = environment.read_text(encoding="utf-8")
assert "MISSIONCORE_MQTT_BIND_ADDRESS=192.168.68.56" in document
assert "MISSIONCORE_MQTT_PASSWORD=do-not-copy" in document
assert stat.S_IMODE(environment.stat().st_mode) == 0o600
assert compose_calls == [root]
assert result["target"] == "broker"
assert result["ready"] is True
def test_broker_apply_rolls_back_environment_when_listener_does_not_open(
tmp_path: Path,
monkeypatch: pytest.MonkeyPatch,
) -> None:
root = tmp_path / "telemetry-plane"
root.mkdir()
environment = root / ".env"
before = (
"MISSIONCORE_MQTT_BIND_ADDRESS=192.168.1.5\n"
"MISSIONCORE_MQTT_PASSWORD=still-private\n"
)
environment.write_text(before, encoding="utf-8")
environment.chmod(0o600)
(root / "compose.yaml").write_text("services: {}\n", encoding="utf-8")
monkeypatch.setattr(network, "_address_belongs_to_host", lambda _value: True)
monkeypatch.setattr(network, "_tcp_reachable", lambda *_args, **_kwargs: False)
monkeypatch.setattr(network, "_run_compose_broker", lambda _path: None)
with pytest.raises(NetworkOperationError, match="не открыл"):
network.apply_broker_network(_target(), root)
assert environment.read_text(encoding="utf-8") == before
def test_worker_apply_uses_private_resolved_endpoint_and_confirms_service(
monkeypatch: pytest.MonkeyPatch,
) -> None:
captured: dict[str, Any] = {}
monkeypatch.setattr(
network,
"_resolve_addresses",
lambda _host, _port: ["192.168.68.56"],
)
def run(
target: ComputeContourNetworkTarget,
script: str,
*,
timeout: float,
) -> dict[str, Any]:
captured.update({"target": target, "script": script, "timeout": timeout})
return {
"node_id": "DESKTOP-OPJ8J04",
"service_status": "Running",
"mqtt_host": "mission-core.local",
"mqtt_port": 1883,
"resolved_addresses": ["192.168.68.56"],
"broker_reachable": True,
}
monkeypatch.setattr(network, "_run_worker_powershell", run)
result = network.apply_worker_network(_target())
assert result["target"] == "worker"
assert result["ready"] is True
assert "__PAYLOAD_BASE64__" not in captured["script"]
assert "MISSIONCORE_MQTT_PASSWORD" not in captured["script"]
assert captured["timeout"] == 35
def test_worker_apply_rejects_public_mqtt_endpoint(
monkeypatch: pytest.MonkeyPatch,
) -> None:
monkeypatch.setattr(
network,
"_resolve_addresses",
lambda _host, _port: ["8.8.8.8"],
)
with pytest.raises(NetworkOperationError, match="локальной сети"):
network.apply_worker_network(_target(mqtt_host="broker.example.test"))