fix(deploy): version device manager edge release contract
This commit is contained in:
@@ -240,10 +240,19 @@ DEVICE_PLANE_MANAGER_V2_CONTROL_PLANE_REL = (
|
||||
DEVICE_PLANE_MANAGER_CONTROL_PLANE_REL = (
|
||||
"deployment/device-manager-release-v1.json"
|
||||
)
|
||||
DEVICE_PLANE_MANAGER_RELEASE_V2_REL = (
|
||||
"deployment/device-manager-release-v2.json"
|
||||
)
|
||||
DEVICE_PLANE_MANAGER_COMPOSE_REL = "docker-compose.device-manager.yml"
|
||||
DEVICE_PLANE_MANAGER_COMPOSE_SHA256 = (
|
||||
DEVICE_PLANE_MANAGER_RELEASE_V1_COMPOSE_SHA256 = (
|
||||
"4954120aaddc999798b64c304d8cf692b79714feb727d873117bd1f3434e865e"
|
||||
)
|
||||
DEVICE_PLANE_MANAGER_RELEASE_V2_COMPOSE_SHA256 = (
|
||||
"369a2acf9c1a1030b9e1c6c366144b1eaf8900aef0ee59bb6bf23250b7b371b9"
|
||||
)
|
||||
DEVICE_PLANE_MANAGER_COMPOSE_SHA256 = (
|
||||
DEVICE_PLANE_MANAGER_RELEASE_V2_COMPOSE_SHA256
|
||||
)
|
||||
DEVICE_PLANE_MANAGER_FAILED_CONTROL_PLANE_ENTRIES = (
|
||||
".dockerignore",
|
||||
"package.json",
|
||||
@@ -283,6 +292,19 @@ DEVICE_PLANE_MANAGER_CONTROL_PLANE_ENTRIES = (
|
||||
"services/device-manager",
|
||||
DEVICE_PLANE_MANAGER_CONTROL_PLANE_REL,
|
||||
)
|
||||
DEVICE_PLANE_MANAGER_RELEASE_V2_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_RELEASE_V2_REL,
|
||||
)
|
||||
DEVICE_PLANE_MANAGER_RECONCILIATION_REL = (
|
||||
"deployment/device-manager-control-plane-reconciliation-v1.json"
|
||||
)
|
||||
@@ -3505,6 +3527,7 @@ def allowed_payload_path(component, rel):
|
||||
DEVICE_PLANE_BACKHAUL_TARGET_REL,
|
||||
DEVICE_PLANE_MANAGER_FAILED_CONTROL_PLANE_REL,
|
||||
DEVICE_PLANE_MANAGER_CONTROL_PLANE_REL,
|
||||
DEVICE_PLANE_MANAGER_RELEASE_V2_REL,
|
||||
DEVICE_PLANE_MANAGER_RECONCILIATION_REL,
|
||||
DEVICE_PLANE_MANAGER_V2_RECONCILIATION_REL,
|
||||
"packages/device-protocol-contract",
|
||||
@@ -8551,7 +8574,7 @@ def load_artifact(artifact, work_dir):
|
||||
manifest["component"],
|
||||
entries,
|
||||
):
|
||||
validate_device_plane_manager_control_plane_payload(
|
||||
validate_device_plane_manager_release_payload(
|
||||
payload_dir,
|
||||
expected_release_id=manifest["id"],
|
||||
)
|
||||
@@ -9023,7 +9046,18 @@ 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
|
||||
and tuple(entries) in (
|
||||
DEVICE_PLANE_MANAGER_CONTROL_PLANE_ENTRIES,
|
||||
DEVICE_PLANE_MANAGER_RELEASE_V2_ENTRIES,
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
def is_device_plane_manager_release_v2_slice(component, entries):
|
||||
return (
|
||||
component == "device-plane"
|
||||
and entries is not None
|
||||
and tuple(entries) == DEVICE_PLANE_MANAGER_RELEASE_V2_ENTRIES
|
||||
)
|
||||
|
||||
|
||||
@@ -9083,12 +9117,22 @@ def expected_platform_device_manager_public_route_descriptor():
|
||||
}
|
||||
|
||||
|
||||
def expected_device_plane_manager_release_boundaries():
|
||||
def expected_device_plane_manager_release_v1_boundaries():
|
||||
return {
|
||||
"service": "device-manager",
|
||||
"publicIngress": "reverse-proxy-only",
|
||||
"deviceCoreManagementApi": "file-token-authenticated",
|
||||
"launcherTrust": "file-token-scoped-to-device-core-handoff",
|
||||
"healthGate": "bounded-container-grace+core-contract",
|
||||
"commandTransport": "disabled",
|
||||
"gelios": "untouched",
|
||||
"rollback": "restore-preapply-snapshot",
|
||||
}
|
||||
|
||||
|
||||
def expected_device_plane_manager_release_v2_boundaries():
|
||||
return {
|
||||
**expected_device_plane_manager_release_v1_boundaries(),
|
||||
"edgeChannel": (
|
||||
"core-initiated-pinned-mtls-enabled-zero-or-more-registered-edges"
|
||||
),
|
||||
@@ -9099,13 +9143,15 @@ def expected_device_plane_manager_release_boundaries():
|
||||
"dedicated-core-only-bridge-no-host-ingress-"
|
||||
"public-ipv4-tcp-8443-registration-policy"
|
||||
),
|
||||
"healthGate": "bounded-container-grace+core-contract",
|
||||
"commandTransport": "disabled",
|
||||
"gelios": "untouched",
|
||||
"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.
|
||||
return expected_device_plane_manager_release_v2_boundaries()
|
||||
|
||||
|
||||
def expected_device_plane_manager_failed_control_plane_descriptor():
|
||||
return {
|
||||
"schemaVersion": (
|
||||
@@ -9231,29 +9277,28 @@ 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_release_descriptor(
|
||||
descriptor,
|
||||
*,
|
||||
schema_version,
|
||||
boundaries,
|
||||
expected_release_id=None,
|
||||
):
|
||||
descriptor = read_strict_json(
|
||||
payload_dir / DEVICE_PLANE_MANAGER_CONTROL_PLANE_REL,
|
||||
"Device Manager release descriptor",
|
||||
max_bytes=16 * 1024,
|
||||
)
|
||||
required_keys = {
|
||||
"schemaVersion",
|
||||
"releaseId",
|
||||
"action",
|
||||
"predecessor",
|
||||
*expected_device_plane_manager_release_boundaries(),
|
||||
*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"
|
||||
):
|
||||
missing = ",".join(sorted(required_keys - set(descriptor))) or "none"
|
||||
extra = ",".join(sorted(set(descriptor) - required_keys)) or "none"
|
||||
die(
|
||||
"Device Manager release descriptor key set mismatch: "
|
||||
f"schema={schema_version} missing={missing} extra={extra}"
|
||||
)
|
||||
if descriptor.get("schemaVersion") != schema_version:
|
||||
die("Device Manager release descriptor schema mismatch")
|
||||
release_id = descriptor.get("releaseId")
|
||||
if (
|
||||
@@ -9284,16 +9329,39 @@ def validate_device_plane_manager_control_plane_payload(
|
||||
!= (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")
|
||||
return descriptor
|
||||
|
||||
|
||||
def validate_device_plane_manager_release_payload_contract(
|
||||
payload_dir,
|
||||
*,
|
||||
descriptor_rel,
|
||||
schema_version,
|
||||
boundaries,
|
||||
compose_sha256,
|
||||
edge_channel,
|
||||
expected_release_id=None,
|
||||
):
|
||||
descriptor = read_strict_json(
|
||||
payload_dir / descriptor_rel,
|
||||
"Device Manager release descriptor",
|
||||
max_bytes=16 * 1024,
|
||||
)
|
||||
validate_device_plane_manager_release_descriptor(
|
||||
descriptor,
|
||||
schema_version=schema_version,
|
||||
boundaries=boundaries,
|
||||
expected_release_id=expected_release_id,
|
||||
)
|
||||
compose_path = payload_dir / DEVICE_PLANE_MANAGER_COMPOSE_REL
|
||||
if sha256_file(compose_path) != DEVICE_PLANE_MANAGER_COMPOSE_SHA256:
|
||||
if sha256_file(compose_path) != compose_sha256:
|
||||
die("Device Manager control-plane Compose mismatch")
|
||||
compose = compose_path.read_text(
|
||||
encoding="utf-8"
|
||||
)
|
||||
for required in (
|
||||
required_compose = [
|
||||
"device-manager:",
|
||||
'DEVICE_MANAGEMENT_API_ENABLED: "true"',
|
||||
"DEVICE_MANAGEMENT_CORE_TOKEN_FILE: "
|
||||
@@ -9302,22 +9370,26 @@ def validate_device_plane_manager_control_plane_payload(
|
||||
"/run/nodedc-secrets/device-core-internal-token",
|
||||
"NODEDC_DEVICE_CORE_TOKEN_FILE: "
|
||||
"/run/nodedc-secrets/management-core-token",
|
||||
'DEVICE_EDGE_CHANNEL_ENABLED: "true"',
|
||||
"DEVICE_EDGE_CHANNEL_CORE_KEY_FILE: "
|
||||
"/run/nodedc-secrets/device-edge-channel/core-private-key.pem",
|
||||
"DEVICE_EDGE_CHANNEL_CORE_CERTIFICATE_FILE: "
|
||||
"/run/nodedc-secrets/device-edge-channel/core-certificate.pem",
|
||||
"DEVICE_EDGE_CHANNEL_TRUST_ROOT: "
|
||||
"/run/nodedc-secrets/device-edge-channel/peers",
|
||||
"source: /volume1/docker/nodedc-device-plane/secrets/"
|
||||
"device-edge-channel/core-private-key.pem",
|
||||
"source: /volume1/docker/nodedc-device-plane/secrets/"
|
||||
"device-edge-channel/core-certificate.pem",
|
||||
"source: /volume1/docker/nodedc-device-plane/secrets/"
|
||||
"device-edge-channel/peers",
|
||||
"name: nodedc-device-plane-egress",
|
||||
"name: nodedc-platform_edge",
|
||||
):
|
||||
]
|
||||
if edge_channel:
|
||||
required_compose.extend((
|
||||
'DEVICE_EDGE_CHANNEL_ENABLED: "true"',
|
||||
"DEVICE_EDGE_CHANNEL_CORE_KEY_FILE: "
|
||||
"/run/nodedc-secrets/device-edge-channel/core-private-key.pem",
|
||||
"DEVICE_EDGE_CHANNEL_CORE_CERTIFICATE_FILE: "
|
||||
"/run/nodedc-secrets/device-edge-channel/core-certificate.pem",
|
||||
"DEVICE_EDGE_CHANNEL_TRUST_ROOT: "
|
||||
"/run/nodedc-secrets/device-edge-channel/peers",
|
||||
"source: /volume1/docker/nodedc-device-plane/secrets/"
|
||||
"device-edge-channel/core-private-key.pem",
|
||||
"source: /volume1/docker/nodedc-device-plane/secrets/"
|
||||
"device-edge-channel/core-certificate.pem",
|
||||
"source: /volume1/docker/nodedc-device-plane/secrets/"
|
||||
"device-edge-channel/peers",
|
||||
"name: nodedc-device-plane-egress",
|
||||
))
|
||||
for required in required_compose:
|
||||
if required not in compose:
|
||||
die(f"Device Manager control-plane boundary missing: {required}")
|
||||
for forbidden in (
|
||||
@@ -9330,6 +9402,59 @@ def validate_device_plane_manager_control_plane_payload(
|
||||
return descriptor
|
||||
|
||||
|
||||
def validate_device_plane_manager_control_plane_payload(
|
||||
payload_dir,
|
||||
*,
|
||||
expected_release_id=None,
|
||||
):
|
||||
return validate_device_plane_manager_release_payload_contract(
|
||||
payload_dir,
|
||||
descriptor_rel=DEVICE_PLANE_MANAGER_CONTROL_PLANE_REL,
|
||||
schema_version="nodedc.device-plane.device-manager-release.v1",
|
||||
boundaries=expected_device_plane_manager_release_v1_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_v2_payload(
|
||||
payload_dir,
|
||||
*,
|
||||
expected_release_id=None,
|
||||
):
|
||||
return validate_device_plane_manager_release_payload_contract(
|
||||
payload_dir,
|
||||
descriptor_rel=DEVICE_PLANE_MANAGER_RELEASE_V2_REL,
|
||||
schema_version="nodedc.device-plane.device-manager-release.v2",
|
||||
boundaries=expected_device_plane_manager_release_v2_boundaries(),
|
||||
compose_sha256=DEVICE_PLANE_MANAGER_RELEASE_V2_COMPOSE_SHA256,
|
||||
edge_channel=True,
|
||||
expected_release_id=expected_release_id,
|
||||
)
|
||||
|
||||
|
||||
def validate_device_plane_manager_release_payload(
|
||||
payload_dir,
|
||||
*,
|
||||
expected_release_id=None,
|
||||
):
|
||||
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()]
|
||||
if len(present) != 1:
|
||||
die("Device Manager release descriptor cardinality mismatch")
|
||||
if present[0] == v2:
|
||||
return validate_device_plane_manager_release_v2_payload(
|
||||
payload_dir,
|
||||
expected_release_id=expected_release_id,
|
||||
)
|
||||
return validate_device_plane_manager_control_plane_payload(
|
||||
payload_dir,
|
||||
expected_release_id=expected_release_id,
|
||||
)
|
||||
|
||||
|
||||
def validate_device_plane_manager_failed_control_plane_payload(payload_dir):
|
||||
descriptor = read_strict_json(
|
||||
payload_dir / DEVICE_PLANE_MANAGER_FAILED_CONTROL_PLANE_REL,
|
||||
@@ -10802,7 +10927,7 @@ def validate_device_plane_manager_reconciliation_evidence(payload_dir):
|
||||
|
||||
|
||||
def validate_device_plane_manager_activation_predecessor(payload_dir):
|
||||
descriptor = validate_device_plane_manager_control_plane_payload(
|
||||
descriptor = validate_device_plane_manager_release_payload(
|
||||
payload_dir
|
||||
)
|
||||
predecessor = descriptor["predecessor"]
|
||||
@@ -10904,18 +11029,26 @@ def validate_device_plane_manager_activation_predecessor(payload_dir):
|
||||
else:
|
||||
if (
|
||||
descriptor["action"] != "upgrade"
|
||||
or tuple(predecessor_entries)
|
||||
!= DEVICE_PLANE_MANAGER_CONTROL_PLANE_ENTRIES
|
||||
or tuple(predecessor_entries) not in (
|
||||
DEVICE_PLANE_MANAGER_CONTROL_PLANE_ENTRIES,
|
||||
DEVICE_PLANE_MANAGER_RELEASE_V2_ENTRIES,
|
||||
)
|
||||
):
|
||||
die("Device Manager release predecessor type mismatch")
|
||||
predecessor_descriptor = (
|
||||
validate_device_plane_manager_control_plane_payload(
|
||||
validate_device_plane_manager_release_payload(
|
||||
predecessor_payload,
|
||||
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
|
||||
)
|
||||
installed_descriptor = read_strict_json(
|
||||
root / DEVICE_PLANE_MANAGER_CONTROL_PLANE_REL,
|
||||
root / predecessor_descriptor_rel,
|
||||
"installed Device Manager release predecessor",
|
||||
max_bytes=16 * 1024,
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user