fix: expose v02 runtime readiness progress
This commit is contained in:
@@ -2368,11 +2368,13 @@ function requiredEnv(name) {
|
||||
const revision = requiredEnv("HWLAB_SOURCE_REVISION");
|
||||
const runtimeNamespace = requiredEnv("HWLAB_RUNTIME_NAMESPACE");
|
||||
const gitopsTarget = requiredEnv("HWLAB_GITOPS_TARGET");
|
||||
const argoApplication = requiredEnv("HWLAB_ARGO_APPLICATION");
|
||||
const pipelineRun = process.env.HWLAB_TEKTON_PIPELINERUN || null;
|
||||
const taskRun = process.env.HWLAB_TEKTON_TASKRUN || null;
|
||||
const task = process.env.HWLAB_TEKTON_TASK || null;
|
||||
const timeoutMs = 240000;
|
||||
const pollMs = 1000;
|
||||
const progressEveryMs = 10000;
|
||||
|
||||
function emit(payload) {
|
||||
console.log(JSON.stringify({
|
||||
@@ -2474,6 +2476,7 @@ function readObservedServiceIds() {
|
||||
}
|
||||
|
||||
const observedServiceIds = readObservedServiceIds();
|
||||
const readinessMode = observedServiceIds ? "service-rollout" : "infra-runtime-change";
|
||||
|
||||
function observedRuntimeItems(items) {
|
||||
if (!observedServiceIds) return items;
|
||||
@@ -2492,8 +2495,57 @@ function readyWorkload(item) {
|
||||
return { ready: observedGeneration >= generation && ready >= desired && updated >= desired, desired, readyReplicas: ready, updatedReplicas: updated };
|
||||
}
|
||||
|
||||
function maybeEmitProgress(state, stage, startedAt, payload) {
|
||||
const now = Date.now();
|
||||
if (now - state.lastProgressAt < progressEveryMs) return;
|
||||
state.lastProgressAt = now;
|
||||
emit({ stage, status: "progress", durationMs: now - startedAt, readinessMode, ...payload });
|
||||
}
|
||||
|
||||
async function argoApplicationState() {
|
||||
const path = "/apis/argoproj.io/v1alpha1/namespaces/argocd/applications/" + encodeURIComponent(argoApplication);
|
||||
const response = await request("GET", path);
|
||||
if (response.statusCode === 403) return { status: "rbac-denied", item: null, statusCode: response.statusCode };
|
||||
if (response.statusCode < 200 || response.statusCode > 299) return { status: "error", item: null, statusCode: response.statusCode, body: response.body.slice(0, 500) };
|
||||
return { status: "ok", item: response.json, statusCode: response.statusCode };
|
||||
}
|
||||
|
||||
async function waitForArgoSyncedHealthy() {
|
||||
const startedAt = Date.now();
|
||||
const progressState = { lastProgressAt: 0 };
|
||||
for (;;) {
|
||||
const application = await argoApplicationState();
|
||||
if (application.status === "rbac-denied") {
|
||||
emit({ stage: "argo-sync-health", status: "failed", reason: "argocd-application-rbac-denied", durationMs: Date.now() - startedAt, readinessMode });
|
||||
process.exitCode = 1;
|
||||
return { observed: false };
|
||||
}
|
||||
if (application.status !== "ok") {
|
||||
emit({ stage: "argo-sync-health", status: "failed", reason: "argocd-application-read-failed", statusCode: application.statusCode, body: application.body || null, durationMs: Date.now() - startedAt, readinessMode });
|
||||
process.exitCode = 1;
|
||||
return { observed: false };
|
||||
}
|
||||
const syncStatus = application.item?.status?.sync?.status || null;
|
||||
const healthStatus = application.item?.status?.health?.status || null;
|
||||
const operationPhase = application.item?.status?.operationState?.phase || null;
|
||||
const operationMessage = application.item?.status?.operationState?.message || null;
|
||||
if (syncStatus === "Synced" && healthStatus === "Healthy") {
|
||||
emit({ stage: "argo-sync-health", status: "succeeded", durationMs: Date.now() - startedAt, readinessMode, syncStatus, healthStatus, operationPhase });
|
||||
return { observed: true };
|
||||
}
|
||||
if (Date.now() - startedAt >= timeoutMs) {
|
||||
emit({ stage: "argo-sync-health", status: "timeout", durationMs: Date.now() - startedAt, readinessMode, syncStatus, healthStatus, operationPhase, operationMessage });
|
||||
process.exitCode = 1;
|
||||
return { observed: false };
|
||||
}
|
||||
maybeEmitProgress(progressState, "argo-sync-health", startedAt, { syncStatus, healthStatus, operationPhase, operationMessage });
|
||||
await sleep(pollMs);
|
||||
}
|
||||
}
|
||||
|
||||
async function waitForArgoRefresh() {
|
||||
const startedAt = Date.now();
|
||||
const progressState = { lastProgressAt: 0 };
|
||||
for (;;) {
|
||||
const runtime = await runtimeItems();
|
||||
if (runtime.status === "rbac-denied") {
|
||||
@@ -2514,12 +2566,14 @@ async function waitForArgoRefresh() {
|
||||
process.exitCode = 1;
|
||||
return { observed: false, skipped: false };
|
||||
}
|
||||
maybeEmitProgress(progressState, "argo-refresh", startedAt, { workloadCount: runtime.items.length, observedCount: observed.length, pending: pending.slice(0, 8) });
|
||||
await sleep(pollMs);
|
||||
}
|
||||
}
|
||||
|
||||
async function waitForWorkloads() {
|
||||
const startedAt = Date.now();
|
||||
const progressState = { lastProgressAt: 0 };
|
||||
for (;;) {
|
||||
const runtime = await runtimeItems();
|
||||
if (runtime.status === "rbac-denied") {
|
||||
@@ -2538,11 +2592,19 @@ async function waitForWorkloads() {
|
||||
process.exitCode = 1;
|
||||
return;
|
||||
}
|
||||
maybeEmitProgress(progressState, "workload-ready", startedAt, { workloadCount: runtime.items.length, observedCount: observed.length, blocked: blocked.slice(0, 8) });
|
||||
await sleep(pollMs);
|
||||
}
|
||||
}
|
||||
|
||||
(async () => {
|
||||
emit({ stage: "runtime-ready", status: "started", readinessMode, observedServiceCount: observedServiceIds ? observedServiceIds.size : 0 });
|
||||
if (!observedServiceIds) {
|
||||
const argo = await waitForArgoSyncedHealthy();
|
||||
if (!argo.observed) return;
|
||||
await waitForWorkloads();
|
||||
return;
|
||||
}
|
||||
const refresh = await waitForArgoRefresh();
|
||||
if (!refresh.observed) return;
|
||||
await waitForWorkloads();
|
||||
@@ -2560,7 +2622,7 @@ function runtimeReadyTask({ profile = "dev" } = {}) {
|
||||
runAfter: ["gitops-promote"],
|
||||
workspaces: [{ name: "source", workspace: "source" }],
|
||||
taskSpec: {
|
||||
params: [{ name: "revision" }, { name: "runtime-namespace" }, { name: "gitops-target" }],
|
||||
params: [{ name: "revision" }, { name: "runtime-namespace" }, { name: "gitops-target" }, { name: "argo-application" }],
|
||||
workspaces: [{ name: "source" }],
|
||||
steps: [{
|
||||
name: "runtime-ready",
|
||||
@@ -2568,7 +2630,8 @@ function runtimeReadyTask({ profile = "dev" } = {}) {
|
||||
env: [
|
||||
...proxyEnv(),
|
||||
{ name: "HWLAB_RUNTIME_NAMESPACE", value: "$(params.runtime-namespace)" },
|
||||
{ name: "HWLAB_GITOPS_TARGET", value: "$(params.gitops-target)" }
|
||||
{ name: "HWLAB_GITOPS_TARGET", value: "$(params.gitops-target)" },
|
||||
{ name: "HWLAB_ARGO_APPLICATION", value: "$(params.argo-application)" }
|
||||
],
|
||||
script: runtimeReadyScript()
|
||||
}]
|
||||
@@ -2576,7 +2639,8 @@ function runtimeReadyTask({ profile = "dev" } = {}) {
|
||||
params: [
|
||||
{ name: "revision", value: "$(params.revision)" },
|
||||
{ name: "runtime-namespace", value: namespaceNameForProfile(profile) },
|
||||
{ name: "gitops-target", value: gitopsTargetForProfile(profile) }
|
||||
{ name: "gitops-target", value: gitopsTargetForProfile(profile) },
|
||||
{ name: "argo-application", value: argoApplicationName(profile) }
|
||||
]
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user