fix: gate d601 v03 postgres mode by yaml switch (#972)
Co-authored-by: Codex <codex@noreply.local>
This commit is contained in:
@@ -144,7 +144,25 @@ lanes:
|
||||
renderDir: runtime-v03
|
||||
runtimeStore:
|
||||
postgres:
|
||||
mode: platform-service
|
||||
mode: local-k3s
|
||||
secretName: hwlab-v03-postgres
|
||||
statefulSet: hwlab-v03-postgres
|
||||
serviceName: hwlab-v03-postgres
|
||||
adminUser: hwlab_v03
|
||||
adminPasswordSourceRef: hwlab/d601-v03-postgres.env
|
||||
adminPasswordSourceKey: HWLAB_V03_POSTGRES_PASSWORD
|
||||
cloudApi:
|
||||
secretName: hwlab-cloud-api-v03-db
|
||||
secretKey: database-url
|
||||
database: hwlab_v03
|
||||
role: hwlab_v03
|
||||
openfga:
|
||||
secretName: hwlab-v03-openfga
|
||||
secretKey: datastore-uri
|
||||
authnKey: authn-preshared-key
|
||||
postgresPasswordKey: postgres-password
|
||||
database: hwlab_openfga
|
||||
role: hwlab_openfga
|
||||
poolMax: 16
|
||||
connectionTimeoutMs: 5000
|
||||
queryRetryMaxAttempts: 5
|
||||
|
||||
@@ -326,6 +326,10 @@ export interface HwlabRuntimeLaneSpec {
|
||||
readonly downloadProfile: HwlabDownloadProfileSpec;
|
||||
}
|
||||
|
||||
export function hwlabRuntimeActiveExternalPostgres(spec: HwlabRuntimeLaneSpec): HwlabRuntimeExternalPostgresSpec | undefined {
|
||||
return spec.runtimeStore?.postgres?.mode === "platform-service" ? spec.externalPostgres : undefined;
|
||||
}
|
||||
|
||||
export const HWLAB_NODE_LANE_CONFIG_PATH = "config/hwlab-node-lanes.yaml";
|
||||
|
||||
interface HwlabLaneConfig {
|
||||
|
||||
@@ -358,7 +358,7 @@ export function withNodeRuntimeControlPlanePlanRendered(result: Record<string, u
|
||||
result.ok === true ? "ok" : "failed",
|
||||
webObserveText(result.mode),
|
||||
webObserveText(checks.runtimeNamespace),
|
||||
webObserveText(checks.externalPostgresDeclared),
|
||||
webObserveText(checks.externalPostgresActive),
|
||||
webObserveText(checks.publicExposureDeclared),
|
||||
]],
|
||||
),
|
||||
@@ -367,6 +367,8 @@ export function withNodeRuntimeControlPlanePlanRendered(result: Record<string, u
|
||||
["CHECK", "VALUE"],
|
||||
[
|
||||
["node-scoped-target", webObserveText(checks.nodeScopedTargetConfigured)],
|
||||
["external-postgres-declared", webObserveText(checks.externalPostgresDeclared)],
|
||||
["external-postgres-active", webObserveText(checks.externalPostgresActive)],
|
||||
["local-postgres-absent", webObserveText(checks.localPostgresExpectedAbsent)],
|
||||
["secret-values-printed", webObserveText(checks.secretValuesPrinted)],
|
||||
],
|
||||
|
||||
@@ -37,8 +37,10 @@ import { compactPrometheusLines, compactRuntimeCommand, isWorkbenchBackendEventM
|
||||
import { compactCommandResultRedacted, record, shellQuote } from "./utils";
|
||||
import { readBootstrapAdminPasswordMaterial } from "./web-probe";
|
||||
import { webProbeCredential } from "./web-probe-observe";
|
||||
import { hwlabRuntimeActiveExternalPostgres } from "../hwlab-node-lanes";
|
||||
|
||||
export function nodeRuntimeControlPlanePlan(scoped: ReturnType<typeof parseNodeScopedDelegatedOptions>): Record<string, unknown> {
|
||||
const activeExternalPostgres = hwlabRuntimeActiveExternalPostgres(scoped.spec);
|
||||
return {
|
||||
ok: true,
|
||||
command: `hwlab nodes control-plane plan --node ${scoped.node} --lane ${scoped.lane}`,
|
||||
@@ -50,6 +52,7 @@ export function nodeRuntimeControlPlanePlan(scoped: ReturnType<typeof parseNodeS
|
||||
checks: {
|
||||
nodeScopedTargetConfigured: true,
|
||||
externalPostgresDeclared: scoped.spec.externalPostgres !== undefined,
|
||||
externalPostgresActive: activeExternalPostgres !== undefined,
|
||||
secretValuesPrinted: false,
|
||||
runtimeNamespace: scoped.spec.runtimeNamespace,
|
||||
localPostgresExpectedAbsent: nodeRuntimeLocalPostgresExpectedAbsent(scoped.spec),
|
||||
@@ -58,9 +61,9 @@ export function nodeRuntimeControlPlanePlan(scoped: ReturnType<typeof parseNodeS
|
||||
next: {
|
||||
infraStatus: `bun scripts/cli.ts hwlab nodes control-plane infra status --node ${scoped.node} --lane ${scoped.lane}`,
|
||||
status: `bun scripts/cli.ts hwlab nodes control-plane status --node ${scoped.node} --lane ${scoped.lane}`,
|
||||
platformDbStatus: scoped.spec.externalPostgres === undefined
|
||||
platformDbStatus: activeExternalPostgres === undefined
|
||||
? null
|
||||
: `bun scripts/cli.ts platform-db postgres status --config ${scoped.spec.externalPostgres.configRef}`,
|
||||
: `bun scripts/cli.ts platform-db postgres status --config ${activeExternalPostgres.configRef}`,
|
||||
publicExposure: scoped.spec.publicExposure === null ? null : `bun scripts/cli.ts hwlab nodes control-plane public-exposure --node ${scoped.node} --lane ${scoped.lane} --confirm`,
|
||||
},
|
||||
};
|
||||
|
||||
@@ -31,6 +31,7 @@ import type { RenderedCliResult } from "../output";
|
||||
import { NODE_RUNTIME_CICD_WAIT_WARNING_SECONDS } from "./entry";
|
||||
import { publicExposureSummary } from "./public-exposure";
|
||||
import { assertNodeId, positiveIntegerOption, requiredOption } from "./utils";
|
||||
import { hwlabRuntimeActiveExternalPostgres } from "../hwlab-node-lanes";
|
||||
|
||||
export function parseNodeScopedDelegatedOptions(domain: DelegatedNodeDomain, args: string[]): {
|
||||
domain: DelegatedNodeDomain;
|
||||
@@ -76,10 +77,11 @@ export function parseNodeScopedDelegatedOptions(domain: DelegatedNodeDomain, arg
|
||||
}
|
||||
|
||||
export function nodeRuntimeLocalPostgresExpectedAbsent(spec: HwlabRuntimeLaneSpec): boolean {
|
||||
return spec.externalPostgres !== undefined || spec.runtimeStore?.postgres?.mode === "platform-service";
|
||||
return spec.runtimeStore?.postgres?.mode === "platform-service";
|
||||
}
|
||||
|
||||
export function nodeRuntimeExpected(spec: HwlabRuntimeLaneSpec): Record<string, unknown> {
|
||||
const activeExternalPostgres = hwlabRuntimeActiveExternalPostgres(spec);
|
||||
return {
|
||||
configPath: hwlabRuntimeLaneConfigPath(),
|
||||
node: spec.nodeId,
|
||||
@@ -151,6 +153,7 @@ export function nodeRuntimeExpected(spec: HwlabRuntimeLaneSpec): Record<string,
|
||||
observability: spec.observability,
|
||||
runtimeImageRewrites: spec.runtimeImageRewrites,
|
||||
externalPostgres: spec.externalPostgres === undefined ? null : {
|
||||
active: activeExternalPostgres !== undefined,
|
||||
provider: spec.externalPostgres.provider,
|
||||
configRef: spec.externalPostgres.configRef,
|
||||
serviceName: spec.externalPostgres.serviceName,
|
||||
@@ -178,8 +181,8 @@ export function nodeRuntimeExpected(spec: HwlabRuntimeLaneSpec): Record<string,
|
||||
valuesPrinted: false,
|
||||
},
|
||||
localPostgres: {
|
||||
shouldRender: spec.externalPostgres === undefined,
|
||||
expectedAbsent: spec.externalPostgres !== undefined,
|
||||
shouldRender: spec.runtimeStore?.postgres?.mode !== "platform-service",
|
||||
expectedAbsent: spec.runtimeStore?.postgres?.mode === "platform-service",
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
@@ -34,6 +34,7 @@ import { transPath } from "./runtime-common";
|
||||
import { bootstrapAdminSecretScript, cloudApiDbSecretScript, codeAgentProviderSecretScript, masterAdminApiKeySecretScript, obsoletePlatformDbCleanupScript, obsoletePlatformDbStatusFromText, obsoleteSecretCleanupScript, openFgaSecretScript, ownedPostgresCleanupScript, platformDbSecretStatusScript, secretStatusFromText } from "./secret-scripts";
|
||||
import { assertLane, assertNodeId, compactCommandResult, keyValueLinesFromText, numericField, optionValue, positiveIntegerOption, readMasterAdminApiKey, requiredOption, shellQuote, statusText } from "./utils";
|
||||
import { parseEnvFile, readBootstrapAdminSecretMaterial, syncNodeExternalPostgresSecrets } from "./web-probe";
|
||||
import { hwlabRuntimeActiveExternalPostgres } from "../hwlab-node-lanes";
|
||||
|
||||
export function isSafeWebProbeScriptRunDir(value: string | null): value is string {
|
||||
return typeof value === "string"
|
||||
@@ -191,10 +192,10 @@ export function parseSecretOptions(args: string[]): NodeSecretOptions {
|
||||
export function runtimeSecretSpec(input: { node: string; lane: string }): RuntimeSecretSpec {
|
||||
const namespace = `hwlab-${input.lane}`;
|
||||
const runtimeLaneSpec = isHwlabRuntimeLane(input.lane) ? hwlabRuntimeLaneSpecForNode(input.lane, input.node) : undefined;
|
||||
const externalPostgres = runtimeLaneSpec?.externalPostgres;
|
||||
const externalPostgres = runtimeLaneSpec === undefined ? undefined : hwlabRuntimeActiveExternalPostgres(runtimeLaneSpec);
|
||||
const postgresStore = runtimeLaneSpec?.runtimeStore?.postgres;
|
||||
const bootstrapAdmin = runtimeLaneSpec?.bootstrapAdmin;
|
||||
const platformDb = externalPostgres !== undefined || postgresStore?.mode === "platform-service";
|
||||
const platformDb = postgresStore?.mode === "platform-service";
|
||||
const localPostgresService = postgresStore?.serviceName ?? `${namespace}-postgres`;
|
||||
const platformPostgresService = externalPostgres?.serviceName ?? postgresStore?.serviceName ?? "g14-platform-postgres";
|
||||
const platformPostgresRuntimeAccess = externalPostgres?.runtimeAccess;
|
||||
|
||||
@@ -38,6 +38,7 @@ import { compactNodeRuntimeGitMirrorStatus, nodeRuntimeGitMirrorStatus } from ".
|
||||
import { keyValueLinesFromText, numericField, optionValue, record, shellQuote } from "./utils";
|
||||
import { externalPostgresBridgeStatus, externalPostgresSecretStatus, getNodeRuntimePipelineRun, isLocalPostgresObject, nodeRuntimeRenderOverlay } from "./web-probe";
|
||||
import { webObserveShort, webObserveText } from "./web-probe-observe";
|
||||
import { hwlabRuntimeActiveExternalPostgres } from "../hwlab-node-lanes";
|
||||
|
||||
export function nodeRuntimeGitMirrorJobName(mirror: NodeRuntimeGitMirrorTargetSpec, action: "sync" | "flush"): string {
|
||||
const prefix = action === "sync" ? mirror.syncJobPrefix : mirror.flushJobPrefix;
|
||||
@@ -178,11 +179,12 @@ export function nodeRuntimeControlPlaneStatus(scoped: ReturnType<typeof parseNod
|
||||
const publicProbes = nodeRuntimePublicProbeStatus(spec);
|
||||
const gitMirror = nodeRuntimeGitMirrorStatus(scoped);
|
||||
const gitMirrorCompact = compactNodeRuntimeGitMirrorStatus(gitMirror);
|
||||
const activeExternalPostgres = hwlabRuntimeActiveExternalPostgres(spec);
|
||||
const controlPlaneReady = serviceAccount.exitCode === 0 && pipeline.exitCode === 0 && argo.exitCode === 0;
|
||||
const workloadsReady = workloadReadiness.length > 0 && workloadReadiness.every((item) => item.ready);
|
||||
const localPostgresExpectedAbsent = nodeRuntimeLocalPostgresExpectedAbsent(spec);
|
||||
const localPostgresReady = localPostgresExpectedAbsent ? localPostgresObjects.length === 0 : localPostgresObjects.length > 0;
|
||||
const runtimeReady = namespaceExists && localPostgresReady && workloadsReady && (spec.externalPostgres === undefined || (bridge.ready && secrets.ready));
|
||||
const runtimeReady = namespaceExists && localPostgresReady && workloadsReady && (activeExternalPostgres === undefined || (bridge.ready && secrets.ready));
|
||||
const argoReady = argo.exitCode === 0 && repoURL === spec.argoRepoUrl && targetRevision === spec.gitopsBranch && path === spec.runtimePath && syncStatus === "Synced" && health === "Healthy";
|
||||
const pipelineRunReady = pipelineRunProbe !== null && pipelineRunProbe.status === "True";
|
||||
const pipelineRunDegradedReason = typeof pipelineRunDiagnostics?.degradedReason === "string"
|
||||
|
||||
@@ -37,10 +37,12 @@ import { compactRuntimeCommand, runNodeHostScript } from "./runtime-common";
|
||||
import { assertLane, assertNodeId, keyValueLinesFromText, numericField, optionValue, optionalStringValue, positiveIntegerOption, positiveIntegerValue, record, requiredOption, shellQuote, statusText, stringValue, stripOptions } from "./utils";
|
||||
import { discoverWebObserveIndexEntry, readWebObserveIndexEntry } from "./web-observe-render";
|
||||
import { assertKnownOptions, nodeWebProbeAutoCommandTimeoutSeconds, nodeWebProbeDefaultUrl, normalizeNodeWebProbeObserveArgs, parseNodeWebProbeObserveOptions, parseNodeWebProbeSentinelOptions, parseWebProbeBrowserProxyMode } from "./web-probe-observe";
|
||||
import { hwlabRuntimeActiveExternalPostgres } from "../hwlab-node-lanes";
|
||||
|
||||
export function nodeRuntimeRenderOverlay(spec: HwlabRuntimeLaneSpec): Record<string, unknown> {
|
||||
const gitSshProxy = httpProxyEndpoint(spec.networkProfile.proxy.http);
|
||||
const gitMirror = nodeRuntimeGitMirrorTarget(spec);
|
||||
const activeExternalPostgres = hwlabRuntimeActiveExternalPostgres(spec);
|
||||
const renderGitMirror = {
|
||||
...gitMirror,
|
||||
egressProxy: gitMirror.egressProxy.mode === "direct" ? {
|
||||
@@ -109,13 +111,13 @@ export function nodeRuntimeRenderOverlay(spec: HwlabRuntimeLaneSpec): Record<str
|
||||
webProxy: spec.publicExposure.webProxy,
|
||||
apiProxy: spec.publicExposure.apiProxy,
|
||||
},
|
||||
externalPostgres: spec.externalPostgres === undefined ? undefined : {
|
||||
externalPostgres: activeExternalPostgres === undefined ? undefined : {
|
||||
enabled: true,
|
||||
serviceName: spec.externalPostgres.serviceName,
|
||||
endpointAddress: spec.externalPostgres.endpointAddress,
|
||||
port: spec.externalPostgres.port,
|
||||
runtimeAccess: spec.externalPostgres.runtimeAccess ?? null,
|
||||
sslmode: spec.externalPostgres.sslmode,
|
||||
serviceName: activeExternalPostgres.serviceName,
|
||||
endpointAddress: activeExternalPostgres.endpointAddress,
|
||||
port: activeExternalPostgres.port,
|
||||
runtimeAccess: activeExternalPostgres.runtimeAccess ?? null,
|
||||
sslmode: activeExternalPostgres.sslmode,
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -460,7 +462,7 @@ export function sleepSync(ms: number): void {
|
||||
}
|
||||
|
||||
export function syncNodeExternalPostgresSecrets(spec: HwlabRuntimeLaneSpec, dryRun: boolean, timeoutSeconds: number): Record<string, unknown> | null {
|
||||
const pg = spec.externalPostgres;
|
||||
const pg = hwlabRuntimeActiveExternalPostgres(spec);
|
||||
if (pg === undefined) return null;
|
||||
const secretRoot = externalPostgresSecretSourceRoot(spec);
|
||||
const cloudApi = readSecretSourceValue(secretRoot, pg.cloudApi.sourceRef, pg.cloudApi.envKey);
|
||||
@@ -905,7 +907,7 @@ export function ensureNodeBaseImage(spec: HwlabRuntimeLaneSpec, dryRun: boolean,
|
||||
}
|
||||
|
||||
export function externalPostgresSecretSetupScript(spec: HwlabRuntimeLaneSpec, dryRun: boolean): string {
|
||||
const pg = spec.externalPostgres;
|
||||
const pg = hwlabRuntimeActiveExternalPostgres(spec);
|
||||
if (pg === undefined) return "true";
|
||||
const authnKey = pg.openfga.authnKey ?? "authn-preshared-key";
|
||||
return [
|
||||
@@ -1068,7 +1070,7 @@ export function isLocalPostgresObject(name: string, spec: HwlabRuntimeLaneSpec):
|
||||
}
|
||||
|
||||
export function externalPostgresBridgeStatus(spec: HwlabRuntimeLaneSpec, namespaceExists: boolean): Record<string, unknown> {
|
||||
const pg = spec.externalPostgres;
|
||||
const pg = hwlabRuntimeActiveExternalPostgres(spec);
|
||||
if (pg === undefined) return { required: false, ready: true };
|
||||
if (!namespaceExists) return { required: true, ready: false, degradedReason: "runtime-namespace-missing" };
|
||||
const runtimeAccess = pg.runtimeAccess ?? { endpointAddress: pg.endpointAddress, port: pg.port };
|
||||
@@ -1113,7 +1115,7 @@ export function externalPostgresBridgeStatus(spec: HwlabRuntimeLaneSpec, namespa
|
||||
}
|
||||
|
||||
export function externalPostgresSecretStatus(spec: HwlabRuntimeLaneSpec, namespaceExists: boolean): Record<string, unknown> {
|
||||
const pg = spec.externalPostgres;
|
||||
const pg = hwlabRuntimeActiveExternalPostgres(spec);
|
||||
if (pg === undefined) return { required: false, ready: true };
|
||||
if (!namespaceExists) return { required: true, ready: false, degradedReason: "runtime-namespace-missing" };
|
||||
const cloudApi = secretKeyStatus(spec, pg.cloudApi.secretName, pg.cloudApi.secretKey);
|
||||
|
||||
Reference in New Issue
Block a user