Files
cloudron-box/src/cron.js
Girish Ramakrishnan f379724128 merge certificates.js and nginx.js to reverseproxy.js
when certs change, we have to call into nginx anyway. since they
go hand in hand, just merge those files. modern reverse proxies
do this job integrated already.
2018-01-30 12:26:09 -08:00

259 lines
8.2 KiB
JavaScript

'use strict';
exports = module.exports = {
initialize: initialize,
uninitialize: uninitialize
};
var apps = require('./apps.js'),
appstore = require('./appstore.js'),
assert = require('assert'),
backups = require('./backups.js'),
caas = require('./caas.js'),
cloudron = require('./cloudron.js'),
config = require('./config.js'),
constants = require('./constants.js'),
CronJob = require('cron').CronJob,
debug = require('debug')('box:cron'),
digest = require('./digest.js'),
dyndns = require('./dyndns.js'),
eventlog = require('./eventlog.js'),
janitor = require('./janitor.js'),
reverseProxy = require('./reverseproxy.js'),
scheduler = require('./scheduler.js'),
settings = require('./settings.js'),
semver = require('semver'),
updateChecker = require('./updatechecker.js');
var gJobs = {
alive: null, // send periodic stats
autoUpdater: null,
appUpdateChecker: null,
backup: null,
boxUpdateChecker: null,
caasHeartbeat: null,
checkDiskSpace: null,
certificateRenew: null,
cleanupBackups: null,
cleanupEventlog: null,
cleanupTokens: null,
digestEmail: null,
dockerVolumeCleaner: null,
dynamicDNS: null,
schedulerSync: null
};
var NOOP_CALLBACK = function (error) { if (error) console.error(error); };
var AUDIT_SOURCE = { userId: null, username: 'cron' };
// cron format
// Seconds: 0-59
// Minutes: 0-59
// Hours: 0-23
// Day of Month: 1-31
// Months: 0-11
// Day of Week: 0-6
function initialize(callback) {
assert.strictEqual(typeof callback, 'function');
if (config.provider() === 'caas') {
// hack: send the first heartbeat only after we are running for 60 seconds
// required as we end up sending a heartbeat and then cloudron-setup reboots the server
var seconds = (new Date()).getSeconds() - 1;
if (seconds === -1) seconds = 59;
gJobs.caasHeartbeat = new CronJob({
cronTime: `${seconds} */1 * * * *`, // every minute
onTick: caas.sendHeartbeat,
start: true
});
}
var randomHourMinute = Math.floor(60*Math.random());
gJobs.alive = new CronJob({
cronTime: '00 ' + randomHourMinute + ' * * * *', // every hour on a random minute
onTick: appstore.sendAliveStatus,
start: true
});
settings.events.on(settings.TIME_ZONE_KEY, recreateJobs);
settings.events.on(settings.AUTOUPDATE_PATTERN_KEY, autoupdatePatternChanged);
settings.events.on(settings.DYNAMIC_DNS_KEY, dynamicDnsChanged);
settings.getAll(function (error, allSettings) {
if (error) return callback(error);
recreateJobs(allSettings[settings.TIME_ZONE_KEY]);
autoupdatePatternChanged(allSettings[settings.AUTOUPDATE_PATTERN_KEY]);
dynamicDnsChanged(allSettings[settings.DYNAMIC_DNS_KEY]);
callback();
});
}
function recreateJobs(tz) {
assert.strictEqual(typeof tz, 'string');
debug('Creating jobs with timezone %s', tz);
if (gJobs.backup) gJobs.backup.stop();
gJobs.backup = new CronJob({
cronTime: '00 00 */6 * * *', // every 6 hours. backups.ensureBackup() will only trigger a backup once per day
onTick: backups.ensureBackup.bind(null, AUDIT_SOURCE, NOOP_CALLBACK),
start: true,
timeZone: tz
});
if (gJobs.checkDiskSpace) gJobs.checkDiskSpace.stop();
gJobs.checkDiskSpace = new CronJob({
cronTime: '00 30 */4 * * *', // every 4 hours
onTick: cloudron.checkDiskSpace,
start: true,
timeZone: tz
});
// randomized pattern per cloudron every hour
var randomMinute = Math.floor(60*Math.random());
if (gJobs.boxUpdateCheckerJob) gJobs.boxUpdateCheckerJob.stop();
gJobs.boxUpdateCheckerJob = new CronJob({
cronTime: '00 ' + randomMinute + ' * * * *', // once an hour
onTick: updateChecker.checkBoxUpdates,
start: true,
timeZone: tz
});
if (gJobs.appUpdateChecker) gJobs.appUpdateChecker.stop();
gJobs.appUpdateChecker = new CronJob({
cronTime: '00 ' + randomMinute + ' * * * *', // once an hour
onTick: updateChecker.checkAppUpdates,
start: true,
timeZone: tz
});
if (gJobs.cleanupTokens) gJobs.cleanupTokens.stop();
gJobs.cleanupTokens = new CronJob({
cronTime: '00 */30 * * * *', // every 30 minutes
onTick: janitor.cleanupTokens,
start: true,
timeZone: tz
});
if (gJobs.cleanupBackups) gJobs.cleanupBackups.stop();
gJobs.cleanupBackups = new CronJob({
cronTime: '00 45 */6 * * *', // every 6 hours. try not to overlap with ensureBackup job
onTick: backups.cleanup.bind(null, AUDIT_SOURCE, NOOP_CALLBACK),
start: true,
timeZone: tz
});
if (gJobs.cleanupEventlog) gJobs.cleanupEventlog.stop();
gJobs.cleanupEventlog = new CronJob({
cronTime: '00 */30 * * * *', // every 30 minutes
onTick: eventlog.cleanup,
start: true,
timeZone: tz
});
if (gJobs.dockerVolumeCleaner) gJobs.dockerVolumeCleaner.stop();
gJobs.dockerVolumeCleaner = new CronJob({
cronTime: '00 00 */12 * * *', // every 12 hours
onTick: janitor.cleanupDockerVolumes,
start: true,
timeZone: tz
});
if (gJobs.schedulerSync) gJobs.schedulerSync.stop();
gJobs.schedulerSync = new CronJob({
cronTime: config.TEST ? '*/10 * * * * *' : '00 */1 * * * *', // every minute
onTick: scheduler.sync,
start: true,
timeZone: tz
});
if (gJobs.certificateRenew) gJobs.certificateRenew.stop();
gJobs.certificateRenew = new CronJob({
cronTime: '00 00 */12 * * *', // every 12 hours
onTick: reverseProxy.renewAll.bind(null, AUDIT_SOURCE, NOOP_CALLBACK),
start: true,
timeZone: tz
});
if (gJobs.digestEmail) gJobs.digestEmail.stop();
gJobs.digestEmail = new CronJob({
cronTime: '00 00 00 * * 3', // every wednesday
onTick: digest.maybeSend,
start: true,
timeZone: tz
});
}
function autoupdatePatternChanged(pattern) {
assert.strictEqual(typeof pattern, 'string');
assert(gJobs.boxUpdateCheckerJob);
debug('Auto update pattern changed to %s', pattern);
if (gJobs.autoUpdater) gJobs.autoUpdater.stop();
if (pattern === constants.AUTOUPDATE_PATTERN_NEVER) return;
gJobs.autoUpdater = new CronJob({
cronTime: pattern,
onTick: function() {
var updateInfo = updateChecker.getUpdateInfo();
if (updateInfo.box) {
if (semver.major(updateInfo.box.version) === semver.major(config.version())) {
debug('Starting autoupdate to %j', updateInfo.box);
cloudron.updateToLatest(AUDIT_SOURCE, NOOP_CALLBACK);
} else {
debug('Block automatic update for major version');
}
} else if (updateInfo.apps) {
debug('Starting app update to %j', updateInfo.apps);
apps.autoupdateApps(updateInfo.apps, AUDIT_SOURCE, NOOP_CALLBACK);
} else {
debug('No auto updates available');
}
},
start: true,
timeZone: gJobs.boxUpdateCheckerJob.cronTime.zone // hack
});
}
function dynamicDnsChanged(enabled) {
assert.strictEqual(typeof enabled, 'boolean');
assert(gJobs.boxUpdateCheckerJob);
debug('Dynamic DNS setting changed to %s', enabled);
if (enabled) {
gJobs.dynamicDNS = new CronJob({
cronTime: '00 */10 * * * *',
onTick: dyndns.sync,
start: true,
timeZone: gJobs.boxUpdateCheckerJob.cronTime.zone // hack
});
} else {
if (gJobs.dynamicDNS) gJobs.dynamicDNS.stop();
gJobs.dynamicDNS = null;
}
}
function uninitialize(callback) {
assert.strictEqual(typeof callback, 'function');
settings.events.removeListener(settings.TIME_ZONE_KEY, recreateJobs);
settings.events.removeListener(settings.AUTOUPDATE_PATTERN_KEY, autoupdatePatternChanged);
settings.events.removeListener(settings.DYNAMIC_DNS_KEY, dynamicDnsChanged);
for (var job in gJobs) {
if (!gJobs[job]) continue;
gJobs[job].stop();
gJobs[job] = null;
}
callback();
}