🌳
pt0/deployF/dbF/doBackupDbF.mts
1import * as _ from 'lodash-es'
2import fs from 'fs'
20export const getDbPodInfo = async ({svcName, cluster_name, isCnPg}: {svcName: string, cluster_name: string, isCnPg?: boolean}) => {
21 return getSinglePod({fuzzyPodName: svcName, cluster_name, labels: isCnPg ? cnpgPrimaryLabels(svcName) : undefined})
24export const doBackupDb = async ({
25 qsName, file_path, format, extraArgsS='', isQuiet,
26 extraArgs2S=[]
27}: {qsName: string, file_path: string, format: string, extraArgsS?: string, isQuiet?: boolean, extraArgs2S?: string[]}) => {
28 runPgOnKlustCtx.enterWith({runPgOnKlust} as Record<string, unknown>)
29 const {extQs, svcName, cluster_name, isCnPg} = await decomposeForkedKubeQs({qsName})
30 klusterCtx.enterWith({...klusterCtx.getStore(), cluster_name})
34 const getCmdA = (dumpFilePath: string) => {
35 let retA = ['pg_dump', `--format=${format}`]
36 if (extraArgsS) retA.push(extraArgsS)
38 if (runPgOnKlust) {
39 retA.push(extQs)
40 } else {
41 retA.push(`'${extQs}'`)
42 }
44 return [
45 ...retA,
46 ...extraArgs2S,
47 `--file=${dumpFilePath}`,
48 '-Upostgres',
49 '--verbose',
50 ]
51 }
53 let remoteSizeS = ''
54 if (runPgOnKlust) {
55 const podInfo = await getDbPodInfo({svcName, cluster_name, isCnPg})
56 assertDefined(podInfo)
57 const {podName, containerName} = podInfo
58 const fromRemotePath = pathDownJoin(
59 remoteWipBackupDir, _.last(_.split(file_path, '/'))!
60 )
62 await doKubeExec({cmdA: getCmdA(fromRemotePath), podName, containerName, isQuiet})
63 remoteSizeS = await doKubeExecCapture({cmdA: ['stat', '-c', '%s', fromRemotePath], podName, containerName})
64 try {
65 await kubeExecCat({fromRemotePath, toLocalPath: file_path, podName, containerName, expectedSize: Number(remoteSizeS)})
66 } finally {
67 await doKubeExec({cmdA: ['rm', fromRemotePath], podName, containerName, isQuiet})
68 }
69 } else {
70 const onDataFnc = (data: string): string | undefined => {
71 if (isQuiet) return undefined
72 const lastLine = data.split("\n")
73 process.stdout.write('\n\r' + lastLine)
74 return undefined
75 }
76 console.log('')
77 await liveSpawnThrow({cmd: getCmdA(file_path).join(' '), printCmd: getCmdA(file_path).map(maskQs).join(' '), isQuiet, onDataFnc})
78 }
79 const {size} = fs.statSync(file_path)
80 const remoteSize = Number(remoteSizeS)
81 if (remoteSize && size !== remoteSize) {
82 fs.unlinkSync(file_path)
83 throw new Error(`backup size mismatch: local=${size} remote=${remoteSize} diff=${remoteSize - size}`)
84 }
85 console.log(chalkGreen(`backed up ` + humanBytes(size)), file_path.replace(process.env.HOME + '/', '~/'))