refactor(deploy): make device manager releases declarative

This commit is contained in:
Codex
2026-08-11 10:37:13 +03:00
parent 1adbabefcf
commit 72b4846b32
4 changed files with 546 additions and 110 deletions
+225 -66
View File
@@ -217,7 +217,7 @@ DEVICE_PLANE_MANAGER_V2_CONTROL_PLANE_REL = (
"deployment/device-manager-control-plane-v2.json"
)
DEVICE_PLANE_MANAGER_CONTROL_PLANE_REL = (
"deployment/device-manager-control-plane-v3.json"
"deployment/device-manager-release-v1.json"
)
DEVICE_PLANE_MANAGER_COMPOSE_REL = "docker-compose.device-manager.yml"
DEVICE_PLANE_MANAGER_COMPOSE_SHA256 = (
@@ -350,17 +350,6 @@ DEVICE_PLANE_MANAGER_V2_FAILED_ARTIFACT_SHA256 = (
DEVICE_PLANE_MANAGER_V2_RECONCILIATION_PATCH_ID = (
"device-manager-control-plane-v2-reconciliation-20260811-004"
)
DEVICE_PLANE_MANAGER_V2_RECONCILIATION_ARTIFACT = (
"nodedc-device-plane-device-manager-control-plane-v2-reconciliation-"
"20260811-004.tgz"
)
DEVICE_PLANE_MANAGER_V2_RECONCILIATION_ARTIFACT_SHA256 = (
"09600bfd99717314b43936e17ffaaf6b6fca1f2fd008beddddc68480cdf3d284"
)
DEVICE_PLANE_MANAGER_V2_RECONCILIATION_APPLY_BACKUP_ID = (
"device-plane-device-manager-control-plane-v2-reconciliation-"
"20260811-004-20260811-100533"
)
DEVICE_PLANE_MANAGER_V2_RECONCILIATION_BACKUP_ID = (
"device-plane-device-manager-control-plane-20260811-003-"
"20260811-012505"
@@ -8332,7 +8321,10 @@ def load_artifact(artifact, work_dir):
manifest["component"],
entries,
):
validate_device_plane_manager_control_plane_payload(payload_dir)
validate_device_plane_manager_control_plane_payload(
payload_dir,
expected_release_id=manifest["id"],
)
if is_device_plane_manager_failed_control_plane_slice(
manifest["component"],
entries,
@@ -8652,6 +8644,34 @@ def state_has_patch_id(patch_id):
return any(row.get("id") == patch_id for row in load_state(STATE_FILE))
def failed_state_has_sha(sha):
return any(
row.get("sha256") == sha
for row in load_state(FAILED_STATE_FILE)
)
def failed_state_has_patch_id(patch_id):
return any(
row.get("id") == patch_id
for row in load_state(FAILED_STATE_FILE)
)
def reject_failed_artifact_replay(manifest, sha256):
patch_id = manifest.get("id")
if failed_state_has_sha(sha256):
die(
"artifact SHA is terminal failed and cannot be replayed; "
"build a new immutable artifact"
)
if patch_id and failed_state_has_patch_id(patch_id):
die(
"patch id is terminal failed and cannot be reused; "
"build a new patch id"
)
def reject_terminal_engine_l2_failed_artifact(manifest, sha256):
if (
manifest.get("id") == ENGINE_L2_CLOSED_LOOP_FAILED_PATCH_ID
@@ -8712,7 +8732,7 @@ def reject_terminal_device_plane_manager_artifact(
die(
"Device Manager control-plane 003 is terminal failed; "
"use the exact v2 reconciliation successor followed by the "
"exact v3 activation successor"
"declarative Device Manager release successor"
)
@@ -8833,19 +8853,8 @@ def expected_platform_device_manager_public_route_descriptor():
}
def expected_device_plane_manager_control_plane_descriptor():
def expected_device_plane_manager_release_boundaries():
return {
"schemaVersion": (
"nodedc.device-plane.device-manager-control-plane.v3"
),
"action": "activate",
"predecessor": {
"patchId": DEVICE_PLANE_MANAGER_V2_RECONCILIATION_PATCH_ID,
"artifactSha256": (
DEVICE_PLANE_MANAGER_V2_RECONCILIATION_ARTIFACT_SHA256
),
"mode": "failed-v2-control-plane-baseline-adoption",
},
"service": "device-manager",
"publicIngress": "reverse-proxy-only",
"deviceCoreManagementApi": "file-token-authenticated",
@@ -8853,7 +8862,7 @@ def expected_device_plane_manager_control_plane_descriptor():
"healthGate": "bounded-container-grace+core-contract",
"commandTransport": "disabled",
"gelios": "untouched",
"rollback": "restore-v2-reconciled-baseline",
"rollback": "restore-preapply-snapshot",
}
@@ -8982,14 +8991,62 @@ def validate_platform_device_manager_public_route_payload(payload_dir):
return descriptor
def validate_device_plane_manager_control_plane_payload(payload_dir):
def validate_device_plane_manager_control_plane_payload(
payload_dir,
*,
expected_release_id=None,
):
descriptor = read_strict_json(
payload_dir / DEVICE_PLANE_MANAGER_CONTROL_PLANE_REL,
"Device Manager control-plane descriptor",
"Device Manager release descriptor",
max_bytes=16 * 1024,
)
if descriptor != expected_device_plane_manager_control_plane_descriptor():
die("Device Manager control-plane descriptor mismatch")
required_keys = {
"schemaVersion",
"releaseId",
"action",
"predecessor",
*expected_device_plane_manager_release_boundaries(),
}
if set(descriptor) != required_keys:
die("Device Manager release descriptor key set mismatch")
if (
descriptor.get("schemaVersion")
!= "nodedc.device-plane.device-manager-release.v1"
):
die("Device Manager release descriptor schema mismatch")
release_id = descriptor.get("releaseId")
if (
not isinstance(release_id, str)
or not re.fullmatch(r"[A-Za-z0-9._-]{1,96}", release_id)
or (expected_release_id is not None and release_id != expected_release_id)
):
die("Device Manager release id mismatch")
action = descriptor.get("action")
predecessor = descriptor.get("predecessor")
if (
action not in ("activate", "upgrade")
or not isinstance(predecessor, dict)
or set(predecessor) != {"kind", "patchId", "artifactSha256"}
or predecessor.get("kind") not in ("reconciliation", "release")
or not isinstance(predecessor.get("patchId"), str)
or not re.fullmatch(
r"[A-Za-z0-9._-]{1,96}",
predecessor["patchId"],
)
or predecessor["patchId"] == release_id
or not isinstance(predecessor.get("artifactSha256"), str)
or not re.fullmatch(
r"[a-f0-9]{64}",
predecessor["artifactSha256"],
)
or (action == "activate")
!= (predecessor["kind"] == "reconciliation")
):
die("Device Manager release predecessor mismatch")
boundaries = expected_device_plane_manager_release_boundaries()
if any(descriptor.get(key) != value for key, value in boundaries.items()):
die("Device Manager release security boundary 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")
@@ -10494,52 +10551,136 @@ def validate_device_plane_manager_activation_predecessor(payload_dir):
descriptor = validate_device_plane_manager_control_plane_payload(
payload_dir
)
reconciliation_artifact = (
APPLIED_DIR / DEVICE_PLANE_MANAGER_V2_RECONCILIATION_ARTIFACT
)
predecessor = descriptor["predecessor"]
patch_id = predecessor["patchId"]
sha256 = predecessor["artifactSha256"]
artifact_name = f"nodedc-device-plane-{patch_id}.tgz"
artifact = APPLIED_DIR / artifact_name
try:
artifact_stat = reconciliation_artifact.lstat()
artifact_stat = artifact.lstat()
except FileNotFoundError:
die("Device Manager reconciliation applied artifact is missing")
die("Device Manager predecessor applied artifact is missing")
if (
stat.S_ISLNK(artifact_stat.st_mode)
or not stat.S_ISREG(artifact_stat.st_mode)
or sha256_file(reconciliation_artifact)
!= DEVICE_PLANE_MANAGER_V2_RECONCILIATION_ARTIFACT_SHA256
or sha256_file(artifact) != sha256
):
die("Device Manager reconciliation applied artifact mismatch")
die("Device Manager predecessor applied artifact mismatch")
records = [
id_records = [
value
for value in load_state(STATE_FILE)
if value.get("id")
== DEVICE_PLANE_MANAGER_V2_RECONCILIATION_PATCH_ID
if value.get("id") == patch_id
]
sha_records = [
value
for value in load_state(STATE_FILE)
if value.get("sha256") == sha256
]
if len(records) != 1:
die("Device Manager reconciliation applied journal count mismatch")
record = records[0]
if (
record.get("artifact")
!= DEVICE_PLANE_MANAGER_V2_RECONCILIATION_ARTIFACT
or record.get("backup_id")
!= DEVICE_PLANE_MANAGER_V2_RECONCILIATION_APPLY_BACKUP_ID
or record.get("component") != "device-plane"
or record.get("sha256")
!= DEVICE_PLANE_MANAGER_V2_RECONCILIATION_ARTIFACT_SHA256
or record.get("status") != "ok"
len(id_records) != 1
or len(sha_records) != 1
or id_records[0] != sha_records[0]
):
die("Device Manager reconciliation applied journal mismatch")
die("Device Manager predecessor applied journal identity mismatch")
record = id_records[0]
backup_id = record.get("backup_id")
if (
record.get("artifact") != artifact_name
or record.get("component") != "device-plane"
or record.get("id") != patch_id
or record.get("sha256") != sha256
or record.get("status") != "ok"
or not isinstance(backup_id, str)
or not backup_id
or safe_name(backup_id) != backup_id
):
die("Device Manager predecessor applied journal mismatch")
backup_dir = BACKUPS_DIR / backup_id
try:
backup_stat = backup_dir.lstat()
except FileNotFoundError:
die("Device Manager predecessor backup is missing")
if stat.S_ISLNK(backup_stat.st_mode) or not stat.S_ISDIR(
backup_stat.st_mode
):
die("Device Manager predecessor backup is unsafe")
backup_dir = validate_device_plane_manager_v2_reconciliation_backup()
runtime = validate_device_plane_manager_v2_reconciled_baseline(
backup_dir,
marker_installed=True,
)
with tempfile.TemporaryDirectory(
prefix="device-manager-applied-predecessor-",
dir=TMP_DIR,
) as directory:
predecessor_manifest, predecessor_entries, predecessor_payload = (
load_artifact(artifact, Path(directory))
)
if (
predecessor_manifest.get("id") != patch_id
or predecessor_manifest.get("component") != "device-plane"
or predecessor_manifest.get("type") != "app-overlay"
):
die("Device Manager predecessor artifact manifest mismatch")
root = component_root("device-plane")
if predecessor["kind"] == "reconciliation":
if (
descriptor["action"] != "activate"
or tuple(predecessor_entries)
!= DEVICE_PLANE_MANAGER_V2_RECONCILIATION_ENTRIES
):
die("Device Manager reconciliation predecessor type mismatch")
predecessor_descriptor = (
validate_device_plane_manager_v2_reconciliation_payload(
predecessor_payload
)
)
installed_descriptor = read_strict_json(
root / DEVICE_PLANE_MANAGER_V2_RECONCILIATION_REL,
"installed Device Manager reconciliation predecessor",
max_bytes=16 * 1024,
)
if installed_descriptor != predecessor_descriptor:
die("Device Manager reconciliation predecessor is not current")
baseline_backup = (
validate_device_plane_manager_v2_reconciliation_backup()
)
runtime = validate_device_plane_manager_v2_reconciled_baseline(
baseline_backup,
marker_installed=True,
)
mode = "reconciled-manager-forward-activation"
else:
if (
descriptor["action"] != "upgrade"
or tuple(predecessor_entries)
!= DEVICE_PLANE_MANAGER_CONTROL_PLANE_ENTRIES
):
die("Device Manager release predecessor type mismatch")
predecessor_descriptor = (
validate_device_plane_manager_control_plane_payload(
predecessor_payload,
expected_release_id=patch_id,
)
)
installed_descriptor = read_strict_json(
root / DEVICE_PLANE_MANAGER_CONTROL_PLANE_REL,
"installed Device Manager release predecessor",
max_bytes=16 * 1024,
)
if installed_descriptor != predecessor_descriptor:
die("Device Manager release predecessor is not current")
for service in (
"device-control-core",
"device-manager",
"device-postgres",
):
healthcheck_compose_service("device-plane", service)
runtime = {"accepted": True}
mode = "active-manager-forward-upgrade"
return {
"mode": "reconciled-v2-manager-forward-activation",
"mode": mode,
"descriptor": descriptor,
"reconciliationArtifact": reconciliation_artifact,
"reconciliationRecord": record,
"predecessorArtifact": artifact,
"predecessorRecord": record,
"predecessorBackup": backup_dir,
"runtime": runtime,
}
@@ -10828,7 +10969,10 @@ def device_plane_inventory_service_names(inventory):
"health",
"restartCount",
}
or item.get("service") not in DEVICE_PLANE_RUNTIME_SERVICES
or item.get("service") not in (
*DEVICE_PLANE_RUNTIME_SERVICES,
"device-manager",
)
or not isinstance(item.get("containerId"), str)
or not re.fullmatch(r"[a-f0-9]{64}", item["containerId"])
or not isinstance(item.get("imageId"), str)
@@ -16391,6 +16535,7 @@ def plan_artifact(artifact):
device_plane_foundation_recovery_preflight = None
with tempfile.TemporaryDirectory(prefix="plan-", dir=TMP_DIR) as tmp:
manifest, entries, payload_dir = load_artifact(artifact, Path(tmp))
reject_failed_artifact_replay(manifest, sha)
reject_terminal_engine_l2_failed_artifact(manifest, sha)
reject_terminal_device_plane_foundation_artifact(manifest, sha)
reject_terminal_device_plane_manager_artifact(
@@ -18162,11 +18307,15 @@ def plan_artifact(artifact):
)
print(
"device_plane_predecessor_patch="
f"{DEVICE_PLANE_MANAGER_V2_RECONCILIATION_PATCH_ID}"
f"{device_plane_manager_activation_preflight['descriptor']['predecessor']['patchId']}"
)
print(
"device_plane_predecessor_artifact_sha256="
f"{DEVICE_PLANE_MANAGER_V2_RECONCILIATION_ARTIFACT_SHA256}"
f"{device_plane_manager_activation_preflight['descriptor']['predecessor']['artifactSha256']}"
)
print(
"device_plane_predecessor_kind="
f"{device_plane_manager_activation_preflight['descriptor']['predecessor']['kind']}"
)
print(
"device_plane_runtime_mutation="
@@ -21469,6 +21618,7 @@ def apply_artifact(artifact):
with tempfile.TemporaryDirectory(prefix=f"apply-{current_stamp}-", dir=TMP_DIR) as tmp:
work = Path(tmp)
manifest, entries, payload_dir = load_artifact(artifact, work)
reject_failed_artifact_replay(manifest, sha)
reject_terminal_engine_l2_failed_artifact(manifest, sha)
reject_terminal_device_plane_foundation_artifact(
manifest,
@@ -21848,9 +21998,18 @@ def apply_artifact(artifact):
if not artifact_only and not DOCKER.is_file():
die(f"docker not found: {DOCKER}")
if component == "device-plane":
inventory_services = DEVICE_PLANE_RUNTIME_SERVICES
if is_device_plane_manager_control_plane_slice(
component,
entries,
):
inventory_services = (
*inventory_services,
"device-manager",
)
device_plane_runtime_before = (
device_plane_runtime_inventory(
DEVICE_PLANE_RUNTIME_SERVICES
inventory_services
)
)