feat(device-plane): add canonical Device Manager runtime

This commit is contained in:
Codex
2026-08-10 22:00:59 +03:00
parent 1d1e9a96b3
commit 29ba5de92e
14 changed files with 1122 additions and 10 deletions
+493 -5
View File
@@ -38,6 +38,30 @@ DOCKER = Path("/usr/local/bin/docker")
MAP_GATEWAY_SECRET_DIR = Path("/volume1/docker/nodedc-platform/secrets")
MAP_GATEWAY_SECRET_FILE = MAP_GATEWAY_SECRET_DIR / "map-gateway-admin-secret"
MAP_EGRESS_PROXY_SECRET_FILE = MAP_GATEWAY_SECRET_DIR / "map-egress-proxy-token"
PLATFORM_DEVICE_CORE_INTERNAL_TOKEN_FILE = (
MAP_GATEWAY_SECRET_DIR / "device-core-internal-token"
)
PLATFORM_DEVICE_CORE_HUB_TRUST_REL = (
"platform/deployment/device-core-hub-trust-v1.json"
)
PLATFORM_DEVICE_CORE_HUB_TRUST_ENTRIES = (
"platform/docker-compose.platform-http.yml",
PLATFORM_DEVICE_CORE_HUB_TRUST_REL,
)
PLATFORM_DEVICE_MANAGER_PUBLIC_ROUTE_REL = (
"platform/deployment/device-manager-public-route-v1.json"
)
PLATFORM_DEVICE_MANAGER_PUBLIC_ROUTE_ENTRIES = (
"platform/Caddyfile.http",
PLATFORM_DEVICE_MANAGER_PUBLIC_ROUTE_REL,
)
LAUNCHER_DEVICE_CORE_SESSION_ENTRIES = (
"server/control-plane-store.mjs",
"server/dev-server.mjs",
"server/device-core-session-access.mjs",
"server/internal-request-auth.mjs",
"src/shared/api/adminApi.ts",
)
PROXY_CONTUR_ENV_FILE = Path("/volume1/docker/proxy-contur/.env")
DC_AMD_PROXY_RUNTIME_DIR = Path("/volume1/docker/dc-amd-proxy/runtime")
DEVICE_PLANE_ROOT = Path("/volume1/docker/nodedc-device-plane")
@@ -45,8 +69,12 @@ DEVICE_PLANE_SECRET_DIR = DEVICE_PLANE_ROOT / "secrets"
DEVICE_PLANE_POSTGRES_PASSWORD_FILE = DEVICE_PLANE_SECRET_DIR / "postgres-password"
DEVICE_PLANE_GATEWAY_CORE_TOKEN_FILE = DEVICE_PLANE_SECRET_DIR / "gateway-core-token"
DEVICE_PLANE_IDENTIFIER_PEPPER_FILE = DEVICE_PLANE_SECRET_DIR / "identifier-pepper"
DEVICE_PLANE_MANAGEMENT_CORE_TOKEN_FILE = (
DEVICE_PLANE_SECRET_DIR / "management-core-token"
)
DEVICE_PLANE_CONTROL_CORE_IMAGE = "nodedc/device-control-core:local"
DEVICE_PLANE_GATEWAY_IMAGE = "nodedc/device-gateway:local"
DEVICE_PLANE_MANAGER_IMAGE = "nodedc/device-manager:local"
DEVICE_PLANE_BACKHAUL_TARGET_IMAGE = "nodedc/device-backhaul-target:local"
DEVICE_PLANE_BACKHAUL_FAILED_TARGET_REL = (
"deployment/device-plane-backhaul-target-v1.json"
@@ -182,6 +210,26 @@ DEVICE_PLANE_FOUNDATION_ENTRIES = (
"services/device-control-core",
"services/device-gateway",
)
DEVICE_PLANE_MANAGER_CONTROL_PLANE_REL = (
"deployment/device-manager-control-plane-v1.json"
)
DEVICE_PLANE_MANAGER_COMPOSE_REL = "docker-compose.device-manager.yml"
DEVICE_PLANE_MANAGER_COMPOSE_SHA256 = (
"4954120aaddc999798b64c304d8cf692b79714feb727d873117bd1f3434e865e"
)
DEVICE_PLANE_MANAGER_CONTROL_PLANE_ENTRIES = (
".dockerignore",
"package.json",
"package-lock.json",
DEVICE_PLANE_MANAGER_COMPOSE_REL,
"packages/device-protocol-contract",
"packages/arusnavi-b2-adapter",
"services/device-control-core",
"services/device-gateway/package.json",
"services/device-edge-relay/package.json",
"services/device-manager",
DEVICE_PLANE_MANAGER_CONTROL_PLANE_REL,
)
DEVICE_PLANE_FOUNDATION_RECOVERY_REL = (
"deployment/device-plane-foundation-recovery-v1.json"
)
@@ -1478,8 +1526,9 @@ COMPONENTS = {
),
"bootstrap_root": True,
"compose_no_deps": True,
# PostgreSQL is durable state infrastructure. Normal application
# overlays can rebuild/recreate only these two stateless services.
# PostgreSQL is durable state infrastructure. The default legacy
# selection remains Core + Gateway; the exact Device Manager slice
# separately registers the third stateless service.
"services": ("device-control-core", "device-gateway"),
},
"proxy-contur": {
@@ -2641,9 +2690,11 @@ def denied_payload_path(component, rel):
pass
elif component == "device-plane" and rel in (
"docker-compose.device-plane.yml",
DEVICE_PLANE_MANAGER_COMPOSE_REL,
DEVICE_PLANE_BACKHAUL_TARGET_COMPOSE_REL,
"services/device-control-core/Dockerfile",
"services/device-gateway/Dockerfile",
"services/device-manager/Dockerfile",
"services/device-backhaul-target/Dockerfile",
):
pass
@@ -2791,8 +2842,10 @@ def denied_payload_path(component, rel):
return "device-plane test path"
if rel.startswith((
"docker-compose.device-plane.yml.bak",
"docker-compose.device-manager.yml.bak",
"services/device-control-core/Dockerfile.bak",
"services/device-gateway/Dockerfile.bak",
"services/device-manager/Dockerfile.bak",
)):
return "device-plane backup file"
elif component == "n8n-private-extension":
@@ -2916,6 +2969,8 @@ def allowed_payload_path(component, rel):
"platform/Caddyfile.http",
"platform/docker-compose.platform-http.yml",
"platform/docker-compose.external-data-plane.yml",
PLATFORM_DEVICE_CORE_HUB_TRUST_REL,
PLATFORM_DEVICE_MANAGER_PUBLIC_ROUTE_REL,
):
return True
if rel == "platform/notification-core" or rel.startswith("platform/notification-core/"):
@@ -3051,6 +3106,7 @@ def allowed_payload_path(component, rel):
"package.json",
"package-lock.json",
"docker-compose.device-plane.yml",
DEVICE_PLANE_MANAGER_COMPOSE_REL,
DEVICE_PLANE_BACKHAUL_TARGET_COMPOSE_REL,
DEVICE_PLANE_POSTGRES_BOOTSTRAP_REL,
DEVICE_PLANE_FOUNDATION_RECOVERY_REL,
@@ -3058,11 +3114,13 @@ def allowed_payload_path(component, rel):
DEVICE_PLANE_B2_DISCOVERY_INGRESS_REL,
DEVICE_PLANE_B2_DISCOVERY_ROLLBACK_RECOVERY_REL,
DEVICE_PLANE_BACKHAUL_TARGET_REL,
DEVICE_PLANE_MANAGER_CONTROL_PLANE_REL,
"packages/device-protocol-contract",
"packages/arusnavi-b2-adapter",
"services/device-control-core",
"services/device-gateway",
"services/device-edge-relay/package.json",
"services/device-manager",
"services/device-backhaul-target",
):
return True
@@ -3071,6 +3129,7 @@ def allowed_payload_path(component, rel):
"packages/arusnavi-b2-adapter/",
"services/device-control-core/",
"services/device-gateway/",
"services/device-manager/",
"services/device-backhaul-target/",
)):
return True
@@ -8086,6 +8145,21 @@ def load_artifact(artifact, work_dir):
die(f"files.txt entry missing in payload: {rel}")
validate_payload_tree(manifest["component"], payload_dir, entries)
if is_platform_device_core_hub_trust_slice(
manifest["component"],
entries,
):
validate_platform_device_core_hub_trust_payload(payload_dir)
if is_platform_device_manager_public_route_slice(
manifest["component"],
entries,
):
validate_platform_device_manager_public_route_payload(payload_dir)
if is_device_plane_manager_control_plane_slice(
manifest["component"],
entries,
):
validate_device_plane_manager_control_plane_payload(payload_dir)
if is_device_plane_postgres_bootstrap_slice(
manifest["component"],
entries,
@@ -8449,6 +8523,156 @@ def component_root(component):
return COMPONENTS[component]["payload_root"]
def is_platform_device_core_hub_trust_slice(component, entries):
return (
component == "platform"
and entries is not None
and tuple(entries) == PLATFORM_DEVICE_CORE_HUB_TRUST_ENTRIES
)
def is_platform_device_manager_public_route_slice(component, entries):
return (
component == "platform"
and entries is not None
and tuple(entries) == PLATFORM_DEVICE_MANAGER_PUBLIC_ROUTE_ENTRIES
)
def is_launcher_device_core_session_slice(component, entries):
return (
component == "launcher"
and entries is not None
and tuple(entries) == LAUNCHER_DEVICE_CORE_SESSION_ENTRIES
)
def is_device_plane_manager_control_plane_slice(component, entries):
return (
component == "device-plane"
and entries is not None
and tuple(entries) == DEVICE_PLANE_MANAGER_CONTROL_PLANE_ENTRIES
)
def expected_platform_device_core_hub_trust_descriptor():
return {
"schemaVersion": "nodedc.platform.device-core-hub-trust.v1",
"action": "activate",
"serviceSlug": "device-core",
"launcherCredential": "runner-managed-file",
"credentialScope": ["handoff.consume", "session.validate"],
"publicRoute": "unchanged",
}
def expected_platform_device_manager_public_route_descriptor():
return {
"schemaVersion": "nodedc.platform.device-manager-public-route.v1",
"action": "activate",
"hostname": "device.nodedc.ru",
"upstream": "device-manager:18122",
"transport": "reverse-proxy",
"rawTcpIngress": "forbidden",
}
def expected_device_plane_manager_control_plane_descriptor():
return {
"schemaVersion": (
"nodedc.device-plane.device-manager-control-plane.v1"
),
"action": "activate",
"service": "device-manager",
"publicIngress": "reverse-proxy-only",
"deviceCoreManagementApi": "file-token-authenticated",
"launcherTrust": "file-token-scoped-to-device-core-handoff",
"commandTransport": "disabled",
"gelios": "untouched",
}
def validate_platform_device_core_hub_trust_payload(payload_dir):
descriptor = read_strict_json(
payload_dir / PLATFORM_DEVICE_CORE_HUB_TRUST_REL,
"Platform Device Core Hub trust descriptor",
max_bytes=16 * 1024,
)
if descriptor != expected_platform_device_core_hub_trust_descriptor():
die("Platform Device Core Hub trust descriptor mismatch")
compose = (
payload_dir / "platform/docker-compose.platform-http.yml"
).read_text(encoding="utf-8")
for required in (
"NODEDC_DEVICE_CORE_INTERNAL_TOKEN_FILE: "
"/run/nodedc-secrets/device-core-internal-token",
"source: /volume1/docker/nodedc-platform/secrets/"
"device-core-internal-token",
"create_host_path: false",
):
if required not in compose:
die(f"Platform Device Core Hub trust boundary missing: {required}")
return descriptor
def validate_platform_device_manager_public_route_payload(payload_dir):
descriptor = read_strict_json(
payload_dir / PLATFORM_DEVICE_MANAGER_PUBLIC_ROUTE_REL,
"Platform Device Manager public route descriptor",
max_bytes=16 * 1024,
)
if descriptor != expected_platform_device_manager_public_route_descriptor():
die("Platform Device Manager public route descriptor mismatch")
caddy = (payload_dir / "platform/Caddyfile.http").read_text(
encoding="utf-8"
)
for required in (
"http://device.nodedc.ru",
"reverse_proxy device-manager:18122",
"header_up X-Forwarded-Proto https",
):
if required not in caddy:
die(f"Platform Device Manager route boundary missing: {required}")
return descriptor
def validate_device_plane_manager_control_plane_payload(payload_dir):
descriptor = read_strict_json(
payload_dir / DEVICE_PLANE_MANAGER_CONTROL_PLANE_REL,
"Device Manager control-plane descriptor",
max_bytes=16 * 1024,
)
if descriptor != expected_device_plane_manager_control_plane_descriptor():
die("Device Manager control-plane descriptor mismatch")
compose_path = payload_dir / DEVICE_PLANE_MANAGER_COMPOSE_REL
if sha256_file(compose_path) != DEVICE_PLANE_MANAGER_COMPOSE_SHA256:
die("Device Manager control-plane Compose mismatch")
compose = compose_path.read_text(
encoding="utf-8"
)
for required in (
"device-manager:",
'DEVICE_MANAGEMENT_API_ENABLED: "true"',
"DEVICE_MANAGEMENT_CORE_TOKEN_FILE: "
"/run/nodedc-secrets/management-core-token",
"NODEDC_LAUNCHER_INTERNAL_TOKEN_FILE: "
"/run/nodedc-secrets/device-core-internal-token",
"NODEDC_DEVICE_CORE_TOKEN_FILE: "
"/run/nodedc-secrets/management-core-token",
"name: nodedc-platform_edge",
):
if required not in compose:
die(f"Device Manager control-plane boundary missing: {required}")
for forbidden in (
"NODEDC_INTERNAL_ACCESS_TOKEN:",
"NODEDC_PLATFORM_SERVICE_TOKEN:",
"0.0.0.0:18122",
):
if forbidden in compose:
die(f"Device Manager control-plane boundary violation: {forbidden}")
return descriptor
def is_device_plane_postgres_bootstrap_slice(component, entries):
return (
component == "device-plane"
@@ -9674,6 +9898,7 @@ def validate_device_plane_b2_discovery_rollback_recovery_evidence(
def device_plane_service_container_ids(service):
if service not in (
*DEVICE_PLANE_RUNTIME_SERVICES,
"device-manager",
DEVICE_PLANE_BACKHAUL_TARGET_SERVICE,
):
die(f"Device Plane runtime service is not registered: {service}")
@@ -11044,7 +11269,7 @@ def validate_device_plane_backhaul_target_runtime(
}
def validate_device_plane_runtime_secret_metadata():
def validate_device_plane_runtime_secret_metadata(include_management=False):
try:
directory_stat = DEVICE_PLANE_SECRET_DIR.lstat()
except FileNotFoundError:
@@ -11057,11 +11282,17 @@ def validate_device_plane_runtime_secret_metadata():
or stat.S_IMODE(directory_stat.st_mode) != 0o710
):
die("Device Plane runtime secret directory boundary mismatch")
for path, label in (
required_secrets = [
(DEVICE_PLANE_POSTGRES_PASSWORD_FILE, "PostgreSQL"),
(DEVICE_PLANE_GATEWAY_CORE_TOKEN_FILE, "Gateway to Core"),
(DEVICE_PLANE_IDENTIFIER_PEPPER_FILE, "identifier pepper"),
):
]
if include_management:
required_secrets.append((
DEVICE_PLANE_MANAGEMENT_CORE_TOKEN_FILE,
"management to Core",
))
for path, label in required_secrets:
try:
path_stat = path.lstat()
except FileNotFoundError:
@@ -11084,6 +11315,111 @@ def validate_device_plane_runtime_secret_metadata():
return "exact"
def validate_device_manager_control_plane_runtime():
core_ids = device_plane_service_container_ids("device-control-core")
manager_ids = device_plane_service_container_ids("device-manager")
if len(core_ids) != 1 or len(manager_ids) != 1:
die("Device Manager control-plane runtime topology mismatch")
core = inspect_device_plane_container(core_ids[0])
manager = inspect_device_plane_container(manager_ids[0])
core_environment = container_environment(core, "Device Control Core")
manager_environment = container_environment(manager, "Device Manager")
if (
core_environment.get("DEVICE_MANAGEMENT_API_ENABLED") != "true"
or core_environment.get("DEVICE_MANAGEMENT_CORE_TOKEN_FILE")
!= "/run/nodedc-secrets/management-core-token"
):
die("Device Control Core management runtime mismatch")
expected_manager_environment = {
"NODE_ENV": "production",
"HOST": "0.0.0.0",
"PORT": "18122",
"NODEDC_DEVICE_MANAGER_AUTH_REQUIRED": "true",
"NODEDC_DEVICE_MANAGER_COOKIE_SECURE": "true",
"NODEDC_DEVICE_MANAGER_LOCAL_PREVIEW": "false",
"NODEDC_DEVICE_MANAGER_SERVICE_SLUG": "device-core",
"NODEDC_LAUNCHER_BASE_URL": "https://hub.nodedc.ru",
"NODEDC_LAUNCHER_INTERNAL_URL": "http://launcher:5173",
"NODEDC_LAUNCHER_INTERNAL_TOKEN_FILE": (
"/run/nodedc-secrets/device-core-internal-token"
),
"NODEDC_DEVICE_CORE_INTERNAL_URL": (
"http://device-control-core:18120"
),
"NODEDC_DEVICE_CORE_TOKEN_FILE": (
"/run/nodedc-secrets/management-core-token"
),
}
if any(
manager_environment.get(key) != value
for key, value in expected_manager_environment.items()
):
die("Device Manager environment mismatch")
for environment in (core_environment, manager_environment):
for forbidden in (
"NODEDC_INTERNAL_ACCESS_TOKEN",
"NODEDC_PLATFORM_SERVICE_TOKEN",
"DEVICE_MANAGEMENT_CORE_TOKEN",
):
if forbidden in environment:
die("Device Manager plaintext secret boundary mismatch")
core_mounts = {
mount.get("Destination"): mount
for mount in core.get("Mounts") or []
}
core_management_mount = core_mounts.get(
"/run/nodedc-secrets/management-core-token"
)
if (
core_management_mount is None
or core_management_mount.get("Type") != "bind"
or core_management_mount.get("Source")
!= str(DEVICE_PLANE_MANAGEMENT_CORE_TOKEN_FILE)
or core_management_mount.get("RW") is not False
):
die("Device Control Core management secret mount mismatch")
manager_mounts = {
mount.get("Destination"): mount
for mount in manager.get("Mounts") or []
}
expected_manager_mounts = {
"/run/nodedc-secrets/device-core-internal-token": (
PLATFORM_DEVICE_CORE_INTERNAL_TOKEN_FILE
),
"/run/nodedc-secrets/management-core-token": (
DEVICE_PLANE_MANAGEMENT_CORE_TOKEN_FILE
),
}
if set(manager_mounts) != set(expected_manager_mounts):
die("Device Manager mount set mismatch")
for destination, source in expected_manager_mounts.items():
mount = manager_mounts[destination]
if (
mount.get("Type") != "bind"
or mount.get("Source") != str(source)
or mount.get("RW") is not False
):
die("Device Manager secret mount mismatch")
ports = (manager.get("NetworkSettings") or {}).get("Ports") or {}
if any(bindings for bindings in ports.values()):
die("Device Manager host port publication is forbidden")
networks = set(
((manager.get("NetworkSettings") or {}).get("Networks") or {}).keys()
)
if networks != {
DEVICE_PLANE_PRIVATE_NETWORK,
"nodedc-platform_edge",
}:
die("Device Manager network boundary mismatch")
validate_device_plane_runtime_secret_metadata(include_management=True)
ensure_platform_runtime_secret(
PLATFORM_DEVICE_CORE_INTERNAL_TOKEN_FILE,
MAP_GATEWAY_SECRET_RE,
"Device Core Hub handoff",
)
return "exact"
def validate_device_plane_foundation_installed_source():
failed_artifact = FAILED_DIR / DEVICE_PLANE_FOUNDATION_FAILED_ARTIFACT
with tempfile.TemporaryDirectory(
@@ -12804,6 +13140,9 @@ def component_services(component, entries=None):
# authorization normalization inside the already-active backend.
return ("nodedc-backend",)
if is_device_plane_manager_control_plane_slice(component, entries):
return ("device-control-core", "device-manager")
if component == "device-plane" and entries is not None:
selected = []
@@ -12882,6 +13221,12 @@ def component_services(component, entries=None):
selected.append("proxy")
return tuple(selected)
if is_platform_device_core_hub_trust_slice(component, entries):
return ("launcher",)
if is_platform_device_manager_public_route_slice(component, entries):
return ("reverse-proxy",)
if component == "platform" and entries is not None:
if is_platform_provider_catalog_only(entries):
return ()
@@ -13045,6 +13390,16 @@ def component_compose_files(
return tuple(files)
files = COMPONENTS[component].get("compose_files", ())
if component == "device-plane":
manager_overlay = DEVICE_PLANE_ROOT / DEVICE_PLANE_MANAGER_COMPOSE_REL
if manager_overlay.exists() or manager_overlay.is_symlink():
if (
manager_overlay.is_symlink()
or not manager_overlay.is_file()
or sha256_file(manager_overlay)
!= DEVICE_PLANE_MANAGER_COMPOSE_SHA256
):
die("installed Device Manager Compose drift detected")
files = (*files, manager_overlay)
overlay = DEVICE_PLANE_ROOT / DEVICE_PLANE_BACKHAUL_TARGET_COMPOSE_REL
if overlay.exists() or overlay.is_symlink():
if (
@@ -13088,6 +13443,39 @@ def component_build_args(component, entries=None):
def component_builds(component, entries=None):
if is_platform_device_core_hub_trust_slice(component, entries):
return ()
if is_platform_device_manager_public_route_slice(component, entries):
return ()
if is_device_plane_manager_control_plane_slice(component, entries):
return (
(
DEVICE_PLANE_ROOT,
(
"build",
"--no-cache",
"--network=host",
"-f",
"services/device-control-core/Dockerfile",
"-t",
DEVICE_PLANE_CONTROL_CORE_IMAGE,
".",
),
),
(
DEVICE_PLANE_ROOT / "services/device-manager",
(
"build",
"--no-cache",
"-t",
DEVICE_PLANE_MANAGER_IMAGE,
".",
),
),
)
if is_device_plane_backhaul_vps_enrollment_slice(component, entries):
return ()
@@ -13155,6 +13543,17 @@ def component_builds(component, entries=None):
".",
),
))
if "device-manager" in selected_services:
builds.append((
DEVICE_PLANE_ROOT / "services/device-manager",
(
"build",
"--no-cache",
"-t",
DEVICE_PLANE_MANAGER_IMAGE,
".",
),
))
return tuple(builds)
if component == "platform" and entries is not None:
@@ -16694,6 +17093,15 @@ def plan_artifact(artifact):
print(f"runtime_secret=runner-managed:{DEVICE_PLANE_POSTGRES_PASSWORD_FILE}")
print(f"runtime_secret=runner-managed:{DEVICE_PLANE_GATEWAY_CORE_TOKEN_FILE}")
print(f"runtime_secret=runner-managed:{DEVICE_PLANE_IDENTIFIER_PEPPER_FILE}")
if is_device_plane_manager_control_plane_slice(component, entries):
print(
"runtime_secret=runner-managed:"
f"{DEVICE_PLANE_MANAGEMENT_CORE_TOKEN_FILE}"
)
print(
"runtime_secret=runner-managed:"
f"{PLATFORM_DEVICE_CORE_INTERNAL_TOKEN_FILE}"
)
print(
"device_postgres="
f"{device_plane_postgres_plan_selection(device_plane_postgres_preflight)}"
@@ -16977,6 +17385,19 @@ def plan_artifact(artifact):
)
print("device_postgres_bootstrap_mode=create-if-absent")
print("device_postgres_rollback_volume=preserve")
if is_platform_device_core_hub_trust_slice(component, entries):
print(
"runtime_secret=runner-managed:"
f"{PLATFORM_DEVICE_CORE_INTERNAL_TOKEN_FILE}"
)
print("device_core_hub_credential_scope=handoff+session-only")
print("device_manager_public_route=unchanged")
if is_platform_device_manager_public_route_slice(component, entries):
print("device_manager_public_route=https-via-reverse-proxy")
print("device_manager_raw_tcp_ingress=forbidden")
if is_launcher_device_core_session_slice(component, entries):
print("device_core_owner_scopes=hub-signed-runtime-claims")
print("device_core_company_scope=active-admin-grant-only")
if touches_external_data_plane:
print(f"runtime_secret=runner-managed:{EXTERNAL_DATA_PLANE_PROVISIONER_SECRET_FILE}")
print(f"runtime_grants=runner-managed:{EXTERNAL_DATA_PLANE_READER_GRANTS_DIR}")
@@ -18227,6 +18648,17 @@ def prepare_component_runtime(component, entries=None):
MAP_GATEWAY_SECRET_RE,
"device plane identifier pepper",
)
if is_device_plane_manager_control_plane_slice(component, entries):
ensure_platform_runtime_secret(
DEVICE_PLANE_MANAGEMENT_CORE_TOKEN_FILE,
MAP_GATEWAY_SECRET_RE,
"device plane management to Core",
)
ensure_platform_runtime_secret(
PLATFORM_DEVICE_CORE_INTERNAL_TOKEN_FILE,
MAP_GATEWAY_SECRET_RE,
"Device Core Hub handoff",
)
if is_device_plane_backhaul_vps_enrollment_slice(
component,
entries,
@@ -18272,6 +18704,12 @@ def prepare_component_runtime(component, entries=None):
return
if component == "platform" and entries is not None:
if is_platform_device_core_hub_trust_slice(component, entries):
ensure_platform_runtime_secret(
PLATFORM_DEVICE_CORE_INTERNAL_TOKEN_FILE,
MAP_GATEWAY_SECRET_RE,
"Device Core Hub handoff",
)
touches_map_gateway = any(rel == "platform/services/map-gateway" or rel.startswith("platform/services/map-gateway/") for rel in entries)
touches_external_data_plane = touches_external_data_plane_files(entries)
if touches_map_gateway:
@@ -18483,6 +18921,44 @@ def module_foundry_healthcheck():
def component_healthchecks(component, entries=None, services=None):
if is_platform_device_core_hub_trust_slice(component, entries):
return ({
"url": "http://127.0.0.1:18080/healthz",
"headers": {"Host": "hub.nodedc.ru"},
},)
if is_platform_device_manager_public_route_slice(component, entries):
return ({
"url": "http://127.0.0.1:18080/healthz",
"headers": {"Host": "device.nodedc.ru"},
"expected_json": {
"ok": True,
"service": "nodedc-device-manager",
"authRequired": True,
"deviceCoreConfigured": True,
},
},)
if is_launcher_device_core_session_slice(component, entries):
return ({
"url": "http://127.0.0.1:18080/healthz",
"headers": {"Host": "hub.nodedc.ru"},
"expected_json": {
"ok": True,
"service": "nodedc-launcher-bff",
"deviceCoreInternalAccessConfigured": True,
},
},)
if is_device_plane_manager_control_plane_slice(component, entries):
return ({
"url": "http://127.0.0.1:18120/healthz",
"expected_json": {
"ok": True,
"service": "nodedc-device-control-core",
"database": "ready",
"discoveryIngest": "enabled",
"managementApi": "enabled",
"commandTransport": "disabled",
},
},)
if is_device_plane_b2_discovery_rollback_recovery_slice(
component,
entries,
@@ -19100,6 +19576,18 @@ def run_healthchecks(component, entries=None, services=None):
healthcheck_url(check)
assert_loopback_tcp_port_open(9921)
return
if is_device_plane_manager_control_plane_slice(component, entries):
if tuple(services or ()) != (
"device-control-core",
"device-manager",
):
die("Device Manager control-plane service set mismatch")
for service in services:
healthcheck_compose_service("device-plane", service)
for check in component_healthchecks(component, entries, services):
healthcheck_url(check)
validate_device_manager_control_plane_runtime()
return
if component == "platform" and entries is not None and is_platform_provider_catalog_only(entries):
return
if is_engine_l2_closed_loop_slice(component, entries):