crontab-ui/crontab.js

236 lines
6.6 KiB
JavaScript
Raw Normal View History

2016-12-03 15:39:12 +00:00
/*jshint esversion: 6*/
2015-06-11 19:21:59 +00:00
//load database
var Datastore = require('nedb');
2017-07-19 14:16:07 +00:00
var path = require("path");
2015-06-11 19:21:59 +00:00
var db = new Datastore({ filename: __dirname + '/crontabs/crontab.db' });
2017-07-19 14:16:07 +00:00
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;
}
2015-06-11 19:21:59 +00:00
db.loadDatabase(function (err) {
if (err) throw err; // no hope, just terminate
2015-06-11 19:21:59 +00:00
});
2015-06-11 19:45:04 +00:00
var exec = require('child_process').exec;
var fs = require('fs');
2016-08-05 18:17:28 +00:00
var cron_parser = require("cron-parser");
2015-06-11 19:21:59 +00:00
2015-12-16 10:04:44 +00:00
exports.log_folder = __dirname + '/crontabs/logs';
2016-02-14 16:28:39 +00:00
exports.env_file = __dirname + '/crontabs/env.db';
2015-12-16 10:04:44 +00:00
2016-12-14 04:18:15 +00:00
crontab = function(name, command, schedule, stopped, logging, mailing){
2015-06-11 19:21:59 +00:00
var data = {};
data.name = name;
2015-06-11 19:21:59 +00:00
data.command = command;
data.schedule = schedule;
2016-09-01 18:10:11 +00:00
if(stopped !== null) {
2015-06-13 20:38:20 +00:00
data.stopped = stopped;
2016-02-14 03:46:27 +00:00
}
2015-06-11 19:21:59 +00:00
data.timestamp = (new Date()).toString();
2015-12-16 10:04:44 +00:00
data.logging = logging;
2016-12-14 04:18:15 +00:00
if (!mailing)
mailing = {};
data.mailing = mailing;
2015-06-11 19:21:59 +00:00
return data;
2016-08-05 18:17:28 +00:00
};
2015-06-11 19:21:59 +00:00
2016-12-14 04:18:15 +00:00
exports.create_new = function(name, command, schedule, logging, mailing){
var tab = crontab(name, command, schedule, false, logging, mailing);
2015-06-13 20:38:20 +00:00
tab.created = new Date().valueOf();
2015-06-11 19:21:59 +00:00
db.insert(tab);
2016-08-05 18:17:28 +00:00
};
2015-06-11 19:21:59 +00:00
2015-06-12 10:17:26 +00:00
exports.update = function(data){
2016-12-14 04:18:15 +00:00
db.update({_id: data._id}, crontab(data.name, data.command, data.schedule, null, data.logging, data.mailing));
2016-08-05 18:17:28 +00:00
};
2015-06-12 19:19:46 +00:00
exports.status = function(_id, stopped){
db.update({_id: _id},{$set: {stopped: stopped}});
2016-08-05 18:17:28 +00:00
};
2015-06-12 19:19:46 +00:00
exports.remove = function(_id){
db.remove({_id: _id}, {});
2016-08-05 18:17:28 +00:00
};
2016-12-13 08:36:13 +00:00
// Iterates through all the crontab entries in the db and calls the callback with the entries
2015-06-11 19:21:59 +00:00
exports.crontabs = function(callback){
2015-06-13 20:38:20 +00:00
db.find({}).sort({ created: -1 }).exec(function(err, docs){
for(var i=0; i<docs.length; i++){
if(docs[i].schedule == "@reboot")
2016-08-05 18:17:28 +00:00
docs[i].next = "Next Reboot";
2015-06-13 20:38:20 +00:00
else
docs[i].next = cron_parser.parseExpression(docs[i].schedule).next().toString();
}
2015-06-11 19:21:59 +00:00
callback(docs);
});
2016-08-05 18:17:28 +00:00
};
2016-12-13 08:36:13 +00:00
exports.get_crontab = function(_id, callback) {
db.find({_id: _id}).exec(function(err, docs){
callback(docs[0]);
});
};
2018-05-07 10:40:41 +00:00
exports.runjob = function(_id, callback) {
db.find({_id: _id}).exec(function(err, docs){
var res = docs[0];
exec(res.command, function(error, stdout, stderr){
console.log(stdout);
});
});
};
2016-12-13 08:36:13 +00:00
// Set actual crontab file from the db
exports.set_crontab = function(env_vars, callback){
2015-06-11 19:45:04 +00:00
exports.crontabs( function(tabs){
var crontab_string = "";
2016-02-14 03:46:27 +00:00
if (env_vars) {
crontab_string = env_vars + "\n";
}
2015-06-11 19:45:04 +00:00
tabs.forEach(function(tab){
if(!tab.stopped) {
2017-07-19 14:16:07 +00:00
let stderr = path.join(cronPath, tab._id + ".stderr");
let stdout = path.join(cronPath, tab._id + ".stdout");
let log_file = path.join(exports.log_folder, tab._id + ".log");
if(tab.command[tab.command.length-1] != ";") // add semicolon
tab.command +=";";
crontab_string += tab.schedule + " ({ " + tab.command + " } | tee " + stdout + ") 3>&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";
2015-06-11 19:45:04 +00:00
}
});
2016-02-14 16:28:39 +00:00
fs.writeFile(exports.env_file, env_vars, function(err) {
if (err) callback(err);
2017-07-19 15:00:17 +00:00
// 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);
2017-07-19 14:16:07 +00:00
/// 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();
}
});
});
2015-06-11 19:45:04 +00:00
});
2016-08-05 18:17:28 +00:00
};
2015-06-12 19:19:46 +00:00
exports.get_backup_names = function(){
2016-08-05 18:17:28 +00:00
var backups = [];
2015-06-12 19:19:46 +00:00
fs.readdirSync(__dirname + '/crontabs').forEach(function(file){
// file name begins with backup
if(file.indexOf("backup") === 0){
2015-06-12 19:19:46 +00:00
backups.push(file);
}
});
2015-06-13 20:38:20 +00:00
// Sort by date. Newest on top
for(var i=0; i<backups.length; i++){
2016-08-05 18:17:28 +00:00
var Ti = backups[i].split("backup")[1];
2015-06-13 20:38:20 +00:00
Ti = new Date(Ti.substring(0, Ti.length-3)).valueOf();
for(var j=0; j<i; j++){
2016-08-05 18:17:28 +00:00
var Tj = backups[j].split("backup")[1];
2015-06-13 20:38:20 +00:00
Tj = new Date(Tj.substring(0, Tj.length-3)).valueOf();
if(Ti > Tj){
var temp = backups[i];
backups[i] = backups[j];
backups[j] = temp;
}
}
}
2015-06-12 19:19:46 +00:00
return backups;
2016-08-05 18:17:28 +00:00
};
2015-06-12 19:19:46 +00:00
exports.backup = function(){
//TODO check if it failed
2015-06-13 02:53:13 +00:00
fs.createReadStream( __dirname + '/crontabs/crontab.db').pipe(fs.createWriteStream( __dirname + '/crontabs/backup ' + (new Date()).toString().replace("+", " ") + '.db'));
2016-08-05 18:17:28 +00:00
};
2015-06-13 02:53:13 +00:00
exports.restore = function(db_name){
fs.createReadStream( __dirname + '/crontabs/' + db_name).pipe(fs.createWriteStream( __dirname + '/crontabs/crontab.db'));
db.loadDatabase(); // reload the database
2016-08-05 18:17:28 +00:00
};
2016-12-03 15:39:12 +00:00
exports.reload_db = function(){
2015-06-13 20:38:20 +00:00
db.loadDatabase();
2016-08-05 18:17:28 +00:00
};
2015-06-13 20:38:20 +00:00
2016-02-14 16:28:39 +00:00
exports.get_env = function(){
if (fs.existsSync(exports.env_file)) {
return fs.readFileSync(exports.env_file , 'utf8').replace("\n", "\n");
}
2016-08-05 18:17:28 +00:00
return "";
};
2016-02-14 16:28:39 +00:00
2015-06-13 20:38:20 +00:00
exports.import_crontab = function(){
exec("crontab -l", function(error, stdout, stderr){
var lines = stdout.split("\n");
2016-08-04 21:49:22 +00:00
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+))/;
2016-08-04 21:49:22 +00:00
var command = line.replace(regex, '').trim();
var schedule = line.replace(command, '').trim();
2016-08-05 18:17:28 +00:00
var is_valid = false;
try { is_valid = cron_parser.parseString(line).expressions.length > 0; } catch (e){}
if(command && schedule && is_valid){
2016-08-04 21:49:22 +00:00
var name = namePrefix + '_' + index;
2016-08-05 18:17:28 +00:00
db.findOne({ command: command, schedule: schedule }, function(err, doc) {
2016-08-04 21:49:22 +00:00
if(err) {
throw err;
}
if(!doc){
2016-08-05 18:17:28 +00:00
exports.create_new(name, command, schedule, null);
2016-08-04 21:49:22 +00:00
}
else{
doc.command = command;
doc.schedule = schedule;
exports.update(doc);
}
});
}
2016-08-05 18:17:28 +00:00
});
2015-06-13 20:38:20 +00:00
});
2016-08-05 18:17:28 +00:00
};
2016-12-03 15:39:12 +00:00
exports.autosave_crontab = function(callback) {
let env_vars = exports.get_env();
exports.set_crontab(env_vars, callback);
};