@neo-one/node-data-backup
Version:
NEO•ONE node data path backup and restore.
117 lines (115 loc) • 21.1 kB
JavaScript
;
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=