fix: migrate external runtime PostgreSQL schema
This commit is contained in:
@@ -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";
|
||||
|
||||
Reference in New Issue
Block a user