feat(deploy): add typed command transport releases
This commit is contained in:
@@ -246,6 +246,9 @@ DEVICE_PLANE_MANAGER_CONTROL_PLANE_REL = (
|
||||
DEVICE_PLANE_MANAGER_RELEASE_V2_REL = (
|
||||
"deployment/device-manager-release-v2.json"
|
||||
)
|
||||
DEVICE_PLANE_MANAGER_RELEASE_V3_REL = (
|
||||
"deployment/device-manager-release-v3.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"
|
||||
@@ -262,6 +265,9 @@ DEVICE_PLANE_EDGE_CORE_CHANNEL_UPGRADE_V4_REL = (
|
||||
DEVICE_PLANE_CONTROL_CORE_RELEASE_REL = (
|
||||
"deployment/device-control-core-release-v1.json"
|
||||
)
|
||||
DEVICE_PLANE_CONTROL_CORE_RELEASE_V2_REL = (
|
||||
"deployment/device-control-core-release-v2.json"
|
||||
)
|
||||
DEVICE_PLANE_EDGE_CORE_CHANNEL_COMPOSE_REL = (
|
||||
"docker-compose.device-edge-core-channel.yml"
|
||||
)
|
||||
@@ -323,12 +329,33 @@ DEVICE_PLANE_CONTROL_CORE_RELEASE_ENTRIES = (
|
||||
"services/device-control-core",
|
||||
DEVICE_PLANE_CONTROL_CORE_RELEASE_REL,
|
||||
)
|
||||
DEVICE_PLANE_CONTROL_CORE_RELEASE_V2_ENTRIES = (
|
||||
".dockerignore",
|
||||
"package.json",
|
||||
"package-lock.json",
|
||||
"packages/device-protocol-contract",
|
||||
"packages/device-edge-channel-contract",
|
||||
"services/device-control-core",
|
||||
DEVICE_PLANE_CONTROL_CORE_RELEASE_V2_REL,
|
||||
)
|
||||
DEVICE_PLANE_CONTROL_CORE_RELEASE_FIRST_PREDECESSOR_PATCH_ID = (
|
||||
"device-edge-core-channel-upgrade-v4-20260812-023"
|
||||
)
|
||||
DEVICE_PLANE_CONTROL_CORE_RELEASE_FIRST_PREDECESSOR_ARTIFACT_SHA256 = (
|
||||
"c10d5b6b7d55ab239f85b6c8130e34ce9f84985e3b46e6e5534733156c7982fc"
|
||||
)
|
||||
DEVICE_PLANE_MANAGER_RELEASE_V3_CONTROL_CORE_PREDECESSOR_PATCH_ID = (
|
||||
"device-control-core-release-v2-20260812-025"
|
||||
)
|
||||
DEVICE_PLANE_MANAGER_RELEASE_V3_CONTROL_CORE_PREDECESSOR_ARTIFACT_SHA256 = (
|
||||
"c61b1f0de1bae23de0caa7289036865ea419ff5705611416f736ca929d1592db"
|
||||
)
|
||||
DEVICE_PLANE_MANAGER_RELEASE_V3_EDGE_CHANNEL_PREDECESSOR_PATCH_ID = (
|
||||
"device-edge-core-channel-upgrade-v4-20260812-023"
|
||||
)
|
||||
DEVICE_PLANE_MANAGER_RELEASE_V3_EDGE_CHANNEL_PREDECESSOR_ARTIFACT_SHA256 = (
|
||||
"c10d5b6b7d55ab239f85b6c8130e34ce9f84985e3b46e6e5534733156c7982fc"
|
||||
)
|
||||
DEVICE_PLANE_EDGE_CORE_CHANNEL_BOOTSTRAP_PREDECESSOR_PATCH_ID = (
|
||||
"device-edge-core-channel-bootstrap-20260812-018"
|
||||
)
|
||||
@@ -460,6 +487,11 @@ DEVICE_PLANE_MANAGER_RELEASE_V2_ENTRIES = (
|
||||
"services/device-manager",
|
||||
DEVICE_PLANE_MANAGER_RELEASE_V2_REL,
|
||||
)
|
||||
DEVICE_PLANE_MANAGER_RELEASE_V3_ENTRIES = (
|
||||
DEVICE_PLANE_MANAGER_COMPOSE_REL,
|
||||
"services/device-manager",
|
||||
DEVICE_PLANE_MANAGER_RELEASE_V3_REL,
|
||||
)
|
||||
DEVICE_PLANE_MANAGER_RECONCILIATION_REL = (
|
||||
"deployment/device-manager-control-plane-reconciliation-v1.json"
|
||||
)
|
||||
@@ -3889,11 +3921,13 @@ def allowed_payload_path(component, rel):
|
||||
DEVICE_PLANE_MANAGER_FAILED_CONTROL_PLANE_REL,
|
||||
DEVICE_PLANE_MANAGER_CONTROL_PLANE_REL,
|
||||
DEVICE_PLANE_MANAGER_RELEASE_V2_REL,
|
||||
DEVICE_PLANE_MANAGER_RELEASE_V3_REL,
|
||||
DEVICE_PLANE_EDGE_CORE_CHANNEL_BOOTSTRAP_REL,
|
||||
DEVICE_PLANE_EDGE_CORE_CHANNEL_UPGRADE_REL,
|
||||
DEVICE_PLANE_EDGE_CORE_CHANNEL_UPGRADE_V2_REL,
|
||||
DEVICE_PLANE_EDGE_CORE_CHANNEL_UPGRADE_V4_REL,
|
||||
DEVICE_PLANE_CONTROL_CORE_RELEASE_REL,
|
||||
DEVICE_PLANE_CONTROL_CORE_RELEASE_V2_REL,
|
||||
DEVICE_PLANE_MANAGER_RECONCILIATION_REL,
|
||||
DEVICE_PLANE_MANAGER_V2_RECONCILIATION_REL,
|
||||
"packages/device-protocol-contract",
|
||||
@@ -9459,6 +9493,7 @@ def is_device_plane_manager_control_plane_slice(component, entries):
|
||||
DEVICE_PLANE_MANAGER_CONTROL_PLANE_ENTRIES,
|
||||
DEVICE_PLANE_MANAGER_RELEASE_V1_SUCCESSOR_ENTRIES,
|
||||
DEVICE_PLANE_MANAGER_RELEASE_V2_ENTRIES,
|
||||
DEVICE_PLANE_MANAGER_RELEASE_V3_ENTRIES,
|
||||
)
|
||||
)
|
||||
|
||||
@@ -9471,6 +9506,14 @@ def is_device_plane_manager_release_v2_slice(component, entries):
|
||||
)
|
||||
|
||||
|
||||
def is_device_plane_manager_release_v3_slice(component, entries):
|
||||
return (
|
||||
component == "device-plane"
|
||||
and entries is not None
|
||||
and tuple(entries) == DEVICE_PLANE_MANAGER_RELEASE_V3_ENTRIES
|
||||
)
|
||||
|
||||
|
||||
def is_device_plane_edge_core_channel_bootstrap_slice(component, entries):
|
||||
return (
|
||||
component == "device-plane"
|
||||
@@ -9516,7 +9559,18 @@ def is_device_plane_control_core_release_slice(component, entries):
|
||||
return (
|
||||
component == "device-plane"
|
||||
and entries is not None
|
||||
and tuple(entries) == DEVICE_PLANE_CONTROL_CORE_RELEASE_ENTRIES
|
||||
and tuple(entries) in (
|
||||
DEVICE_PLANE_CONTROL_CORE_RELEASE_ENTRIES,
|
||||
DEVICE_PLANE_CONTROL_CORE_RELEASE_V2_ENTRIES,
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
def is_device_plane_control_core_release_v2_slice(component, entries):
|
||||
return (
|
||||
component == "device-plane"
|
||||
and entries is not None
|
||||
and tuple(entries) == DEVICE_PLANE_CONTROL_CORE_RELEASE_V2_ENTRIES
|
||||
)
|
||||
|
||||
|
||||
@@ -9605,6 +9659,49 @@ def expected_device_plane_manager_release_v2_boundaries():
|
||||
}
|
||||
|
||||
|
||||
def expected_device_plane_manager_release_v3_boundaries():
|
||||
return {
|
||||
"controlCorePredecessor": {
|
||||
"patchId": (
|
||||
DEVICE_PLANE_MANAGER_RELEASE_V3_CONTROL_CORE_PREDECESSOR_PATCH_ID
|
||||
),
|
||||
"artifactSha256": (
|
||||
DEVICE_PLANE_MANAGER_RELEASE_V3_CONTROL_CORE_PREDECESSOR_ARTIFACT_SHA256
|
||||
),
|
||||
},
|
||||
"edgeChannelPredecessor": {
|
||||
"patchId": (
|
||||
DEVICE_PLANE_MANAGER_RELEASE_V3_EDGE_CHANNEL_PREDECESSOR_PATCH_ID
|
||||
),
|
||||
"artifactSha256": (
|
||||
DEVICE_PLANE_MANAGER_RELEASE_V3_EDGE_CHANNEL_PREDECESSOR_ARTIFACT_SHA256
|
||||
),
|
||||
},
|
||||
"service": "device-manager",
|
||||
"publicIngress": "reverse-proxy-only",
|
||||
"deviceCoreManagementApi": "file-token-authenticated",
|
||||
"launcherTrust": "file-token-scoped-to-device-core-handoff",
|
||||
"edgeChannel": "preserve-active-v4-core-initiated-pinned-mtls",
|
||||
"edgeChannelIdentity": (
|
||||
"reuse-runner-managed-host-local-private-key-"
|
||||
"public-certificate-export"
|
||||
),
|
||||
"edgeChannelEgress": (
|
||||
"preserve-dedicated-core-only-bridge-no-host-ingress-"
|
||||
"public-ipv4-tcp-443-only"
|
||||
),
|
||||
"healthGate": "bounded-container-grace+core-contract",
|
||||
"commandTransport": "typed-service-ping-v1",
|
||||
"commandCatalog": "allowlisted-adapter-typed-commands-only",
|
||||
"credentialBoundary": (
|
||||
"transient-core-memory-then-single-pinned-mtls-command-envelope-"
|
||||
"to-edge-never-persisted-never-logged-never-returned"
|
||||
),
|
||||
"gelios": "untouched-legacy-only",
|
||||
"rollback": "restore-preapply-snapshot",
|
||||
}
|
||||
|
||||
|
||||
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.
|
||||
@@ -9823,10 +9920,12 @@ def expected_device_plane_edge_core_channel_upgrade_v4_descriptor(
|
||||
def expected_device_plane_control_core_release_descriptor(
|
||||
release_id,
|
||||
predecessor,
|
||||
*,
|
||||
schema_version="v1",
|
||||
):
|
||||
return {
|
||||
descriptor = {
|
||||
"schemaVersion": (
|
||||
"nodedc.device-plane.device-control-core-release.v1"
|
||||
f"nodedc.device-plane.device-control-core-release.{schema_version}"
|
||||
),
|
||||
"releaseId": release_id,
|
||||
"action": "upgrade",
|
||||
@@ -9847,8 +9946,16 @@ def expected_device_plane_control_core_release_descriptor(
|
||||
],
|
||||
"publicIngress": "none-on-synology",
|
||||
"edgeRegistrations": "preserved",
|
||||
"commandTransport": "disabled",
|
||||
"gelios": "untouched",
|
||||
"commandTransport": (
|
||||
"typed-service-ping-v1"
|
||||
if schema_version == "v2"
|
||||
else "disabled"
|
||||
),
|
||||
"gelios": (
|
||||
"untouched-legacy-only"
|
||||
if schema_version == "v2"
|
||||
else "untouched"
|
||||
),
|
||||
"preservedServices": [
|
||||
"device-manager",
|
||||
"device-gateway",
|
||||
@@ -9861,6 +9968,15 @@ def expected_device_plane_control_core_release_descriptor(
|
||||
),
|
||||
"rollback": "restore-preapply-source-and-core-runtime",
|
||||
}
|
||||
if schema_version == "v2":
|
||||
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"
|
||||
)
|
||||
return descriptor
|
||||
|
||||
|
||||
def expected_device_plane_manager_failed_control_plane_descriptor():
|
||||
@@ -10145,6 +10261,22 @@ def validate_device_plane_manager_release_v2_payload(
|
||||
)
|
||||
|
||||
|
||||
def validate_device_plane_manager_release_v3_payload(
|
||||
payload_dir,
|
||||
*,
|
||||
expected_release_id=None,
|
||||
):
|
||||
return validate_device_plane_manager_release_payload_contract(
|
||||
payload_dir,
|
||||
descriptor_rel=DEVICE_PLANE_MANAGER_RELEASE_V3_REL,
|
||||
schema_version="nodedc.device-plane.device-manager-release.v3",
|
||||
boundaries=expected_device_plane_manager_release_v3_boundaries(),
|
||||
compose_sha256=DEVICE_PLANE_MANAGER_RELEASE_V1_COMPOSE_SHA256,
|
||||
edge_channel=False,
|
||||
expected_release_id=expected_release_id,
|
||||
)
|
||||
|
||||
|
||||
def validate_device_plane_manager_release_payload(
|
||||
payload_dir,
|
||||
*,
|
||||
@@ -10152,9 +10284,18 @@ def validate_device_plane_manager_release_payload(
|
||||
):
|
||||
v1 = payload_dir / DEVICE_PLANE_MANAGER_CONTROL_PLANE_REL
|
||||
v2 = payload_dir / DEVICE_PLANE_MANAGER_RELEASE_V2_REL
|
||||
present = [path for path in (v1, v2) if path.exists() or path.is_symlink()]
|
||||
v3 = payload_dir / DEVICE_PLANE_MANAGER_RELEASE_V3_REL
|
||||
present = [
|
||||
path for path in (v1, v2, v3)
|
||||
if path.exists() or path.is_symlink()
|
||||
]
|
||||
if len(present) != 1:
|
||||
die("Device Manager release descriptor cardinality mismatch")
|
||||
if present[0] == v3:
|
||||
return validate_device_plane_manager_release_v3_payload(
|
||||
payload_dir,
|
||||
expected_release_id=expected_release_id,
|
||||
)
|
||||
if present[0] == v2:
|
||||
return validate_device_plane_manager_release_v2_payload(
|
||||
payload_dir,
|
||||
@@ -10285,8 +10426,14 @@ def validate_device_plane_control_core_release_payload(
|
||||
*,
|
||||
expected_release_id=None,
|
||||
):
|
||||
v1 = payload_dir / DEVICE_PLANE_CONTROL_CORE_RELEASE_REL
|
||||
v2 = payload_dir / DEVICE_PLANE_CONTROL_CORE_RELEASE_V2_REL
|
||||
present = [path for path in (v1, v2) if path.exists() or path.is_symlink()]
|
||||
if len(present) != 1:
|
||||
die("Device Control Core release descriptor cardinality mismatch")
|
||||
schema_version = "v2" if present[0] == v2 else "v1"
|
||||
descriptor = read_strict_json(
|
||||
payload_dir / DEVICE_PLANE_CONTROL_CORE_RELEASE_REL,
|
||||
present[0],
|
||||
"Device Control Core release descriptor",
|
||||
max_bytes=16 * 1024,
|
||||
)
|
||||
@@ -10326,7 +10473,7 @@ def validate_device_plane_control_core_release_payload(
|
||||
if (
|
||||
not isinstance(release_id, str)
|
||||
or not re.fullmatch(
|
||||
r"device-control-core-release-[A-Za-z0-9._-]{1,67}",
|
||||
r"device-control-core-release(?:-v2)?-[A-Za-z0-9._-]{1,67}",
|
||||
release_id,
|
||||
)
|
||||
or (
|
||||
@@ -10338,6 +10485,7 @@ def validate_device_plane_control_core_release_payload(
|
||||
!= expected_device_plane_control_core_release_descriptor(
|
||||
release_id,
|
||||
predecessor,
|
||||
schema_version=schema_version,
|
||||
)
|
||||
):
|
||||
die("Device Control Core release descriptor mismatch")
|
||||
@@ -10419,6 +10567,7 @@ def installed_device_plane_manager_compose_sha256():
|
||||
root = DEVICE_PLANE_ROOT
|
||||
v1 = root / DEVICE_PLANE_MANAGER_CONTROL_PLANE_REL
|
||||
v2 = root / DEVICE_PLANE_MANAGER_RELEASE_V2_REL
|
||||
v3 = root / DEVICE_PLANE_MANAGER_RELEASE_V3_REL
|
||||
|
||||
# A successful v2 overlay intentionally leaves the immutable v1 release
|
||||
# descriptor as predecessor evidence. Prefer the highest installed
|
||||
@@ -10426,6 +10575,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 v3.exists() or v3.is_symlink():
|
||||
descriptor = read_strict_json(
|
||||
v3,
|
||||
"installed Device Manager release v3 descriptor",
|
||||
max_bytes=16 * 1024,
|
||||
)
|
||||
validate_device_plane_manager_release_descriptor(
|
||||
descriptor,
|
||||
schema_version="nodedc.device-plane.device-manager-release.v3",
|
||||
boundaries=expected_device_plane_manager_release_v3_boundaries(),
|
||||
)
|
||||
return DEVICE_PLANE_MANAGER_RELEASE_V1_COMPOSE_SHA256
|
||||
|
||||
if v2.exists() or v2.is_symlink():
|
||||
descriptor = read_strict_json(
|
||||
v2,
|
||||
@@ -11926,6 +12088,152 @@ def validate_device_plane_manager_reconciliation_evidence(payload_dir):
|
||||
}
|
||||
|
||||
|
||||
def validate_device_plane_manager_v3_active_baseline(descriptor):
|
||||
if descriptor.get("schemaVersion") != (
|
||||
"nodedc.device-plane.device-manager-release.v3"
|
||||
):
|
||||
return None
|
||||
|
||||
def successful_applied_artifact(reference, label):
|
||||
patch_id = reference["patchId"]
|
||||
artifact_sha256 = reference["artifactSha256"]
|
||||
artifact_name = f"nodedc-device-plane-{patch_id}.tgz"
|
||||
artifact = APPLIED_DIR / artifact_name
|
||||
if (
|
||||
not artifact.is_file()
|
||||
or artifact.is_symlink()
|
||||
or sha256_file(artifact) != artifact_sha256
|
||||
):
|
||||
die(f"Device Manager v3 {label} applied artifact mismatch")
|
||||
records = [
|
||||
row for row in load_state(STATE_FILE)
|
||||
if row.get("id") == patch_id
|
||||
and row.get("sha256") == artifact_sha256
|
||||
]
|
||||
if (
|
||||
len(records) != 1
|
||||
or records[0].get("status") != "ok"
|
||||
or records[0].get("component") != "device-plane"
|
||||
or records[0].get("artifact") != artifact_name
|
||||
):
|
||||
die(f"Device Manager v3 {label} applied journal mismatch")
|
||||
backup_id = records[0].get("backup_id")
|
||||
backup = BACKUPS_DIR / backup_id if isinstance(backup_id, str) else None
|
||||
if (
|
||||
backup is None
|
||||
or safe_name(backup_id) != backup_id
|
||||
or not backup.is_dir()
|
||||
or backup.is_symlink()
|
||||
):
|
||||
die(f"Device Manager v3 {label} backup is unsafe")
|
||||
return artifact
|
||||
|
||||
core_reference = descriptor["controlCorePredecessor"]
|
||||
edge_reference = descriptor["edgeChannelPredecessor"]
|
||||
core_artifact = successful_applied_artifact(
|
||||
core_reference,
|
||||
"Device Control Core predecessor",
|
||||
)
|
||||
edge_artifact = successful_applied_artifact(
|
||||
edge_reference,
|
||||
"Device Edge channel predecessor",
|
||||
)
|
||||
|
||||
with tempfile.TemporaryDirectory(
|
||||
prefix="device-manager-v3-core-baseline-",
|
||||
dir=TMP_DIR,
|
||||
) as directory:
|
||||
core_manifest, core_entries, core_payload = load_artifact(
|
||||
core_artifact,
|
||||
Path(directory),
|
||||
)
|
||||
if (
|
||||
core_manifest.get("id") != core_reference["patchId"]
|
||||
or core_manifest.get("component") != "device-plane"
|
||||
or core_manifest.get("type") != "app-overlay"
|
||||
or tuple(core_entries) != DEVICE_PLANE_CONTROL_CORE_RELEASE_V2_ENTRIES
|
||||
):
|
||||
die("Device Manager v3 Device Control Core predecessor type mismatch")
|
||||
expected_core_descriptor = (
|
||||
validate_device_plane_control_core_release_payload(
|
||||
core_payload,
|
||||
expected_release_id=core_reference["patchId"],
|
||||
)
|
||||
)
|
||||
installed_core_descriptor = read_strict_json(
|
||||
DEVICE_PLANE_ROOT / DEVICE_PLANE_CONTROL_CORE_RELEASE_V2_REL,
|
||||
"installed Device Manager v3 Device Control Core predecessor",
|
||||
max_bytes=16 * 1024,
|
||||
)
|
||||
if installed_core_descriptor != expected_core_descriptor:
|
||||
die("Device Manager v3 Device Control Core predecessor is not current")
|
||||
expected_core_source = collect_exact_files(
|
||||
core_payload,
|
||||
DEVICE_PLANE_CONTROL_CORE_RELEASE_V2_ENTRIES,
|
||||
"Device Manager v3 Device Control Core predecessor source",
|
||||
)
|
||||
actual_core_source = collect_exact_files(
|
||||
DEVICE_PLANE_ROOT,
|
||||
DEVICE_PLANE_CONTROL_CORE_RELEASE_V2_ENTRIES,
|
||||
"installed Device Manager v3 Device Control Core predecessor source",
|
||||
)
|
||||
if actual_core_source != expected_core_source:
|
||||
die("installed Device Manager v3 Device Control Core source drift detected")
|
||||
|
||||
with tempfile.TemporaryDirectory(
|
||||
prefix="device-manager-v3-edge-baseline-",
|
||||
dir=TMP_DIR,
|
||||
) as directory:
|
||||
edge_manifest, edge_entries, edge_payload = load_artifact(
|
||||
edge_artifact,
|
||||
Path(directory),
|
||||
)
|
||||
if (
|
||||
edge_manifest.get("id") != edge_reference["patchId"]
|
||||
or edge_manifest.get("component") != "device-plane"
|
||||
or edge_manifest.get("type") != "app-overlay"
|
||||
or tuple(edge_entries)
|
||||
!= DEVICE_PLANE_EDGE_CORE_CHANNEL_UPGRADE_V4_ENTRIES
|
||||
):
|
||||
die("Device Manager v3 Device Edge channel predecessor type mismatch")
|
||||
expected_edge_descriptor = (
|
||||
validate_device_plane_edge_core_channel_upgrade_v4_payload(
|
||||
edge_payload,
|
||||
expected_transition_id=edge_reference["patchId"],
|
||||
)
|
||||
)
|
||||
installed_edge_descriptor = read_strict_json(
|
||||
DEVICE_PLANE_ROOT / DEVICE_PLANE_EDGE_CORE_CHANNEL_UPGRADE_V4_REL,
|
||||
"installed Device Manager v3 Device Edge channel predecessor",
|
||||
max_bytes=16 * 1024,
|
||||
)
|
||||
if installed_edge_descriptor != expected_edge_descriptor:
|
||||
die("Device Manager v3 Device Edge channel predecessor is not current")
|
||||
expected_base_compose_sha256 = sha256_file(
|
||||
edge_payload / "docker-compose.device-plane.yml"
|
||||
)
|
||||
installed_base_compose = DEVICE_PLANE_ROOT / "docker-compose.device-plane.yml"
|
||||
if (
|
||||
installed_base_compose.is_symlink()
|
||||
or not installed_base_compose.is_file()
|
||||
or sha256_file(installed_base_compose) != expected_base_compose_sha256
|
||||
):
|
||||
die("installed Device Manager v3 Device Edge topology drift detected")
|
||||
|
||||
identity_state = inspect_device_edge_channel_core_identity_state()
|
||||
if identity_state != "valid-reuse-at-apply":
|
||||
die("Device Manager v3 requires the valid active Edge identity")
|
||||
validate_device_manager_control_plane_runtime(
|
||||
require_edge_channel=True,
|
||||
core_network_mode="private-egress",
|
||||
)
|
||||
return {
|
||||
"controlCoreArtifact": core_artifact,
|
||||
"edgeChannelArtifact": edge_artifact,
|
||||
"identityState": identity_state,
|
||||
}
|
||||
|
||||
|
||||
def validate_device_plane_manager_activation_predecessor(payload_dir):
|
||||
descriptor = validate_device_plane_manager_release_payload(
|
||||
payload_dir
|
||||
@@ -12033,6 +12341,7 @@ def validate_device_plane_manager_activation_predecessor(payload_dir):
|
||||
DEVICE_PLANE_MANAGER_CONTROL_PLANE_ENTRIES,
|
||||
DEVICE_PLANE_MANAGER_RELEASE_V1_SUCCESSOR_ENTRIES,
|
||||
DEVICE_PLANE_MANAGER_RELEASE_V2_ENTRIES,
|
||||
DEVICE_PLANE_MANAGER_RELEASE_V3_ENTRIES,
|
||||
)
|
||||
):
|
||||
die("Device Manager release predecessor type mismatch")
|
||||
@@ -12042,11 +12351,14 @@ def validate_device_plane_manager_activation_predecessor(payload_dir):
|
||||
expected_release_id=patch_id,
|
||||
)
|
||||
)
|
||||
predecessor_descriptor_rel = (
|
||||
DEVICE_PLANE_MANAGER_RELEASE_V2_REL
|
||||
if tuple(predecessor_entries)
|
||||
== DEVICE_PLANE_MANAGER_RELEASE_V2_ENTRIES
|
||||
else DEVICE_PLANE_MANAGER_CONTROL_PLANE_REL
|
||||
predecessor_descriptor_rel = {
|
||||
DEVICE_PLANE_MANAGER_RELEASE_V2_ENTRIES:
|
||||
DEVICE_PLANE_MANAGER_RELEASE_V2_REL,
|
||||
DEVICE_PLANE_MANAGER_RELEASE_V3_ENTRIES:
|
||||
DEVICE_PLANE_MANAGER_RELEASE_V3_REL,
|
||||
}.get(
|
||||
tuple(predecessor_entries),
|
||||
DEVICE_PLANE_MANAGER_CONTROL_PLANE_REL,
|
||||
)
|
||||
installed_descriptor = read_strict_json(
|
||||
root / predecessor_descriptor_rel,
|
||||
@@ -12062,6 +12374,11 @@ def validate_device_plane_manager_activation_predecessor(payload_dir):
|
||||
):
|
||||
healthcheck_compose_service("device-plane", service)
|
||||
runtime = {"accepted": True}
|
||||
v3_baseline = validate_device_plane_manager_v3_active_baseline(
|
||||
descriptor
|
||||
)
|
||||
if v3_baseline is not None:
|
||||
runtime["v3Baseline"] = v3_baseline
|
||||
mode = "active-manager-forward-upgrade"
|
||||
return {
|
||||
"mode": mode,
|
||||
@@ -16086,6 +16403,9 @@ def component_services(component, entries=None):
|
||||
if is_device_plane_control_core_release_slice(component, entries):
|
||||
return ("device-control-core",)
|
||||
|
||||
if is_device_plane_manager_release_v3_slice(component, entries):
|
||||
return ("device-manager",)
|
||||
|
||||
if is_device_plane_edge_core_channel_bootstrap_slice(component, entries):
|
||||
return ("device-control-core",)
|
||||
|
||||
@@ -16683,6 +17003,18 @@ def component_builds(component, entries=None):
|
||||
),
|
||||
),)
|
||||
|
||||
if is_device_plane_manager_release_v3_slice(component, entries):
|
||||
return ((
|
||||
DEVICE_PLANE_ROOT / "services/device-manager",
|
||||
(
|
||||
"build",
|
||||
"--no-cache",
|
||||
"-t",
|
||||
DEVICE_PLANE_MANAGER_IMAGE,
|
||||
".",
|
||||
),
|
||||
),)
|
||||
|
||||
if is_device_plane_manager_control_plane_slice(component, entries):
|
||||
return (
|
||||
(
|
||||
@@ -20427,7 +20759,15 @@ def plan_artifact(artifact):
|
||||
print("device_control_core_discovery_ingest=enabled:authenticated")
|
||||
else:
|
||||
print("device_gateway_public_ingress=disabled")
|
||||
print("device_gateway_command_transport=disabled")
|
||||
if (
|
||||
device_plane_manager_activation_preflight is not None
|
||||
and device_plane_manager_activation_preflight["descriptor"].get(
|
||||
"commandTransport"
|
||||
) == "typed-service-ping-v1"
|
||||
):
|
||||
print("device_gateway_command_transport=typed-service-ping-v1")
|
||||
else:
|
||||
print("device_gateway_command_transport=disabled")
|
||||
print("gelios=untouched")
|
||||
if device_plane_foundation_recovery_preflight is not None:
|
||||
print(
|
||||
@@ -20589,15 +20929,36 @@ def plan_artifact(artifact):
|
||||
)
|
||||
print(
|
||||
"device_plane_runtime_mutation="
|
||||
"build+recreate:device-control-core,device-manager"
|
||||
+ (
|
||||
"build+recreate:device-manager"
|
||||
if device_plane_manager_activation_preflight["descriptor"].get(
|
||||
"schemaVersion"
|
||||
) == "nodedc.device-plane.device-manager-release.v3"
|
||||
else "build+recreate:device-control-core,device-manager"
|
||||
)
|
||||
)
|
||||
print(
|
||||
"device_plane_runtime_services="
|
||||
"preserved:device-gateway,device-postgres,"
|
||||
"device-backhaul-target"
|
||||
+ (
|
||||
"preserved:device-control-core,device-gateway,"
|
||||
"device-postgres,device-backhaul-target"
|
||||
if device_plane_manager_activation_preflight["descriptor"].get(
|
||||
"schemaVersion"
|
||||
) == "nodedc.device-plane.device-manager-release.v3"
|
||||
else "preserved:device-gateway,device-postgres,"
|
||||
"device-backhaul-target"
|
||||
)
|
||||
)
|
||||
print("device_manager_health_gate=bounded-grace+contract")
|
||||
print("device_manager_public_route=unchanged:absent")
|
||||
if device_plane_manager_activation_preflight["descriptor"].get(
|
||||
"commandTransport"
|
||||
) == "typed-service-ping-v1":
|
||||
print("device_manager_public_route=unchanged:active")
|
||||
print("device_edge_channel_commands=typed-service-ping-v1")
|
||||
print("device_command_credential=transient-core-memory-only")
|
||||
print("gelios=untouched:legacy-only")
|
||||
else:
|
||||
print("device_manager_public_route=unchanged:absent")
|
||||
print("device_gateway_tcp_9921=preserved:loopback-only")
|
||||
print(
|
||||
"device_plane_rollback="
|
||||
@@ -20637,11 +20998,14 @@ def plan_artifact(artifact):
|
||||
print("device_edge_channel=preserved:core-initiated:pinned-mtls:registered-edges-only")
|
||||
print("device_edge_channel_networks=preserved:device-plane-private,device-plane-egress")
|
||||
print("device_edge_channel_registrations=preserved")
|
||||
print("device_edge_channel_commands=disabled")
|
||||
print(
|
||||
"device_edge_channel_commands="
|
||||
f"{descriptor['commandTransport']}"
|
||||
)
|
||||
print("device_manager=preserved:active")
|
||||
print("device_manager_public_route=unchanged:active")
|
||||
print("device_gateway_tcp_9921=preserved:loopback-only")
|
||||
print("gelios=untouched")
|
||||
print(f"gelios={descriptor['gelios']}")
|
||||
print("device_plane_rollback=source+preapply-core-runtime")
|
||||
if device_plane_edge_core_channel_preflight is not None:
|
||||
print(
|
||||
@@ -22571,7 +22935,12 @@ def component_healthchecks(component, entries=None, services=None):
|
||||
},
|
||||
},)
|
||||
if is_device_plane_manager_control_plane_slice(component, entries):
|
||||
return ({
|
||||
command_transport = (
|
||||
"typed-service-ping-v1"
|
||||
if is_device_plane_manager_release_v3_slice(component, entries)
|
||||
else "disabled"
|
||||
)
|
||||
checks = ({
|
||||
"url": "http://127.0.0.1:18120/healthz",
|
||||
"expected_json": {
|
||||
"ok": True,
|
||||
@@ -22579,9 +22948,21 @@ def component_healthchecks(component, entries=None, services=None):
|
||||
"database": "ready",
|
||||
"discoveryIngest": "enabled",
|
||||
"managementApi": "enabled",
|
||||
"commandTransport": "disabled",
|
||||
"commandTransport": command_transport,
|
||||
},
|
||||
},)
|
||||
if is_device_plane_manager_release_v3_slice(component, entries):
|
||||
checks += ({
|
||||
"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,
|
||||
},
|
||||
},)
|
||||
return checks
|
||||
if (
|
||||
is_device_plane_control_core_release_slice(component, entries)
|
||||
or is_device_plane_edge_core_channel_bootstrap_slice(
|
||||
@@ -22597,7 +22978,14 @@ def component_healthchecks(component, entries=None, services=None):
|
||||
"database": "ready",
|
||||
"discoveryIngest": "enabled",
|
||||
"managementApi": "enabled",
|
||||
"commandTransport": "disabled",
|
||||
"commandTransport": (
|
||||
"typed-service-ping-v1"
|
||||
if is_device_plane_control_core_release_v2_slice(
|
||||
component,
|
||||
entries,
|
||||
)
|
||||
else "disabled"
|
||||
),
|
||||
},
|
||||
},)
|
||||
if is_device_plane_b2_discovery_rollback_recovery_slice(
|
||||
@@ -23319,10 +23707,12 @@ def run_healthchecks(component, entries=None, services=None):
|
||||
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",
|
||||
):
|
||||
expected_services = (
|
||||
("device-manager",)
|
||||
if is_device_plane_manager_release_v3_slice(component, entries)
|
||||
else ("device-control-core", "device-manager")
|
||||
)
|
||||
if tuple(services or ()) != expected_services:
|
||||
die("Device Manager control-plane service set mismatch")
|
||||
for service in services:
|
||||
healthcheck_compose_service_with_grace(
|
||||
|
||||
Reference in New Issue
Block a user