fix(agent99): deploy backup freshness exporter atomically
This commit is contained in:
@@ -16,8 +16,9 @@ from pathlib import Path
|
||||
|
||||
|
||||
EXPECTED_DESTINATION = Path("/backup/scripts")
|
||||
EXPECTED_EXPORTER_DESTINATION = Path("/home/wooo/scripts/backup-health-textfile-exporter.py")
|
||||
RUNTIME_LOCK = Path("/tmp/agent99-host110-backup-runtime.lock")
|
||||
EXPECTED_FILES = (
|
||||
EXPECTED_BACKUP_FILES = (
|
||||
"common.sh",
|
||||
"backup-all.sh",
|
||||
"backup-host188-products.sh",
|
||||
@@ -36,6 +37,8 @@ EXPECTED_FILES = (
|
||||
"verify-offsite-full-sync.sh",
|
||||
"enforce-latest-only-retention.sh",
|
||||
)
|
||||
EXPORTER_FILE = "backup-health-textfile-exporter.py"
|
||||
EXPECTED_FILES = EXPECTED_BACKUP_FILES + (EXPORTER_FILE,)
|
||||
|
||||
|
||||
def fail(reason: str) -> None:
|
||||
@@ -78,6 +81,7 @@ def main() -> None:
|
||||
manifest_source.add_argument("--manifest")
|
||||
manifest_source.add_argument("--manifest-base64")
|
||||
parser.add_argument("--destination", required=True)
|
||||
parser.add_argument("--exporter-destination", required=True)
|
||||
parser.add_argument("--source-revision", required=True)
|
||||
parser.add_argument("--run-id", required=True)
|
||||
parser.add_argument("--expected-verifier-sha256", required=True)
|
||||
@@ -90,6 +94,9 @@ def main() -> None:
|
||||
destination = Path(args.destination)
|
||||
if destination != EXPECTED_DESTINATION or destination.is_symlink() or not destination.is_dir():
|
||||
fail("invalid_destination")
|
||||
exporter_destination = Path(args.exporter_destination)
|
||||
if exporter_destination != EXPECTED_EXPORTER_DESTINATION:
|
||||
fail("invalid_exporter_destination")
|
||||
runtime_lock = acquire_runtime_read_lock(destination)
|
||||
|
||||
if not re.fullmatch(r"[0-9a-f]{64}", args.expected_verifier_sha256):
|
||||
@@ -131,11 +138,14 @@ def main() -> None:
|
||||
|
||||
root = destination.resolve(strict=True)
|
||||
for name in EXPECTED_FILES:
|
||||
path = destination / name
|
||||
path = exporter_destination if name == EXPORTER_FILE else destination / name
|
||||
if path.is_symlink() or not path.is_file():
|
||||
fail("runtime_file_type_failed")
|
||||
resolved = path.resolve(strict=True)
|
||||
if resolved.parent != root:
|
||||
if name == EXPORTER_FILE:
|
||||
if resolved != exporter_destination:
|
||||
fail("runtime_file_boundary_failed")
|
||||
elif resolved.parent != root:
|
||||
fail("runtime_file_boundary_failed")
|
||||
stat = resolved.stat()
|
||||
if stat.st_uid != os.getuid() or stat.st_gid != os.getgid() or stat.st_mode & 0o777 != 0o755:
|
||||
@@ -149,7 +159,10 @@ def main() -> None:
|
||||
"sourceRevision": args.source_revision,
|
||||
"runId": args.run_id,
|
||||
"fileCount": len(EXPECTED_FILES),
|
||||
"backupScriptFileCount": len(EXPECTED_BACKUP_FILES),
|
||||
"backupHealthExporterIncluded": True,
|
||||
"destination": str(EXPECTED_DESTINATION),
|
||||
"exporterDestination": str(EXPECTED_EXPORTER_DESTINATION),
|
||||
"remoteWritePerformed": False,
|
||||
"secretValuesRead": False,
|
||||
"selfIdentityVerified": self_identity_verified,
|
||||
|
||||
Reference in New Issue
Block a user