apps: backup is not a state anymore
this is launched as a separate task
This commit is contained in:
+29
-32
@@ -2,10 +2,10 @@
|
||||
|
||||
exports = module.exports = {
|
||||
fullBackup,
|
||||
appBackup,
|
||||
|
||||
restore,
|
||||
|
||||
backupApp,
|
||||
downloadApp,
|
||||
|
||||
backupMail,
|
||||
@@ -34,20 +34,6 @@ const apps = require('./apps.js'),
|
||||
|
||||
const BACKUP_UPLOAD_CMD = path.join(__dirname, 'scripts/backupupload.js');
|
||||
|
||||
function canBackupApp(app) {
|
||||
// only backup apps that are installed or specific pending states
|
||||
|
||||
// stopped apps cannot be backed up because addons might be down (redis)
|
||||
if (app.runState === apps.RSTATE_STOPPED) return false;
|
||||
|
||||
// we used to check the health here but that doesn't work for stopped apps. it's better to just fail
|
||||
// and inform the user if the backup fails and the app addons have not been setup yet.
|
||||
return app.installationState === apps.ISTATE_INSTALLED ||
|
||||
app.installationState === apps.ISTATE_PENDING_CONFIGURE ||
|
||||
app.installationState === apps.ISTATE_PENDING_BACKUP || // called from apptask
|
||||
app.installationState === apps.ISTATE_PENDING_UPDATE; // called from apptask
|
||||
}
|
||||
|
||||
async function checkPreconditions(backupConfig, dataLayout) {
|
||||
assert.strictEqual(typeof backupConfig, 'object');
|
||||
assert(dataLayout instanceof DataLayout, 'dataLayout must be a DataLayout');
|
||||
@@ -316,20 +302,6 @@ async function rotateAppBackup(backupConfig, app, tag, options, progressCallback
|
||||
return id;
|
||||
}
|
||||
|
||||
async function backupApp(app, options, progressCallback) {
|
||||
assert.strictEqual(typeof app, 'object');
|
||||
assert.strictEqual(typeof options, 'object');
|
||||
assert.strictEqual(typeof progressCallback, 'function');
|
||||
|
||||
if (options.snapshotOnly) return await snapshotApp(app, progressCallback);
|
||||
|
||||
const tag = (new Date()).toISOString().replace(/[T.]/g, '-').replace(/[:Z]/g,'');
|
||||
|
||||
debug(`backupApp: backing up ${app.fqdn} with tag ${tag}`);
|
||||
|
||||
return await backupAppWithTag(app, tag, options, progressCallback);
|
||||
}
|
||||
|
||||
async function snapshotApp(app, progressCallback) {
|
||||
assert.strictEqual(typeof app, 'object');
|
||||
assert.strictEqual(typeof progressCallback, 'function');
|
||||
@@ -380,7 +352,7 @@ async function backupAppWithTag(app, tag, options, progressCallback) {
|
||||
assert.strictEqual(typeof options, 'object');
|
||||
assert.strictEqual(typeof progressCallback, 'function');
|
||||
|
||||
if (!canBackupApp(app)) { // if we cannot backup, reuse it's most recent backup
|
||||
if (!apps.canBackupApp(app)) { // if we cannot backup, reuse it's most recent backup
|
||||
const results = await backups.getByIdentifierAndStatePaged(app.id, backups.BACKUP_STATE_NORMAL, 1, 1);
|
||||
if (results.length === 0) return null; // no backup to re-use
|
||||
|
||||
@@ -510,11 +482,11 @@ async function fullBackup(options, progressCallback) {
|
||||
}
|
||||
|
||||
progressCallback({ percent, message: `Backing up ${app.fqdn} (${i+1}/${allApps.length}). Waiting for lock` });
|
||||
await locks.wait(`${locks.TYPE_APP_TASK_PREFIX}${app.id}`);
|
||||
await locks.wait(`${locks.TYPE_APP_BACKUP_PREFIX}${app.id}`);
|
||||
const startTime = new Date();
|
||||
const [appBackupError, appBackupId] = await safe(backupAppWithTag(app, tag, options, (progress) => progressCallback({ percent, message: progress.message })));
|
||||
debug(`fullBackup: app ${app.fqdn} backup finished. Took ${(new Date() - startTime)/1000} seconds`);
|
||||
await locks.release(`${locks.TYPE_APP_TASK_PREFIX}${app.id}`);
|
||||
await locks.release(`${locks.TYPE_APP_BACKUP_PREFIX}${app.id}`);
|
||||
if (appBackupError) throw appBackupError;
|
||||
if (appBackupId) appBackupIds.push(appBackupId); // backupId can be null if in BAD_STATE and never backed up
|
||||
}
|
||||
@@ -530,3 +502,28 @@ async function fullBackup(options, progressCallback) {
|
||||
const backupId = await backupBox(dependsOn, tag, options, (progress) => progressCallback({ percent, message: progress.message }));
|
||||
return backupId;
|
||||
}
|
||||
|
||||
// this function is called from external process
|
||||
async function appBackup(appId, options, progressCallback) {
|
||||
assert.strictEqual(typeof appId, 'string');
|
||||
assert.strictEqual(typeof options, 'object');
|
||||
assert.strictEqual(typeof progressCallback, 'function');
|
||||
|
||||
const app = await apps.get(appId);
|
||||
if (!app) throw new BoxError(BoxError.BAD_FIELD, 'App not found');
|
||||
|
||||
let backupId = null;
|
||||
await progressCallback({ percent: 1, message: `Backing up ${app.fqdn}. Waiting for lock` });
|
||||
await locks.wait(`${locks.TYPE_APP_BACKUP_PREFIX}${app.id}`);
|
||||
const startTime = new Date();
|
||||
if (options.snapshotOnly) {
|
||||
await snapshotApp(app, progressCallback);
|
||||
} else {
|
||||
const tag = (new Date()).toISOString().replace(/[T.]/g, '-').replace(/[:Z]/g,'');
|
||||
backupId = await backupAppWithTag(app, tag, options, progressCallback);
|
||||
}
|
||||
await locks.release(`${locks.TYPE_APP_BACKUP_PREFIX}${app.id}`);
|
||||
|
||||
await progressCallback({ percent: 100, message: `app ${app.fqdn} backup finished. Took ${(new Date() - startTime)/1000} seconds` });
|
||||
return backupId;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user