12import type { V1Volume, V1VolumeMount } from '@kubernetes/client-node' 14const scaleDeploy = async ({cluster_name, name, replicas}: {cluster_name: string, name: string, replicas: number}) => { 15 await eptKubeCli([cluster_name, 'scale', 'deployment', name, `--replicas=${replicas}`]) 18const waitForNoPods = async ({cluster_name, name}: {cluster_name: string, name: string}) => { 20 predicate: async () => (await getAppPods({cluster_name, name})).length > 0, 21 timeoutLabel: `vaultwarden ${name} scale-down`, 27// runs a one-off Job to completion: delete any stale prior (specs immutable), apply, stream logs, 28// fail on backoff, then clean up. returns when the job succeeds. 29const runRestoreJob = async ({job, jobName, cluster_name}: {job: KubeResource, jobName: string, cluster_name: string}) => { 32 const podName = (await getAppPods({cluster_name, name: jobName}))[0]?.metadata?.name 34 const failed = await awaitJobPod({job, podName, containerName: jobName, cluster_name}) 35 if (failed) throw new Error(`${jobName} failed: ${failed.failReason}`) 39// restores vaultwarden /data from haS3: db.sqlite3 via litestream, then attachments/sends/rsa_key 40// via rclone. scales the deployment to 0 for exclusive PVC access, runs both restore Jobs, scales up. 41export const vwRestoreAction = ({name}: {name: string}) => { 42 const vwrestore = async () => { 46 const pvcVolume: V1Volume = {name, persistentVolumeClaim: {claimName: name}} 47 const dataMount: V1VolumeMount = {name, mountPath: '/data'} 49 AWS_ACCESS_KEY_ID: {secretKeyRef: {name: secName, key: 'AWS_ACCESS_KEY_ID'}}, 50 AWS_SECRET_ACCESS_KEY: {secretKeyRef: {name: secName, key: 'AWS_SECRET_ACCESS_KEY'}}, 52 const gitSha = String(Date.now()) 54 await scaleDeploy({cluster_name, name, replicas: 0}) 55 await waitForNoPods({cluster_name, name}) 57 const dbJobName = `${name}-litestream-restore` 59 jobType: {kind: 'Job', backoffLimit: 0, ttlSecondsAfterFinished: 60}, 60 name: dbJobName, cluster_name, image: litestreamImg, git_sha: gitSha, 61 volumes: [pvcVolume, {name: configVolName, configMap: {name: configVolName}}], 62 volumeMounts: [dataMount, configMount], 66 await runRestoreJob({job: dbJob, jobName: dbJobName, cluster_name}) 68 const filesJobName = `${name}-rclone-restore` 70 jobType: {kind: 'Job', backoffLimit: 0, ttlSecondsAfterFinished: 60}, 71 name: filesJobName, cluster_name, image: rcloneImg, git_sha: gitSha, 73 volumeMounts: [dataMount], 77 await runRestoreJob({job: filesJob, jobName: filesJobName, cluster_name}) 79 await scaleDeploy({cluster_name, name, replicas: 1}) 80 console.log(`vaultwarden ${name} restored from haS3 on ${cluster_name} (db + attachments/sends/rsa_key)`) 82 vwrestore.cliDescript = `restore ${name} from haS3 (litestream db + rclone files): scale->0, restore, scale->1`