Fix Account/Backup (#2642)

Signed-off-by: Andrey Sobolev <haiodo@gmail.com>
This commit is contained in:
Andrey Sobolev 2023-02-16 10:43:36 +07:00 committed by GitHub
parent a17d24c965
commit 54e62d9547
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 38 additions and 15 deletions

View File

@ -283,10 +283,17 @@ export function devTool (
program program
.command('backup-restore <dirName> <workspace> [date]') .command('backup-restore <dirName> <workspace> [date]')
.option('-m, --merge', 'Enable merge of remote and backup content.', false)
.description('dump workspace transactions and minio resources') .description('dump workspace transactions and minio resources')
.action(async (dirName: string, workspace: string, date, cmd) => { .action(async (dirName: string, workspace: string, date, cmd: { merge: boolean }) => {
const storage = await createFileBackupStorage(dirName) const storage = await createFileBackupStorage(dirName)
return await restore(transactorUrl, getWorkspaceId(workspace, productId), storage, parseInt(date ?? '-1')) return await restore(
transactorUrl,
getWorkspaceId(workspace, productId),
storage,
parseInt(date ?? '-1'),
cmd.merge
)
}) })
program program

View File

@ -25,8 +25,6 @@ interface Config {
MinioEndpoint: string MinioEndpoint: string
MinioAccessKey: string MinioAccessKey: string
MinioSecretKey: string MinioSecretKey: string
ProductId: string
} }
const envMap: { [key in keyof Config]: string } = { const envMap: { [key in keyof Config]: string } = {
@ -38,8 +36,7 @@ const envMap: { [key in keyof Config]: string } = {
Interval: 'INTERVAL', Interval: 'INTERVAL',
MinioEndpoint: 'MINIO_ENDPOINT', MinioEndpoint: 'MINIO_ENDPOINT',
MinioAccessKey: 'MINIO_ACCESS_KEY', MinioAccessKey: 'MINIO_ACCESS_KEY',
MinioSecretKey: 'MINIO_SECRET_KEY', MinioSecretKey: 'MINIO_SECRET_KEY'
ProductId: 'PRODUCT_ID'
} }
const required: Array<keyof Config> = [ const required: Array<keyof Config> = [
@ -63,8 +60,7 @@ const config: Config = (() => {
Interval: parseInt(process.env[envMap.Interval] ?? '3600'), Interval: parseInt(process.env[envMap.Interval] ?? '3600'),
MinioEndpoint: process.env[envMap.MinioEndpoint], MinioEndpoint: process.env[envMap.MinioEndpoint],
MinioAccessKey: process.env[envMap.MinioAccessKey], MinioAccessKey: process.env[envMap.MinioAccessKey],
MinioSecretKey: process.env[envMap.MinioSecretKey], MinioSecretKey: process.env[envMap.MinioSecretKey]
ProductId: process.env[envMap.ProductId] ?? ''
} }
const missingEnv = required.filter((key) => params[key] === undefined).map((key) => envMap[key]) const missingEnv = required.filter((key) => params[key] === undefined).map((key) => envMap[key])

View File

@ -19,9 +19,21 @@ import { setMetadata } from '@hcengineering/platform'
import { backup, createMinioBackupStorage } from '@hcengineering/server-backup' import { backup, createMinioBackupStorage } from '@hcengineering/server-backup'
import serverToken from '@hcengineering/server-token' import serverToken from '@hcengineering/server-token'
import got from 'got' import got from 'got'
import { ObjectId } from 'mongodb'
import config from './config' import config from './config'
async function getWorkspaces (): Promise<string[]> { /**
* @public
*/
export interface Workspace {
_id: ObjectId
workspace: string
organisation: string
accounts: ObjectId[]
productId: string
}
async function getWorkspaces (): Promise<Workspace[]> {
const { body }: { body: { error?: string, result?: any[] } } = await got.post(config.AccountsURL, { const { body }: { body: { error?: string, result?: any[] } } = await got.post(config.AccountsURL, {
json: { json: {
method: 'listWorkspaces', method: 'listWorkspaces',
@ -34,7 +46,7 @@ async function getWorkspaces (): Promise<string[]> {
throw Error(body.error) throw Error(body.error)
} }
return (body.result ?? []).map((x) => x.workspace) return (body.result as Workspace[]) ?? []
} }
export class PlatformWorker { export class PlatformWorker {
@ -79,8 +91,12 @@ export class PlatformWorker {
for (const ws of workspaces) { for (const ws of workspaces) {
console.log('\n\nBACKUP WORKSPACE ', ws) console.log('\n\nBACKUP WORKSPACE ', ws)
try { try {
const storage = await createMinioBackupStorage(this.minio, getWorkspaceId('backups', config.ProductId), ws) const storage = await createMinioBackupStorage(
await backup(config.TransactorURL, getWorkspaceId(ws, config.ProductId), storage) this.minio,
getWorkspaceId('backups', ws.productId),
ws.workspace
)
await backup(config.TransactorURL, getWorkspaceId(ws.workspace, ws.productId), storage)
} catch (err: any) { } catch (err: any) {
console.error('\n\nFAILED to BACKUP', ws, err) console.error('\n\nFAILED to BACKUP', ws, err)
} }

View File

@ -377,7 +377,9 @@ export async function createAccount (
* @public * @public
*/ */
export async function listWorkspaces (db: Db, productId: string): Promise<Workspace[]> { export async function listWorkspaces (db: Db, productId: string): Promise<Workspace[]> {
return await db.collection<Workspace>(WORKSPACE_COLLECTION).find(withProductId(productId, {})).toArray() return (await db.collection<Workspace>(WORKSPACE_COLLECTION).find(withProductId(productId, {})).toArray()).map(
(it) => ({ ...it, productId })
)
} }
/** /**

View File

@ -326,7 +326,8 @@ export async function restore (
transactorUrl: string, transactorUrl: string,
workspaceId: WorkspaceId, workspaceId: WorkspaceId,
storage: BackupStorage, storage: BackupStorage,
date: number date: number,
merge?: boolean
): Promise<void> { ): Promise<void> {
const infoFile = 'backup.json.gz' const infoFile = 'backup.json.gz'
@ -357,6 +358,7 @@ export async function restore (
mode: 'backup', mode: 'backup',
model: 'upgrade' model: 'upgrade'
})) as unknown as CoreClient & BackupClient })) as unknown as CoreClient & BackupClient
try { try {
for (const c of domains) { for (const c of domains) {
console.log('loading server changeset for', c) console.log('loading server changeset for', c)
@ -514,7 +516,7 @@ export async function restore (
} }
await sendChunk(undefined, 0) await sendChunk(undefined, 0)
if (docsToRemove.length > 0) { if (docsToRemove.length > 0 && merge !== true) {
console.log('cleanup', docsToRemove.length) console.log('cleanup', docsToRemove.length)
await connection.clean(c, docsToRemove) await connection.clean(c, docsToRemove)
} }