UNPKG

@neo-one/node-data-backup

Version:

NEO•ONE node data path backup and restore.

117 lines (115 loc) 21.1 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const tslib_1 = require("tslib"); const fs = tslib_1.__importStar(require("fs-extra")); const path = tslib_1.__importStar(require("path")); const extract_1 = require("./extract"); const Provider_1 = require("./Provider"); const upload_1 = require("./upload"); const METADATA_NAME = 'metadata'; const MAX_SIZE = 1000000000; const KEEP_BACKUP_COUNT = 10; const extractTime = (prefix, file) => parseInt(file.name.slice(prefix.length).split('/')[1], 10); class GCloudProvider extends Provider_1.Provider { constructor({ environment, options }) { super(); this.environment = environment; this.options = options; } async canRestore() { const { time } = await this.getLatestTime(); return time !== undefined; } async restore(monitorIn) { const monitor = monitorIn.at('gcloud_provider'); const { prefix } = this.options; const { dataPath, tmpPath } = this.environment; const { time, files } = await this.getLatestTime(); if (time === undefined) { throw new Error('Cannot restore'); } const filePrefix = [prefix, time].join('/'); const fileAndPaths = files .filter((file) => file.name.startsWith(filePrefix) && path.basename(file.name) !== METADATA_NAME) .map((file) => ({ file, filePath: path.resolve(tmpPath, path.basename(file.name)), })); for (const { file, filePath } of fileAndPaths) { await monitor .withData({ filePath }) .captureSpanLog(async () => file.download({ destination: filePath, validation: true }), { name: 'neo_restore_download', }); } await Promise.all(fileAndPaths.map(async ({ filePath }) => monitor.withData({ filePath }).captureSpanLog(async () => extract_1.extract({ downloadPath: filePath, dataPath, }), { name: 'neo_restore_extract' }))); } async backup(monitorIn) { const monitor = monitorIn.at('gcloud_provider'); const { bucket, prefix, keepBackupCount = KEEP_BACKUP_COUNT, maxSizeBytes = MAX_SIZE } = this.options; const { dataPath } = this.environment; const files = await fs.readdir(dataPath); const fileAndStats = await Promise.all(files.map(async (file) => { const stat = await fs.stat(path.resolve(dataPath, file)); return { file, stat }; })); const mutableFileLists = []; let mutableCurrentFileList = []; let currentSize = 0; for (const { file, stat } of fileAndStats) { if (currentSize > maxSizeBytes) { mutableFileLists.push(mutableCurrentFileList); mutableCurrentFileList = []; currentSize = 0; } mutableCurrentFileList.push(file); currentSize += stat.size; } if (mutableCurrentFileList.length > 0) { mutableFileLists.push(mutableCurrentFileList); } const storage = await this.getStorage(); const time = Math.round(Date.now() / 1000); for (const [idx, fileList] of mutableFileLists.entries()) { await monitor.withData({ part: idx }).captureSpanLog(async () => upload_1.upload({ dataPath, write: storage .bucket(bucket) .file([prefix, `${time}`, `storage_part_${idx}.db.tar.gz`].join('/')) .createWriteStream({ validation: true }), fileList, }), { name: 'neo_backup_push' }); } await monitor.captureSpanLog(async () => storage .bucket(bucket) .file([prefix, `${time}`, METADATA_NAME].join('/')) .save('', undefined), { name: 'neo_backup_push' }); const [fileNames] = await monitor.captureSpanLog(async () => storage.bucket(bucket).getFiles({ prefix }), { name: 'neo_backup_list_files', }); const times = [...new Set(fileNames.map((file) => extractTime(prefix, file)))]; times.sort(); const deleteTimes = times.slice(0, -keepBackupCount); await monitor.captureSpanLog(async () => Promise.all(deleteTimes.map(async (deleteTime) => storage.bucket(bucket).deleteFiles({ prefix: [prefix, `${deleteTime}`].join('/') }))), { name: 'neo_backup_delete_old' }); } async getLatestTime() { const { bucket, prefix } = this.options; const storage = await this.getStorage(); const [files] = (await storage.bucket(bucket).getFiles({ prefix })); const metadataTimes = files .filter((file) => path.basename(file.name) === METADATA_NAME) .map((file) => extractTime(prefix, file)); metadataTimes.sort(); const time = metadataTimes[metadataTimes.length - 1]; return { time, files }; } async getStorage() { const storage = await Promise.resolve().then(() => tslib_1.__importStar(require('@google-cloud/storage'))); return new storage.Storage({ projectId: this.options.projectID }); } } exports.GCloudProvider = GCloudProvider; //# sourceMappingURL=data:application/json;charset=utf8;base64,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QyIsImZpbGUiOiJuZW8tb25lLW5vZGUtZGF0YS1iYWNrdXAvc3JjL3Byb3ZpZGVyL0dDbG91ZFByb3ZpZGVyLmpzIiwic291cmNlc0NvbnRlbnQiOlsiLy8gdHNsaW50OmRpc2FibGUtbmV4dC1saW5lOm5vLXN1Ym1vZHVsZS1pbXBvcnRzXG5pbXBvcnQgeyBGaWxlIH0gZnJvbSAnQGdvb2dsZS1jbG91ZC9zdG9yYWdlL2J1aWxkL3NyYy9maWxlJztcbmltcG9ydCB7IE1vbml0b3IgfSBmcm9tICdAbmVvLW9uZS9tb25pdG9yJztcbmltcG9ydCAqIGFzIGZzIGZyb20gJ2ZzLWV4dHJhJztcbmltcG9ydCAqIGFzIHBhdGggZnJvbSAncGF0aCc7XG5pbXBvcnQgeyBFbnZpcm9ubWVudCB9IGZyb20gJy4uL3R5cGVzJztcbmltcG9ydCB7IGV4dHJhY3QgfSBmcm9tICcuL2V4dHJhY3QnO1xuaW1wb3J0IHsgUHJvdmlkZXIgfSBmcm9tICcuL1Byb3ZpZGVyJztcbmltcG9ydCB7IHVwbG9hZCB9IGZyb20gJy4vdXBsb2FkJztcblxuZXhwb3J0IGludGVyZmFjZSBPcHRpb25zIHtcbiAgcmVhZG9ubHkgcHJvamVjdElEOiBzdHJpbmc7XG4gIHJlYWRvbmx5IGJ1Y2tldDogc3RyaW5nO1xuICByZWFkb25seSBwcmVmaXg6IHN0cmluZztcbiAgcmVhZG9ubHkga2VlcEJhY2t1cENvdW50PzogbnVtYmVyO1xuICByZWFkb25seSBtYXhTaXplQnl0ZXM/OiBudW1iZXI7XG59XG5cbmNvbnN0IE1FVEFEQVRBX05BTUUgPSAnbWV0YWRhdGEnO1xuY29uc3QgTUFYX1NJWkUgPSAxXzAwMF8wMDBfMDAwO1xuY29uc3QgS0VFUF9CQUNLVVBfQ09VTlQgPSAxMDtcblxuY29uc3QgZXh0cmFjdFRpbWUgPSAocHJlZml4OiBzdHJpbmcsIGZpbGU6IEZpbGUpID0+IHBhcnNlSW50KGZpbGUubmFtZS5zbGljZShwcmVmaXgubGVuZ3RoKS5zcGxpdCgnLycpWzFdLCAxMCk7XG5cbmV4cG9ydCBjbGFzcyBHQ2xvdWRQcm92aWRlciBleHRlbmRzIFByb3ZpZGVyIHtcbiAgcHJpdmF0ZSByZWFkb25seSBlbnZpcm9ubWVudDogRW52aXJvbm1lbnQ7XG4gIHByaXZhdGUgcmVhZG9ubHkgb3B0aW9uczogT3B0aW9ucztcblxuICBwdWJsaWMgY29uc3RydWN0b3IoeyBlbnZpcm9ubWVudCwgb3B0aW9ucyB9OiB7IHJlYWRvbmx5IGVudmlyb25tZW50OiBFbnZpcm9ubWVudDsgcmVhZG9ubHkgb3B0aW9uczogT3B0aW9ucyB9KSB7XG4gICAgc3VwZXIoKTtcbiAgICB0aGlzLmVudmlyb25tZW50ID0gZW52aXJvbm1lbnQ7XG4gICAgdGhpcy5vcHRpb25zID0gb3B0aW9ucztcbiAgfVxuXG4gIHB1YmxpYyBhc3luYyBjYW5SZXN0b3JlKCk6IFByb21pc2U8Ym9vbGVhbj4ge1xuICAgIGNvbnN0IHsgdGltZSB9ID0gYXdhaXQgdGhpcy5nZXRMYXRlc3RUaW1lKCk7XG5cbiAgICByZXR1cm4gdGltZSAhPT0gdW5kZWZpbmVkO1xuICB9XG5cbiAgcHVibGljIGFzeW5jIHJlc3RvcmUobW9uaXRvckluOiBNb25pdG9yKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgY29uc3QgbW9uaXRvciA9IG1vbml0b3JJbi5hdCgnZ2Nsb3VkX3Byb3ZpZGVyJyk7XG4gICAgY29uc3QgeyBwcmVmaXggfSA9IHRoaXMub3B0aW9ucztcbiAgICBjb25zdCB7IGRhdGFQYXRoLCB0bXBQYXRoIH0gPSB0aGlzLmVudmlyb25tZW50O1xuXG4gICAgY29uc3QgeyB0aW1lLCBmaWxlcyB9ID0gYXdhaXQgdGhpcy5nZXRMYXRlc3RUaW1lKCk7XG4gICAgaWYgKHRpbWUgPT09IHVuZGVmaW5lZCkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdDYW5ub3QgcmVzdG9yZScpO1xuICAgIH1cblxuICAgIGNvbnN0IGZpbGVQcmVmaXggPSBbcHJlZml4LCB0aW1lXS5qb2luKCcvJyk7XG4gICAgY29uc3QgZmlsZUFuZFBhdGhzID0gZmlsZXNcbiAgICAgIC5maWx0ZXIoKGZpbGUpID0+IGZpbGUubmFtZS5zdGFydHNXaXRoKGZpbGVQcmVmaXgpICYmIHBhdGguYmFzZW5hbWUoZmlsZS5uYW1lKSAhPT0gTUVUQURBVEFfTkFNRSlcbiAgICAgIC5tYXAoKGZpbGUpID0+ICh7XG4gICAgICAgIGZpbGUsXG4gICAgICAgIGZpbGVQYXRoOiBwYXRoLnJlc29sdmUodG1wUGF0aCwgcGF0aC5iYXNlbmFtZShmaWxlLm5hbWUpKSxcbiAgICAgIH0pKTtcblxuICAgIC8vIHRzbGludDpkaXNhYmxlLW5leHQtbGluZSBuby1sb29wLXN0YXRlbWVudFxuICAgIGZvciAoY29uc3QgeyBmaWxlLCBmaWxlUGF0aCB9IG9mIGZpbGVBbmRQYXRocykge1xuICAgICAgYXdhaXQgbW9uaXRvclxuICAgICAgICAud2l0aERhdGEoeyBmaWxlUGF0aCB9KVxuICAgICAgICAuY2FwdHVyZVNwYW5Mb2coYXN5bmMgKCkgPT4gZmlsZS5kb3dubG9hZCh7IGRlc3RpbmF0aW9uOiBmaWxlUGF0aCwgdmFsaWRhdGlvbjogdHJ1ZSB9KSwge1xuICAgICAgICAgIG5hbWU6ICduZW9fcmVzdG9yZV9kb3dubG9hZCcsXG4gICAgICAgIH0pO1xuICAgIH1cbiAgICBhd2FpdCBQcm9taXNlLmFsbChcbiAgICAgIGZpbGVBbmRQYXRocy5tYXAoYXN5bmMgKHsgZmlsZVBhdGggfSkgPT5cbiAgICAgICAgbW9uaXRvci53aXRoRGF0YSh7IGZpbGVQYXRoIH0pLmNhcHR1cmVTcGFuTG9nKFxuICAgICAgICAgIGFzeW5jICgpID0+XG4gICAgICAgICAgICBleHRyYWN0KHtcbiAgICAgICAgICAgICAgZG93bmxvYWRQYXRoOiBmaWxlUGF0aCxcbiAgICAgICAgICAgICAgZGF0YVBhdGgsXG4gICAgICAgICAgICB9KSxcbiAgICAgICAgICB7IG5hbWU6ICduZW9fcmVzdG9yZV9leHRyYWN0JyB9LFxuICAgICAgICApLFxuICAgICAgKSxcbiAgICApO1xuICB9XG5cbiAgcHVibGljIGFzeW5jIGJhY2t1cChtb25pdG9ySW46IE1vbml0b3IpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBjb25zdCBtb25pdG9yID0gbW9uaXRvckluLmF0KCdnY2xvdWRfcHJvdmlkZXInKTtcbiAgICBjb25zdCB7IGJ1Y2tldCwgcHJlZml4LCBrZWVwQmFja3VwQ291bnQgPSBLRUVQX0JBQ0tVUF9DT1VOVCwgbWF4U2l6ZUJ5dGVzID0gTUFYX1NJWkUgfSA9IHRoaXMub3B0aW9ucztcbiAgICBjb25zdCB7IGRhdGFQYXRoIH0gPSB0aGlzLmVudmlyb25tZW50O1xuXG4gICAgY29uc3QgZmlsZXMgPSBhd2FpdCBmcy5yZWFkZGlyKGRhdGFQYXRoKTtcbiAgICBjb25zdCBmaWxlQW5kU3RhdHMgPSBhd2FpdCBQcm9taXNlLmFsbChcbiAgICAgIGZpbGVzLm1hcChhc3luYyAoZmlsZSkgPT4ge1xuICAgICAgICBjb25zdCBzdGF0ID0gYXdhaXQgZnMuc3RhdChwYXRoLnJlc29sdmUoZGF0YVBhdGgsIGZpbGUpKTtcblxuICAgICAgICByZXR1cm4geyBmaWxlLCBzdGF0IH07XG4gICAgICB9KSxcbiAgICApO1xuXG4gICAgY29uc3QgbXV0YWJsZUZpbGVMaXN0cyA9IFtdO1xuICAgIGxldCBtdXRhYmxlQ3VycmVudEZpbGVMaXN0ID0gW107XG4gICAgbGV0IGN1cnJlbnRTaXplID0gMDtcbiAgICAvLyB0c2xpbnQ6ZGlzYWJsZS1uZXh0LWxpbmUgbm8tbG9vcC1zdGF0ZW1lbnRcbiAgICBmb3IgKGNvbnN0IHsgZmlsZSwgc3RhdCB9IG9mIGZpbGVBbmRTdGF0cykge1xuICAgICAgaWYgKGN1cnJlbnRTaXplID4gbWF4U2l6ZUJ5dGVzKSB7XG4gICAgICAgIG11dGFibGVGaWxlTGlzdHMucHVzaChtdXRhYmxlQ3VycmVudEZpbGVMaXN0KTtcbiAgICAgICAgbXV0YWJsZUN1cnJlbnRGaWxlTGlzdCA9IFtdO1xuICAgICAgICBjdXJyZW50U2l6ZSA9IDA7XG4gICAgICB9XG5cbiAgICAgIG11dGFibGVDdXJyZW50RmlsZUxpc3QucHVzaChmaWxlKTtcbiAgICAgIGN1cnJlbnRTaXplICs9IHN0YXQuc2l6ZTtcbiAgICB9XG5cbiAgICBpZiAobXV0YWJsZUN1cnJlbnRGaWxlTGlzdC5sZW5ndGggPiAwKSB7XG4gICAgICBtdXRhYmxlRmlsZUxpc3RzLnB1c2gobXV0YWJsZUN1cnJlbnRGaWxlTGlzdCk7XG4gICAgfVxuXG4gICAgY29uc3Qgc3RvcmFnZSA9IGF3YWl0IHRoaXMuZ2V0U3RvcmFnZSgpO1xuICAgIGNvbnN0IHRpbWUgPSBNYXRoLnJvdW5kKERhdGUubm93KCkgLyAxMDAwKTtcbiAgICAvLyB0c2xpbnQ6ZGlzYWJsZS1uZXh0LWxpbmUgbm8tbG9vcC1zdGF0ZW1lbnRcbiAgICBmb3IgKGNvbnN0IFtpZHgsIGZpbGVMaXN0XSBvZiBtdXRhYmxlRmlsZUxpc3RzLmVudHJpZXMoKSkge1xuICAgICAgYXdhaXQgbW9uaXRvci53aXRoRGF0YSh7IHBhcnQ6IGlkeCB9KS5jYXB0dXJlU3BhbkxvZyhcbiAgICAgICAgYXN5bmMgKCkgPT5cbiAgICAgICAgICB1cGxvYWQoe1xuICAgICAgICAgICAgZGF0YVBhdGgsXG4gICAgICAgICAgICB3cml0ZTogc3RvcmFnZVxuICAgICAgICAgICAgICAuYnVja2V0KGJ1Y2tldClcbiAgICAgICAgICAgICAgLmZpbGUoW3ByZWZpeCwgYCR7dGltZX1gLCBgc3RvcmFnZV9wYXJ0XyR7aWR4fS5kYi50YXIuZ3pgXS5qb2luKCcvJykpXG4gICAgICAgICAgICAgIC5jcmVhdGVXcml0ZVN0cmVhbSh7IHZhbGlkYXRpb246IHRydWUgfSksXG4gICAgICAgICAgICBmaWxlTGlzdCxcbiAgICAgICAgICB9KSxcbiAgICAgICAgeyBuYW1lOiAnbmVvX2JhY2t1cF9wdXNoJyB9LFxuICAgICAgKTtcbiAgICB9XG5cbiAgICBhd2FpdCBtb25pdG9yLmNhcHR1cmVTcGFuTG9nPFByb21pc2U8dm9pZD4+KFxuICAgICAgYXN5bmMgKCkgPT5cbiAgICAgICAgc3RvcmFnZVxuICAgICAgICAgIC5idWNrZXQoYnVja2V0KVxuICAgICAgICAgIC5maWxlKFtwcmVmaXgsIGAke3RpbWV9YCwgTUVUQURBVEFfTkFNRV0uam9pbignLycpKVxuICAgICAgICAgIC5zYXZlKCcnLCB1bmRlZmluZWQpLFxuICAgICAgeyBuYW1lOiAnbmVvX2JhY2t1cF9wdXNoJyB9LFxuICAgICk7XG5cbiAgICBjb25zdCBbZmlsZU5hbWVzXSA9IGF3YWl0IG1vbml0b3IuY2FwdHVyZVNwYW5Mb2coXG4gICAgICAvLyB0c2xpbnQ6ZGlzYWJsZS1uZXh0LWxpbmUgbm8tYW55IG5vLXZvaWQtZXhwcmVzc2lvbiBuby11c2Utb2YtZW1wdHktcmV0dXJuLXZhbHVlXG4gICAgICBhc3luYyAoKSA9PiAoc3RvcmFnZS5idWNrZXQoYnVja2V0KS5nZXRGaWxlcyh7IHByZWZpeCB9KSBhcyBhbnkpIGFzIFByb21pc2U8W0ZpbGVbXV0+LFxuICAgICAge1xuICAgICAgICBuYW1lOiAnbmVvX2JhY2t1cF9saXN0X2ZpbGVzJyxcbiAgICAgIH0sXG4gICAgKTtcbiAgICBjb25zdCB0aW1lcyA9IFsuLi5uZXcgU2V0KGZpbGVOYW1lcy5tYXAoKGZpbGUpID0+IGV4dHJhY3RUaW1lKHByZWZpeCwgZmlsZSkpKV07XG4gICAgLy8gdHNsaW50OmRpc2FibGUtbmV4dC1saW5lIG5vLWFycmF5LW11dGF0aW9uXG4gICAgdGltZXMuc29ydCgpO1xuXG4gICAgY29uc3QgZGVsZXRlVGltZXMgPSB0aW1lcy5zbGljZSgwLCAta2VlcEJhY2t1cENvdW50KTtcbiAgICBhd2FpdCBtb25pdG9yLmNhcHR1cmVTcGFuTG9nPFByb21pc2U8dm9pZFtdPj4oXG4gICAgICBhc3luYyAoKSA9PlxuICAgICAgICBQcm9taXNlLmFsbChcbiAgICAgICAgICBkZWxldGVUaW1lcy5tYXAoYXN5bmMgKGRlbGV0ZVRpbWUpID0+XG4gICAgICAgICAgICBzdG9yYWdlLmJ1Y2tldChidWNrZXQpLmRlbGV0ZUZpbGVzKHsgcHJlZml4OiBbcHJlZml4LCBgJHtkZWxldGVUaW1lfWBdLmpvaW4oJy8nKSB9KSxcbiAgICAgICAgICApLFxuICAgICAgICApLFxuICAgICAgeyBuYW1lOiAnbmVvX2JhY2t1cF9kZWxldGVfb2xkJyB9LFxuICAgICk7XG4gIH1cblxuICBwcml2YXRlIGFzeW5jIGdldExhdGVzdFRpbWUoKTogUHJvbWlzZTx7XG4gICAgcmVhZG9ubHkgdGltZTogbnVtYmVyIHwgdW5kZWZpbmVkO1xuICAgIHJlYWRvbmx5IGZpbGVzOiByZWFkb25seSBGaWxlW107XG4gIH0+IHtcbiAgICBjb25zdCB7IGJ1Y2tldCwgcHJlZml4IH0gPSB0aGlzLm9wdGlvbnM7XG5cbiAgICBjb25zdCBzdG9yYWdlID0gYXdhaXQgdGhpcy5nZXRTdG9yYWdlKCk7XG4gICAgLy8gdHNsaW50OmRpc2FibGUtbmV4dC1saW5lIG5vLWFueSBuby12b2lkLWV4cHJlc3Npb24gbm8tdXNlLW9mLWVtcHR5LXJldHVybi12YWx1ZVxuICAgIGNvbnN0IFtmaWxlc10gPSAoYXdhaXQgKHN0b3JhZ2UuYnVja2V0KGJ1Y2tldCkuZ2V0RmlsZXMoeyBwcmVmaXggfSkgYXMgYW55KSkgYXMgW0ZpbGVbXV07XG5cbiAgICBjb25zdCBtZXRhZGF0YVRpbWVzID0gZmlsZXNcbiAgICAgIC5maWx0ZXIoKGZpbGUpID0+IHBhdGguYmFzZW5hbWUoZmlsZS5uYW1lKSA9PT0gTUVUQURBVEFfTkFNRSlcbiAgICAgIC5tYXAoKGZpbGUpID0+IGV4dHJhY3RUaW1lKHByZWZpeCwgZmlsZSkpO1xuICAgIC8vIHRzbGludDpkaXNhYmxlLW5leHQtbGluZSBuby1hcnJheS1tdXRhdGlvblxuICAgIG1ldGFkYXRhVGltZXMuc29ydCgpO1xuXG4gICAgY29uc3QgdGltZSA9IG1ldGFkYXRhVGltZXNbbWV0YWRhdGFUaW1lcy5sZW5ndGggLSAxXSBhcyBudW1iZXIgfCB1bmRlZmluZWQ7XG5cbiAgICByZXR1cm4geyB0aW1lLCBmaWxlcyB9O1xuICB9XG5cbiAgcHJpdmF0ZSBhc3luYyBnZXRTdG9yYWdlKCkge1xuICAgIGNvbnN0IHN0b3JhZ2UgPSBhd2FpdCBpbXBvcnQoJ0Bnb29nbGUtY2xvdWQvc3RvcmFnZScpO1xuXG4gICAgLy8gdHNsaW50OmRpc2FibGUtbmV4dC1saW5lIG5vLWFueVxuICAgIHJldHVybiBuZXcgc3RvcmFnZS5TdG9yYWdlKHsgcHJvamVjdElkOiB0aGlzLm9wdGlvbnMucHJvamVjdElEIH0pO1xuICB9XG59XG4iXX0=