mostly because code is being autogenerated by all the AI stuff using this prefix. it's also used in the stack trace.
105 lines
4.6 KiB
JavaScript
105 lines
4.6 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');
|
|
|
|
exports.up = async function (db) {
|
|
const cmd = 'CREATE TABLE IF NOT EXISTS backupTargets(' +
|
|
'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),' +
|
|
'main BOOLEAN DEFAULT false,' +
|
|
'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 db.runSql('DELETE FROM settings WHERE name=? OR name=? OR name=?', [ 'backup_storage', 'backup_limits', 'backup_policy']);
|
|
return;
|
|
}
|
|
|
|
const name = 'Default', main = 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 = `bc-${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;
|
|
|
|
// the s3 and filesystem backend use the _provider internal property
|
|
if (provider !== 'gcs' && provider !== 'noop') 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 backupTargets (id, name, provider, configJson, limitsJson, integrityKeyPairJson, retentionJson, schedule, encryptionJson, format, main) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)',
|
|
[ id, name, provider, JSON.stringify(config), JSON.stringify(limits), JSON.stringify(integrityKeyPair), JSON.stringify(retention), schedule, JSON.stringify(encryption), format, main ]);
|
|
await db.runSql('DELETE FROM settings WHERE name=? OR name=? OR name=?', [ 'backup_storage', 'backup_limits', 'backup_policy' ]);
|
|
await db.runSql('COMMIT');
|
|
};
|
|
|
|
exports.down = async function (db) {
|
|
await db.runSql('DROP TABLE backupTargets');
|
|
};
|