feat(deploy): register canonical manager v8

This commit is contained in:
Codex
2026-08-22 15:33:06 +03:00
parent e2ea7e177d
commit 0438fbd80b
2 changed files with 205 additions and 3 deletions
+158 -3
View File
@@ -275,6 +275,9 @@ DEVICE_PLANE_MANAGER_RELEASE_V6_REL = (
DEVICE_PLANE_MANAGER_RELEASE_V7_REL = (
"deployment/device-manager-release-v7.json"
)
DEVICE_PLANE_MANAGER_RELEASE_V8_REL = (
"deployment/device-manager-release-v8.json"
)
DEVICE_PLANE_MANAGER_COMPOSE_REL = "docker-compose.device-manager.yml"
DEVICE_PLANE_EDGE_CORE_CHANNEL_BOOTSTRAP_REL = (
"deployment/device-edge-core-channel-bootstrap-v1.json"
@@ -412,6 +415,18 @@ DEVICE_PLANE_MANAGER_RELEASE_V7_CONTROL_CORE_PREDECESSOR_PATCH_ID = (
DEVICE_PLANE_MANAGER_RELEASE_V7_CONTROL_CORE_PREDECESSOR_ARTIFACT_SHA256 = (
"8708cc4b59fa0cd5e9c6e6a7b2654ba01ea60271549167aca2631f94000d3da3"
)
DEVICE_PLANE_MANAGER_RELEASE_V8_PREDECESSOR_PATCH_ID = (
"device-manager-release-v6-20260822-035"
)
DEVICE_PLANE_MANAGER_RELEASE_V8_PREDECESSOR_ARTIFACT_SHA256 = (
"193faabe930e2b3f212f8eb45288e39f850ec714528b28881095be654baf9a80"
)
DEVICE_PLANE_MANAGER_RELEASE_V8_CONTROL_CORE_PREDECESSOR_PATCH_ID = (
"device-control-core-release-v2-20260822-038"
)
DEVICE_PLANE_MANAGER_RELEASE_V8_CONTROL_CORE_PREDECESSOR_ARTIFACT_SHA256 = (
"e2d062b82b022dba662522b5d6e192026ac964d78950d903295ca3cbbc95ab28"
)
DEVICE_PLANE_EDGE_CORE_CHANNEL_BOOTSTRAP_PREDECESSOR_PATCH_ID = (
"device-edge-core-channel-bootstrap-20260812-018"
)
@@ -482,6 +497,9 @@ DEVICE_PLANE_MANAGER_RELEASE_V6_COMPOSE_SHA256 = (
DEVICE_PLANE_MANAGER_RELEASE_V7_COMPOSE_SHA256 = (
DEVICE_PLANE_MANAGER_RELEASE_V6_COMPOSE_SHA256
)
DEVICE_PLANE_MANAGER_RELEASE_V8_COMPOSE_SHA256 = (
DEVICE_PLANE_MANAGER_RELEASE_V6_COMPOSE_SHA256
)
DEVICE_PLANE_MANAGER_FAVICON_SHA256 = {
"favicon.ico": (
"f8933114a85646335ea5c94944f56d3cd8c48a6032016719f7905ff244ec0aa2"
@@ -603,6 +621,11 @@ DEVICE_PLANE_MANAGER_RELEASE_V7_ENTRIES = (
"services/device-manager",
DEVICE_PLANE_MANAGER_RELEASE_V7_REL,
)
DEVICE_PLANE_MANAGER_RELEASE_V8_ENTRIES = (
DEVICE_PLANE_MANAGER_COMPOSE_REL,
"services/device-manager",
DEVICE_PLANE_MANAGER_RELEASE_V8_REL,
)
DEVICE_PLANE_MANAGER_RECONCILIATION_REL = (
"deployment/device-manager-control-plane-reconciliation-v1.json"
)
@@ -4645,6 +4668,7 @@ def allowed_payload_path(component, rel):
DEVICE_PLANE_MANAGER_RELEASE_V5_REL,
DEVICE_PLANE_MANAGER_RELEASE_V6_REL,
DEVICE_PLANE_MANAGER_RELEASE_V7_REL,
DEVICE_PLANE_MANAGER_RELEASE_V8_REL,
DEVICE_PLANE_EDGE_CORE_CHANNEL_BOOTSTRAP_REL,
DEVICE_PLANE_EDGE_CORE_CHANNEL_UPGRADE_REL,
DEVICE_PLANE_EDGE_CORE_CHANNEL_UPGRADE_V2_REL,
@@ -11586,6 +11610,7 @@ def is_device_plane_manager_control_plane_slice(component, entries):
DEVICE_PLANE_MANAGER_RELEASE_V5_ENTRIES,
DEVICE_PLANE_MANAGER_RELEASE_V6_ENTRIES,
DEVICE_PLANE_MANAGER_RELEASE_V7_ENTRIES,
DEVICE_PLANE_MANAGER_RELEASE_V8_ENTRIES,
)
)
@@ -11638,12 +11663,21 @@ def is_device_plane_manager_release_v7_slice(component, entries):
)
def is_device_plane_manager_release_v8_slice(component, entries):
return (
component == "device-plane"
and entries is not None
and tuple(entries) == DEVICE_PLANE_MANAGER_RELEASE_V8_ENTRIES
)
def is_device_plane_manager_persistent_release_slice(component, entries):
return (
is_device_plane_manager_release_v4_slice(component, entries)
or is_device_plane_manager_release_v5_slice(component, entries)
or is_device_plane_manager_release_v6_slice(component, entries)
or is_device_plane_manager_release_v7_slice(component, entries)
or is_device_plane_manager_release_v8_slice(component, entries)
)
@@ -11922,6 +11956,42 @@ def expected_device_plane_manager_release_v7_boundaries():
}
def expected_device_plane_manager_release_v8_boundaries():
return {
**expected_device_plane_manager_release_v6_boundaries(),
"predecessor": {
"kind": "release",
"patchId": DEVICE_PLANE_MANAGER_RELEASE_V8_PREDECESSOR_PATCH_ID,
"artifactSha256": (
DEVICE_PLANE_MANAGER_RELEASE_V8_PREDECESSOR_ARTIFACT_SHA256
),
},
"controlCorePredecessor": {
"patchId": (
DEVICE_PLANE_MANAGER_RELEASE_V8_CONTROL_CORE_PREDECESSOR_PATCH_ID
),
"artifactSha256": (
DEVICE_PLANE_MANAGER_RELEASE_V8_CONTROL_CORE_PREDECESSOR_ARTIFACT_SHA256
),
},
"commandFormLayout": "aligned-control-row-v1",
"secondaryEmptyTypography": "help-text-sm-v1",
"infrastructureHostProjection": "ontology-backed-host-runtime-v1",
"ontologyFoundation": (
"ontology-core-device-foundation-20260822-001"
),
"ontologyCatalogHash": "229c61c02a790906",
"assetBinding": "temporal-device-asset-binding-v1",
"infrastructureRuntime": (
"host-endpoint-deployment-service-instance-v1"
),
"healthEvidence": "ttl-observation-missing-not-unhealthy-v1",
"interactiveShell": (
"disabled-pending-managed-session-boundary"
),
}
def expected_device_plane_manager_release_boundaries():
# Compatibility name for the current release builder/tests. Immutable v1
# predecessors always use expected_device_plane_manager_release_v1_boundaries.
@@ -12441,6 +12511,7 @@ def validate_device_plane_manager_release_payload_contract(
"nodedc.device-plane.device-manager-release.v5",
"nodedc.device-plane.device-manager-release.v6",
"nodedc.device-plane.device-manager-release.v7",
"nodedc.device-plane.device-manager-release.v8",
):
required_compose.extend((
"NODEDC_DEVICE_MANAGER_PRESENTATION_PATH: "
@@ -12613,6 +12684,24 @@ def validate_device_plane_manager_release_v7_payload(
return descriptor
def validate_device_plane_manager_release_v8_payload(
payload_dir,
*,
expected_release_id=None,
):
descriptor = validate_device_plane_manager_release_payload_contract(
payload_dir,
descriptor_rel=DEVICE_PLANE_MANAGER_RELEASE_V8_REL,
schema_version="nodedc.device-plane.device-manager-release.v8",
boundaries=expected_device_plane_manager_release_v8_boundaries(),
compose_sha256=DEVICE_PLANE_MANAGER_RELEASE_V8_COMPOSE_SHA256,
edge_channel=False,
expected_release_id=expected_release_id,
)
validate_device_plane_manager_v6_favicon_bundle(payload_dir)
return descriptor
def validate_device_plane_manager_release_payload(
payload_dir,
*,
@@ -12625,12 +12714,18 @@ def validate_device_plane_manager_release_payload(
v5 = payload_dir / DEVICE_PLANE_MANAGER_RELEASE_V5_REL
v6 = payload_dir / DEVICE_PLANE_MANAGER_RELEASE_V6_REL
v7 = payload_dir / DEVICE_PLANE_MANAGER_RELEASE_V7_REL
v8 = payload_dir / DEVICE_PLANE_MANAGER_RELEASE_V8_REL
present = [
path for path in (v1, v2, v3, v4, v5, v6, v7)
path for path in (v1, v2, v3, v4, v5, v6, v7, v8)
if path.exists() or path.is_symlink()
]
if len(present) != 1:
die("Device Manager release descriptor cardinality mismatch")
if present[0] == v8:
return validate_device_plane_manager_release_v8_payload(
payload_dir,
expected_release_id=expected_release_id,
)
if present[0] == v7:
return validate_device_plane_manager_release_v7_payload(
payload_dir,
@@ -12932,6 +13027,7 @@ def installed_device_plane_manager_compose_sha256():
v5 = root / DEVICE_PLANE_MANAGER_RELEASE_V5_REL
v6 = root / DEVICE_PLANE_MANAGER_RELEASE_V6_REL
v7 = root / DEVICE_PLANE_MANAGER_RELEASE_V7_REL
v8 = root / DEVICE_PLANE_MANAGER_RELEASE_V8_REL
# A successful v2 overlay intentionally leaves the immutable v1 release
# descriptor as predecessor evidence. Prefer the highest installed
@@ -12939,6 +13035,19 @@ def installed_device_plane_manager_compose_sha256():
# the generation-specific Compose digest. During a failed v2 apply,
# rollback removes the candidate-only v2 descriptor before rebuilding the
# restored v1 runtime, so the same lookup follows the restored source.
if v8.exists() or v8.is_symlink():
descriptor = read_strict_json(
v8,
"installed Device Manager release v8 descriptor",
max_bytes=16 * 1024,
)
validate_device_plane_manager_release_descriptor(
descriptor,
schema_version="nodedc.device-plane.device-manager-release.v8",
boundaries=expected_device_plane_manager_release_v8_boundaries(),
)
return DEVICE_PLANE_MANAGER_RELEASE_V8_COMPOSE_SHA256
if v7.exists() or v7.is_symlink():
descriptor = read_strict_json(
v7,
@@ -14511,6 +14620,7 @@ def validate_device_plane_manager_v3_active_baseline(descriptor):
"nodedc.device-plane.device-manager-release.v5",
"nodedc.device-plane.device-manager-release.v6",
"nodedc.device-plane.device-manager-release.v7",
"nodedc.device-plane.device-manager-release.v8",
):
return None
@@ -14661,6 +14771,7 @@ def device_plane_manager_preserved_runtime_health_services(descriptor):
"nodedc.device-plane.device-manager-release.v5",
"nodedc.device-plane.device-manager-release.v6",
"nodedc.device-plane.device-manager-release.v7",
"nodedc.device-plane.device-manager-release.v8",
):
return (
"device-control-core",
@@ -14796,6 +14907,7 @@ def validate_device_plane_manager_activation_predecessor(
DEVICE_PLANE_MANAGER_RELEASE_V5_ENTRIES,
DEVICE_PLANE_MANAGER_RELEASE_V6_ENTRIES,
DEVICE_PLANE_MANAGER_RELEASE_V7_ENTRIES,
DEVICE_PLANE_MANAGER_RELEASE_V8_ENTRIES,
)
):
die("Device Manager release predecessor type mismatch")
@@ -14818,6 +14930,8 @@ def validate_device_plane_manager_activation_predecessor(
DEVICE_PLANE_MANAGER_RELEASE_V6_REL,
DEVICE_PLANE_MANAGER_RELEASE_V7_ENTRIES:
DEVICE_PLANE_MANAGER_RELEASE_V7_REL,
DEVICE_PLANE_MANAGER_RELEASE_V8_ENTRIES:
DEVICE_PLANE_MANAGER_RELEASE_V8_REL,
}.get(
tuple(predecessor_entries),
DEVICE_PLANE_MANAGER_CONTROL_PLANE_REL,
@@ -17197,6 +17311,7 @@ def validate_device_manager_control_plane_runtime(
require_edge_channel = edge_descriptor.is_file() and not edge_descriptor.is_symlink()
if require_persistent_data is None:
data_descriptors = (
DEVICE_PLANE_ROOT / DEVICE_PLANE_MANAGER_RELEASE_V8_REL,
DEVICE_PLANE_ROOT / DEVICE_PLANE_MANAGER_RELEASE_V7_REL,
DEVICE_PLANE_ROOT / DEVICE_PLANE_MANAGER_RELEASE_V6_REL,
DEVICE_PLANE_ROOT / DEVICE_PLANE_MANAGER_RELEASE_V5_REL,
@@ -29850,6 +29965,7 @@ def plan_artifact(artifact):
"nodedc.device-plane.device-manager-release.v5",
"nodedc.device-plane.device-manager-release.v6",
"nodedc.device-plane.device-manager-release.v7",
"nodedc.device-plane.device-manager-release.v8",
)
else "build+recreate:device-control-core,device-manager"
)
@@ -29867,6 +29983,7 @@ def plan_artifact(artifact):
"nodedc.device-plane.device-manager-release.v5",
"nodedc.device-plane.device-manager-release.v6",
"nodedc.device-plane.device-manager-release.v7",
"nodedc.device-plane.device-manager-release.v8",
)
else "preserved:device-gateway,device-postgres,"
"device-backhaul-target"
@@ -29880,6 +29997,7 @@ def plan_artifact(artifact):
"nodedc.device-plane.device-manager-release.v5",
"nodedc.device-plane.device-manager-release.v6",
"nodedc.device-plane.device-manager-release.v7",
"nodedc.device-plane.device-manager-release.v8",
)
print(
"device_manager_health_gate="
@@ -29903,6 +30021,7 @@ def plan_artifact(artifact):
"nodedc.device-plane.device-manager-release.v5",
"nodedc.device-plane.device-manager-release.v6",
"nodedc.device-plane.device-manager-release.v7",
"nodedc.device-plane.device-manager-release.v8",
):
print(
"device_manager_overview_layout="
@@ -29911,13 +30030,18 @@ def plan_artifact(artifact):
if manager_schema in (
"nodedc.device-plane.device-manager-release.v6",
"nodedc.device-plane.device-manager-release.v7",
"nodedc.device-plane.device-manager-release.v8",
):
print("device_manager_favicon_set=nodedc-adaptive-v1")
if manager_schema == (
"nodedc.device-plane.device-manager-release.v7"
if manager_schema in (
"nodedc.device-plane.device-manager-release.v7",
"nodedc.device-plane.device-manager-release.v8",
):
print("device_manager_command_form=aligned-control-row-v1")
print("device_manager_secondary_empty_text=help-text-sm-v1")
if manager_schema == (
"nodedc.device-plane.device-manager-release.v7"
):
print(
"device_manager_infrastructure_hosts="
"edge-registration-live-channel-v1"
@@ -29926,6 +30050,37 @@ def plan_artifact(artifact):
"device_manager_host_ontology="
"candidate-not-canonical"
)
if manager_schema == (
"nodedc.device-plane.device-manager-release.v8"
):
print(
"device_manager_infrastructure_hosts="
"ontology-backed-host-runtime-v1"
)
print(
"device_manager_ontology_foundation="
"ontology-core-device-foundation-20260822-001"
)
print(
"device_manager_ontology_catalog_hash="
"229c61c02a790906"
)
print(
"device_manager_asset_binding="
"temporal-device-asset-binding-v1"
)
print(
"device_manager_infrastructure_runtime="
"host-endpoint-deployment-service-instance-v1"
)
print(
"device_manager_health_evidence="
"ttl-observation-missing-not-unhealthy-v1"
)
print(
"device_manager_interactive_shell="
"disabled-pending-managed-session-boundary"
)
if device_plane_manager_activation_preflight["descriptor"].get(
"commandTransport"
) == "typed-service-ping-v1":
@@ -29,6 +29,53 @@ RUNNER = load_runner()
class DevicePlaneRegistryTest(unittest.TestCase):
def test_manager_v8_pins_production_v6_and_canonical_ontology_runtime(self):
self.assertEqual(
RUNNER.DEVICE_PLANE_MANAGER_RELEASE_V8_PREDECESSOR_PATCH_ID,
"device-manager-release-v6-20260822-035",
)
self.assertEqual(
RUNNER.DEVICE_PLANE_MANAGER_RELEASE_V8_PREDECESSOR_ARTIFACT_SHA256,
"193faabe930e2b3f212f8eb45288e39f850ec714528b28881095be654baf9a80",
)
self.assertEqual(
RUNNER.DEVICE_PLANE_MANAGER_RELEASE_V8_CONTROL_CORE_PREDECESSOR_PATCH_ID,
"device-control-core-release-v2-20260822-038",
)
self.assertEqual(
RUNNER.DEVICE_PLANE_MANAGER_RELEASE_V8_CONTROL_CORE_PREDECESSOR_ARTIFACT_SHA256,
"e2d062b82b022dba662522b5d6e192026ac964d78950d903295ca3cbbc95ab28",
)
self.assertEqual(
RUNNER.DEVICE_PLANE_MANAGER_RELEASE_V8_COMPOSE_SHA256,
RUNNER.DEVICE_PLANE_MANAGER_RELEASE_V6_COMPOSE_SHA256,
)
boundaries = RUNNER.expected_device_plane_manager_release_v8_boundaries()
self.assertEqual(
boundaries["infrastructureHostProjection"],
"ontology-backed-host-runtime-v1",
)
self.assertEqual(
boundaries["ontologyFoundation"],
"ontology-core-device-foundation-20260822-001",
)
self.assertEqual(boundaries["ontologyCatalogHash"], "229c61c02a790906")
self.assertEqual(
boundaries["assetBinding"],
"temporal-device-asset-binding-v1",
)
self.assertEqual(
boundaries["healthEvidence"],
"ttl-observation-missing-not-unhealthy-v1",
)
self.assertEqual(
RUNNER.component_services(
"device-plane",
RUNNER.DEVICE_PLANE_MANAGER_RELEASE_V8_ENTRIES,
),
("device-manager",),
)
def test_manager_v7_pins_v6_and_live_edge_host_projection(self):
self.assertEqual(
RUNNER.DEVICE_PLANE_MANAGER_RELEASE_V7_PREDECESSOR_PATCH_ID,