feat: 自动物化 AgentRun managed repositories

This commit is contained in:
Codex
2026-07-11 23:32:41 +02:00
parent 0830857292
commit eaea6f4725
8 changed files with 1613 additions and 57 deletions
+110 -21
View File
@@ -15,7 +15,6 @@ import { runRemoteSshCommandCapture } from "../remote";
import { startJob } from "../jobs";
import {
AGENTRUN_CONFIG_PATH,
agentRunLaneSummary,
agentRunPipelineRunName,
agentRunProviderCredentialRefs,
resolveAgentRunLaneTarget,
@@ -32,11 +31,11 @@ import {
type AgentRunArtifactService,
} from "../agentrun-manifests";
import { sha256Fingerprint } from "../platform-infra-ops-library";
import { pacAutomaticDeliveryFix, pacReadOnlyNext, resolveCicdDeliveryAuthority } from "../cicd-delivery-authority";
import { pacAutomaticDeliveryFix, resolveCicdDeliveryAuthority } from "../cicd-delivery-authority";
import type { GitMirrorStatusOptions } from "./options";
import { readGitMirrorStatus } from "./rest-bridge";
import { compactCapture, shQuote } from "./utils";
import { compactCapture, record, shQuote } from "./utils";
export function cleanupRunnersFinalizeNodeScript(): string {
return String.raw`
@@ -484,19 +483,67 @@ export async function gitMirrorStatus(config: UniDeskConfig, options: GitMirrorS
});
const observation = await readGitMirrorStatus(config, target);
const summary = observation.summary;
const outputSummary = options.full || options.raw ? summary : compactManagedRepositoryStatus(summary);
const expanded = options.full || options.raw;
const compactTarget = {
node: spec.nodeId,
lane: spec.lane,
namespace: spec.gitMirror.namespace,
controller: spec.gitMirror.repositoryReconciler.deploymentName,
repositories: spec.gitMirror.repositories.map((repository) => ({ key: repository.key, sourceBranch: repository.sourceBranch })),
};
const fullTarget = {
...compactTarget,
version: spec.version,
sourceAuthority: spec.source.sourceAuthority,
gitMirror: {
readService: spec.gitMirror.readService,
readDeployment: spec.gitMirror.readDeployment,
writeService: spec.gitMirror.writeService,
writeDeployment: spec.gitMirror.writeDeployment,
resourceBundleBaseUrl: spec.gitMirror.resourceBundleBaseUrl,
cachePvc: spec.gitMirror.cachePvc,
cacheHostPath: spec.gitMirror.cacheHostPath,
sshSecretName: spec.gitMirror.sshSecretName,
githubProxy: spec.gitMirror.githubProxy,
repositoryReconciler: spec.gitMirror.repositoryReconciler,
repositories: spec.gitMirror.repositories.map((repository) => ({
key: repository.key,
repository: repository.repository,
sourceBranch: repository.sourceBranch,
gitopsBranch: repository.gitopsBranch ?? null,
remoteConfigured: true,
})),
},
};
const outputNext = deliveryAuthority.kind === "pac-pr-merge"
? {
status: `bun scripts/cli.ts platform-infra pipelines-as-code status --target ${deliveryAuthority.consumer.node} --consumer ${deliveryAuthority.consumer.consumerId}`,
history: `bun scripts/cli.ts platform-infra pipelines-as-code history --target ${deliveryAuthority.consumer.node} --consumer ${deliveryAuthority.consumer.consumerId}`,
valuesPrinted: false,
}
: deliveryAuthority.kind === "unknown"
? {
status: `bun scripts/cli.ts agentrun control-plane status --node ${spec.nodeId} --lane ${spec.lane}`,
...(expanded ? { fixAutomaticDelivery: pacAutomaticDeliveryFix(deliveryAuthority) } : {}),
valuesPrinted: false,
}
: {
sync: `bun scripts/cli.ts agentrun git-mirror sync --node ${spec.nodeId} --lane ${spec.lane} --confirm`,
flush: summary.pendingFlush === true ? `bun scripts/cli.ts agentrun git-mirror flush --node ${spec.nodeId} --lane ${spec.lane} --confirm` : null,
};
return {
ok: observation.ok,
command: "agentrun git-mirror status",
mode: "yaml-declared-node-lane",
configPath: target.configPath,
deliveryAuthority,
target: agentRunLaneSummary(spec),
deliveryAuthority: compactDeliveryAuthority(deliveryAuthority),
target: expanded ? fullTarget : compactTarget,
namespace: spec.gitMirror.namespace,
readUrl: spec.gitMirror.readUrl,
writeUrl: spec.gitMirror.writeUrl,
summary,
...(expanded ? { readUrl: spec.gitMirror.readUrl, writeUrl: spec.gitMirror.writeUrl } : {}),
summary: outputSummary,
...(options.raw ? { raw: observation.raw } : {}),
probe: compactCapture(observation.result, { full: options.full || options.raw, stdoutTailChars: 6000, stderrTailChars: 3000 }),
probe: compactCapture(observation.result, { full: options.raw, stdoutTailChars: 6000, stderrTailChars: 3000 }),
disclosure: {
defaultView: "compact-low-noise",
full: options.full,
@@ -506,17 +553,59 @@ export async function gitMirrorStatus(config: UniDeskConfig, options: GitMirrorS
expandWith: `bun scripts/cli.ts agentrun git-mirror status --node ${spec.nodeId} --lane ${spec.lane} --full`,
rawWith: `bun scripts/cli.ts agentrun git-mirror status --node ${spec.nodeId} --lane ${spec.lane} --raw`,
},
next: deliveryAuthority.kind === "pac-pr-merge"
? pacReadOnlyNext(deliveryAuthority.consumer.node, deliveryAuthority.consumer.consumerId)
: deliveryAuthority.kind === "unknown"
? {
status: `bun scripts/cli.ts agentrun control-plane status --node ${spec.nodeId} --lane ${spec.lane}`,
fixAutomaticDelivery: pacAutomaticDeliveryFix(deliveryAuthority),
valuesPrinted: false,
}
: {
sync: `bun scripts/cli.ts agentrun git-mirror sync --node ${spec.nodeId} --lane ${spec.lane} --confirm`,
flush: summary.pendingFlush === true ? `bun scripts/cli.ts agentrun git-mirror flush --node ${spec.nodeId} --lane ${spec.lane} --confirm` : null,
},
next: outputNext,
};
}
function compactDeliveryAuthority(authority: ReturnType<typeof resolveCicdDeliveryAuthority>): Record<string, unknown> {
return authority.kind === "pac-pr-merge"
? {
kind: authority.kind,
migrated: authority.migrated,
mutationHintsAllowed: authority.mutationHintsAllowed,
consumer: {
consumerId: authority.consumer.consumerId,
node: authority.consumer.node,
lane: authority.consumer.lane,
},
valuesPrinted: false,
}
: {
kind: authority.kind,
migrated: authority.migrated,
mutationHintsAllowed: authority.mutationHintsAllowed,
valuesPrinted: false,
};
}
function compactManagedRepositoryStatus(summary: Record<string, unknown>): Record<string, unknown> {
const controller = record(summary.controller);
const repositories = Array.isArray(summary.repositories)
? summary.repositories.map((value) => record(value)).map((repository) => ({
key: repository.key ?? null,
sourceBranch: repository.sourceBranch ?? null,
ref: shortCommit(repository.cacheCommit),
refPresent: repository.cacheRefPresent === true,
fresh: repository.fresh === true,
served: shortCommit(repository.servedCommit),
servedRefPresent: repository.servedRefPresent === true,
aligned: repository.refAligned === true && repository.remoteFingerprintAligned === true,
}))
: [];
return {
ok: summary.ok === true,
controller: {
deploymentReady: controller.deploymentReady === true,
desiredRendered: controller.configRendered === true && controller.workloadRendered === true,
statusAligned: controller.statusAligned === true,
heartbeatFresh: controller.heartbeatFresh === true,
},
repositories,
firstDrift: summary.firstDrift ?? null,
valuesPrinted: false,
};
}
function shortCommit(value: unknown): string | null {
return typeof value === "string" && /^[0-9a-f]{40}$/u.test(value) ? value.slice(0, 12) : null;
}
+196 -32
View File
@@ -34,6 +34,10 @@ import {
renderAgentRunGitopsFiles,
type AgentRunArtifactService,
} from "../agentrun-manifests";
import {
agentRunManagedRepositoryDesiredConfig,
agentRunManagedRepositoryRenderHash,
} from "../agentrun-managed-repository-reconciler";
import { sha256Fingerprint } from "../platform-infra-ops-library";
import { capture, captureJsonPayload, compactCapture, progressEvent, record, shQuote, sleep, stringOrNull } from "./utils";
@@ -629,6 +633,28 @@ export function yamlLaneGitMirrorFlushShell(spec: AgentRunLaneSpec): string {
}
export function yamlLaneGitMirrorStatusScript(spec: AgentRunLaneSpec): string {
const reconciler = spec.gitMirror.repositoryReconciler;
const desired = agentRunManagedRepositoryDesiredConfig(spec);
const expectedRepositories = desired.repositories.map((repository) => ({
key: repository.key,
repository: repository.repository,
sourceBranch: repository.sourceBranch,
desiredFingerprint: repository.desiredFingerprint,
remoteFingerprint: sha256Fingerprint(repository.remote),
}));
const repositoryReadProbes = expectedRepositories.flatMap((repository) => {
const url = `${spec.gitMirror.resourceBundleBaseUrl.replace(/\/+$/u, "")}/${repository.repository}.git`;
const ref = `refs/heads/${repository.sourceBranch}`;
const inner = [
"url=\"$1\"",
"ref=\"$2\"",
"commit=$(timeout 15 git ls-remote \"$url\" \"$ref\" 2>/dev/null | awk 'NR == 1 { print $1 }')",
"printf '%s\\t%s\\n' \"$3\" \"$commit\"",
].join("; ");
return [
`( timeout 20 kubectl -n "$namespace" exec deploy/"$controller_deployment" -- sh -lc ${shQuote(inner)} sh ${shQuote(url)} ${shQuote(ref)} ${shQuote(repository.key)} 2>/dev/null || printf '%s\\t\\n' ${shQuote(repository.key)} ) >${shQuote(`/tmp/agentrun-managed-repository-read-refs/${repository.key}.tsv`)} &`,
];
});
return [
"set +e",
`namespace=${shQuote(spec.gitMirror.namespace)}`,
@@ -637,52 +663,176 @@ export function yamlLaneGitMirrorStatusScript(spec: AgentRunLaneSpec): string {
`write_service=${shQuote(spec.gitMirror.writeService)}`,
`cache_pvc=${shQuote(spec.gitMirror.cachePvc)}`,
`cache_host_path=${spec.gitMirror.cacheHostPath === null ? "''" : shQuote(spec.gitMirror.cacheHostPath)}`,
`controller_deployment=${shQuote(reconciler.deploymentName)}`,
`controller_configmap=${shQuote(reconciler.configMapName)}`,
`expected_desired_hash=${shQuote(desired.desiredHash)}`,
`expected_render_hash=${shQuote(agentRunManagedRepositoryRenderHash(spec))}`,
`repositories_json=${shQuote(JSON.stringify(expectedRepositories))}`,
`repository=${shQuote(spec.source.repository)}`,
`source_branch=${shQuote(spec.source.branch)}`,
`gitops_branch=${shQuote(spec.gitops.branch)}`,
`repositories_json=${shQuote(JSON.stringify(spec.gitMirror.repositories))}`,
"kubectl -n \"$namespace\" get svc \"$read_service\" -o json >/tmp/agentrun-gitmirror-read.json 2>/dev/null",
"read_exit=$?",
"kubectl -n \"$namespace\" get svc \"$write_service\" -o json >/tmp/agentrun-gitmirror-write.json 2>/dev/null",
"write_exit=$?",
"kubectl -n \"$namespace\" get deploy \"$read_deployment\" -o json >/tmp/agentrun-gitmirror-read-deploy.json 2>/dev/null",
"read_deploy_exit=$?",
"kubectl -n \"$namespace\" get svc \"$read_service\" -o json >/tmp/agentrun-gitmirror-read-service.json 2>/dev/null",
"read_service_exit=$?",
"kubectl -n \"$namespace\" get endpoints \"$read_service\" -o json >/tmp/agentrun-gitmirror-read-endpoints.json 2>/dev/null",
"read_endpoints_exit=$?",
"kubectl -n \"$namespace\" get svc \"$write_service\" -o json >/tmp/agentrun-gitmirror-write-service.json 2>/dev/null",
"write_service_exit=$?",
"kubectl -n \"$namespace\" get endpoints \"$write_service\" -o json >/tmp/agentrun-gitmirror-write-endpoints.json 2>/dev/null",
"write_endpoints_exit=$?",
"kubectl -n \"$namespace\" get pvc \"$cache_pvc\" -o json >/tmp/agentrun-gitmirror-cache.json 2>/dev/null",
"cache_exit=$?",
"kubectl -n \"$namespace\" get deploy \"$controller_deployment\" -o json >/tmp/agentrun-managed-repository-controller.json 2>/dev/null",
"controller_deploy_exit=$?",
"kubectl -n \"$namespace\" get configmap \"$controller_configmap\" -o json >/tmp/agentrun-managed-repository-configmap.json 2>/dev/null",
"controller_configmap_exit=$?",
"cache_mode=pvc",
"if [ -n \"$cache_host_path\" ]; then cache_mode=hostPath; fi",
"kubectl -n \"$namespace\" get deploy,svc,pvc -o name > /tmp/agentrun-gitmirror-names.txt 2>/dev/null",
"repo_path=\"/cache/${repository}.git\"",
"rm -f /tmp/agentrun-gitmirror-refs.txt",
"if [ \"$read_exit\" -eq 0 ]; then",
" kubectl -n \"$namespace\" exec deploy/\"$read_deployment\" -- sh -lc 'repo_path=\"$1\"; source_branch=\"$2\"; gitops_branch=\"$3\"; source_commit=$(git --git-dir=\"$repo_path\" rev-parse --verify \"refs/heads/$source_branch^{commit}\" 2>/dev/null || true); gitops_commit=$(git --git-dir=\"$repo_path\" rev-parse --verify \"refs/heads/$gitops_branch^{commit}\" 2>/dev/null || true); printf \"sourceCommit=%s\\n\" \"$source_commit\"; printf \"gitopsCommit=%s\\n\" \"$gitops_commit\"' sh \"$repo_path\" \"$source_branch\" \"$gitops_branch\" > /tmp/agentrun-gitmirror-refs.txt 2>/dev/null",
"fi",
"NAMESPACE=\"$namespace\" READ_EXIT=\"$read_exit\" WRITE_EXIT=\"$write_exit\" CACHE_EXIT=\"$cache_exit\" CACHE_MODE=\"$cache_mode\" CACHE_HOST_PATH=\"$cache_host_path\" REPOSITORY=\"$repository\" SOURCE_BRANCH=\"$source_branch\" GITOPS_BRANCH=\"$gitops_branch\" REPOSITORIES_JSON=\"$repositories_json\" python3 - <<'PY'",
"import json, os, re",
"def read_text(path):",
"timeout 10 kubectl -n \"$namespace\" exec deploy/\"$controller_deployment\" -- node /etc/agentrun-managed-repository/controller.mjs --status --config /etc/agentrun-managed-repository/config.json >/tmp/agentrun-managed-repository-status.json 2>/dev/null",
"controller_status_exit=$?",
"rm -f /tmp/agentrun-gitmirror-legacy-refs.txt",
"timeout 10 kubectl -n \"$namespace\" exec deploy/\"$read_deployment\" -- sh -lc 'repo_path=\"$1\"; source_branch=\"$2\"; gitops_branch=\"$3\"; source_commit=$(git --git-dir=\"$repo_path\" rev-parse --verify \"refs/heads/$source_branch^{commit}\" 2>/dev/null || true); gitops_commit=$(git --git-dir=\"$repo_path\" rev-parse --verify \"refs/heads/$gitops_branch^{commit}\" 2>/dev/null || true); printf \"sourceCommit=%s\\n\" \"$source_commit\"; printf \"gitopsCommit=%s\\n\" \"$gitops_commit\"' sh \"/cache/${repository}.git\" \"$source_branch\" \"$gitops_branch\" >/tmp/agentrun-gitmirror-legacy-refs.txt 2>/dev/null",
"rm -rf /tmp/agentrun-managed-repository-read-refs",
"mkdir -p /tmp/agentrun-managed-repository-read-refs",
...repositoryReadProbes,
"wait",
"cat /tmp/agentrun-managed-repository-read-refs/*.tsv > /tmp/agentrun-managed-repository-read-refs.tsv 2>/dev/null || true",
"NAMESPACE=\"$namespace\" READ_DEPLOY_EXIT=\"$read_deploy_exit\" READ_SERVICE_EXIT=\"$read_service_exit\" READ_ENDPOINTS_EXIT=\"$read_endpoints_exit\" WRITE_SERVICE_EXIT=\"$write_service_exit\" WRITE_ENDPOINTS_EXIT=\"$write_endpoints_exit\" CACHE_EXIT=\"$cache_exit\" CONTROLLER_DEPLOY_EXIT=\"$controller_deploy_exit\" CONTROLLER_CONFIGMAP_EXIT=\"$controller_configmap_exit\" CONTROLLER_STATUS_EXIT=\"$controller_status_exit\" CACHE_MODE=\"$cache_mode\" CACHE_HOST_PATH=\"$cache_host_path\" EXPECTED_DESIRED_HASH=\"$expected_desired_hash\" EXPECTED_RENDER_HASH=\"$expected_render_hash\" REPOSITORIES_JSON=\"$repositories_json\" REPOSITORY=\"$repository\" SOURCE_BRANCH=\"$source_branch\" GITOPS_BRANCH=\"$gitops_branch\" python3 - <<'PY'",
"import json, os",
"def read_json(path):",
" try:",
" with open(path, 'r', encoding='utf-8') as fh:",
" return fh.read()",
" value = json.load(fh)",
" return value if isinstance(value, dict) else {}",
" except Exception:",
" return ''",
"def ref_value(text, key):",
" return {}",
"def exit_ok(name):",
" return os.environ.get(name) == '0'",
"def deployment_ready(value):",
" status = value.get('status') or {}",
" spec = value.get('spec') or {}",
" replicas = int(spec.get('replicas') or 0)",
" available = int(status.get('availableReplicas') or 0)",
" return replicas > 0 and available >= replicas and int(status.get('observedGeneration') or 0) >= int((value.get('metadata') or {}).get('generation') or 0)",
"def endpoint_ready(value):",
" for subset in value.get('subsets') or []:",
" if len(subset.get('addresses') or []) > 0:",
" return True",
" return False",
"def annotation(value, key):",
" return ((value.get('metadata') or {}).get('annotations') or {}).get(key)",
"def pod_annotation(value, key):",
" return (((((value.get('spec') or {}).get('template') or {}).get('metadata') or {}).get('annotations') or {}).get(key))",
"def read_refs(path):",
" result = {}",
" try:",
" with open(path, 'r', encoding='utf-8') as fh:",
" for line in fh:",
" parts = line.rstrip('\\n').split('\\t', 1)",
" if len(parts) == 2:",
" result[parts[0]] = parts[1] or None",
" except Exception:",
" pass",
" return result",
"def legacy_ref(path, key):",
" prefix = key + '='",
" for line in re.split(r'\\r?\\n', text):",
" if line.startswith(prefix):",
" value = line[len(prefix):].strip()",
" return value or None",
" try:",
" with open(path, 'r', encoding='utf-8') as fh:",
" for line in fh:",
" if line.startswith(prefix):",
" return line[len(prefix):].strip() or None",
" except Exception:",
" pass",
" return None",
"try:",
" repositories = json.loads(os.environ.get('REPOSITORIES_JSON') or '[]')",
"except Exception:",
" repositories = []",
"names = read_text('/tmp/agentrun-gitmirror-names.txt')",
"refs = read_text('/tmp/agentrun-gitmirror-refs.txt')",
"read_ready = os.environ.get('READ_EXIT') == '0'",
"write_ready = os.environ.get('WRITE_EXIT') == '0'",
"cache_pvc_exists = os.environ.get('CACHE_EXIT') == '0'",
"read_deploy = read_json('/tmp/agentrun-gitmirror-read-deploy.json')",
"read_endpoints = read_json('/tmp/agentrun-gitmirror-read-endpoints.json')",
"write_endpoints = read_json('/tmp/agentrun-gitmirror-write-endpoints.json')",
"cache = read_json('/tmp/agentrun-gitmirror-cache.json')",
"controller_deploy = read_json('/tmp/agentrun-managed-repository-controller.json')",
"controller_configmap = read_json('/tmp/agentrun-managed-repository-configmap.json')",
"controller_status = read_json('/tmp/agentrun-managed-repository-status.json')",
"served_refs = read_refs('/tmp/agentrun-managed-repository-read-refs.tsv')",
"expected_desired_hash = os.environ.get('EXPECTED_DESIRED_HASH')",
"expected_render_hash = os.environ.get('EXPECTED_RENDER_HASH')",
"read_ready = exit_ok('READ_DEPLOY_EXIT') and deployment_ready(read_deploy) and exit_ok('READ_SERVICE_EXIT') and exit_ok('READ_ENDPOINTS_EXIT') and endpoint_ready(read_endpoints)",
"write_ready = exit_ok('WRITE_SERVICE_EXIT') and exit_ok('WRITE_ENDPOINTS_EXIT') and endpoint_ready(write_endpoints)",
"cache_pvc_exists = exit_ok('CACHE_EXIT')",
"cache_mode = os.environ.get('CACHE_MODE') or 'pvc'",
"cache_ready = True if cache_mode == 'hostPath' else cache_pvc_exists",
"cache_ready = True if cache_mode == 'hostPath' else cache_pvc_exists and (cache.get('status') or {}).get('phase') == 'Bound'",
"controller_deployment_ready = exit_ok('CONTROLLER_DEPLOY_EXIT') and deployment_ready(controller_deploy)",
"controller_config_rendered = exit_ok('CONTROLLER_CONFIGMAP_EXIT') and annotation(controller_configmap, 'unidesk.ai/managed-repository-desired-sha') == expected_desired_hash and annotation(controller_configmap, 'unidesk.ai/managed-repository-render-sha') == expected_render_hash",
"controller_workload_rendered = annotation(controller_deploy, 'unidesk.ai/managed-repository-desired-sha') == expected_desired_hash and annotation(controller_deploy, 'unidesk.ai/managed-repository-render-sha') == expected_render_hash and pod_annotation(controller_deploy, 'unidesk.ai/managed-repository-desired-sha') == expected_desired_hash and pod_annotation(controller_deploy, 'unidesk.ai/managed-repository-render-sha') == expected_render_hash",
"controller_status_aligned = exit_ok('CONTROLLER_STATUS_EXIT') and controller_status.get('desiredHash') == expected_desired_hash",
"status_repositories = {item.get('desiredFingerprint'): item for item in controller_status.get('repositories') or [] if isinstance(item, dict)}",
"repository_status = []",
"for desired in repositories:",
" observed = status_repositories.get(desired.get('desiredFingerprint')) or {}",
" served_commit = served_refs.get(desired.get('key'))",
" cache_commit = observed.get('commit')",
" remote_fingerprint_aligned = observed.get('remoteFingerprint') == desired.get('remoteFingerprint')",
" cache_ref_present = observed.get('refPresent') is True and isinstance(cache_commit, str) and len(cache_commit) == 40",
" served_ref_present = isinstance(served_commit, str) and len(served_commit) == 40",
" repository_status.append({",
" 'key': desired.get('key'),",
" 'repository': desired.get('repository'),",
" 'sourceBranch': desired.get('sourceBranch'),",
" 'desiredFingerprint': desired.get('desiredFingerprint'),",
" 'remoteFingerprint': desired.get('remoteFingerprint'),",
" 'observedRemoteFingerprint': observed.get('remoteFingerprint'),",
" 'remoteFingerprintAligned': remote_fingerprint_aligned,",
" 'cacheRefPresent': cache_ref_present,",
" 'cacheCommit': cache_commit if cache_ref_present else None,",
" 'servedRefPresent': served_ref_present,",
" 'servedCommit': served_commit if served_ref_present else None,",
" 'refAligned': cache_ref_present and served_ref_present and cache_commit == served_commit,",
" 'fresh': observed.get('fresh') is True,",
" 'lastSuccessAt': observed.get('lastSuccessAt'),",
" 'lastSuccessAgeMs': observed.get('lastSuccessAgeMs'),",
" 'lastAttemptOk': observed.get('lastAttemptOk') is True,",
" 'errorCode': observed.get('errorCode'),",
" 'errorFingerprint': observed.get('errorFingerprint'),",
" })",
"first_drift = None",
"if not controller_config_rendered:",
" first_drift = 'rendered-desired-not-applied'",
"elif not controller_workload_rendered:",
" first_drift = 'controller-workload-render-mismatch'",
"elif not controller_deployment_ready:",
" first_drift = 'controller-not-ready'",
"elif not cache_ready:",
" first_drift = 'cache-not-ready'",
"elif not controller_status_aligned:",
" first_drift = 'controller-status-not-aligned'",
"elif not read_ready:",
" first_drift = 'read-service-not-ready'",
"elif not write_ready:",
" first_drift = 'write-service-not-ready'",
"else:",
" for item in repository_status:",
" if not item.get('cacheRefPresent'):",
" first_drift = 'cache-ref-missing:' + str(item.get('key'))",
" break",
" if not item.get('remoteFingerprintAligned'):",
" first_drift = 'remote-fingerprint-mismatch:' + str(item.get('key'))",
" break",
" if not item.get('fresh'):",
" first_drift = 'repository-stale:' + str(item.get('key'))",
" break",
" if not item.get('servedRefPresent'):",
" first_drift = 'served-ref-missing:' + str(item.get('key'))",
" break",
" if not item.get('refAligned'):",
" first_drift = 'served-ref-mismatch:' + str(item.get('key'))",
" break",
"repositories_ready = len(repository_status) == len(repositories) and all(item.get('cacheRefPresent') and item.get('fresh') and item.get('refAligned') and item.get('remoteFingerprintAligned') for item in repository_status)",
"ok = controller_config_rendered and controller_workload_rendered and controller_deployment_ready and controller_status_aligned and cache_ready and read_ready and write_ready and repositories_ready",
"print(json.dumps({",
" 'ok': read_ready and write_ready and cache_ready,",
" 'ok': ok,",
" 'namespace': os.environ.get('NAMESPACE'),",
" 'readReady': read_ready,",
" 'writeReady': write_ready,",
@@ -690,13 +840,27 @@ export function yamlLaneGitMirrorStatusScript(spec: AgentRunLaneSpec): string {
" 'cacheReady': cache_ready,",
" 'cachePvcExists': cache_pvc_exists,",
" 'cacheHostPath': os.environ.get('CACHE_HOST_PATH') or None,",
" 'resources': [line for line in re.split(r'\\r?\\n', names) if line][:40],",
" 'repository': os.environ.get('REPOSITORY'),",
" 'sourceBranch': os.environ.get('SOURCE_BRANCH'),",
" 'gitopsBranch': os.environ.get('GITOPS_BRANCH'),",
" 'sourceCommit': ref_value(refs, 'sourceCommit'),",
" 'gitopsCommit': ref_value(refs, 'gitopsCommit'),",
" 'repositories': repositories,",
" 'sourceCommit': legacy_ref('/tmp/agentrun-gitmirror-legacy-refs.txt', 'sourceCommit'),",
" 'gitopsCommit': legacy_ref('/tmp/agentrun-gitmirror-legacy-refs.txt', 'gitopsCommit'),",
" 'controller': {",
" 'deploymentReady': controller_deployment_ready,",
" 'configRendered': controller_config_rendered,",
" 'workloadRendered': controller_workload_rendered,",
" 'statusAligned': controller_status_aligned,",
" 'desiredHash': expected_desired_hash,",
" 'renderHash': expected_render_hash,",
" 'observedDesiredHash': controller_status.get('desiredHash'),",
" 'heartbeatAt': controller_status.get('heartbeatAt'),",
" 'heartbeatAgeMs': controller_status.get('heartbeatAgeMs'),",
" 'heartbeatFresh': controller_status.get('heartbeatFresh') is True,",
" },",
" 'repositoriesReady': repositories_ready,",
" 'repositories': repository_status,",
" 'firstDrift': first_drift,",
" 'pendingFlush': None,",
" 'valuesPrinted': False",
"}, ensure_ascii=False))",
"PY",