fix: add dev DB DNS contract
This commit is contained in:
@@ -339,7 +339,7 @@ function blockerHint(blocker) {
|
||||
return "Restore the public DEV health path and confirm it identifies HWLAB dev, not a substitute runtime.";
|
||||
}
|
||||
if (blocker.scope === "dev-health-db" || blocker.scope === "cloud-api-db" || blocker.scope === "cloud-api-db-config") {
|
||||
return "Configure and verify the DEV cloud-api DB env readiness through health output, without reading secret values.";
|
||||
return "Configure and verify the DEV cloud-api DB env and stable DNS readiness through health output, without reading secret values.";
|
||||
}
|
||||
return blocker.summary;
|
||||
}
|
||||
@@ -543,7 +543,7 @@ function validateK8s(devKustomization, namespaceDoc, workloads, services, health
|
||||
};
|
||||
}
|
||||
|
||||
async function checkCloudApiDb(deploy, workloads, blockers) {
|
||||
async function checkCloudApiDb(deploy, workloads, services, blockers) {
|
||||
const deployEnv = deploy?.services?.find((service) => service.serviceId === "hwlab-cloud-api")?.env ?? {};
|
||||
const envNames = new Set(Object.keys(deployEnv));
|
||||
const workloadEnv = new Map();
|
||||
@@ -586,16 +586,22 @@ async function checkCloudApiDb(deploy, workloads, blockers) {
|
||||
const missingSecretRefs = requiredEnv
|
||||
.filter((env) => env.secretRef && !env.secretRef.present)
|
||||
.map((env) => `${env.secretRef.secretName}/${env.secretRef.secretKey}`);
|
||||
if (missingManifest.length > 0 || missingK8s.length > 0 || missingSecretRefs.length > 0) {
|
||||
const dnsContract = inspectCloudApiDbDnsContract(deployEnv, workloadEnv, services);
|
||||
const missingDnsContract = dnsContract.missing;
|
||||
if (missingManifest.length > 0 || missingK8s.length > 0 || missingSecretRefs.length > 0 || missingDnsContract.length > 0) {
|
||||
addBlocker(
|
||||
blockers,
|
||||
"runtime_blocker",
|
||||
"cloud-api-db-config",
|
||||
`cloud-api DEV DB env contract is incomplete; missing ${[...missingManifest, ...missingK8s, ...missingSecretRefs].join(", ")}`
|
||||
`cloud-api DEV DB env/DNS contract is incomplete; missing ${[...missingManifest, ...missingK8s, ...missingSecretRefs, ...missingDnsContract].join(", ")}`
|
||||
);
|
||||
}
|
||||
|
||||
const configReady = missingManifest.length === 0 && missingK8s.length === 0 && missingSecretRefs.length === 0;
|
||||
const configReady =
|
||||
missingManifest.length === 0 &&
|
||||
missingK8s.length === 0 &&
|
||||
missingSecretRefs.length === 0 &&
|
||||
missingDnsContract.length === 0;
|
||||
const health = {
|
||||
status: configReady ? "degraded" : "blocked",
|
||||
ready: false,
|
||||
@@ -628,12 +634,71 @@ async function checkCloudApiDb(deploy, workloads, blockers) {
|
||||
missingManifest,
|
||||
missingK8s,
|
||||
missingSecretRefs,
|
||||
missingDnsContract,
|
||||
dns: dnsContract,
|
||||
runtimeHealth: summarizeDbContract(health),
|
||||
secretMaterialRead: false,
|
||||
valuesRedacted: true,
|
||||
liveDbEvidence: false,
|
||||
fixtureEvidence: false,
|
||||
note: "This check records DB env/Secret reference presence only. It is not live DB evidence."
|
||||
note: "This check records DB env, Secret reference, and stable DNS Service presence only. It is not live DB evidence."
|
||||
};
|
||||
}
|
||||
|
||||
function inspectCloudApiDbDnsContract(deployEnv, workloadEnv, services) {
|
||||
const dns = DEV_DB_ENV_CONTRACT.dns;
|
||||
const expectedHost = `${dns.serviceName}.${dns.namespace}.svc.cluster.local`;
|
||||
const service = listItems(services).find((item) => item?.metadata?.name === dns.serviceName) ?? null;
|
||||
const port = service?.spec?.ports?.find((entry) => entry.name === dns.portName) ?? null;
|
||||
const actual = {
|
||||
deployServiceName: deployEnv.HWLAB_CLOUD_DB_SERVICE_NAME,
|
||||
deployServiceNamespace: deployEnv.HWLAB_CLOUD_DB_SERVICE_NAMESPACE,
|
||||
deployHost: deployEnv.HWLAB_CLOUD_DB_HOST,
|
||||
deployPort: deployEnv.HWLAB_CLOUD_DB_PORT,
|
||||
workloadServiceName: workloadEnv.get("HWLAB_CLOUD_DB_SERVICE_NAME")?.value,
|
||||
workloadServiceNamespace: workloadEnv.get("HWLAB_CLOUD_DB_SERVICE_NAMESPACE")?.value,
|
||||
workloadHost: workloadEnv.get("HWLAB_CLOUD_DB_HOST")?.value,
|
||||
workloadPort: workloadEnv.get("HWLAB_CLOUD_DB_PORT")?.value,
|
||||
serviceName: service?.metadata?.name,
|
||||
serviceNamespace: service?.metadata?.namespace,
|
||||
serviceType: service?.spec?.type,
|
||||
serviceSelector: service?.spec?.selector ?? null,
|
||||
portName: port?.name,
|
||||
port: port?.port,
|
||||
targetPort: port?.targetPort
|
||||
};
|
||||
const checks = [
|
||||
["deployEnv.HWLAB_CLOUD_DB_SERVICE_NAME", actual.deployServiceName, dns.serviceName],
|
||||
["deployEnv.HWLAB_CLOUD_DB_SERVICE_NAMESPACE", actual.deployServiceNamespace, dns.namespace],
|
||||
["deployEnv.HWLAB_CLOUD_DB_HOST", actual.deployHost, expectedHost],
|
||||
["deployEnv.HWLAB_CLOUD_DB_PORT", actual.deployPort, String(dns.port)],
|
||||
["workloadEnv.HWLAB_CLOUD_DB_SERVICE_NAME", actual.workloadServiceName, dns.serviceName],
|
||||
["workloadEnv.HWLAB_CLOUD_DB_SERVICE_NAMESPACE", actual.workloadServiceNamespace, dns.namespace],
|
||||
["workloadEnv.HWLAB_CLOUD_DB_HOST", actual.workloadHost, expectedHost],
|
||||
["workloadEnv.HWLAB_CLOUD_DB_PORT", actual.workloadPort, String(dns.port)],
|
||||
["Service.metadata.name", actual.serviceName, dns.serviceName],
|
||||
["Service.metadata.namespace", actual.serviceNamespace, dns.namespace],
|
||||
["Service.spec.type", actual.serviceType, "ClusterIP"],
|
||||
["Service.spec.selector", actual.serviceSelector, null],
|
||||
["Service.port.name", actual.portName, dns.portName],
|
||||
["Service.port.port", actual.port, dns.port],
|
||||
["Service.port.targetPort", actual.targetPort, dns.portName]
|
||||
];
|
||||
const missing = checks
|
||||
.filter(([, actualValue, expectedValue]) => !Object.is(actualValue, expectedValue))
|
||||
.map(([name, actualValue, expectedValue]) => `${name} expected ${expectedValue} got ${actualValue ?? "missing"}`);
|
||||
|
||||
return {
|
||||
ready: missing.length === 0,
|
||||
host: expectedHost,
|
||||
serviceName: dns.serviceName,
|
||||
namespace: dns.namespace,
|
||||
port: dns.port,
|
||||
selectorless: service ? service.spec?.selector === undefined : false,
|
||||
secretMaterialRead: false,
|
||||
liveDbEvidence: false,
|
||||
missing,
|
||||
actual
|
||||
};
|
||||
}
|
||||
|
||||
@@ -937,7 +1002,7 @@ export async function runDevDeployApply(argv, io = {}) {
|
||||
|
||||
const artifactEvidence = validateDeployAndCatalog(deploy, catalog, commitId, blockers);
|
||||
const k8sManifest = validateK8s(devKustomization, namespaceDoc, workloads, services, healthContract, deploy, blockers);
|
||||
const cloudApiDb = await checkCloudApiDb(deploy, workloads, blockers);
|
||||
const cloudApiDb = await checkCloudApiDb(deploy, workloads, services, blockers);
|
||||
if (!(await readText("internal/cloud/server.mjs")).includes('url.pathname === "/health/live"')) {
|
||||
addBlocker(blockers, "contract_blocker", "cloud-api-health-path", "cloud-api does not implement the k8s /health/live path");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user