From b7912f7345e1de66d5458b79101c29efff282112 Mon Sep 17 00:00:00 2001 From: kenji suzuki <41730006+suzulabo@users.noreply.github.com> Date: Tue, 4 Jan 2022 12:58:06 +0900 Subject: [PATCH] Firestore backup (#57) --- scripts/index.ts | 3 ++- src/functions/index.ts | 8 ++++++++ src/functions/pubsub/backup-firestore.ts | 26 ++++++++++++++++++++++++ src/shared/appenv.ts | 13 ++++++++---- 4 files changed, 45 insertions(+), 5 deletions(-) create mode 100644 src/functions/pubsub/backup-firestore.ts diff --git a/scripts/index.ts b/scripts/index.ts index 02b68f9..4c16f9b 100644 --- a/scripts/index.ts +++ b/scripts/index.ts @@ -24,6 +24,7 @@ const entries: ScriptEntries = [ ], ['firebase.start', RunP(['functions.build.watch', 'firebase.serve'])], ['firebase.docs', Cmd('docsify serve docs', 'firebase')], + ['firebase.shell', Cmd('firebase functions:shell', 'firebase')], [ 'firebase.build', @@ -74,7 +75,7 @@ const entries: ScriptEntries = [ // secrets ['secrets.copy', secrets.copy], - ['secrets.pack', secrets.pack], + ['secrets.pack', RunS([secrets.pack, Cmd('git commit -a -m "Update"', 'secrets')])], ['secrets.unpack', secrets.unpack], // dev-proxy diff --git a/src/functions/index.ts b/src/functions/index.ts index 7405766..58866fe 100644 --- a/src/functions/index.ts +++ b/src/functions/index.ts @@ -10,6 +10,7 @@ import { immediateNotificationWriteHandler, } from './firestore'; import { httpsRequestHandler } from './https'; +import { pubsubBackupFirestore } from './pubsub/backup-firestore'; import { pubsubExternalAnnounceFetch } from './pubsub/external-announce-fetch'; import { pubsubSendNotification } from './pubsub/send-notification'; @@ -57,4 +58,11 @@ export const pubsub = { await pubsubExternalAnnounceFetch(msg, context, adminApp); return 0; }), + backupFirestore: region.pubsub + .schedule(appEnv.firestoreBackup.schedule) + .timeZone(appEnv.firestoreBackup.timeZone) + .onRun(async context => { + await pubsubBackupFirestore(context, adminApp); + return 0; + }), }; diff --git a/src/functions/pubsub/backup-firestore.ts b/src/functions/pubsub/backup-firestore.ts new file mode 100644 index 0000000..e1e73d8 --- /dev/null +++ b/src/functions/pubsub/backup-firestore.ts @@ -0,0 +1,26 @@ +import admin from 'firebase-admin'; +import { AppEnv, AppError } from '../../shared'; +import { EventContext, FirebaseAdminApp } from '../firebase'; +import { logger } from '../utils/logger'; + +const appEnv = new AppEnv().env; + +export const pubsubBackupFirestore = async (_context: EventContext, adminApp: FirebaseAdminApp) => { + const projectID = adminApp.options.projectId; + if (!projectID) { + throw new AppError('missing projectID'); + } + + const prefix = appEnv.firestoreBackup.bucketPrefix(); + + const client = new admin.firestore.v1.FirestoreAdminClient(); + const databaseName = client.databasePath(projectID, '(default)'); + + logger.info('exportDocuments', { prefix }); + + return client.exportDocuments({ + name: databaseName, + outputUriPrefix: prefix, + collectionIds: [], + }); +}; diff --git a/src/shared/appenv.ts b/src/shared/appenv.ts index b6b5454..41fa660 100644 --- a/src/shared/appenv.ts +++ b/src/shared/appenv.ts @@ -1,7 +1,7 @@ import { _appEnv } from '../../secrets/appenv.env'; interface AppEnvironment { - firebaseConfig: { + readonly firebaseConfig: { readonly apiKey: string; readonly authDomain: string; readonly projectId: string; @@ -9,13 +9,18 @@ interface AppEnvironment { readonly messagingSenderId: string; readonly appId: string; }; + readonly firestoreBackup: { + readonly bucketPrefix: () => string; + readonly schedule: string; + readonly timeZone: string; + }; readonly functionsRegion: string; readonly vapidKey: string; readonly contact: string; sites: { - console: string; - client: string; - docs: string; + readonly console: string; + readonly client: string; + readonly docs: string; }; }