113 lines
4.9 KiB
JavaScript
113 lines
4.9 KiB
JavaScript
'use strict';
|
|
|
|
const child_process = require('node:child_process'),
|
|
crypto = require('node:crypto'),
|
|
fs = require('node:fs'),
|
|
path = require('node:path'),
|
|
paths = require('../src/paths.js');
|
|
|
|
async function deleteOldSettings(db) {
|
|
await db.runSql('DELETE FROM settings WHERE name=? OR name=? OR name=?', [ 'backup_storage', 'backup_limits', 'backup_policy' ]);
|
|
}
|
|
|
|
exports.up = async function (db) {
|
|
const cmd = 'CREATE TABLE IF NOT EXISTS backupSites(' +
|
|
'id VARCHAR(128) NOT NULL UNIQUE,' +
|
|
'name VARCHAR(128) NOT NULL,' +
|
|
'provider VARCHAR(32) NOT NULL,' +
|
|
'configJson TEXT,' +
|
|
'limitsJson TEXT,' +
|
|
'retentionJson TEXT,' +
|
|
'encryptionJson TEXT,' +
|
|
'integrityKeyPairJson TEXT,' +
|
|
'format VARCHAR(16) NOT NULL,' +
|
|
'schedule VARCHAR(128),' +
|
|
'enableForUpdates BOOLEAN DEFAULT false,' +
|
|
'contentsJson TEXT,' +
|
|
'creationTime TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,' +
|
|
'ts TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,' +
|
|
'PRIMARY KEY (id)) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin';
|
|
|
|
await db.runSql(cmd);
|
|
|
|
const results = await db.runSql('SELECT name, value FROM settings WHERE name=? OR name=? OR name=?', [ 'backup_storage', 'backup_limits', 'backup_policy' ]);
|
|
|
|
const domainCountResults = await db.runSql('SELECT COUNT(*) AS total FROM domains');
|
|
if (domainCountResults[0].total === 0) {
|
|
console.log('This cloudron is not activated. Deleting the default backup config from 20171205124434-settings-default-backupConfig.js'); // will be added at provision time
|
|
await deleteOldSettings(db);
|
|
return;
|
|
}
|
|
|
|
const name = 'Default', enableForUpdates = true;
|
|
let config = null, limits = null, encryption = null, format = null, provider = null;
|
|
let retention = { keepWithinSecs: 2 * 24 * 60 * 60 };
|
|
let schedule = '00 00 23 * * *';
|
|
const integrityKeyPair = crypto.generateKeyPairSync('ed25519', {
|
|
publicKeyEncoding: { type: 'spki', format: 'pem' },
|
|
privateKeyEncoding: { type: 'pkcs8', format: 'pem' }
|
|
});
|
|
|
|
const id = crypto.randomUUID();
|
|
|
|
// convert existing configuration into a backup target
|
|
for (const r of results) {
|
|
if (r.name === 'backup_storage') {
|
|
const tmp = JSON.parse(r.value);
|
|
// provider is top level
|
|
provider = tmp.provider;
|
|
|
|
if (provider === 'noop') return await deleteOldSettings(db); // noop is migrated as 0 sites. user has to manually update with skipBackup
|
|
|
|
// the s3 and filesystem backend use the _provider internal property
|
|
if (provider !== 'gcs') tmp._provider = tmp.provider;
|
|
delete tmp.provider;
|
|
|
|
// backupFolder is now backupDir
|
|
if ('backupFolder' in tmp) {
|
|
tmp.backupDir = tmp.backupFolder;
|
|
delete tmp.backupFolder;
|
|
}
|
|
|
|
// encryption is not part of config anymore, it is top level
|
|
encryption = tmp.encryption || null;
|
|
delete tmp.encryption;
|
|
|
|
// format is not part of config anymore, it is top level
|
|
format = tmp.format;
|
|
delete tmp.format;
|
|
|
|
// previous releases only had a single "managed" mount at /mnt/cloudronbackup .
|
|
// new release has it under /mnt/managedbackups .
|
|
if (tmp.mountOptions) tmp._managedMountPath = '/mnt/cloudronbackup';
|
|
|
|
config = tmp;
|
|
} else if (r.name === 'backup_limits') {
|
|
limits = JSON.parse(r.value);
|
|
} else if (r.name === 'backup_policy') {
|
|
const tmp = JSON.parse(r.value);
|
|
retention = tmp.retention;
|
|
schedule = tmp.schedule;
|
|
}
|
|
}
|
|
|
|
const targetInfoDir = path.join(paths.BACKUP_INFO_DIR, id);
|
|
console.log(`Moving existing cache and snapshot file into ${targetInfoDir}`);
|
|
fs.mkdirSync(targetInfoDir, { recursive: true });
|
|
child_process.execSync(`find ${paths.BACKUP_INFO_DIR}/ -maxdepth 1 -type f -exec mv -t ${targetInfoDir}/ {} +`);
|
|
|
|
console.log(`Delete any existing rsync cache files since old one has no integrity information`);
|
|
child_process.execSync(`rm -f ${targetInfoDir}/*.cache`);
|
|
|
|
await db.runSql('START TRANSACTION');
|
|
await db.runSql('INSERT INTO backupSites (id, name, provider, configJson, limitsJson, integrityKeyPairJson, retentionJson, schedule, encryptionJson, format, enableForUpdates) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)',
|
|
[ id, name, provider, JSON.stringify(config), JSON.stringify(limits), JSON.stringify(integrityKeyPair), JSON.stringify(retention), schedule, encryption ? JSON.stringify(encryption) : null, format, enableForUpdates ]);
|
|
await deleteOldSettings(db);
|
|
await db.runSql('UPDATE tasks SET type=? WHERE type=?', [ `backup_${id}`, 'backup' ]); // migrate the tasks
|
|
await db.runSql('COMMIT');
|
|
};
|
|
|
|
exports.down = async function (db) {
|
|
await db.runSql('DROP TABLE backupSites');
|
|
};
|