diff --git a/migrations/20200820050259-settings-merge-autoupdate-pattern.js b/migrations/20200820050259-settings-merge-autoupdate-pattern.js new file mode 100644 index 000000000..e6f68bd48 --- /dev/null +++ b/migrations/20200820050259-settings-merge-autoupdate-pattern.js @@ -0,0 +1,22 @@ +'use strict'; + +var async = require('async'); + +exports.up = function(db, callback) { + db.runSql('SELECT * FROM settings WHERE name=?', ['app_autoupdate_pattern'], function (error, results) { + if (error || results.length === 0) return callback(error); // will use defaults from box code + + var updatePattern = results[0].value; // use app auto update patter for the box as well + + async.series([ + db.runSql.bind(db, 'START TRANSACTION;'), + db.runSql.bind(db, 'DELETE FROM settings WHERE name=? OR name=?', ['app_autoupdate_pattern', 'box_autoupdate_pattern']), + db.runSql.bind(db, 'INSERT settings (name, value) VALUES(?, ?)', ['autoupdate_pattern', updatePattern]), + db.runSql.bind(db, 'COMMIT') + ], callback); + }); +}; + +exports.down = function(db, callback) { + callback(); +}; diff --git a/src/cron.js b/src/cron.js index 377452b07..18428c6e8 100644 --- a/src/cron.js +++ b/src/cron.js @@ -4,8 +4,7 @@ // If the patterns overlap all the time, then the task may not ever get a chance to run! // If you change this change dashboard patterns in settings.html const DEFAULT_CLEANUP_BACKUPS_PATTERN = '00 30 1,3,5,23 * * *', - DEFAULT_BOX_AUTOUPDATE_PATTERN = '00 00 1,3,5,23 * * *', - DEFAULT_APP_AUTOUPDATE_PATTERN = '00 15 1,3,5,23 * * *'; + DEFAULT_AUTOUPDATE_PATTERN = '00 00 1,3,5,23 * * *'; exports = module.exports = { startJobs, @@ -14,8 +13,7 @@ exports = module.exports = { handleSettingsChanged, - DEFAULT_BOX_AUTOUPDATE_PATTERN, - DEFAULT_APP_AUTOUPDATE_PATTERN + DEFAULT_AUTOUPDATE_PATTERN, }; var appHealthMonitor = require('./apphealthmonitor.js'), @@ -38,8 +36,7 @@ var appHealthMonitor = require('./apphealthmonitor.js'), updateChecker = require('./updatechecker.js'); var gJobs = { - appAutoUpdater: null, - boxAutoUpdater: null, + autoUpdater: null, backup: null, updateChecker: null, systemChecks: null, @@ -134,8 +131,7 @@ function startJobs(callback) { const tz = allSettings[settings.TIME_ZONE_KEY]; backupConfigChanged(allSettings[settings.BACKUP_CONFIG_KEY], tz); - appAutoupdatePatternChanged(allSettings[settings.APP_AUTOUPDATE_PATTERN_KEY], tz); - boxAutoupdatePatternChanged(allSettings[settings.BOX_AUTOUPDATE_PATTERN_KEY], tz); + autoupdatePatternChanged(allSettings[settings.AUTOUPDATE_PATTERN_KEY], tz); dynamicDnsChanged(allSettings[settings.DYNAMIC_DNS_KEY]); callback(); @@ -150,8 +146,7 @@ function handleSettingsChanged(key, value) { switch (key) { case settings.TIME_ZONE_KEY: case settings.BACKUP_CONFIG_KEY: - case settings.APP_AUTOUPDATE_PATTERN_KEY: - case settings.BOX_AUTOUPDATE_PATTERN_KEY: + case settings.AUTOUPDATE_PATTERN_KEY: case settings.DYNAMIC_DNS_KEY: debug('handleSettingsChanged: recreating all jobs'); async.series([ @@ -180,44 +175,27 @@ function backupConfigChanged(value, tz) { }); } -function boxAutoupdatePatternChanged(pattern, tz) { +function autoupdatePatternChanged(pattern, tz) { assert.strictEqual(typeof pattern, 'string'); assert.strictEqual(typeof tz, 'string'); - debug(`boxAutoupdatePatternChanged: pattern - ${pattern} (${tz})`); + debug(`autoupdatePatternChanged: pattern - ${pattern} (${tz})`); - if (gJobs.boxAutoUpdater) gJobs.boxAutoUpdater.stop(); + if (gJobs.autoUpdater) gJobs.autoUpdater.stop(); if (pattern === constants.AUTOUPDATE_PATTERN_NEVER) return; - gJobs.boxAutoUpdater = new CronJob({ + gJobs.autoUpdater = new CronJob({ cronTime: pattern, onTick: function() { - var updateInfo = updateChecker.getUpdateInfo(); - if (!updateInfo.box) return debug('No box auto updates available'); - if (updateInfo.box.unstable) return debug('Will not auto-update to unstable release'); - debug('Starting autoupdate to %j', updateInfo.box); - updater.updateToLatest({ skipBackup: false }, auditSource.CRON, NOOP_CALLBACK); - }, - start: true, - timeZone: tz - }); -} + const updateInfo = updateChecker.getUpdateInfo(); + // do box before app updates. for the off chance that the box logic fixes some app update logic issue + if (updateInfo.box && !updateInfo.box.unstable) { + debug('Starting box autoupdate to %j', updateInfo.box); + updater.updateToLatest({ skipBackup: false }, auditSource.CRON, NOOP_CALLBACK); + return; + } -function appAutoupdatePatternChanged(pattern, tz) { - assert.strictEqual(typeof pattern, 'string'); - assert.strictEqual(typeof tz, 'string'); - - debug(`appAutoupdatePatternChanged: pattern ${pattern} (${tz})`); - - if (gJobs.appAutoUpdater) gJobs.appAutoUpdater.stop(); - - if (pattern === constants.AUTOUPDATE_PATTERN_NEVER) return; - - gJobs.appAutoUpdater = new CronJob({ - cronTime: pattern, - onTick: function() { - var updateInfo = updateChecker.getUpdateInfo(); if (updateInfo.apps) { debug('Starting app update to %j', updateInfo.apps); apps.autoupdateApps(updateInfo.apps, auditSource.CRON, NOOP_CALLBACK); @@ -225,6 +203,7 @@ function appAutoupdatePatternChanged(pattern, tz) { debug('No app auto updates available'); } }, + start: true, timeZone: tz }); diff --git a/src/routes/settings.js b/src/routes/settings.js index 2c91ac767..4f2b7b068 100644 --- a/src/routes/settings.js +++ b/src/routes/settings.js @@ -17,40 +17,20 @@ var assert = require('assert'), HttpSuccess = require('connect-lastmile').HttpSuccess, settings = require('../settings.js'); -function getAppAutoupdatePattern(req, res, next) { - settings.getAppAutoupdatePattern(function (error, pattern) { +function getAutoupdatePattern(req, res, next) { + settings.getAutoupdatePattern(function (error, pattern) { if (error) return next(BoxError.toHttpError(error)); next(new HttpSuccess(200, { pattern: pattern })); }); } -function setAppAutoupdatePattern(req, res, next) { +function setAutoupdatePattern(req, res, next) { assert.strictEqual(typeof req.body, 'object'); if (typeof req.body.pattern !== 'string') return next(new HttpError(400, 'pattern is required')); - settings.setAppAutoupdatePattern(req.body.pattern, function (error) { - if (error) return next(BoxError.toHttpError(error)); - - next(new HttpSuccess(200, {})); - }); -} - -function getBoxAutoupdatePattern(req, res, next) { - settings.getBoxAutoupdatePattern(function (error, pattern) { - if (error) return next(BoxError.toHttpError(error)); - - next(new HttpSuccess(200, { pattern: pattern })); - }); -} - -function setBoxAutoupdatePattern(req, res, next) { - assert.strictEqual(typeof req.body, 'object'); - - if (typeof req.body.pattern !== 'string') return next(new HttpError(400, 'pattern is required')); - - settings.setBoxAutoupdatePattern(req.body.pattern, function (error) { + settings.setAutoupdatePattern(req.body.pattern, function (error) { if (error) return next(BoxError.toHttpError(error)); next(new HttpSuccess(200, {})); @@ -305,8 +285,7 @@ function get(req, res, next) { case settings.REGISTRY_CONFIG_KEY: return getRegistryConfig(req, res, next); case settings.SYSINFO_CONFIG_KEY: return getSysinfoConfig(req, res, next); - case settings.APP_AUTOUPDATE_PATTERN_KEY: return getAppAutoupdatePattern(req, res, next); - case settings.BOX_AUTOUPDATE_PATTERN_KEY: return getBoxAutoupdatePattern(req, res, next); + case settings.AUTOUPDATE_PATTERN_KEY: return getAutoupdatePattern(req, res, next); case settings.TIME_ZONE_KEY: return getTimeZone(req, res, next); case settings.DIRECTORY_CONFIG_KEY: return getDirectoryConfig(req, res, next); @@ -327,8 +306,7 @@ function set(req, res, next) { case settings.REGISTRY_CONFIG_KEY: return setRegistryConfig(req, res, next); case settings.SYSINFO_CONFIG_KEY: return setSysinfoConfig(req, res, next); - case settings.APP_AUTOUPDATE_PATTERN_KEY: return setAppAutoupdatePattern(req, res, next); - case settings.BOX_AUTOUPDATE_PATTERN_KEY: return setBoxAutoupdatePattern(req, res, next); + case settings.AUTOUPDATE_PATTERN_KEY: return setAutoupdatePattern(req, res, next); case settings.TIME_ZONE_KEY: return setTimeZone(req, res, next); case settings.DIRECTORY_CONFIG_KEY: return setDirectoryConfig(req, res, next); diff --git a/src/routes/test/settings-test.js b/src/routes/test/settings-test.js index b2bf1aea8..a731fed67 100644 --- a/src/routes/test/settings-test.js +++ b/src/routes/test/settings-test.js @@ -58,9 +58,9 @@ describe('Settings API', function () { before(setup); after(cleanup); - describe('app_autoupdate_pattern', function () { + describe('autoupdate_pattern', function () { it('can get app auto update pattern (default)', function (done) { - superagent.get(SERVER_URL + '/api/v1/settings/app_autoupdate_pattern') + superagent.get(SERVER_URL + '/api/v1/settings/autoupdate_pattern') .query({ access_token: token }) .end(function (err, res) { expect(res.statusCode).to.equal(200); @@ -69,8 +69,8 @@ describe('Settings API', function () { }); }); - it('cannot set app_autoupdate_pattern without pattern', function (done) { - superagent.post(SERVER_URL + '/api/v1/settings/app_autoupdate_pattern') + it('cannot set autoupdate_pattern without pattern', function (done) { + superagent.post(SERVER_URL + '/api/v1/settings/autoupdate_pattern') .query({ access_token: token }) .end(function (err, res) { expect(res.statusCode).to.equal(400); @@ -78,8 +78,8 @@ describe('Settings API', function () { }); }); - it('can set app_autoupdate_pattern', function (done) { - superagent.post(SERVER_URL + '/api/v1/settings/app_autoupdate_pattern') + it('can set autoupdate_pattern', function (done) { + superagent.post(SERVER_URL + '/api/v1/settings/autoupdate_pattern') .query({ access_token: token }) .send({ pattern: '00 30 11 * * 1-5' }) .end(function (err, res) { @@ -88,8 +88,8 @@ describe('Settings API', function () { }); }); - it('can get app auto update pattern', function (done) { - superagent.get(SERVER_URL + '/api/v1/settings/app_autoupdate_pattern') + it('can get auto update pattern', function (done) { + superagent.get(SERVER_URL + '/api/v1/settings/autoupdate_pattern') .query({ access_token: token }) .end(function (err, res) { expect(res.statusCode).to.equal(200); @@ -98,8 +98,8 @@ describe('Settings API', function () { }); }); - it('can set app_autoupdate_pattern to never', function (done) { - superagent.post(SERVER_URL + '/api/v1/settings/app_autoupdate_pattern') + it('can set autoupdate_pattern to never', function (done) { + superagent.post(SERVER_URL + '/api/v1/settings/autoupdate_pattern') .query({ access_token: token }) .send({ pattern: constants.AUTOUPDATE_PATTERN_NEVER }) .end(function (err, res) { @@ -108,8 +108,8 @@ describe('Settings API', function () { }); }); - it('can get app auto update pattern', function (done) { - superagent.get(SERVER_URL + '/api/v1/settings/app_autoupdate_pattern') + it('can get auto update pattern', function (done) { + superagent.get(SERVER_URL + '/api/v1/settings/autoupdate_pattern') .query({ access_token: token }) .end(function (err, res) { expect(res.statusCode).to.equal(200); @@ -118,79 +118,8 @@ describe('Settings API', function () { }); }); - it('cannot set invalid app_autoupdate_pattern', function (done) { - superagent.post(SERVER_URL + '/api/v1/settings/app_autoupdate_pattern') - .query({ access_token: token }) - .send({ pattern: '1 3 x 5 6' }) - .end(function (err, res) { - expect(res.statusCode).to.equal(400); - done(); - }); - }); - }); - - describe('box_autoupdate_pattern', function () { - it('can get app auto update pattern (default)', function (done) { - superagent.get(SERVER_URL + '/api/v1/settings/box_autoupdate_pattern') - .query({ access_token: token }) - .end(function (err, res) { - expect(res.statusCode).to.equal(200); - expect(res.body.pattern).to.be.ok(); - done(); - }); - }); - - it('cannot set box_autoupdate_pattern without pattern', function (done) { - superagent.post(SERVER_URL + '/api/v1/settings/box_autoupdate_pattern') - .query({ access_token: token }) - .end(function (err, res) { - expect(res.statusCode).to.equal(400); - done(); - }); - }); - - it('can set box_autoupdate_pattern', function (done) { - superagent.post(SERVER_URL + '/api/v1/settings/box_autoupdate_pattern') - .query({ access_token: token }) - .send({ pattern: '00 30 11 * * 1-5' }) - .end(function (err, res) { - expect(res.statusCode).to.equal(200); - done(); - }); - }); - - it('can get app auto update pattern', function (done) { - superagent.get(SERVER_URL + '/api/v1/settings/box_autoupdate_pattern') - .query({ access_token: token }) - .end(function (err, res) { - expect(res.statusCode).to.equal(200); - expect(res.body.pattern).to.be('00 30 11 * * 1-5'); - done(); - }); - }); - - it('can set box_autoupdate_pattern to never', function (done) { - superagent.post(SERVER_URL + '/api/v1/settings/box_autoupdate_pattern') - .query({ access_token: token }) - .send({ pattern: constants.AUTOUPDATE_PATTERN_NEVER }) - .end(function (err, res) { - expect(res.statusCode).to.equal(200); - done(); - }); - }); - - it('can get app auto update pattern', function (done) { - superagent.get(SERVER_URL + '/api/v1/settings/box_autoupdate_pattern') - .query({ access_token: token }) - .end(function (err, res) { - expect(res.statusCode).to.equal(200); - expect(res.body.pattern).to.be(constants.AUTOUPDATE_PATTERN_NEVER); - done(); - }); - }); - - it('cannot set invalid box_autoupdate_pattern', function (done) { - superagent.post(SERVER_URL + '/api/v1/settings/box_autoupdate_pattern') + it('cannot set invalid autoupdate_pattern', function (done) { + superagent.post(SERVER_URL + '/api/v1/settings/autoupdate_pattern') .query({ access_token: token }) .send({ pattern: '1 3 x 5 6' }) .end(function (err, res) { diff --git a/src/settings.js b/src/settings.js index 0e8e4b782..9bbff7522 100644 --- a/src/settings.js +++ b/src/settings.js @@ -1,11 +1,8 @@ 'use strict'; exports = module.exports = { - getAppAutoupdatePattern, - setAppAutoupdatePattern, - - getBoxAutoupdatePattern, - setBoxAutoupdatePattern, + getAutoupdatePattern, + setAutoupdatePattern, getTimeZone, setTimeZone, @@ -92,8 +89,7 @@ exports = module.exports = { DIRECTORY_CONFIG_KEY: 'directory_config', // strings - APP_AUTOUPDATE_PATTERN_KEY: 'app_autoupdate_pattern', - BOX_AUTOUPDATE_PATTERN_KEY: 'box_autoupdate_pattern', + AUTOUPDATE_PATTERN_KEY: 'autoupdate_pattern', TIME_ZONE_KEY: 'time_zone', CLOUDRON_NAME_KEY: 'cloudron_name', LICENSE_KEY: 'license_key', @@ -137,8 +133,7 @@ var addons = require('./addons.js'), let gDefaults = (function () { var result = { }; - result[exports.APP_AUTOUPDATE_PATTERN_KEY] = cron.DEFAULT_APP_AUTOUPDATE_PATTERN; - result[exports.BOX_AUTOUPDATE_PATTERN_KEY] = cron.DEFAULT_BOX_AUTOUPDATE_PATTERN; + result[exports.AUTOUPDATE_PATTERN_KEY] = cron.DEFAULT_AUTOUPDATE_PATTERN; result[exports.TIME_ZONE_KEY] = 'America/Los_Angeles'; result[exports.CLOUDRON_NAME_KEY] = 'Cloudron'; result[exports.DYNAMIC_DNS_KEY] = false; @@ -206,7 +201,7 @@ function notifyChange(key, value) { cron.handleSettingsChanged(key, value); } -function setAppAutoupdatePattern(pattern, callback) { +function setAutoupdatePattern(pattern, callback) { assert.strictEqual(typeof pattern, 'string'); assert.strictEqual(typeof callback, 'function'); @@ -215,49 +210,20 @@ function setAppAutoupdatePattern(pattern, callback) { if (!job) return callback(new BoxError(BoxError.BAD_FIELD, 'Invalid pattern', { field: 'pattern' })); } - settingsdb.set(exports.APP_AUTOUPDATE_PATTERN_KEY, pattern, function (error) { + settingsdb.set(exports.AUTOUPDATE_PATTERN_KEY, pattern, function (error) { if (error) return callback(error); - notifyChange(exports.APP_AUTOUPDATE_PATTERN_KEY, pattern); + notifyChange(exports.AUTOUPDATE_PATTERN_KEY, pattern); return callback(null); }); } -function getAppAutoupdatePattern(callback) { +function getAutoupdatePattern(callback) { assert.strictEqual(typeof callback, 'function'); - settingsdb.get(exports.APP_AUTOUPDATE_PATTERN_KEY, function (error, pattern) { - if (error && error.reason === BoxError.NOT_FOUND) return callback(null, gDefaults[exports.APP_AUTOUPDATE_PATTERN_KEY]); - if (error) return callback(error); - - callback(null, pattern); - }); -} - -function setBoxAutoupdatePattern(pattern, callback) { - assert.strictEqual(typeof pattern, 'string'); - assert.strictEqual(typeof callback, 'function'); - - if (pattern !== constants.AUTOUPDATE_PATTERN_NEVER) { // check if pattern is valid - var job = safe.safeCall(function () { return new CronJob(pattern); }); - if (!job) return callback(new BoxError(BoxError.BAD_FIELD, 'Invalid pattern', { field: 'pattern' })); - } - - settingsdb.set(exports.BOX_AUTOUPDATE_PATTERN_KEY, pattern, function (error) { - if (error) return callback(error); - - notifyChange(exports.BOX_AUTOUPDATE_PATTERN_KEY, pattern); - - return callback(null); - }); -} - -function getBoxAutoupdatePattern(callback) { - assert.strictEqual(typeof callback, 'function'); - - settingsdb.get(exports.BOX_AUTOUPDATE_PATTERN_KEY, function (error, pattern) { - if (error && error.reason === BoxError.NOT_FOUND) return callback(null, gDefaults[exports.BOX_AUTOUPDATE_PATTERN_KEY]); + settingsdb.get(exports.AUTOUPDATE_PATTERN_KEY, function (error, pattern) { + if (error && error.reason === BoxError.NOT_FOUND) return callback(null, gDefaults[exports.AUTOUPDATE_PATTERN_KEY]); if (error) return callback(error); callback(null, pattern);