🌳
pt0/deployF/dbF/eptVanillaPg.mts
1import * as _ from 'lodash-es'
17import { isDbUp } from './dbToolsF.mts'
21import { scryptSync } from 'node:crypto'
23const vanillaPgPwSeedSecretName = 'vanilla-pg-pw-seed'
25const getVanillaPgDeterministicPw = async (dbName: string) => {
26 const seed = await genPlainSecretIfMissing({secretName: vanillaPgPwSeedSecretName, autoYes: true})
27 if (!seed) return null
28 return scryptSync(dbName, seed, 16).toString('base64url')
31const buildVanillaPgQs = ({svcName, password}: {svcName: string, password: string}) => `postgres://postgres:${password}@${svcName}`
33export const eptVanillaPgK8sRes = {kind: 'Cluster', apiVersion: 'postgresql.cnpg.io/v1'}
34export const eptVanillaPg = async ({
35 importMetaUrl,
37 ...props
38}: {importMetaUrl: string, action?: string, pvcNameOffset?: number, dbQsCfg: {dbQsName: string, gpIsProd?: boolean}, sizeGb: number, migrationOpts?: Record<string, unknown>, dbType?: string, kyselyOutFile?: string, [k: string]: unknown}) => {
39 if (!isDirectlyRun(importMetaUrl)) return {importMetaUrl}
41 let {pvcNameOffset, dbQsCfg, sizeGb, migrationOpts, dbType, kyselyOutFile} = props
43 const {dbQsName: qsName, gpIsProd} = dbQsCfg
44 const svcName = qsName.replace(/_qs$/, '')
46 const deterministicPw = await getVanillaPgDeterministicPw(svcName)
48 secretName: qsName,
49 genValue: () => buildVanillaPgQs({svcName, password: deterministicPw!}),
50 autoYes: true,
51 })
54 gpIsProd: !!gpIsProd, action, name: qsName,
55 dangerousActions: ['delete', 'apply'],
56 warnOnlyActions: ['dbconsole'],
57 })
58 const {extQs, dbQs, cluster_name, svcName: decomposedSvcName, nodePort, password} = await decomposeQsFromSec(tsSec(qsName))
60 deployDbCtx.enterWith({migrationOpts, gpIsProd, dbType, qsName, kyselyOutFile}) // ctx:clear
62 const dbName = svcName
64 if (action == 'info') {
65 const backupsDir = getDbBackupDir({dbName})
66 console.log({qsName, extQs, dbQs, backupsDir})
67 }
69 if (action != 'info' && await runDbAction({action, qsName})) {
70 return
71 }
73 if (isActionSupported(action)) {
75 const resources = await createPgDbFromQs({qsName, sizeGb, action, dbType, cluster_name, pvcNameOffset: pvcNameOffset != null ? String(pvcNameOffset) : undefined})
77 if (action == 'apply' && cluster_name != 'minik') {
78 const dbWaitTimeoutMs = 60 * 1000 // 1 min
79 const logProgress = mkProgressLogger('waiting for db to come online..', dbWaitTimeoutMs)
80 const startTime = Date.now()
81 const timeoutMs = dbWaitTimeoutMs
82 while (true) {
83 if (Date.now() - startTime > timeoutMs) {
84 console.log(' timeout')
85 throwDebugH({qsName, timeoutMs, message: 'db failed to come online within 60 seconds'})
86 }
87 const isUp = await isDbUp({qsName: tsSec(qsName)})
88 if (isUp) {
89 console.log(' ready')
90 break
91 }
92 logProgress('Connecting')
93 await sleep(10 * 1000)
94 }
95 console.log(`
96${chalkGreen(`db created & online!`)}
97now run:
98node ${getFilename(getProcArgv()[1])} migrate # migrate a new db
99OR
100node ${getFilename(getProcArgv()[1])} restore # restore latest db backup from ${getDbBackupDir({dbName})}
101`)
102 }
103 return resources
104 }
106 if (action != 'help') {
107 console.log(`unknown action "${action}"`)
108 }
109 const actionsH = {...resourcesActionsH(), ...module1ToObj(dbActions)}
110 cliHelp({actionsH})