fix(device-edge): route Core through dedicated egress
This commit is contained in:
@@ -256,12 +256,21 @@ DEVICE_PLANE_EDGE_CORE_CHANNEL_UPGRADE_REL = (
|
||||
DEVICE_PLANE_EDGE_CORE_CHANNEL_UPGRADE_V2_REL = (
|
||||
"deployment/device-edge-core-channel-upgrade-v2.json"
|
||||
)
|
||||
DEVICE_PLANE_EDGE_CORE_CHANNEL_UPGRADE_V3_REL = (
|
||||
"deployment/device-edge-core-channel-upgrade-v3.json"
|
||||
)
|
||||
DEVICE_PLANE_EDGE_CORE_CHANNEL_COMPOSE_REL = (
|
||||
"docker-compose.device-edge-core-channel.yml"
|
||||
)
|
||||
DEVICE_PLANE_EDGE_CORE_CHANNEL_COMPOSE_SHA256 = (
|
||||
"cac1e06b21202d8d96f5694b1adb1e67c0a3cdd31fcfca56cb7e19839c8516d8"
|
||||
)
|
||||
DEVICE_PLANE_EDGE_CORE_CHANNEL_UPGRADE_V3_PREDECESSOR_BASE_COMPOSE_SHA256 = (
|
||||
"eb1018cc0ffeaa0c019944d8810e2daa01eeca4c06289efff175785fb16457e7"
|
||||
)
|
||||
DEVICE_PLANE_EDGE_CORE_CHANNEL_UPGRADE_V3_BASE_COMPOSE_SHA256 = (
|
||||
"6a4c08313cc97bbfd86c4e133c6b2e55ba18a499a3bb6f267c7059754f83e8cf"
|
||||
)
|
||||
DEVICE_PLANE_EDGE_CORE_CHANNEL_BOOTSTRAP_ENTRIES = (
|
||||
".dockerignore",
|
||||
"package.json",
|
||||
@@ -292,6 +301,16 @@ DEVICE_PLANE_EDGE_CORE_CHANNEL_UPGRADE_V2_ENTRIES = (
|
||||
"services/device-control-core",
|
||||
DEVICE_PLANE_EDGE_CORE_CHANNEL_UPGRADE_V2_REL,
|
||||
)
|
||||
DEVICE_PLANE_EDGE_CORE_CHANNEL_UPGRADE_V3_ENTRIES = (
|
||||
".dockerignore",
|
||||
"package.json",
|
||||
"package-lock.json",
|
||||
"docker-compose.device-plane.yml",
|
||||
"packages/device-protocol-contract",
|
||||
"packages/device-edge-channel-contract",
|
||||
"services/device-control-core",
|
||||
DEVICE_PLANE_EDGE_CORE_CHANNEL_UPGRADE_V3_REL,
|
||||
)
|
||||
DEVICE_PLANE_EDGE_CORE_CHANNEL_BOOTSTRAP_PREDECESSOR_PATCH_ID = (
|
||||
"device-edge-core-channel-bootstrap-20260812-018"
|
||||
)
|
||||
@@ -304,6 +323,12 @@ DEVICE_PLANE_EDGE_CORE_CHANNEL_UPGRADE_V2_PREDECESSOR_PATCH_ID = (
|
||||
DEVICE_PLANE_EDGE_CORE_CHANNEL_UPGRADE_V2_PREDECESSOR_ARTIFACT_SHA256 = (
|
||||
"8e9a220275959f378c1c4b00be5c7192e79afe2134eaab808a64e515870a8438"
|
||||
)
|
||||
DEVICE_PLANE_EDGE_CORE_CHANNEL_UPGRADE_V3_PREDECESSOR_PATCH_ID = (
|
||||
"device-edge-core-channel-upgrade-v2-20260812-021"
|
||||
)
|
||||
DEVICE_PLANE_EDGE_CORE_CHANNEL_UPGRADE_V3_PREDECESSOR_ARTIFACT_SHA256 = (
|
||||
"e40a6fd24edfecac09e42cd82635a77850541bcf047788db3e9c55d2b9e58867"
|
||||
)
|
||||
DEVICE_PLANE_EDGE_CORE_CHANNEL_MANAGER_PREDECESSOR_PATCH_ID = (
|
||||
"device-manager-release-20260811-010"
|
||||
)
|
||||
@@ -3835,6 +3860,7 @@ def allowed_payload_path(component, 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_V3_REL,
|
||||
DEVICE_PLANE_MANAGER_RECONCILIATION_REL,
|
||||
DEVICE_PLANE_MANAGER_V2_RECONCILIATION_REL,
|
||||
"packages/device-protocol-contract",
|
||||
@@ -8891,7 +8917,15 @@ def load_artifact(artifact, work_dir):
|
||||
manifest["component"],
|
||||
entries,
|
||||
):
|
||||
if is_device_plane_edge_core_channel_upgrade_v2_slice(
|
||||
if is_device_plane_edge_core_channel_upgrade_v3_slice(
|
||||
manifest["component"],
|
||||
entries,
|
||||
):
|
||||
validate_device_plane_edge_core_channel_upgrade_v3_payload(
|
||||
payload_dir,
|
||||
expected_transition_id=manifest["id"],
|
||||
)
|
||||
elif is_device_plane_edge_core_channel_upgrade_v2_slice(
|
||||
manifest["component"],
|
||||
entries,
|
||||
):
|
||||
@@ -9404,6 +9438,7 @@ def is_device_plane_edge_core_channel_bootstrap_slice(component, entries):
|
||||
DEVICE_PLANE_EDGE_CORE_CHANNEL_BOOTSTRAP_ENTRIES,
|
||||
DEVICE_PLANE_EDGE_CORE_CHANNEL_UPGRADE_ENTRIES,
|
||||
DEVICE_PLANE_EDGE_CORE_CHANNEL_UPGRADE_V2_ENTRIES,
|
||||
DEVICE_PLANE_EDGE_CORE_CHANNEL_UPGRADE_V3_ENTRIES,
|
||||
)
|
||||
)
|
||||
|
||||
@@ -9415,6 +9450,7 @@ def is_device_plane_edge_core_channel_upgrade_slice(component, entries):
|
||||
and tuple(entries) in (
|
||||
DEVICE_PLANE_EDGE_CORE_CHANNEL_UPGRADE_ENTRIES,
|
||||
DEVICE_PLANE_EDGE_CORE_CHANNEL_UPGRADE_V2_ENTRIES,
|
||||
DEVICE_PLANE_EDGE_CORE_CHANNEL_UPGRADE_V3_ENTRIES,
|
||||
)
|
||||
)
|
||||
|
||||
@@ -9427,6 +9463,14 @@ def is_device_plane_edge_core_channel_upgrade_v2_slice(component, entries):
|
||||
)
|
||||
|
||||
|
||||
def is_device_plane_edge_core_channel_upgrade_v3_slice(component, entries):
|
||||
return (
|
||||
component == "device-plane"
|
||||
and entries is not None
|
||||
and tuple(entries) == DEVICE_PLANE_EDGE_CORE_CHANNEL_UPGRADE_V3_ENTRIES
|
||||
)
|
||||
|
||||
|
||||
def is_device_plane_manager_v2_control_plane_slice(component, entries):
|
||||
return (
|
||||
component == "device-plane"
|
||||
@@ -9661,6 +9705,58 @@ def expected_device_plane_edge_core_channel_upgrade_v2_descriptor(
|
||||
}
|
||||
|
||||
|
||||
def expected_device_plane_edge_core_channel_upgrade_v3_descriptor(
|
||||
transition_id,
|
||||
):
|
||||
return {
|
||||
"schemaVersion": (
|
||||
"nodedc.device-plane.device-edge-core-channel-upgrade.v3"
|
||||
),
|
||||
"transitionId": transition_id,
|
||||
"action": "upgrade",
|
||||
"upgradePredecessor": {
|
||||
"patchId": (
|
||||
DEVICE_PLANE_EDGE_CORE_CHANNEL_UPGRADE_V3_PREDECESSOR_PATCH_ID
|
||||
),
|
||||
"artifactSha256": (
|
||||
DEVICE_PLANE_EDGE_CORE_CHANNEL_UPGRADE_V3_PREDECESSOR_ARTIFACT_SHA256
|
||||
),
|
||||
},
|
||||
"service": "device-control-core",
|
||||
"composeActivation": (
|
||||
"replace-core-network-membership-with-private-plus-egress"
|
||||
),
|
||||
"identity": (
|
||||
"reuse-existing-runner-managed-host-local-private-key-"
|
||||
"public-certificate-export"
|
||||
),
|
||||
"identityRecovery": "forbidden-valid-existing-identity-required",
|
||||
"tlsPurpose": "clientAuth",
|
||||
"direction": "core-initiated",
|
||||
"endpointPolicy": "public-ipv4-standard-https-tcp-443-only",
|
||||
"coreNetworks": [
|
||||
"device-plane-private",
|
||||
"device-plane-egress",
|
||||
],
|
||||
"removedCoreNetwork": "device-plane-control",
|
||||
"composeCompatibility": "synology-compose-v2.20-no-gw-priority",
|
||||
"publicIngress": "none-on-synology",
|
||||
"edgeRegistrations": "preserved",
|
||||
"commandTransport": "disabled",
|
||||
"gelios": "untouched",
|
||||
"preservedServices": [
|
||||
"device-manager",
|
||||
"device-gateway",
|
||||
"device-postgres",
|
||||
"device-backhaul-target",
|
||||
],
|
||||
"healthGate": "bounded-container-grace+core-edge-contract",
|
||||
"rollback": (
|
||||
"restore-upgrade-v2-021-source-and-preapply-core-runtime"
|
||||
),
|
||||
}
|
||||
|
||||
|
||||
def expected_device_plane_manager_failed_control_plane_descriptor():
|
||||
return {
|
||||
"schemaVersion": (
|
||||
@@ -10048,6 +10144,36 @@ def validate_device_plane_edge_core_channel_upgrade_v2_payload(
|
||||
return descriptor
|
||||
|
||||
|
||||
def validate_device_plane_edge_core_channel_upgrade_v3_payload(
|
||||
payload_dir,
|
||||
*,
|
||||
expected_transition_id=None,
|
||||
):
|
||||
descriptor = read_strict_json(
|
||||
payload_dir / DEVICE_PLANE_EDGE_CORE_CHANNEL_UPGRADE_V3_REL,
|
||||
"Device Edge Core channel upgrade v3 descriptor",
|
||||
max_bytes=16 * 1024,
|
||||
)
|
||||
transition_id = descriptor.get("transitionId")
|
||||
if (
|
||||
not isinstance(transition_id, str)
|
||||
or not re.fullmatch(r"[A-Za-z0-9._-]{1,96}", transition_id)
|
||||
or (
|
||||
expected_transition_id is not None
|
||||
and transition_id != expected_transition_id
|
||||
)
|
||||
or descriptor
|
||||
!= expected_device_plane_edge_core_channel_upgrade_v3_descriptor(
|
||||
transition_id
|
||||
)
|
||||
):
|
||||
die("Device Edge Core channel upgrade v3 descriptor mismatch")
|
||||
validate_device_plane_edge_core_channel_upgrade_v3_base_compose(
|
||||
payload_dir
|
||||
)
|
||||
return descriptor
|
||||
|
||||
|
||||
def validate_device_plane_edge_core_channel_compose(payload_dir):
|
||||
compose = payload_dir / DEVICE_PLANE_EDGE_CORE_CHANNEL_COMPOSE_REL
|
||||
if sha256_file(compose) != DEVICE_PLANE_EDGE_CORE_CHANNEL_COMPOSE_SHA256:
|
||||
@@ -10087,6 +10213,39 @@ def validate_device_plane_edge_core_channel_compose(payload_dir):
|
||||
return compose
|
||||
|
||||
|
||||
def validate_device_plane_edge_core_channel_upgrade_v3_base_compose(
|
||||
payload_dir,
|
||||
):
|
||||
compose = payload_dir / "docker-compose.device-plane.yml"
|
||||
if (
|
||||
sha256_file(compose)
|
||||
!= DEVICE_PLANE_EDGE_CORE_CHANNEL_UPGRADE_V3_BASE_COMPOSE_SHA256
|
||||
):
|
||||
die("Device Edge Core channel v3 base Compose mismatch")
|
||||
compose_text = compose.read_text(encoding="utf-8")
|
||||
try:
|
||||
core_block = compose_text.split(
|
||||
"\n device-control-core:", 1
|
||||
)[1].split("\n device-gateway:", 1)[0]
|
||||
gateway_block = compose_text.split(
|
||||
"\n device-gateway:", 1
|
||||
)[1].split("\nnetworks:", 1)[0]
|
||||
except IndexError:
|
||||
die("Device Edge Core channel v3 service topology is incomplete")
|
||||
if (
|
||||
" - device-plane-private" not in core_block
|
||||
or " - device-plane-control" in core_block
|
||||
or " - device-plane-private" not in gateway_block
|
||||
or " - device-plane-control" not in gateway_block
|
||||
or "gw_priority:" in compose_text
|
||||
or "network_mode:" in compose_text
|
||||
or "privileged:" in compose_text
|
||||
):
|
||||
die("Device Edge Core channel v3 network boundary mismatch")
|
||||
return compose
|
||||
return compose
|
||||
|
||||
|
||||
def installed_device_plane_manager_compose_sha256():
|
||||
root = DEVICE_PLANE_ROOT
|
||||
v1 = root / DEVICE_PLANE_MANAGER_CONTROL_PLANE_REL
|
||||
@@ -11777,6 +11936,12 @@ def inspect_device_edge_channel_core_identity_state():
|
||||
def validate_device_plane_edge_core_channel_bootstrap_predecessor(
|
||||
payload_dir,
|
||||
):
|
||||
if (
|
||||
payload_dir / DEVICE_PLANE_EDGE_CORE_CHANNEL_UPGRADE_V3_REL
|
||||
).exists():
|
||||
return validate_device_plane_edge_core_channel_upgrade_v3_predecessor(
|
||||
payload_dir
|
||||
)
|
||||
if (
|
||||
payload_dir / DEVICE_PLANE_EDGE_CORE_CHANNEL_UPGRADE_V2_REL
|
||||
).exists():
|
||||
@@ -12075,6 +12240,96 @@ def validate_device_plane_edge_core_channel_upgrade_v2_predecessor(
|
||||
}
|
||||
|
||||
|
||||
def validate_device_plane_edge_core_channel_upgrade_v3_predecessor(
|
||||
payload_dir,
|
||||
):
|
||||
descriptor = validate_device_plane_edge_core_channel_upgrade_v3_payload(
|
||||
payload_dir
|
||||
)
|
||||
installed_upgrade = (
|
||||
DEVICE_PLANE_ROOT / DEVICE_PLANE_EDGE_CORE_CHANNEL_UPGRADE_V3_REL
|
||||
)
|
||||
if installed_upgrade.exists() or installed_upgrade.is_symlink():
|
||||
die("Device Edge Core channel upgrade v3 is already installed")
|
||||
predecessor = descriptor["upgradePredecessor"]
|
||||
artifact_name = f"nodedc-device-plane-{predecessor['patchId']}.tgz"
|
||||
artifact = APPLIED_DIR / artifact_name
|
||||
if (
|
||||
not artifact.is_file()
|
||||
or artifact.is_symlink()
|
||||
or sha256_file(artifact) != predecessor["artifactSha256"]
|
||||
):
|
||||
die("Device Edge Core channel upgrade v3 predecessor mismatch")
|
||||
records = [
|
||||
row for row in load_state(STATE_FILE)
|
||||
if row.get("id") == predecessor["patchId"]
|
||||
and row.get("sha256") == predecessor["artifactSha256"]
|
||||
]
|
||||
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("Device Edge Core channel upgrade v3 predecessor journal mismatch")
|
||||
with tempfile.TemporaryDirectory(
|
||||
prefix="device-edge-core-channel-upgrade-v3-predecessor-",
|
||||
dir=TMP_DIR,
|
||||
) as directory:
|
||||
manifest, entries, predecessor_payload = load_artifact(
|
||||
artifact,
|
||||
Path(directory),
|
||||
)
|
||||
if (
|
||||
manifest.get("id") != predecessor["patchId"]
|
||||
or manifest.get("component") != "device-plane"
|
||||
or manifest.get("type") != "app-overlay"
|
||||
or tuple(entries)
|
||||
!= DEVICE_PLANE_EDGE_CORE_CHANNEL_UPGRADE_V2_ENTRIES
|
||||
):
|
||||
die("Device Edge Core channel upgrade v3 predecessor type mismatch")
|
||||
validate_device_plane_edge_core_channel_upgrade_v2_payload(
|
||||
predecessor_payload,
|
||||
expected_transition_id=predecessor["patchId"],
|
||||
)
|
||||
expected_source = collect_exact_files(
|
||||
predecessor_payload,
|
||||
DEVICE_PLANE_EDGE_CORE_CHANNEL_UPGRADE_V2_ENTRIES,
|
||||
"Device Edge Core channel upgrade v3 predecessor source",
|
||||
)
|
||||
actual_source = collect_exact_files(
|
||||
DEVICE_PLANE_ROOT,
|
||||
DEVICE_PLANE_EDGE_CORE_CHANNEL_UPGRADE_V2_ENTRIES,
|
||||
"installed Device Edge Core channel upgrade v2 source",
|
||||
)
|
||||
if actual_source != expected_source:
|
||||
die("installed Device Edge Core channel upgrade v2 source drift detected")
|
||||
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)
|
||||
!= DEVICE_PLANE_EDGE_CORE_CHANNEL_UPGRADE_V3_PREDECESSOR_BASE_COMPOSE_SHA256
|
||||
):
|
||||
die("installed Device Edge Core channel v3 base predecessor drift detected")
|
||||
identity_state = inspect_device_edge_channel_core_identity_state()
|
||||
if identity_state != "valid-reuse-at-apply":
|
||||
die("Device Edge Core channel upgrade v3 requires the valid active identity")
|
||||
for service in (
|
||||
"device-control-core",
|
||||
"device-manager",
|
||||
"device-gateway",
|
||||
"device-postgres",
|
||||
):
|
||||
healthcheck_compose_service("device-plane", service)
|
||||
return {
|
||||
"mode": "edge-core-channel-private-plus-egress-upgrade-v3",
|
||||
"descriptor": descriptor,
|
||||
"identityState": identity_state,
|
||||
"upgradeArtifact": artifact,
|
||||
}
|
||||
|
||||
|
||||
def validate_device_plane_manager_v2_reconciliation_backup():
|
||||
backup_dir = (
|
||||
BACKUPS_DIR / DEVICE_PLANE_MANAGER_V2_RECONCILIATION_BACKUP_ID
|
||||
@@ -15883,6 +16138,9 @@ def component_compose_files(
|
||||
edge_upgrade_v2_descriptor = (
|
||||
DEVICE_PLANE_ROOT / DEVICE_PLANE_EDGE_CORE_CHANNEL_UPGRADE_V2_REL
|
||||
)
|
||||
edge_upgrade_v3_descriptor = (
|
||||
DEVICE_PLANE_ROOT / DEVICE_PLANE_EDGE_CORE_CHANNEL_UPGRADE_V3_REL
|
||||
)
|
||||
edge_override = (
|
||||
DEVICE_PLANE_ROOT / DEVICE_PLANE_EDGE_CORE_CHANNEL_COMPOSE_REL
|
||||
)
|
||||
@@ -15897,6 +16155,10 @@ def component_compose_files(
|
||||
edge_upgrade_v2_descriptor.exists()
|
||||
or edge_upgrade_v2_descriptor.is_symlink()
|
||||
)
|
||||
edge_upgrade_v3_descriptor_exists = (
|
||||
edge_upgrade_v3_descriptor.exists()
|
||||
or edge_upgrade_v3_descriptor.is_symlink()
|
||||
)
|
||||
edge_override_exists = edge_override.exists() or edge_override.is_symlink()
|
||||
if (
|
||||
edge_override_exists
|
||||
@@ -15904,6 +16166,7 @@ def component_compose_files(
|
||||
edge_descriptor_exists
|
||||
or edge_upgrade_descriptor_exists
|
||||
or edge_upgrade_v2_descriptor_exists
|
||||
or edge_upgrade_v3_descriptor_exists
|
||||
)
|
||||
or edge_upgrade_descriptor_exists
|
||||
and not edge_descriptor_exists
|
||||
@@ -15911,6 +16174,12 @@ def component_compose_files(
|
||||
and not (
|
||||
edge_descriptor_exists and edge_upgrade_descriptor_exists
|
||||
)
|
||||
or edge_upgrade_v3_descriptor_exists
|
||||
and not (
|
||||
edge_descriptor_exists
|
||||
and edge_upgrade_descriptor_exists
|
||||
and edge_upgrade_v2_descriptor_exists
|
||||
)
|
||||
):
|
||||
die("installed Device Edge Core channel source is incomplete")
|
||||
if edge_descriptor_exists:
|
||||
@@ -15988,6 +16257,35 @@ def component_compose_files(
|
||||
)
|
||||
):
|
||||
die("installed Device Edge Core channel upgrade v2 descriptor drift detected")
|
||||
if edge_upgrade_v3_descriptor_exists:
|
||||
if (
|
||||
upgrade_v2_id
|
||||
!= DEVICE_PLANE_EDGE_CORE_CHANNEL_UPGRADE_V3_PREDECESSOR_PATCH_ID
|
||||
or edge_upgrade_v3_descriptor.is_symlink()
|
||||
or not edge_upgrade_v3_descriptor.is_file()
|
||||
or sha256_file(
|
||||
DEVICE_PLANE_ROOT / "docker-compose.device-plane.yml"
|
||||
)
|
||||
!= DEVICE_PLANE_EDGE_CORE_CHANNEL_UPGRADE_V3_BASE_COMPOSE_SHA256
|
||||
):
|
||||
die("installed Device Edge Core channel upgrade v3 predecessor drift detected")
|
||||
upgrade_v3 = read_strict_json(
|
||||
edge_upgrade_v3_descriptor,
|
||||
"installed Device Edge Core channel upgrade v3 descriptor",
|
||||
max_bytes=16 * 1024,
|
||||
)
|
||||
upgrade_v3_id = upgrade_v3.get("transitionId")
|
||||
if (
|
||||
not isinstance(upgrade_v3_id, str)
|
||||
or not re.fullmatch(
|
||||
r"[A-Za-z0-9._-]{1,96}", upgrade_v3_id
|
||||
)
|
||||
or upgrade_v3
|
||||
!= expected_device_plane_edge_core_channel_upgrade_v3_descriptor(
|
||||
upgrade_v3_id
|
||||
)
|
||||
):
|
||||
die("installed Device Edge Core channel upgrade v3 descriptor drift detected")
|
||||
files = (*files, edge_override)
|
||||
overlay = DEVICE_PLANE_ROOT / DEVICE_PLANE_BACKHAUL_TARGET_COMPOSE_REL
|
||||
if overlay.exists() or overlay.is_symlink():
|
||||
@@ -19983,6 +20281,19 @@ def plan_artifact(artifact):
|
||||
f"{predecessor['artifactSha256']}"
|
||||
)
|
||||
print("device_edge_channel_endpoint_policy=public-ipv4-standard-https-tcp-443-only")
|
||||
if "coreNetworks" in edge_descriptor:
|
||||
print(
|
||||
"device_edge_channel_core_networks="
|
||||
f"{','.join(edge_descriptor['coreNetworks'])}"
|
||||
)
|
||||
print(
|
||||
"device_edge_channel_removed_core_network="
|
||||
f"{edge_descriptor['removedCoreNetwork']}"
|
||||
)
|
||||
print(
|
||||
"device_edge_channel_compose_compatibility="
|
||||
f"{edge_descriptor['composeCompatibility']}"
|
||||
)
|
||||
else:
|
||||
print(
|
||||
"device_plane_predecessor_patch="
|
||||
|
||||
Reference in New Issue
Block a user