fix(reboot): project vmx locator receipt readback
All checks were successful
CD Pipeline / workflow-shape (push) Successful in 0s
CD Pipeline / cancel-stale-cd (push) Has been skipped
CD Pipeline / tests (push) Successful in 3m47s
CD Pipeline / build-and-deploy (push) Successful in 4m48s
CD Pipeline / post-deploy-checks (push) Successful in 1m52s
All checks were successful
CD Pipeline / workflow-shape (push) Successful in 0s
CD Pipeline / cancel-stale-cd (push) Has been skipped
CD Pipeline / tests (push) Successful in 3m47s
CD Pipeline / build-and-deploy (push) Successful in 4m48s
CD Pipeline / post-deploy-checks (push) Successful in 1m52s
This commit is contained in:
@@ -3457,6 +3457,24 @@ def _enrich_from_current_readbacks(
|
||||
state["windows99_vmx_source_locator_expected_vmx_path_count"] = _int(
|
||||
windows99_vmx_source_locator_readback.get("expected_vmx_path_count")
|
||||
)
|
||||
state["windows99_vmx_source_locator_candidate_source_count"] = _int(
|
||||
windows99_vmx_source_locator_readback.get("candidate_source_count")
|
||||
)
|
||||
state["windows99_vmx_source_locator_alias_hint_candidate_count"] = _int(
|
||||
windows99_vmx_source_locator_readback.get("alias_hint_candidate_count")
|
||||
)
|
||||
state["windows99_vmx_source_locator_unassigned_ubuntu_candidate_count"] = _int(
|
||||
windows99_vmx_source_locator_readback.get("unassigned_ubuntu_candidate_count")
|
||||
)
|
||||
state["windows99_vmx_source_locator_identity_unassigned_ubuntu_candidate_count"] = _int(
|
||||
windows99_vmx_source_locator_readback.get(
|
||||
"identity_unassigned_ubuntu_candidate_count"
|
||||
)
|
||||
)
|
||||
state["windows99_vmx_source_locator_candidate_confirmation_required"] = bool(
|
||||
windows99_vmx_source_locator_readback.get("candidate_confirmation_required")
|
||||
is True
|
||||
)
|
||||
state["windows99_vmx_source_locator_candidate_source_count_known"] = bool(
|
||||
windows99_vmx_source_locator_readback.get("candidate_source_count_known")
|
||||
is True
|
||||
@@ -3856,6 +3874,23 @@ def _enrich_from_current_readbacks(
|
||||
evidence["windows99_vmx_source_locator_expected_vmx_path_count"] = state[
|
||||
"windows99_vmx_source_locator_expected_vmx_path_count"
|
||||
]
|
||||
evidence["windows99_vmx_source_locator_candidate_source_count"] = state[
|
||||
"windows99_vmx_source_locator_candidate_source_count"
|
||||
]
|
||||
evidence["windows99_vmx_source_locator_alias_hint_candidate_count"] = state[
|
||||
"windows99_vmx_source_locator_alias_hint_candidate_count"
|
||||
]
|
||||
evidence["windows99_vmx_source_locator_unassigned_ubuntu_candidate_count"] = state[
|
||||
"windows99_vmx_source_locator_unassigned_ubuntu_candidate_count"
|
||||
]
|
||||
evidence[
|
||||
"windows99_vmx_source_locator_identity_unassigned_ubuntu_candidate_count"
|
||||
] = state[
|
||||
"windows99_vmx_source_locator_identity_unassigned_ubuntu_candidate_count"
|
||||
]
|
||||
evidence["windows99_vmx_source_locator_candidate_confirmation_required"] = state[
|
||||
"windows99_vmx_source_locator_candidate_confirmation_required"
|
||||
]
|
||||
evidence["windows99_vmx_source_locator_candidate_source_count_known"] = state[
|
||||
"windows99_vmx_source_locator_candidate_source_count_known"
|
||||
]
|
||||
@@ -4630,6 +4665,24 @@ def _set_rollups_and_summary(
|
||||
"windows99_vmx_source_locator_expected_vmx_path_count": _int(
|
||||
state.get("windows99_vmx_source_locator_expected_vmx_path_count")
|
||||
),
|
||||
"windows99_vmx_source_locator_candidate_source_count": _int(
|
||||
state.get("windows99_vmx_source_locator_candidate_source_count")
|
||||
),
|
||||
"windows99_vmx_source_locator_alias_hint_candidate_count": _int(
|
||||
state.get("windows99_vmx_source_locator_alias_hint_candidate_count")
|
||||
),
|
||||
"windows99_vmx_source_locator_unassigned_ubuntu_candidate_count": _int(
|
||||
state.get("windows99_vmx_source_locator_unassigned_ubuntu_candidate_count")
|
||||
),
|
||||
"windows99_vmx_source_locator_identity_unassigned_ubuntu_candidate_count": _int(
|
||||
state.get(
|
||||
"windows99_vmx_source_locator_identity_unassigned_ubuntu_candidate_count"
|
||||
)
|
||||
),
|
||||
"windows99_vmx_source_locator_candidate_confirmation_required": (
|
||||
state.get("windows99_vmx_source_locator_candidate_confirmation_required")
|
||||
is True
|
||||
),
|
||||
"windows99_vmx_source_locator_candidate_source_count_known": (
|
||||
state.get("windows99_vmx_source_locator_candidate_source_count_known")
|
||||
is True
|
||||
@@ -4934,6 +4987,24 @@ def _set_rollups_and_summary(
|
||||
"windows99_vmx_source_locator_expected_vmx_path_count": _int(
|
||||
state.get("windows99_vmx_source_locator_expected_vmx_path_count")
|
||||
),
|
||||
"windows99_vmx_source_locator_candidate_source_count": _int(
|
||||
state.get("windows99_vmx_source_locator_candidate_source_count")
|
||||
),
|
||||
"windows99_vmx_source_locator_alias_hint_candidate_count": _int(
|
||||
state.get("windows99_vmx_source_locator_alias_hint_candidate_count")
|
||||
),
|
||||
"windows99_vmx_source_locator_unassigned_ubuntu_candidate_count": _int(
|
||||
state.get("windows99_vmx_source_locator_unassigned_ubuntu_candidate_count")
|
||||
),
|
||||
"windows99_vmx_source_locator_identity_unassigned_ubuntu_candidate_count": _int(
|
||||
state.get(
|
||||
"windows99_vmx_source_locator_identity_unassigned_ubuntu_candidate_count"
|
||||
)
|
||||
),
|
||||
"windows99_vmx_source_locator_candidate_confirmation_required": (
|
||||
state.get("windows99_vmx_source_locator_candidate_confirmation_required")
|
||||
is True
|
||||
),
|
||||
"windows99_vmx_source_locator_candidate_source_count_known": (
|
||||
state.get("windows99_vmx_source_locator_candidate_source_count_known")
|
||||
is True
|
||||
|
||||
@@ -8,19 +8,25 @@ start VMs, stop VMs, restart services, or reboot hosts.
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
from src.services.reboot_auto_recovery_slo_scorecard import (
|
||||
_taipei_now_iso,
|
||||
load_latest_reboot_auto_recovery_slo_scorecard,
|
||||
)
|
||||
from src.services.snapshot_paths import default_operations_dir
|
||||
from src.services.windows99_vmx_source_repair_package import (
|
||||
build_windows99_vmx_source_repair_package,
|
||||
)
|
||||
|
||||
_DEFAULT_OPERATIONS_DIR = default_operations_dir(Path(__file__))
|
||||
_SCHEMA_VERSION = "windows99_vmx_source_locator_readback_v1"
|
||||
_COLLECTOR_SCHEMA_VERSION = "windows99_vmx_source_locator_collector_v1"
|
||||
_LOCATOR_SCHEMA_VERSION = "windows99_vmx_source_locator_v1"
|
||||
_RECEIPT_SCHEMA_VERSION = "windows99_vmx_source_locator_receipt_v1"
|
||||
_RECEIPT_FILE = "windows99-vmx-source-locator-receipt.snapshot.json"
|
||||
_COLLECTOR_SCRIPT_PATH = "scripts/reboot-recovery/locate-windows99-vmx-source.sh"
|
||||
_LOCATOR_SCRIPT_PATH = "scripts/reboot-recovery/windows99-vmx-source-locator.ps1"
|
||||
|
||||
@@ -41,6 +47,33 @@ def _bool(value: Any) -> bool:
|
||||
return value is True
|
||||
|
||||
|
||||
def _int(value: Any, default: int | None = None) -> int | None:
|
||||
if isinstance(value, bool):
|
||||
return default
|
||||
if isinstance(value, int):
|
||||
return value
|
||||
if isinstance(value, str) and value.strip().isdigit():
|
||||
return int(value.strip())
|
||||
return default
|
||||
|
||||
|
||||
def _load_locator_receipt(operations_dir: Path | None = None) -> dict[str, Any]:
|
||||
path = (operations_dir or _DEFAULT_OPERATIONS_DIR) / _RECEIPT_FILE
|
||||
if not path.exists():
|
||||
return {}
|
||||
payload = json.loads(path.read_text(encoding="utf-8"))
|
||||
if not isinstance(payload, dict):
|
||||
raise ValueError(f"{path}: expected JSON object")
|
||||
if payload.get("schema_version") != _RECEIPT_SCHEMA_VERSION:
|
||||
raise ValueError(f"{path}: unexpected schema_version")
|
||||
serialized = json.dumps(payload, ensure_ascii=False)
|
||||
forbidden = ["192.168.0.", "D:\\", "C:\\", "E:\\", "uuid.", "generatedAddress"]
|
||||
leaked = [fragment for fragment in forbidden if fragment in serialized]
|
||||
if leaked:
|
||||
raise ValueError(f"{path}: unsafe locator receipt fragments: {leaked}")
|
||||
return payload
|
||||
|
||||
|
||||
def _vm_rows_for_aliases(
|
||||
repair_package: dict[str, Any],
|
||||
target_aliases: list[str],
|
||||
@@ -60,6 +93,8 @@ def build_windows99_vmx_source_locator_readback(
|
||||
scorecard: dict[str, Any],
|
||||
*,
|
||||
repair_package: dict[str, Any] | None = None,
|
||||
collector_receipt: dict[str, Any] | None = None,
|
||||
operations_dir: Path | None = None,
|
||||
generated_at: str | None = None,
|
||||
) -> dict[str, Any]:
|
||||
package = repair_package or build_windows99_vmx_source_repair_package(scorecard)
|
||||
@@ -111,6 +146,21 @@ def build_windows99_vmx_source_locator_readback(
|
||||
"--collect"
|
||||
)
|
||||
|
||||
receipt = collector_receipt if collector_receipt is not None else _load_locator_receipt(operations_dir)
|
||||
receipt = _dict(receipt)
|
||||
receipt_aliases = _strings(receipt.get("target_vm_aliases"))
|
||||
receipt_applies = bool(
|
||||
receipt.get("collector_readback_present") is True
|
||||
and receipt.get("target_host_alias") == "99"
|
||||
and receipt_aliases
|
||||
and set(receipt_aliases).issubset(set(target_aliases or receipt_aliases))
|
||||
)
|
||||
receipt_locate_status = str(receipt.get("locate_status") or "")
|
||||
if receipt_applies:
|
||||
status = "collector_readback_single_identity_candidate_confirmation_required"
|
||||
next_step = "confirm_single_unassigned_ubuntu_candidate_before_scoped_relink_dry_run"
|
||||
safe_next_step = str(receipt.get("safe_next_step") or safe_next_step)
|
||||
|
||||
return {
|
||||
"schema_version": _SCHEMA_VERSION,
|
||||
"generated_at": generated_at
|
||||
@@ -127,8 +177,14 @@ def build_windows99_vmx_source_locator_readback(
|
||||
"locator_script_path": _LOCATOR_SCRIPT_PATH,
|
||||
"collector_schema_version": _COLLECTOR_SCHEMA_VERSION,
|
||||
"locator_schema_version": _LOCATOR_SCHEMA_VERSION,
|
||||
"collector_readback_present": False,
|
||||
"collector_collection_status": "not_collected_by_api_readback",
|
||||
"collector_readback_present": receipt_applies,
|
||||
"collector_receipt_ref": str(receipt.get("receipt_ref") or "") if receipt_applies else "",
|
||||
"collector_receipt_generated_at": str(receipt.get("generated_at") or "") if receipt_applies else "",
|
||||
"collector_collection_status": (
|
||||
str(receipt.get("collector_collection_status") or "")
|
||||
if receipt_applies
|
||||
else "not_collected_by_api_readback"
|
||||
),
|
||||
"management_channel_ready": management_channel_ready,
|
||||
"can_collect_vmware_verify_without_secret": (
|
||||
can_collect_vmware_verify_without_secret
|
||||
@@ -143,15 +199,57 @@ def build_windows99_vmx_source_locator_readback(
|
||||
),
|
||||
"remote_locator_mode": "in_memory_stdin_scriptblock",
|
||||
"expected_vmx_path_count": expected_vmx_path_count,
|
||||
"expected_vmx_path_present_count": None,
|
||||
"candidate_source_count": None,
|
||||
"candidate_source_count_known": False,
|
||||
"candidate_source_fingerprint_count": None,
|
||||
"expected_vmx_path_present_count": (
|
||||
_int(receipt.get("expected_vmx_path_present_count"))
|
||||
if receipt_applies
|
||||
else None
|
||||
),
|
||||
"candidate_source_count": (
|
||||
_int(receipt.get("candidate_source_count")) if receipt_applies else None
|
||||
),
|
||||
"candidate_source_count_known": bool(receipt_applies),
|
||||
"candidate_source_fingerprint_count": (
|
||||
_int(receipt.get("candidate_source_fingerprint_count"), 0)
|
||||
if receipt_applies
|
||||
else None
|
||||
),
|
||||
"alias_hint_candidate_count": (
|
||||
_int(receipt.get("alias_hint_candidate_count"), 0)
|
||||
if receipt_applies
|
||||
else None
|
||||
),
|
||||
"unassigned_ubuntu_candidate_count": (
|
||||
_int(receipt.get("unassigned_ubuntu_candidate_count"), 0)
|
||||
if receipt_applies
|
||||
else None
|
||||
),
|
||||
"identity_metadata_read": bool(
|
||||
receipt_applies and receipt.get("identity_metadata_read") is True
|
||||
),
|
||||
"identity_target_hint_count": (
|
||||
_int(receipt.get("identity_target_hint_count"), 0)
|
||||
if receipt_applies
|
||||
else None
|
||||
),
|
||||
"identity_unassigned_ubuntu_candidate_count": (
|
||||
_int(receipt.get("identity_unassigned_ubuntu_candidate_count"), 0)
|
||||
if receipt_applies
|
||||
else None
|
||||
),
|
||||
"locate_status": receipt_locate_status if receipt_applies else "",
|
||||
"candidate_confirmation_required": bool(
|
||||
receipt_applies and "requires_confirmation" in receipt_locate_status
|
||||
),
|
||||
"public_lan_topology_redacted": True,
|
||||
"redacted_public_display_only": True,
|
||||
"raw_path_output": False,
|
||||
"path_fingerprint_only": True,
|
||||
"file_content_read": False,
|
||||
"file_content_read": bool(
|
||||
receipt_applies and receipt.get("identity_metadata_read") is True
|
||||
),
|
||||
"bounded_identity_metadata_only": bool(
|
||||
receipt_applies and receipt.get("bounded_identity_metadata_only") is True
|
||||
),
|
||||
"secret_value_read": False,
|
||||
"password_prompt_allowed": False,
|
||||
"remote_write_performed": False,
|
||||
@@ -165,7 +263,12 @@ def build_windows99_vmx_source_locator_readback(
|
||||
"operation_boundaries": {
|
||||
"secret_value_read": False,
|
||||
"password_prompt_allowed": False,
|
||||
"file_content_read": False,
|
||||
"file_content_read": bool(
|
||||
receipt_applies and receipt.get("identity_metadata_read") is True
|
||||
),
|
||||
"bounded_identity_metadata_only": bool(
|
||||
receipt_applies and receipt.get("bounded_identity_metadata_only") is True
|
||||
),
|
||||
"raw_path_output": False,
|
||||
"remote_write_performed": False,
|
||||
"host_reboot_performed": False,
|
||||
@@ -177,7 +280,12 @@ def build_windows99_vmx_source_locator_readback(
|
||||
"allowed": locator_check_mode_ready,
|
||||
"effective_collect_ready": effective_locator_collect_ready,
|
||||
"path_existence_only": True,
|
||||
"vmx_file_content_read": False,
|
||||
"vmx_file_content_read": bool(
|
||||
receipt_applies and receipt.get("identity_metadata_read") is True
|
||||
),
|
||||
"bounded_identity_metadata_only": bool(
|
||||
receipt_applies and receipt.get("bounded_identity_metadata_only") is True
|
||||
),
|
||||
"raw_path_output": False,
|
||||
"path_fingerprint_only": True,
|
||||
"collector_command": safe_next_step if locator_check_mode_ready else "",
|
||||
|
||||
Reference in New Issue
Block a user