fix: migrate external runtime PostgreSQL schema

This commit is contained in:
root
2026-07-16 23:31:31 +02:00
parent 49bcd22640
commit bc9e3a349a
3 changed files with 108 additions and 3 deletions
@@ -740,8 +740,24 @@ function externalPostgresConfigForLane(deploy, profile, args = {}) {
return { serviceName: effective.serviceName, endpointAddress: effective.endpointAddress, port };
}
function externalPostgresManifest({ profile = "v03", config, source, deploy = null }) {
function externalPostgresManifest({ profile = "v03", config, source, deploy = null, migrationSources = [], catalog = null, registryPrefix = defaultRegistryPrefix, useDeployImages = false }) {
const namespace = namespaceNameForProfile(profile, deploy);
assert.ok(Array.isArray(migrationSources) && migrationSources.length > 0, "external Postgres migration chain is required");
const migrationData = Object.fromEntries(migrationSources.map((migration) => [path.basename(migration.path), migration.sql]));
const migrationSha256 = createHash("sha256").update(migrationSources.map((migration) => migration.sql).join("\n")).digest("hex");
const migrationRunner = externalPostgresMigrationRunner();
const migrationImage = runtimeImageForService({
catalog,
deploy,
serviceId: "hwlab-cloud-api",
source,
registryPrefix,
useDeployImages,
digestPin: true,
envReuseServiceIds: envReuseServiceIdsForLane(deploy, profile)
});
const executionSha256 = createHash("sha256").update(`${migrationSha256}\n${migrationImage}\n${migrationRunner}`).digest("hex");
const migrationName = `${namespace}-external-postgres-migrate-${executionSha256.slice(0, 12)}`;
const labels = {
"app.kubernetes.io/name": config.serviceName,
"app.kubernetes.io/part-of": "hwlab",
@@ -756,6 +772,50 @@ function externalPostgresManifest({ profile = "v03", config, source, deploy = nu
apiVersion: "v1",
kind: "List",
items: [
{
apiVersion: "v1",
kind: "ConfigMap",
metadata: { name: migrationName, namespace, labels, annotations: { ...annotations, "hwlab.pikastech.local/migration-sha256": migrationSha256 } },
data: {
"run.mjs": migrationRunner,
...migrationData
}
},
{
apiVersion: "batch/v1",
kind: "Job",
metadata: {
name: migrationName,
namespace,
labels,
annotations: {
...annotations,
"argocd.argoproj.io/sync-wave": "-1",
"hwlab.pikastech.local/migration-sha256": migrationSha256
}
},
spec: {
backoffLimit: 2,
template: {
metadata: { labels: { ...labels, "app.kubernetes.io/name": migrationName } },
spec: {
restartPolicy: "Never",
containers: [{
name: "migrate",
image: migrationImage,
imagePullPolicy: "IfNotPresent",
command: ["node", "/opt/hwlab-migrations/run.mjs"],
env: [{
name: "DATABASE_URL",
valueFrom: { secretKeyRef: { name: `hwlab-cloud-api-${profile}-db`, key: "database-url" } }
}],
volumeMounts: [{ name: "migrations", mountPath: "/opt/hwlab-migrations", readOnly: true }]
}],
volumes: [{ name: "migrations", configMap: { name: migrationName } }]
}
}
}
},
{
apiVersion: "v1",
kind: "Service",
@@ -774,6 +834,27 @@ function externalPostgresManifest({ profile = "v03", config, source, deploy = nu
};
}
function externalPostgresMigrationRunner() {
return [
'import { readdir, readFile } from "node:fs/promises";',
'import { createRequire } from "node:module";',
'const require = createRequire("/opt/hwlab-env/package.json");',
'const { Pool } = require("/opt/hwlab-env/node_modules/pg");',
'const root = "/opt/hwlab-migrations";',
'const files = (await readdir(root)).filter((name) => /^\\d+_.*\\.sql$/u.test(name)).sort();',
'const pool = new Pool({ connectionString: process.env.DATABASE_URL, max: 1 });',
'try {',
' for (const file of files) {',
' await pool.query(await readFile(`${root}/${file}`, "utf8"));',
' console.error(JSON.stringify({ event: "hwlab-runtime-migration-applied", file, valuesPrinted: false }));',
' }',
'} finally {',
' await pool.end();',
'}',
''
].join("\n");
}
function v02OpenFgaManifest({ profile = "v02", source, deploy = null }) {
const namespace = namespaceNameForProfile(profile, deploy);
const name = "hwlab-openfga";