feat(device-plane): accept core edge transport ADR
This commit is contained in:
@@ -132,6 +132,27 @@ DEVICE_PLANE_BACKHAUL_ENROLLMENT_DIR = DEVICE_PLANE_ROOT / "enrollment"
|
||||
DEVICE_PLANE_BACKHAUL_ENROLLMENT_PUBLIC_KEY_FILE = (
|
||||
DEVICE_PLANE_BACKHAUL_ENROLLMENT_DIR / "device-edge-backhaul.pub"
|
||||
)
|
||||
DEVICE_PLANE_BACKHAUL_VPS_ENROLLMENT_PUBLIC_KEY_FILE = (
|
||||
DEVICE_PLANE_BACKHAUL_ENROLLMENT_DIR / "device-edge-vps-backhaul.pub"
|
||||
)
|
||||
DEVICE_PLANE_BACKHAUL_VPS_ENROLLMENT_REL = (
|
||||
"deployment/device-plane-backhaul-vps-enrollment-v1.json"
|
||||
)
|
||||
DEVICE_PLANE_BACKHAUL_VPS_ENROLLMENT_ENTRIES = (
|
||||
DEVICE_PLANE_BACKHAUL_VPS_ENROLLMENT_REL,
|
||||
)
|
||||
DEVICE_PLANE_BACKHAUL_VPS_ENROLLMENT_PREDECESSOR_PATCH_ID = (
|
||||
"device-plane-backhaul-target-tailnet-serve-20260804-002"
|
||||
)
|
||||
DEVICE_PLANE_BACKHAUL_VPS_ENROLLMENT_PREDECESSOR_ARTIFACT_SHA256 = (
|
||||
"219408705dd4d80a962ed00eeb53a69df0b9ab6458443734d5c9cd1d1f795eba"
|
||||
)
|
||||
DEVICE_PLANE_BACKHAUL_VPS_ENROLLMENT_FINGERPRINT = (
|
||||
"SHA256:HHTiDYiCRxSiKjBLCip6JMSzGfLGrDz5g8SIkosJcVw"
|
||||
)
|
||||
DEVICE_PLANE_BACKHAUL_AUTHORIZED_KEYS_BACKUP = (
|
||||
"device-plane-backhaul-authorized-keys-before"
|
||||
)
|
||||
DEVICE_PLANE_BACKHAUL_SECRET_DIR = DEVICE_PLANE_SECRET_DIR / "backhaul-target"
|
||||
DEVICE_PLANE_BACKHAUL_HOST_KEY_FILE = (
|
||||
DEVICE_PLANE_BACKHAUL_SECRET_DIR / "ssh_host_ed25519_key"
|
||||
@@ -8053,6 +8074,12 @@ def load_artifact(artifact, work_dir):
|
||||
manifest = parse_manifest(manifest_path)
|
||||
entries = parse_files_list(files_path)
|
||||
|
||||
if is_device_plane_backhaul_vps_enrollment_slice(
|
||||
manifest["component"],
|
||||
entries,
|
||||
):
|
||||
die("vps_initiated_transport_frozen:ADR-0001")
|
||||
|
||||
for rel in entries:
|
||||
allowed_payload_path(manifest["component"], rel)
|
||||
if not (payload_dir / rel).exists():
|
||||
@@ -8093,6 +8120,11 @@ def load_artifact(artifact, work_dir):
|
||||
entries,
|
||||
):
|
||||
validate_device_plane_backhaul_target_payload(payload_dir)
|
||||
if is_device_plane_backhaul_vps_enrollment_slice(
|
||||
manifest["component"],
|
||||
entries,
|
||||
):
|
||||
validate_device_plane_backhaul_vps_enrollment_payload(payload_dir)
|
||||
if manifest["component"] == "n8n-private-extension":
|
||||
validate_n8n_private_extension_release(payload_dir, entries)
|
||||
if manifest["component"] == "engine":
|
||||
@@ -8470,6 +8502,63 @@ def is_device_plane_backhaul_target_slice(component, entries):
|
||||
)
|
||||
|
||||
|
||||
def is_device_plane_backhaul_vps_enrollment_slice(component, entries):
|
||||
return (
|
||||
component == "device-plane"
|
||||
and entries is not None
|
||||
and tuple(entries)
|
||||
== DEVICE_PLANE_BACKHAUL_VPS_ENROLLMENT_ENTRIES
|
||||
)
|
||||
|
||||
|
||||
def expected_device_plane_backhaul_vps_enrollment_descriptor():
|
||||
return {
|
||||
"schemaVersion": (
|
||||
"nodedc.device-plane.backhaul-vps-enrollment.v1"
|
||||
),
|
||||
"mode": "rotate-backhaul-client-mini-to-vps",
|
||||
"predecessorPatchId": (
|
||||
DEVICE_PLANE_BACKHAUL_VPS_ENROLLMENT_PREDECESSOR_PATCH_ID
|
||||
),
|
||||
"predecessorArtifactSha256": (
|
||||
DEVICE_PLANE_BACKHAUL_VPS_ENROLLMENT_PREDECESSOR_ARTIFACT_SHA256
|
||||
),
|
||||
"sourceAction": "publish-vps-enrollment-marker-only",
|
||||
"runtimeAction": (
|
||||
"rotate-authorized-key-and-recreate-backhaul-target"
|
||||
),
|
||||
"selectedServices": [DEVICE_PLANE_BACKHAUL_TARGET_SERVICE],
|
||||
"preservedServices": list(DEVICE_PLANE_RUNTIME_SERVICES),
|
||||
"previousEnrollment": "device-edge-backhaul.pub",
|
||||
"nextEnrollment": "device-edge-vps-backhaul.pub",
|
||||
"nextKeyFingerprint": (
|
||||
DEVICE_PLANE_BACKHAUL_VPS_ENROLLMENT_FINGERPRINT
|
||||
),
|
||||
"permittedTarget": DEVICE_PLANE_BACKHAUL_PERMITTED_TARGET,
|
||||
"tailnetAddress": DEVICE_PLANE_BACKHAUL_TAILNET_ADDRESS,
|
||||
"dockerPortPublication": "disabled",
|
||||
"routerNatFirewall": "unchanged",
|
||||
"edgePublicIngress": "disabled",
|
||||
"funnel": "disabled",
|
||||
"commandTransport": "disabled",
|
||||
"gelios": "untouched",
|
||||
"rollback": (
|
||||
"restore-previous-authorized-key-and-recreate-target"
|
||||
),
|
||||
}
|
||||
|
||||
|
||||
def validate_device_plane_backhaul_vps_enrollment_payload(payload_dir):
|
||||
descriptor = read_strict_json(
|
||||
payload_dir / DEVICE_PLANE_BACKHAUL_VPS_ENROLLMENT_REL,
|
||||
"Device Plane VPS backhaul enrollment descriptor",
|
||||
max_bytes=16 * 1024,
|
||||
)
|
||||
if descriptor != expected_device_plane_backhaul_vps_enrollment_descriptor():
|
||||
die("Device Plane VPS backhaul enrollment descriptor mismatch")
|
||||
return descriptor
|
||||
|
||||
|
||||
def expected_device_plane_backhaul_target_descriptor():
|
||||
return {
|
||||
"schemaVersion": (
|
||||
@@ -8534,14 +8623,13 @@ def validate_device_plane_backhaul_target_payload(payload_dir):
|
||||
return descriptor
|
||||
|
||||
|
||||
def read_device_plane_backhaul_enrollment_public_key():
|
||||
path = DEVICE_PLANE_BACKHAUL_ENROLLMENT_PUBLIC_KEY_FILE
|
||||
def read_device_plane_ed25519_enrollment_public_key(path, comment, label):
|
||||
try:
|
||||
path_stat = path.lstat()
|
||||
text = path.read_text(encoding="ascii")
|
||||
except (FileNotFoundError, OSError, UnicodeDecodeError):
|
||||
die(
|
||||
"Device Plane Edge enrollment public key is missing or unreadable: "
|
||||
f"{label} is missing or unreadable: "
|
||||
f"{path}"
|
||||
)
|
||||
if (
|
||||
@@ -8549,28 +8637,56 @@ def read_device_plane_backhaul_enrollment_public_key():
|
||||
or not stat.S_ISREG(path_stat.st_mode)
|
||||
or path_stat.st_size > 1024
|
||||
):
|
||||
die("Device Plane Edge enrollment public key is unsafe")
|
||||
die(f"{label} is unsafe")
|
||||
if text != text.strip() + "\n" or "\n" in text.strip():
|
||||
die("Device Plane Edge enrollment public key must be one line")
|
||||
die(f"{label} must be one line")
|
||||
parts = text.strip().split()
|
||||
if len(parts) not in (2, 3) or parts[0] != "ssh-ed25519":
|
||||
die("Device Plane Edge enrollment public key type mismatch")
|
||||
die(f"{label} type mismatch")
|
||||
try:
|
||||
blob = base64.b64decode(parts[1], validate=True)
|
||||
except Exception:
|
||||
die("Device Plane Edge enrollment public key encoding mismatch")
|
||||
die(f"{label} encoding mismatch")
|
||||
expected_prefix = b"\x00\x00\x00\x0bssh-ed25519\x00\x00\x00\x20"
|
||||
if len(blob) != len(expected_prefix) + 32 or not blob.startswith(
|
||||
expected_prefix
|
||||
):
|
||||
die("Device Plane Edge enrollment public key shape mismatch")
|
||||
normalized = f"ssh-ed25519 {parts[1]} nodedc-device-edge-backhaul"
|
||||
die(f"{label} shape mismatch")
|
||||
normalized = f"ssh-ed25519 {parts[1]} {comment}"
|
||||
return {
|
||||
"line": normalized,
|
||||
"sha256": hashlib.sha256((normalized + "\n").encode("ascii")).hexdigest(),
|
||||
"fingerprint": (
|
||||
"SHA256:"
|
||||
+ base64.b64encode(hashlib.sha256(blob).digest())
|
||||
.decode("ascii")
|
||||
.rstrip("=")
|
||||
),
|
||||
}
|
||||
|
||||
|
||||
def read_device_plane_backhaul_enrollment_public_key():
|
||||
return read_device_plane_ed25519_enrollment_public_key(
|
||||
DEVICE_PLANE_BACKHAUL_ENROLLMENT_PUBLIC_KEY_FILE,
|
||||
"nodedc-device-edge-backhaul",
|
||||
"Device Plane Edge enrollment public key",
|
||||
)
|
||||
|
||||
|
||||
def read_device_plane_backhaul_vps_enrollment_public_key():
|
||||
enrollment = read_device_plane_ed25519_enrollment_public_key(
|
||||
DEVICE_PLANE_BACKHAUL_VPS_ENROLLMENT_PUBLIC_KEY_FILE,
|
||||
"nodedc-device-edge-vps-backhaul",
|
||||
"Device Plane VPS Edge enrollment public key",
|
||||
)
|
||||
if (
|
||||
enrollment["fingerprint"]
|
||||
!= DEVICE_PLANE_BACKHAUL_VPS_ENROLLMENT_FINGERPRINT
|
||||
):
|
||||
die("Device Plane VPS Edge enrollment fingerprint mismatch")
|
||||
return enrollment
|
||||
|
||||
|
||||
def device_plane_tailscale_drop_privileges(uid, gid):
|
||||
def demote():
|
||||
os.setgroups([])
|
||||
@@ -9136,6 +9252,37 @@ def validate_device_plane_backhaul_target_evidence(payload_dir):
|
||||
}
|
||||
|
||||
|
||||
def validate_device_plane_backhaul_vps_enrollment_evidence(payload_dir):
|
||||
descriptor = validate_device_plane_backhaul_vps_enrollment_payload(
|
||||
payload_dir
|
||||
)
|
||||
if not state_has_patch_id(
|
||||
DEVICE_PLANE_BACKHAUL_VPS_ENROLLMENT_PREDECESSOR_PATCH_ID
|
||||
):
|
||||
die("Device Plane VPS enrollment predecessor patch is not applied")
|
||||
if not state_has_sha(
|
||||
DEVICE_PLANE_BACKHAUL_VPS_ENROLLMENT_PREDECESSOR_ARTIFACT_SHA256
|
||||
):
|
||||
die("Device Plane VPS enrollment predecessor artifact is not applied")
|
||||
root = component_root("device-plane")
|
||||
marker = root / DEVICE_PLANE_BACKHAUL_VPS_ENROLLMENT_REL
|
||||
if marker.exists() or marker.is_symlink():
|
||||
die("Device Plane VPS enrollment marker already exists")
|
||||
runtime = device_plane_runtime_inventory(DEVICE_PLANE_RUNTIME_SERVICES)
|
||||
validate_device_plane_backhaul_target_runtime(runtime)
|
||||
previous = read_device_plane_backhaul_enrollment_public_key()
|
||||
next_enrollment = read_device_plane_backhaul_vps_enrollment_public_key()
|
||||
if previous["line"] == next_enrollment["line"]:
|
||||
die("Device Plane VPS enrollment key is not a new identity")
|
||||
return {
|
||||
"mode": descriptor["mode"],
|
||||
"runtime": runtime,
|
||||
"previousEnrollmentPublicKeySha256": previous["sha256"],
|
||||
"nextEnrollmentPublicKeySha256": next_enrollment["sha256"],
|
||||
"nextKeyFingerprint": next_enrollment["fingerprint"],
|
||||
}
|
||||
|
||||
|
||||
def expected_device_plane_foundation_recovery_descriptor():
|
||||
return {
|
||||
"schemaVersion": "nodedc.device-plane.foundation-recovery.v1",
|
||||
@@ -10713,7 +10860,10 @@ def validate_device_plane_preserved_runtime_unchanged(runtime_before, label):
|
||||
return current
|
||||
|
||||
|
||||
def validate_device_plane_backhaul_target_runtime(runtime_before):
|
||||
def validate_device_plane_backhaul_target_runtime(
|
||||
runtime_before,
|
||||
expected_enrollment=None,
|
||||
):
|
||||
current = validate_device_plane_preserved_runtime_unchanged(
|
||||
runtime_before,
|
||||
"Device Plane backhaul",
|
||||
@@ -10840,7 +10990,11 @@ def validate_device_plane_backhaul_target_runtime(runtime_before):
|
||||
f"{required}"
|
||||
)
|
||||
|
||||
enrollment = read_device_plane_backhaul_enrollment_public_key()
|
||||
enrollment = (
|
||||
expected_enrollment
|
||||
if expected_enrollment is not None
|
||||
else read_device_plane_backhaul_enrollment_public_key()
|
||||
)
|
||||
authorized = (
|
||||
'restrict,port-forwarding,permitopen="127.0.0.1:9921" '
|
||||
f"{enrollment['line']}\n"
|
||||
@@ -12557,6 +12711,9 @@ def is_platform_provider_catalog_only(entries):
|
||||
|
||||
|
||||
def component_services(component, entries=None):
|
||||
if is_device_plane_backhaul_vps_enrollment_slice(component, entries):
|
||||
return (DEVICE_PLANE_BACKHAUL_TARGET_SERVICE,)
|
||||
|
||||
if is_device_plane_backhaul_target_slice(component, entries):
|
||||
return (DEVICE_PLANE_BACKHAUL_TARGET_SERVICE,)
|
||||
|
||||
@@ -12931,6 +13088,9 @@ def component_build_args(component, entries=None):
|
||||
|
||||
|
||||
def component_builds(component, entries=None):
|
||||
if is_device_plane_backhaul_vps_enrollment_slice(component, entries):
|
||||
return ()
|
||||
|
||||
if is_device_plane_backhaul_target_slice(component, entries):
|
||||
return ((
|
||||
DEVICE_PLANE_ROOT,
|
||||
@@ -14940,6 +15100,7 @@ def plan_artifact(artifact):
|
||||
device_plane_b2_ingress_preflight = None
|
||||
device_plane_b2_recovery_preflight = None
|
||||
device_plane_backhaul_preflight = None
|
||||
device_plane_backhaul_vps_enrollment_preflight = None
|
||||
device_plane_runtime_before = None
|
||||
composite_provider_v4_preflight = None
|
||||
provider_rotating_slot_preflight = None
|
||||
@@ -15149,6 +15310,15 @@ def plan_artifact(artifact):
|
||||
device_plane_backhaul_preflight = (
|
||||
validate_device_plane_backhaul_target_evidence(payload_dir)
|
||||
)
|
||||
if is_device_plane_backhaul_vps_enrollment_slice(
|
||||
manifest["component"],
|
||||
entries,
|
||||
):
|
||||
device_plane_backhaul_vps_enrollment_preflight = (
|
||||
validate_device_plane_backhaul_vps_enrollment_evidence(
|
||||
payload_dir
|
||||
)
|
||||
)
|
||||
|
||||
component = manifest["component"]
|
||||
root = component_root(component)
|
||||
@@ -16677,6 +16847,55 @@ def plan_artifact(artifact):
|
||||
)
|
||||
print("device_gateway_tcp_9921=disabled:unpublished")
|
||||
print("device_plane_rollback=marker-only-runtime-unchanged")
|
||||
if device_plane_backhaul_vps_enrollment_preflight is not None:
|
||||
print(
|
||||
"device_plane_transition="
|
||||
f"{device_plane_backhaul_vps_enrollment_preflight['mode']}"
|
||||
)
|
||||
print(
|
||||
"device_plane_predecessor_patch="
|
||||
f"{DEVICE_PLANE_BACKHAUL_VPS_ENROLLMENT_PREDECESSOR_PATCH_ID}"
|
||||
)
|
||||
print(
|
||||
"device_plane_predecessor_artifact_sha256="
|
||||
f"{DEVICE_PLANE_BACKHAUL_VPS_ENROLLMENT_PREDECESSOR_ARTIFACT_SHA256}"
|
||||
)
|
||||
print("device_plane_build=none")
|
||||
print(
|
||||
"device_plane_runtime_mutation="
|
||||
"rotate-authorized-key+recreate:device-backhaul-target"
|
||||
)
|
||||
print(
|
||||
"device_plane_runtime_services="
|
||||
"preserved:device-control-core,device-gateway,device-postgres"
|
||||
)
|
||||
print(
|
||||
"device_backhaul_previous_enrollment_public_key_sha256="
|
||||
f"{device_plane_backhaul_vps_enrollment_preflight['previousEnrollmentPublicKeySha256']}"
|
||||
)
|
||||
print(
|
||||
"device_backhaul_next_enrollment_public_key_sha256="
|
||||
f"{device_plane_backhaul_vps_enrollment_preflight['nextEnrollmentPublicKeySha256']}"
|
||||
)
|
||||
print(
|
||||
"device_backhaul_next_key_fingerprint="
|
||||
f"{device_plane_backhaul_vps_enrollment_preflight['nextKeyFingerprint']}"
|
||||
)
|
||||
print(
|
||||
"device_backhaul_permitopen="
|
||||
f"{DEVICE_PLANE_BACKHAUL_PERMITTED_TARGET}"
|
||||
)
|
||||
print("device_backhaul_docker_port_publication=disabled")
|
||||
print("device_backhaul_tailscale_serve=unchanged")
|
||||
print("device_backhaul_tailscale_funnel=disabled")
|
||||
print("device_backhaul_router_nat_firewall=unchanged")
|
||||
print("device_edge_public_ingress=disabled")
|
||||
print("device_command_transport=disabled")
|
||||
print("gelios=untouched")
|
||||
print(
|
||||
"device_plane_rollback="
|
||||
"restore-previous-authorized-key+recreate-target"
|
||||
)
|
||||
if device_plane_backhaul_preflight is not None:
|
||||
print(
|
||||
"device_plane_transition="
|
||||
@@ -16849,6 +17068,25 @@ def create_backup(root, backup_dir, entries, include_nginx_html):
|
||||
(backup_dir / "missing-files.txt").write_text("\n".join(missing) + ("\n" if missing else ""), encoding="utf-8")
|
||||
|
||||
|
||||
def backup_device_plane_backhaul_authorized_keys(backup_dir):
|
||||
source_stat = DEVICE_PLANE_BACKHAUL_AUTHORIZED_KEYS_FILE.lstat()
|
||||
if (
|
||||
stat.S_ISLNK(source_stat.st_mode)
|
||||
or not stat.S_ISREG(source_stat.st_mode)
|
||||
or source_stat.st_uid != 0
|
||||
or stat.S_IMODE(source_stat.st_mode) != 0o444
|
||||
or source_stat.st_size > 2048
|
||||
):
|
||||
die("Device Plane backhaul authorized_keys backup source is unsafe")
|
||||
destination = backup_dir / DEVICE_PLANE_BACKHAUL_AUTHORIZED_KEYS_BACKUP
|
||||
if destination.exists() or destination.is_symlink():
|
||||
die("Device Plane backhaul authorized_keys backup collision")
|
||||
shutil.copy2(DEVICE_PLANE_BACKHAUL_AUTHORIZED_KEYS_FILE, destination)
|
||||
os.chown(destination, 0, 0)
|
||||
destination.chmod(0o600)
|
||||
return sha256_file(destination)
|
||||
|
||||
|
||||
def read_backup_path_list(path):
|
||||
if not path.is_file():
|
||||
die(f"deploy backup path list missing: {path}")
|
||||
@@ -17216,6 +17454,53 @@ def rollback_device_plane_apply(
|
||||
return f"source+runtime-restored:{restored_count}"
|
||||
|
||||
|
||||
def rollback_device_plane_backhaul_vps_enrollment(
|
||||
root,
|
||||
backup_dir,
|
||||
entries,
|
||||
current_stamp,
|
||||
runtime_before,
|
||||
):
|
||||
restored_count = restore_platform_overlay(
|
||||
root,
|
||||
backup_dir,
|
||||
entries,
|
||||
current_stamp,
|
||||
)
|
||||
backup = backup_dir / DEVICE_PLANE_BACKHAUL_AUTHORIZED_KEYS_BACKUP
|
||||
backup_stat = backup.lstat()
|
||||
previous = read_device_plane_backhaul_enrollment_public_key()
|
||||
expected = (
|
||||
'restrict,port-forwarding,permitopen="127.0.0.1:9921" '
|
||||
f"{previous['line']}\n"
|
||||
)
|
||||
if (
|
||||
stat.S_ISLNK(backup_stat.st_mode)
|
||||
or not stat.S_ISREG(backup_stat.st_mode)
|
||||
or backup_stat.st_uid != 0
|
||||
or stat.S_IMODE(backup_stat.st_mode) != 0o600
|
||||
or backup_stat.st_size > 2048
|
||||
or backup.read_text(encoding="ascii") != expected
|
||||
):
|
||||
die("Device Plane VPS enrollment rollback backup mismatch")
|
||||
install_device_plane_backhaul_authorized_key(previous)
|
||||
run_compose(
|
||||
"device-plane",
|
||||
(DEVICE_PLANE_BACKHAUL_TARGET_SERVICE,),
|
||||
entries,
|
||||
)
|
||||
run_healthchecks(
|
||||
"device-plane",
|
||||
entries,
|
||||
(DEVICE_PLANE_BACKHAUL_TARGET_SERVICE,),
|
||||
)
|
||||
validate_device_plane_backhaul_target_runtime(
|
||||
runtime_before,
|
||||
expected_enrollment=previous,
|
||||
)
|
||||
return f"previous-key+target+source-restored:{restored_count}"
|
||||
|
||||
|
||||
def rollback_engine_apply(root, backup_dir, entries, current_stamp, runtime_started, applied_services):
|
||||
existing = read_backup_path_list(backup_dir / "existing-files.txt")
|
||||
missing = read_backup_path_list(backup_dir / "missing-files.txt")
|
||||
@@ -17764,6 +18049,32 @@ def run_engine_node_intelligence_compose(services, entries):
|
||||
)
|
||||
|
||||
|
||||
def install_device_plane_backhaul_authorized_key(enrollment):
|
||||
DEVICE_PLANE_BACKHAUL_SECRET_DIR.mkdir(
|
||||
parents=True,
|
||||
exist_ok=True,
|
||||
)
|
||||
os.chown(DEVICE_PLANE_BACKHAUL_SECRET_DIR, 0, 0)
|
||||
DEVICE_PLANE_BACKHAUL_SECRET_DIR.chmod(0o700)
|
||||
authorized = (
|
||||
'restrict,port-forwarding,permitopen="127.0.0.1:9921" '
|
||||
f"{enrollment['line']}\n"
|
||||
)
|
||||
temporary = DEVICE_PLANE_BACKHAUL_AUTHORIZED_KEYS_FILE.with_suffix(
|
||||
".installing"
|
||||
)
|
||||
if temporary.exists() or temporary.is_symlink():
|
||||
die("Device Plane backhaul authorized_keys staging path exists")
|
||||
temporary.write_text(authorized, encoding="ascii")
|
||||
os.chown(temporary, 0, 0)
|
||||
temporary.chmod(0o444)
|
||||
os.replace(temporary, DEVICE_PLANE_BACKHAUL_AUTHORIZED_KEYS_FILE)
|
||||
expected_sha256 = hashlib.sha256(authorized.encode("ascii")).hexdigest()
|
||||
if sha256_file(DEVICE_PLANE_BACKHAUL_AUTHORIZED_KEYS_FILE) != expected_sha256:
|
||||
die("Device Plane backhaul authorized key verification failed")
|
||||
return expected_sha256
|
||||
|
||||
|
||||
def ensure_device_plane_backhaul_target_state():
|
||||
enrollment = read_device_plane_backhaul_enrollment_public_key()
|
||||
DEVICE_PLANE_BACKHAUL_SECRET_DIR.mkdir(
|
||||
@@ -17818,19 +18129,9 @@ def ensure_device_plane_backhaul_target_state():
|
||||
os.chown(path, 0, 0)
|
||||
path.chmod(expected_mode)
|
||||
|
||||
authorized = (
|
||||
'restrict,port-forwarding,permitopen="127.0.0.1:9921" '
|
||||
f"{enrollment['line']}\n"
|
||||
expected_authorized_sha256 = install_device_plane_backhaul_authorized_key(
|
||||
enrollment
|
||||
)
|
||||
temporary = DEVICE_PLANE_BACKHAUL_AUTHORIZED_KEYS_FILE.with_suffix(
|
||||
".installing"
|
||||
)
|
||||
if temporary.exists() or temporary.is_symlink():
|
||||
die("Device Plane backhaul authorized_keys staging path exists")
|
||||
temporary.write_text(authorized, encoding="ascii")
|
||||
os.chown(temporary, 0, 0)
|
||||
temporary.chmod(0o444)
|
||||
os.replace(temporary, DEVICE_PLANE_BACKHAUL_AUTHORIZED_KEYS_FILE)
|
||||
|
||||
DEVICE_PLANE_BACKHAUL_TRUST_DIR.mkdir(parents=True, exist_ok=True)
|
||||
os.chown(DEVICE_PLANE_BACKHAUL_TRUST_DIR, 0, 0)
|
||||
@@ -17846,9 +18147,6 @@ def ensure_device_plane_backhaul_target_state():
|
||||
public_temporary.chmod(0o444)
|
||||
os.replace(public_temporary, DEVICE_PLANE_BACKHAUL_HOST_PUBLIC_KEY_FILE)
|
||||
|
||||
expected_authorized_sha256 = hashlib.sha256(
|
||||
authorized.encode("ascii")
|
||||
).hexdigest()
|
||||
if (
|
||||
sha256_file(DEVICE_PLANE_BACKHAUL_AUTHORIZED_KEYS_FILE)
|
||||
!= expected_authorized_sha256
|
||||
@@ -17929,6 +18227,14 @@ def prepare_component_runtime(component, entries=None):
|
||||
MAP_GATEWAY_SECRET_RE,
|
||||
"device plane identifier pepper",
|
||||
)
|
||||
if is_device_plane_backhaul_vps_enrollment_slice(
|
||||
component,
|
||||
entries,
|
||||
):
|
||||
install_device_plane_backhaul_authorized_key(
|
||||
read_device_plane_backhaul_vps_enrollment_public_key()
|
||||
)
|
||||
return
|
||||
if is_device_plane_backhaul_target_slice(component, entries):
|
||||
ensure_device_plane_backhaul_target_state()
|
||||
return
|
||||
@@ -18685,6 +18991,17 @@ process.stdout.write('engine-l2-closed-loop:0.7.0:cas+safe-profile+external-plan
|
||||
|
||||
|
||||
def run_healthchecks(component, entries=None, services=None):
|
||||
if is_device_plane_backhaul_vps_enrollment_slice(component, entries):
|
||||
if tuple(services or ()) != (DEVICE_PLANE_BACKHAUL_TARGET_SERVICE,):
|
||||
die("Device Plane VPS enrollment service set mismatch")
|
||||
for service in DEVICE_PLANE_RUNTIME_SERVICES:
|
||||
healthcheck_compose_service("device-plane", service)
|
||||
healthcheck_compose_service(
|
||||
"device-plane",
|
||||
DEVICE_PLANE_BACKHAUL_TARGET_SERVICE,
|
||||
)
|
||||
return
|
||||
|
||||
if is_device_plane_backhaul_target_slice(component, entries):
|
||||
if tuple(services or ()) != (DEVICE_PLANE_BACKHAUL_TARGET_SERVICE,):
|
||||
die("Device Plane backhaul target service set mismatch")
|
||||
@@ -19551,6 +19868,7 @@ def apply_artifact(artifact):
|
||||
node_intelligence_descriptor = None
|
||||
l2_closed_loop_preflight = None
|
||||
device_plane_backhaul_preflight = None
|
||||
device_plane_backhaul_vps_enrollment_preflight = None
|
||||
node_intelligence_service_stopped = False
|
||||
apply_started = False
|
||||
engine_backend_recreated = False
|
||||
@@ -19628,6 +19946,15 @@ def apply_artifact(artifact):
|
||||
payload_dir
|
||||
)
|
||||
)
|
||||
if is_device_plane_backhaul_vps_enrollment_slice(
|
||||
component,
|
||||
entries,
|
||||
):
|
||||
device_plane_backhaul_vps_enrollment_preflight = (
|
||||
validate_device_plane_backhaul_vps_enrollment_evidence(
|
||||
payload_dir
|
||||
)
|
||||
)
|
||||
if not root.is_dir():
|
||||
if bootstrap_root:
|
||||
root.mkdir(parents=True, exist_ok=True)
|
||||
@@ -19955,6 +20282,13 @@ def apply_artifact(artifact):
|
||||
encoding="utf-8",
|
||||
)
|
||||
runtime_inventory_path.chmod(0o600)
|
||||
if (
|
||||
device_plane_backhaul_vps_enrollment_preflight
|
||||
is not None
|
||||
):
|
||||
backup_device_plane_backhaul_authorized_keys(
|
||||
backup_dir
|
||||
)
|
||||
if device_plane_backhaul_preflight is not None:
|
||||
tailscale_before_path = (
|
||||
backup_dir / "tailscale-serve-before.json"
|
||||
@@ -20067,6 +20401,21 @@ def apply_artifact(artifact):
|
||||
validate_device_plane_backhaul_target_runtime(
|
||||
device_plane_runtime_before
|
||||
)
|
||||
if is_device_plane_backhaul_vps_enrollment_slice(
|
||||
component,
|
||||
entries,
|
||||
):
|
||||
if device_plane_runtime_before is None:
|
||||
die(
|
||||
"Device Plane VPS enrollment predecessor runtime "
|
||||
"inventory is missing"
|
||||
)
|
||||
validate_device_plane_backhaul_target_runtime(
|
||||
device_plane_runtime_before,
|
||||
expected_enrollment=(
|
||||
read_device_plane_backhaul_vps_enrollment_public_key()
|
||||
),
|
||||
)
|
||||
|
||||
applied_path = move_artifact(artifact, APPLIED_DIR)
|
||||
append_jsonl(STATE_FILE, {
|
||||
@@ -20305,6 +20654,41 @@ def apply_artifact(artifact):
|
||||
"automatic-rollback=failed",
|
||||
file=sys.stderr,
|
||||
)
|
||||
elif (
|
||||
is_device_plane_backhaul_vps_enrollment_slice(
|
||||
component,
|
||||
entries,
|
||||
)
|
||||
and device_plane_runtime_before is not None
|
||||
):
|
||||
try:
|
||||
restored_state = (
|
||||
rollback_device_plane_backhaul_vps_enrollment(
|
||||
root,
|
||||
backup_dir,
|
||||
entries,
|
||||
current_stamp,
|
||||
device_plane_runtime_before,
|
||||
)
|
||||
)
|
||||
rollback_status = (
|
||||
"ok:device-plane-vps-enrollment:"
|
||||
f"{restored_state}"
|
||||
)
|
||||
print(
|
||||
"device-plane-vps-enrollment-"
|
||||
f"automatic-rollback={rollback_status}",
|
||||
file=sys.stderr,
|
||||
)
|
||||
except Exception as rollback_exc:
|
||||
rollback_status = (
|
||||
f"failed:{type(rollback_exc).__name__}"
|
||||
)
|
||||
print(
|
||||
"device-plane-vps-enrollment-"
|
||||
"automatic-rollback=failed",
|
||||
file=sys.stderr,
|
||||
)
|
||||
elif (
|
||||
component == "device-plane"
|
||||
and entries is not None
|
||||
|
||||
Reference in New Issue
Block a user