fix(deploy): model replay 011 predecessor
This commit is contained in:
@@ -517,6 +517,28 @@ DEVICE_PLANE_CONTROL_CORE_FINAL_COMMAND_KINDS = (
|
|||||||
"infrastructure_service_instance.ensure",
|
"infrastructure_service_instance.ensure",
|
||||||
"health_observation.record",
|
"health_observation.record",
|
||||||
)
|
)
|
||||||
|
DEVICE_PLANE_CONTROL_CORE_REPLAY_011_COMMAND_KINDS = (
|
||||||
|
"owner_scope.ensure",
|
||||||
|
"project.ensure",
|
||||||
|
"collection.ensure",
|
||||||
|
"project_grant.upsert",
|
||||||
|
"adapter_package.ensure",
|
||||||
|
"adapter_version.register",
|
||||||
|
"model_profile.register",
|
||||||
|
"edge.ensure",
|
||||||
|
"route.ensure",
|
||||||
|
"enrollment_intent.ensure",
|
||||||
|
"device.claim",
|
||||||
|
"device.transfer",
|
||||||
|
"discovery.reject",
|
||||||
|
"discovery.expire",
|
||||||
|
"device_credential_binding.upsert",
|
||||||
|
"device_credential_binding.revoke",
|
||||||
|
"device_binding.ensure",
|
||||||
|
"device_binding.revoke",
|
||||||
|
"device_configuration_revision.create",
|
||||||
|
"device_configuration_desired.set",
|
||||||
|
)
|
||||||
DEVICE_PLANE_CONTROL_CORE_MIGRATION_014_TRIGGER_KINDS = (
|
DEVICE_PLANE_CONTROL_CORE_MIGRATION_014_TRIGGER_KINDS = (
|
||||||
"asset.ensure",
|
"asset.ensure",
|
||||||
"asset_binding.ensure",
|
"asset_binding.ensure",
|
||||||
@@ -16865,6 +16887,19 @@ def device_plane_control_core_migration_replay_database_invariants_match(
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def device_plane_control_core_migration_replay_predecessor_invariants_match(
|
||||||
|
evidence,
|
||||||
|
):
|
||||||
|
return (
|
||||||
|
evidence["invalidCommandKindCount"] == 0
|
||||||
|
and evidence["triggeringReceiptCount"] >= 1
|
||||||
|
and not evidence["constraintValidated"]
|
||||||
|
and not evidence["constraintCoversFinalKinds"]
|
||||||
|
and evidence["constraintMatchesReplay011Kinds"]
|
||||||
|
and evidence["hostTelemetryTableAbsent"]
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def emit_device_plane_control_core_migration_replay_database_evidence(
|
def emit_device_plane_control_core_migration_replay_database_evidence(
|
||||||
evidence,
|
evidence,
|
||||||
):
|
):
|
||||||
@@ -16891,15 +16926,26 @@ def emit_device_plane_control_core_migration_replay_database_evidence(
|
|||||||
"device_control_core_host_telemetry_table_absent="
|
"device_control_core_host_telemetry_table_absent="
|
||||||
f"{boolean(evidence['hostTelemetryTableAbsent'])}"
|
f"{boolean(evidence['hostTelemetryTableAbsent'])}"
|
||||||
)
|
)
|
||||||
|
print(
|
||||||
|
"device_control_core_constraint_matches_replay_011_kinds="
|
||||||
|
f"{boolean(evidence['constraintMatchesReplay011Kinds'])}"
|
||||||
|
)
|
||||||
print(
|
print(
|
||||||
"device_control_core_recovery_044_ready="
|
"device_control_core_recovery_044_ready="
|
||||||
f"{boolean(evidence['recovery044Ready'])}"
|
f"{boolean(evidence['recovery044Ready'])}"
|
||||||
)
|
)
|
||||||
|
print(
|
||||||
|
"device_control_core_recovery_final_state_ready="
|
||||||
|
f"{boolean(evidence['finalStateReady'])}"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def collect_device_plane_control_core_migration_replay_database_evidence(
|
def collect_device_plane_control_core_migration_replay_database_evidence(
|
||||||
enforce_recovery_invariants=True,
|
enforce_recovery_invariants=True,
|
||||||
|
expected_state="final",
|
||||||
):
|
):
|
||||||
|
if expected_state not in ("final", "replay-011-predecessor"):
|
||||||
|
die("Device Control Core migration recovery database state is invalid")
|
||||||
postgres_ids = device_plane_service_container_ids("device-postgres")
|
postgres_ids = device_plane_service_container_ids("device-postgres")
|
||||||
if len(postgres_ids) != 1:
|
if len(postgres_ids) != 1:
|
||||||
die("Device Control Core migration recovery PostgreSQL is missing")
|
die("Device Control Core migration recovery PostgreSQL is missing")
|
||||||
@@ -16911,14 +16957,32 @@ def collect_device_plane_control_core_migration_replay_database_evidence(
|
|||||||
"'" + value.replace("'", "''") + "'"
|
"'" + value.replace("'", "''") + "'"
|
||||||
for value in DEVICE_PLANE_CONTROL_CORE_MIGRATION_014_TRIGGER_KINDS
|
for value in DEVICE_PLANE_CONTROL_CORE_MIGRATION_014_TRIGGER_KINDS
|
||||||
)
|
)
|
||||||
|
replay_011 = ",".join(
|
||||||
|
"'" + value.replace("'", "''") + "'"
|
||||||
|
for value in DEVICE_PLANE_CONTROL_CORE_REPLAY_011_COMMAND_KINDS
|
||||||
|
)
|
||||||
query = f"""
|
query = f"""
|
||||||
with constraint_state as (
|
with constraint_state as (
|
||||||
select convalidated,
|
select convalidated,
|
||||||
|
pg_get_constraintdef(c.oid) as definition,
|
||||||
(select bool_and(pg_get_constraintdef(c.oid) like '%' || kind || '%')
|
(select bool_and(pg_get_constraintdef(c.oid) like '%' || kind || '%')
|
||||||
from unnest(array[{allowed}]::text[]) as kind) as covers_final
|
from unnest(array[{allowed}]::text[]) as kind) as covers_final
|
||||||
from pg_constraint c
|
from pg_constraint c
|
||||||
where c.conrelid = 'public.device_management_command_receipts'::regclass
|
where c.conrelid = 'public.device_management_command_receipts'::regclass
|
||||||
and c.conname = 'device_management_command_receipts_command_kind_check'
|
and c.conname = 'device_management_command_receipts_command_kind_check'
|
||||||
|
),
|
||||||
|
constraint_literals as (
|
||||||
|
select array_agg((matched.value)[1] order by (matched.value)[1]) as values
|
||||||
|
from constraint_state
|
||||||
|
cross join lateral regexp_matches(
|
||||||
|
constraint_state.definition,
|
||||||
|
'''([^'']+)''',
|
||||||
|
'g'
|
||||||
|
) as matched(value)
|
||||||
|
),
|
||||||
|
expected_replay_011 as (
|
||||||
|
select array_agg(kind order by kind) as values
|
||||||
|
from unnest(array[{replay_011}]::text[]) as expected(kind)
|
||||||
)
|
)
|
||||||
select (
|
select (
|
||||||
select count(*)
|
select count(*)
|
||||||
@@ -16933,7 +16997,12 @@ select (
|
|||||||
coalesce((select convalidated::text from constraint_state), 'missing'),
|
coalesce((select convalidated::text from constraint_state), 'missing'),
|
||||||
coalesce((select covers_final::text from constraint_state), 'false'),
|
coalesce((select covers_final::text from constraint_state), 'false'),
|
||||||
(to_regclass('public.device_infrastructure_host_telemetry_samples')
|
(to_regclass('public.device_infrastructure_host_telemetry_samples')
|
||||||
is null)::text
|
is null)::text,
|
||||||
|
coalesce((
|
||||||
|
select constraint_literals.values = expected_replay_011.values
|
||||||
|
from constraint_literals
|
||||||
|
cross join expected_replay_011
|
||||||
|
), false)::text
|
||||||
""".strip()
|
""".strip()
|
||||||
result = subprocess.run(
|
result = subprocess.run(
|
||||||
[
|
[
|
||||||
@@ -16963,12 +17032,13 @@ select (
|
|||||||
if (
|
if (
|
||||||
result.returncode != 0
|
result.returncode != 0
|
||||||
or result.stderr.strip()
|
or result.stderr.strip()
|
||||||
or len(values) != 5
|
or len(values) != 6
|
||||||
or not re.fullmatch(r"[0-9]+", values[0])
|
or not re.fullmatch(r"[0-9]+", values[0])
|
||||||
or not re.fullmatch(r"[0-9]+", values[1])
|
or not re.fullmatch(r"[0-9]+", values[1])
|
||||||
or values[2] not in ("true", "false", "missing")
|
or values[2] not in ("true", "false", "missing")
|
||||||
or values[3] not in ("true", "false")
|
or values[3] not in ("true", "false")
|
||||||
or values[4] not in ("true", "false")
|
or values[4] not in ("true", "false")
|
||||||
|
or values[5] not in ("true", "false")
|
||||||
):
|
):
|
||||||
die("Device Control Core migration recovery database read failed")
|
die("Device Control Core migration recovery database read failed")
|
||||||
evidence = {
|
evidence = {
|
||||||
@@ -16977,14 +17047,25 @@ select (
|
|||||||
"constraintValidated": values[2] == "true",
|
"constraintValidated": values[2] == "true",
|
||||||
"constraintCoversFinalKinds": values[3] == "true",
|
"constraintCoversFinalKinds": values[3] == "true",
|
||||||
"hostTelemetryTableAbsent": values[4] == "true",
|
"hostTelemetryTableAbsent": values[4] == "true",
|
||||||
|
"constraintMatchesReplay011Kinds": values[5] == "true",
|
||||||
"query": query,
|
"query": query,
|
||||||
}
|
}
|
||||||
evidence["recovery044Ready"] = (
|
evidence["finalStateReady"] = (
|
||||||
device_plane_control_core_migration_replay_database_invariants_match(
|
device_plane_control_core_migration_replay_database_invariants_match(
|
||||||
evidence
|
evidence
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
if enforce_recovery_invariants and not evidence["recovery044Ready"]:
|
evidence["recovery044Ready"] = (
|
||||||
|
device_plane_control_core_migration_replay_predecessor_invariants_match(
|
||||||
|
evidence
|
||||||
|
)
|
||||||
|
)
|
||||||
|
expected_ready = (
|
||||||
|
evidence["recovery044Ready"]
|
||||||
|
if expected_state == "replay-011-predecessor"
|
||||||
|
else evidence["finalStateReady"]
|
||||||
|
)
|
||||||
|
if enforce_recovery_invariants and not expected_ready:
|
||||||
emit_device_plane_control_core_migration_replay_database_evidence(
|
emit_device_plane_control_core_migration_replay_database_evidence(
|
||||||
evidence
|
evidence
|
||||||
)
|
)
|
||||||
@@ -17169,7 +17250,9 @@ def validate_device_plane_control_core_migration_replay_recovery_evidence(
|
|||||||
if image_id != DEVICE_PLANE_CONTROL_CORE_V3_PREAPPLY_IMAGE_ID:
|
if image_id != DEVICE_PLANE_CONTROL_CORE_V3_PREAPPLY_IMAGE_ID:
|
||||||
die("Device Control Core migration recovery predecessor image is missing")
|
die("Device Control Core migration recovery predecessor image is missing")
|
||||||
database = (
|
database = (
|
||||||
collect_device_plane_control_core_migration_replay_database_evidence()
|
collect_device_plane_control_core_migration_replay_database_evidence(
|
||||||
|
expected_state="replay-011-predecessor",
|
||||||
|
)
|
||||||
)
|
)
|
||||||
return {
|
return {
|
||||||
"mode": descriptor["mode"],
|
"mode": descriptor["mode"],
|
||||||
@@ -17222,7 +17305,9 @@ def accept_device_plane_control_core_migration_replay_recovery():
|
|||||||
):
|
):
|
||||||
die("Device Control Core migration recovery did not converge")
|
die("Device Control Core migration recovery did not converge")
|
||||||
database = (
|
database = (
|
||||||
collect_device_plane_control_core_migration_replay_database_evidence()
|
collect_device_plane_control_core_migration_replay_database_evidence(
|
||||||
|
expected_state="final",
|
||||||
|
)
|
||||||
)
|
)
|
||||||
validate_device_manager_control_plane_runtime(
|
validate_device_manager_control_plane_runtime(
|
||||||
require_edge_channel=True,
|
require_edge_channel=True,
|
||||||
@@ -32231,9 +32316,16 @@ def plan_artifact(artifact):
|
|||||||
f"{database['triggeringReceiptCount']}"
|
f"{database['triggeringReceiptCount']}"
|
||||||
)
|
)
|
||||||
print(
|
print(
|
||||||
"device_control_core_final_constraint="
|
"device_control_core_current_constraint="
|
||||||
|
"not-validated:exact-migration-011-command-kinds"
|
||||||
|
)
|
||||||
|
print(
|
||||||
|
"device_control_core_target_constraint="
|
||||||
"validated:covers-migration-016-command-kinds"
|
"validated:covers-migration-016-command-kinds"
|
||||||
)
|
)
|
||||||
|
emit_device_plane_control_core_migration_replay_database_evidence(
|
||||||
|
database
|
||||||
|
)
|
||||||
print("device_postgres_row_mutation=none")
|
print("device_postgres_row_mutation=none")
|
||||||
print("device_postgres_telemetry_table=absent")
|
print("device_postgres_telemetry_table=absent")
|
||||||
print(
|
print(
|
||||||
|
|||||||
Reference in New Issue
Block a user