/*jshint esversion: 6*/ //load database var Datastore = require('nedb'); var path = require("path"); var db = new Datastore({ filename: __dirname + '/crontabs/crontab.db' }); var cronPath = "/tmp"; if(process.env.CRON_PATH !== undefined) { console.log(`Path to crond files set using env variables ${process.env.CRON_PATH}`); cronPath = process.env.CRON_PATH; } db.loadDatabase(function (err) { if (err) throw err; // no hope, just terminate }); var exec = require('child_process').exec; var fs = require('fs'); var cron_parser = require("cron-parser"); exports.log_folder = __dirname + '/crontabs/logs'; exports.env_file = __dirname + '/crontabs/env.db'; crontab = function(name, command, schedule, stopped, logging, mailing){ var data = {}; data.name = name; data.command = command; data.schedule = schedule; if(stopped !== null) { data.stopped = stopped; } data.timestamp = (new Date()).toString(); data.logging = logging; if (!mailing) mailing = {}; data.mailing = mailing; return data; }; exports.create_new = function(name, command, schedule, logging, mailing){ var tab = crontab(name, command, schedule, false, logging, mailing); tab.created = new Date().valueOf(); db.insert(tab); }; exports.update = function(data){ db.update({_id: data._id}, crontab(data.name, data.command, data.schedule, null, data.logging, data.mailing)); }; exports.status = function(_id, stopped){ db.update({_id: _id},{$set: {stopped: stopped}}); }; exports.remove = function(_id){ db.remove({_id: _id}, {}); }; // Iterates through all the crontab entries in the db and calls the callback with the entries exports.crontabs = function(callback){ db.find({}).sort({ created: -1 }).exec(function(err, docs){ for(var i=0; i&1 1>&2 2>&3 | tee " + stderr; if (tab.logging && tab.logging == "true") { crontab_string += "; if test -f " + stderr + "; then date >> " + log_file + "; cat " + stderr + " >> " + log_file + "; fi"; } if (tab.hook) { crontab_string += "; if test -f " + stdout + "; then " + tab.hook + " < " + stdout + "; fi"; } if (tab.mailing && JSON.stringify(tab.mailing) != "{}"){ crontab_string += "; /usr/local/bin/node " + __dirname + "/bin/crontab-ui-mailer.js " + tab._id + " " + stdout + " " + stderr; } crontab_string += "\n"; } }); fs.writeFile(exports.env_file, env_vars, function(err) { if (err) callback(err); // In docker we're running as the root user, so we need to write the file as root and not crontab var fileName = "crontab" if(process.env.CRON_IN_DOCKER !== undefined) { fileName = "root" } fs.writeFile(path.join(cronPath, fileName), crontab_string, function(err) { if (err) return callback(err); /// In docker we're running crond using busybox implementation of crond /// It is launched as part of the container startup process, so no need to run it again if(process.env.CRON_IN_DOCKER === undefined) { exec("crontab " + path.join(cronPath, "crontab"), function(err) { if (err) return callback(err); else callback(); }); } else { callback(); } }); }); }); }; exports.get_backup_names = function(){ var backups = []; fs.readdirSync(__dirname + '/crontabs').forEach(function(file){ // file name begins with backup if(file.indexOf("backup") === 0){ backups.push(file); } }); // Sort by date. Newest on top for(var i=0; i Tj){ var temp = backups[i]; backups[i] = backups[j]; backups[j] = temp; } } } return backups; }; exports.backup = function(){ //TODO check if it failed fs.createReadStream( __dirname + '/crontabs/crontab.db').pipe(fs.createWriteStream( __dirname + '/crontabs/backup ' + (new Date()).toString().replace("+", " ") + '.db')); }; exports.restore = function(db_name){ fs.createReadStream( __dirname + '/crontabs/' + db_name).pipe(fs.createWriteStream( __dirname + '/crontabs/crontab.db')); db.loadDatabase(); // reload the database }; exports.reload_db = function(){ db.loadDatabase(); }; exports.get_env = function(){ if (fs.existsSync(exports.env_file)) { return fs.readFileSync(exports.env_file , 'utf8').replace("\n", "\n"); } return ""; }; exports.import_crontab = function(){ exec("crontab -l", function(error, stdout, stderr){ var lines = stdout.split("\n"); var namePrefix = new Date().getTime(); lines.forEach(function(line, index){ line = line.replace(/\t+/g, ' '); var regex = /^((\@[a-zA-Z]+\s+)|(([^\s]+)\s+([^\s]+)\s+([^\s]+)\s+([^\s]+)\s+([^\s]+)\s+))/; var command = line.replace(regex, '').trim(); var schedule = line.replace(command, '').trim(); var is_valid = false; try { is_valid = cron_parser.parseString(line).expressions.length > 0; } catch (e){} if(command && schedule && is_valid){ var name = namePrefix + '_' + index; db.findOne({ command: command, schedule: schedule }, function(err, doc) { if(err) { throw err; } if(!doc){ exports.create_new(name, command, schedule, null); } else{ doc.command = command; doc.schedule = schedule; exports.update(doc); } }); } }); }); }; exports.autosave_crontab = function(callback) { let env_vars = exports.get_env(); exports.set_crontab(env_vars, callback); };