diff --git a/deployment/device-manager-release-v3.json b/deployment/device-manager-release-v3.json index 02603b6..0b2b80d 100644 --- a/deployment/device-manager-release-v3.json +++ b/deployment/device-manager-release-v3.json @@ -8,8 +8,8 @@ "artifactSha256": "d4132993216eb674967dc6fc65d9670cfc2a9efdf46186ca019030f259de2d0e" }, "controlCorePredecessor": { - "patchId": "device-control-core-release-v2-20260813-028", - "artifactSha256": "816ef07fd81923328c3ff54d833dcc49f873aef13256259ae4f66061e7453635" + "patchId": "device-control-core-release-v2-20260821-030", + "artifactSha256": "8459521a662541a5a87cb0188991cdcfb51727427db8ec2a232ce4846bfc3454" }, "edgeChannelPredecessor": { "patchId": "device-edge-core-channel-upgrade-v4-20260812-023", diff --git a/infra/deploy-runner/build-device-manager-control-plane-artifact.mjs b/infra/deploy-runner/build-device-manager-control-plane-artifact.mjs index eaa3443..736a661 100644 --- a/infra/deploy-runner/build-device-manager-control-plane-artifact.mjs +++ b/infra/deploy-runner/build-device-manager-control-plane-artifact.mjs @@ -145,8 +145,8 @@ try { || descriptor.commandTransport !== "typed-service-ping-v1" || descriptor.commandCatalog !== "allowlisted-adapter-typed-commands-only" || descriptor.credentialBoundary !== "transient-core-memory-then-single-pinned-mtls-command-envelope-to-edge-never-persisted-never-logged-never-returned" - || descriptor.controlCorePredecessor?.patchId !== "device-control-core-release-v2-20260813-028" - || descriptor.controlCorePredecessor?.artifactSha256 !== "816ef07fd81923328c3ff54d833dcc49f873aef13256259ae4f66061e7453635" + || descriptor.controlCorePredecessor?.patchId !== "device-control-core-release-v2-20260821-030" + || descriptor.controlCorePredecessor?.artifactSha256 !== "8459521a662541a5a87cb0188991cdcfb51727427db8ec2a232ce4846bfc3454" || descriptor.edgeChannelPredecessor?.patchId !== "device-edge-core-channel-upgrade-v4-20260812-023" || descriptor.edgeChannelPredecessor?.artifactSha256 !== "c10d5b6b7d55ab239f85b6c8130e34ce9f84985e3b46e6e5534733156c7982fc" || descriptor.edgeChannel !== "preserve-active-v4-core-initiated-pinned-mtls" diff --git a/infra/deploy-runner/test_device_manager_control_plane_artifacts.py b/infra/deploy-runner/test_device_manager_control_plane_artifacts.py index 91f57a6..352425d 100644 --- a/infra/deploy-runner/test_device_manager_control_plane_artifacts.py +++ b/infra/deploy-runner/test_device_manager_control_plane_artifacts.py @@ -43,7 +43,11 @@ LAUNCHER_HUB_SERVICE_TRUST_UI_ENTRIES = ( ) -def healthy_device_plane_inventory(*, include_manager=False): +def healthy_device_plane_inventory( + *, + include_manager=False, + include_backhaul=False, +): services = [ ("device-control-core", "a"), ("device-gateway", "b"), @@ -51,6 +55,8 @@ def healthy_device_plane_inventory(*, include_manager=False): ] if include_manager: services.append(("device-manager", "d")) + if include_backhaul: + services.append(("device-backhaul-target", "e")) return { "schemaVersion": "nodedc.device-plane.runtime-inventory.v1", "composeProject": "nodedc-device-plane", @@ -299,6 +305,23 @@ class DeviceManagerControlPlaneArtifactsTest(unittest.TestCase): ("device-manager",), ) self.assertEqual(result["services"], ["device-manager"]) + template = json.loads( + ( + DEVICE_CORE_ROOT + / "deployment/device-manager-release-v3.json" + ).read_text(encoding="utf-8") + ) + self.assertEqual( + template["controlCorePredecessor"], + { + "patchId": ( + "device-control-core-release-v2-20260821-030" + ), + "artifactSha256": ( + "8459521a662541a5a87cb0188991cdcfb51727427db8ec2a232ce4846bfc3454" + ), + }, + ) self.assertIn( "payload/deployment/device-manager-release-v3.json", names, @@ -599,6 +622,7 @@ class DeviceManagerControlPlaneArtifactsTest(unittest.TestCase): ("device-plane", "device-manager"), ("device-plane", "device-gateway"), ("device-plane", "device-postgres"), + ("device-plane", "device-backhaul-target"), ], ) url_health.assert_called_once_with( @@ -849,6 +873,11 @@ class DeviceManagerControlPlaneArtifactsTest(unittest.TestCase): "inspect_device_edge_channel_core_identity_state", return_value="valid-reuse-at-apply", ), + mock.patch.object( + RUNNER, + "validate_device_plane_control_core_selected_predecessor_runtime", + return_value={"health": "unhealthy"}, + ), mock.patch.object(RUNNER, "healthcheck_compose_service"), mock.patch.object( RUNNER, @@ -857,7 +886,8 @@ class DeviceManagerControlPlaneArtifactsTest(unittest.TestCase): ): result = ( RUNNER.validate_device_plane_control_core_release_predecessor( - root / "candidate-payload" + root / "candidate-payload", + preflight_phase="plan", ) ) @@ -1648,7 +1678,8 @@ class DeviceManagerControlPlaneArtifactsTest(unittest.TestCase): ): result = ( RUNNER.validate_device_plane_manager_activation_predecessor( - root / "payload" + root / "payload", + preflight_phase="plan", ) ) @@ -1782,18 +1813,15 @@ class DeviceManagerControlPlaneArtifactsTest(unittest.TestCase): ): result = ( RUNNER.validate_device_plane_manager_activation_predecessor( - root / "candidate-payload" + root / "candidate-payload", + preflight_phase="plan", ) ) self.assertEqual(result["mode"], "active-manager-forward-upgrade") self.assertEqual( [call.args for call in health.call_args_list], - [ - ("device-plane", "device-control-core"), - ("device-plane", "device-manager"), - ("device-plane", "device-postgres"), - ], + [], ) def test_initial_install_rollback_removes_manager_and_restores_core_only(self): @@ -2110,9 +2138,13 @@ class DeviceManagerControlPlaneArtifactsTest(unittest.TestCase): encoding="utf-8", ) (backup / "runtime-before.json").write_text( - json.dumps(healthy_device_plane_inventory(include_manager=True)), + json.dumps(healthy_device_plane_inventory( + include_manager=True, + include_backhaul=True, + )), encoding="utf-8", ) + restored_core_id = "f" * 64 with ( mock.patch.object( RUNNER, @@ -2131,6 +2163,23 @@ class DeviceManagerControlPlaneArtifactsTest(unittest.TestCase): RUNNER, "healthcheck_compose_service_with_grace", ) as restore_health, + mock.patch.object( + RUNNER, + "compose_service_container_id", + return_value=restored_core_id, + ), + mock.patch.object( + RUNNER, + "inspect_device_plane_container", + return_value={ + "Id": restored_core_id, + "State": { + "Status": "running", + "Running": True, + "Health": {"Status": "healthy"}, + }, + }, + ), mock.patch.object( RUNNER, "validate_device_manager_control_plane_runtime", @@ -2154,10 +2203,10 @@ class DeviceManagerControlPlaneArtifactsTest(unittest.TestCase): self.assertEqual( [call.args for call in restore_health.call_args_list], [ - ("device-plane", "device-control-core"), ("device-plane", "device-manager"), ("device-plane", "device-gateway"), ("device-plane", "device-postgres"), + ("device-plane", "device-backhaul-target"), ], ) runtime_acceptance.assert_called_once_with(