Improved MongoDB autobackup and error handling.

Ylian Saint-Hilaire committed Dec 28, 2020 at 19:25 UTC cce68922d798b892a517407e0139724ab7e9e03b
2 files changed +37 -4
db.js
+34 -4
@@ -1329,6 +1329,30 @@ module.exports.CreateDB = function (parent, func) {
1329 return r;
1330 }
1331
1332 + // Check that the server is capable of performing a backup
1333 + obj.checkBackupCapability = function (func) {
1334 + if ((obj.databaseType == 2) || (obj.databaseType == 3)) {
1335 + // Check that we have access to MongoDump
1336 + var backupPath = parent.backuppath;
1337 + if (parent.config.settings.autobackup && parent.config.settings.autobackup.backuppath) { backupPath = parent.config.settings.autobackup.backuppath; }
1338 + var mongoDumpPath = 'mongodump';
1339 + if (parent.config.settings.autobackup && parent.config.settings.autobackup.mongodumppath) { mongoDumpPath = parent.config.settings.autobackup.mongodumppath; }
1340 + const child_process = require('child_process');
1341 + child_process.exec('"' + mongoDumpPath + '"', { cwd: backupPath }, function (error, stdout, stderr) {
1342 + try {
1343 + if ((error != null) && (error != '')) {
1344 + func(1, "Unable to find mongodump.exe, MongoDB database auto-backup will not be performed.");
1345 + } else {
1346 + func();
1347 + }
1348 + } catch (ex) { console.log(ex); }
1349 + });
1350 + } else {
1351 + func();
1352 + }
1353 + }
1354 +
1355 + // Perform a server backup
1356 obj.performingBackup = false;
1357 obj.performBackup = function (func) {
1358 try {
@@ -1354,11 +1378,12 @@ module.exports.CreateDB = function (parent, func) {
1378 if (parent.config.settings.autobackup && parent.config.settings.autobackup.mongodumppath) { mongoDumpPath = parent.config.settings.autobackup.mongodumppath; }
1379 const child_process = require('child_process');
1380 var cmd = '\"' + mongoDumpPath + '\" --db=\"' + dbname + '\" --archive=\"' + newBackupPath + '.archive\"';
1357 - if (dburl) { cmd = '\"' + mongoDumpPath + '\" --uri=\"' + dburl + '\" --archive=\"' + newBackupPath + '.archive\"'; }
1381 + if (dburl) { cmd = '\"' + mongoDumpPath + '\" --uri=\"' + dburl.replace('?', '/?') + '\" --archive=\"' + newBackupPath + '.archive\"'; }
1382 var backupProcess = child_process.exec(cmd, { cwd: backupPath }, function (error, stdout, stderr) {
1383 try {
1384 + var mongoDumpSuccess = true;
1385 backupProcess = null;
1361 - if ((error != null) && (error != '')) { console.log('ERROR: Unable to perform database backup: ' + error + '\r\n'); obj.performingBackup = false; return; }
1386 + if ((error != null) && (error != '')) { mongoDumpSuccess = false; console.log('ERROR: Unable to perform MongoDB backup: ' + error + '\r\n'); }
1387
1388 // Perform archive compression
1389 var archiver = require('archiver');
@@ -1370,12 +1395,17 @@ module.exports.CreateDB = function (parent, func) {
1395 } else {
1396 archive = archiver('zip', { zlib: { level: 9 } });
1397 }
1373 - output.on('close', function () { obj.performingBackup = false; if (func) { func('Auto-backup completed.'); } obj.performCloudBackup(newAutoBackupPath + '.zip', func); setTimeout(function () { try { parent.fs.unlink(newBackupPath + '.archive', function () { }); } catch (ex) { console.log(ex); } }, 5000); });
1398 + output.on('close', function () {
1399 + obj.performingBackup = false;
1400 + if (func) { if (mongoDumpSuccess) { func('Auto-backup completed.'); } else { func('Auto-backup completed without mongodb database: ' + error); } }
1401 + obj.performCloudBackup(newAutoBackupPath + '.zip', func);
1402 + setTimeout(function () { try { parent.fs.unlink(newBackupPath + '.archive', function () { }); } catch (ex) { console.log(ex); } }, 5000);
1403 + });
1404 output.on('end', function () { });
1405 archive.on('warning', function (err) { console.log('Backup warning: ' + err); if (func) { func('Backup warning: ' + err); } });
1406 archive.on('error', function (err) { console.log('Backup error: ' + err); if (func) { func('Backup error: ' + err); } });
1407 archive.pipe(output);
1378 - archive.file(newBackupPath + '.archive', { name: newBackupFile + '.archive' });
1408 + if (mongoDumpSuccess == true) { archive.file(newBackupPath + '.archive', { name: newBackupFile + '.archive' }); }
1409 archive.directory(parent.datapath, 'meshcentral-data');
1410 archive.finalize();
1411 } catch (ex) { console.log(ex); }
meshcentral.js
+3
@@ -987,6 +987,9 @@ function CreateMeshCentralServer(config, args) {
987 return;
988 }
989
990 + // Check if the database is capable of performing a backup
991 + obj.db.checkBackupCapability(function (err, msg) { if (msg != null) { obj.addServerWarning(msg, true) } });
992 +
993 // Load configuration for database if needed
994 if (obj.args.loadconfigfromdb) {
995 var key = null;