craydent-deploy
Version:
craydent deploy helper
721 lines (675 loc) • 31.2 kB
JavaScript
/*/---------------------------------------------------------/*/
/*/ Craydent LLC deploy-v1.2.0 /*/
/*/ Copyright 2011 (http://craydent.com/about) /*/
/*/ Dual licensed under the MIT or GPL Version 2 licenses. /*/
/*/ (http://craydent.com/license) /*/
/*/---------------------------------------------------------/*/
/*/---------------------------------------------------------/*/
/* deploy_server params
1=>interpreter/node command (not used)
2=>node file being executed (not used)
3=>socket port
4=>http port
5=>SAC
6=>http auth username
7=>http auth password
*/
const pkg = require('./package.json'),
ns = !pkg.name.indexOf('@craydent/') ? "@craydent/" : "";
require(ns + 'craydent/global');
$c.DEBUG_MODE = true;
const CL = new CLI({});
CL
.add({
option: "-s,--socketport",
type:"number",
description:"Port number for the socket server to listen on"
})
.add({
option: "-h,httpport",
type:"number",
description:"Port number for the web server to listen on"
})
.add({
option: "-c,--cuid",
type:"string",
description:"Token/cuid to use for admin rights to API and web interface"
})
.add({
option: "-u,--httpuser",
type:"string",
description:"Username for http authentication"
})
.add({
option: "-p,--httppassword",
type:"string",
description:"Password for http authentication"
})
.add({
option: "-e,--environment",
type:"string",
description:"Environment for the current server"
})
.add({
option: "-x,--basepath",
type:"string",
description:"Base path of cdeploy"
});
CL.validate();
const BASE_PATH = CL.basepath || "/var/craydent/";
const GIT_BASE_PATH = BASE_PATH + "git/";
const CONFIG_BASE_PATH = BASE_PATH + "config/";
const PROJECT_PATH = BASE_PATH + "nodejs/craydent-deploy/";
const CONFIG_PATH = BASE_PATH + "config/craydent-deploy/";
const LOG_BASE_PATH = BASE_PATH + "log/";
const LOG_PATH = LOG_BASE_PATH + "/craydent-deploy/";
const KEY_PATH = BASE_PATH + "key/";
const LISTENERS = include('./config/listeners.json');
const CPROXY_PATH = CONFIG_BASE_PATH + 'craydent-proxy/pconfig.json';
var pconfig = include(CPROXY_PATH);
var fs = require('fs');
var git = require('./libs/git_actions');
var utils = require('./libs/utils'),
writeNodeConfig = utils.writeNodeConfig,
writeAppConfig = utils.writeAppConfig,
encrypt_password = utils.encrypt_password,
correct_password = utils.correct_password,
authorized = utils.authorized;
var actions = include('./config/actions.json'),
deploying = {},
log_tracker = {},
apps = include(CONFIG_PATH + 'craydent_deploy_config.json'),
nconfig = include(CONFIG_PATH + 'nodeconfig.js'),
shelldir = __dirname + '/shell_scripts/',
fswrite = yieldable(fs.writeFile,fs),
fsreaddir = yieldable(fs.readdir,fs),
fsread = yieldable(fs.readFile,fs),
fsexists = yieldable(fs.exists,fs),
//fsopen = yieldable(fs.open,fs),
//fsstat = yieldable(fs.stat,fs),
config = {apps:apps,keys:["master_id_rsa"],deploying:deploying},
io, apptimeouts = {};
var cb = function(event_type, filename){
try {
if (event_type == "change") {
filename == 'nodeconfig.js' ?
(nconfig = include(CONFIG_PATH + 'nodeconfig.js',true)) :
(apps = include(CONFIG_PATH + 'craydent_deploy_config.json',true)) ;
check_apps();
} else if (event_type == "rename") {
if (filename == 'nodeconfig.js') {
try {
nwatcher && nwatcher.close();
nwatcher = fs.watch(CONFIG_PATH + 'nodeconfig.js', cb);
} catch (e) {
e.errno == "ENOENT" ? flog(CONFIG_PATH + "nodeconfig.js not found") : flog(e);
}
} else {
try {
cwatcher && cwatcher.close();
cwatcher = fs.watch(CONFIG_PATH + 'craydent_deploy_config.json', cb);
} catch (e) {
e.errno == "ENOENT" ? flog(CONFIG_PATH + "craydent_deploy_config.json not found") : flog(e);
}
}
}
} catch (e) {
flog(e);
}
}, nwatcher, cwatcher;
try { nwatcher = fs.watch(CONFIG_PATH + 'nodeconfig.js', cb); } catch (e) {e.errno == "ENOENT" ? flog(CONFIG_PATH + "nodeconfig.js not found") : flog(e); }
try { cwatcher = fs.watch(CONFIG_PATH + 'craydent_deploy_config.json', cb); } catch (e) {e.errno == "ENOENT" ? flog(CONFIG_PATH + "craydent_deploy_config.json not found") : flog(e); }
syncroit(function *(){
if (!config.apps) {
config.apps = [{
"name": "craydent-deploy",
"servers": ["deploy_server.js"],
"logfile": [LOG_PATH + "deploy_server.log"],
"size":{},
"fd":{},
"www": "",
"nodejs":"node",
"webdir":"",
"email":"",
"email2": "",
"autostart": false,
"email_interval": 3600000,
"health_check_interval": 30000
}];
yield writeAppConfig(config.apps);
}
config.apps = apps;
global.SOCKET_PORT = CL.socketport || global.SOCKET_PORT || 4900;
global.HTTP_PORT = CL.httpport || global.HTTP_PORT || 4800;
global.SAC = CL.cuid || global.SAC;
global.ENV = CL.environment || global.ENV || "prod";
global.HTTP_AUTH = global.HTTP_AUTH || {};
var usernames = (CL.httpuser || "admin").split(','),
passwords = (CL.httppassword || "admin").split(',');
for (var i = 0, len = usernames.length; i < len; i++) {
global.HTTP_AUTH[usernames[i]] = global.HTTP_AUTH[usernames[i]] || { "access": ['*'] };
global.HTTP_AUTH[usernames[i]].password = encrypt_password(passwords[i]);
}
if (nconfig === false) {
global.SAC = global.SAC || cuid();
yield writeNodeConfig(CONFIG_PATH);
}
io = require('socket.io')(SOCKET_PORT);
logit('socket start on port: ' + SOCKET_PORT);
// store all keys to config.keys variable as a string of names
try {
config.keys = yield fsreaddir(KEY_PATH);
for (var i = 0,len = config.keys.length; i < len; i++) {
if (!config.keys[i].endsWith('.pub')) {
config.keys.removeAt(i);
len--;
}
}
} catch(e) { }
// start all log tails
for (var i = 0, len = config.apps.length; i < len; i++) {
start_app(config.apps[i]);
}
io.on('connection', function (socket) {
logit('connection made');
socket.on(LISTENERS['deploy'], function(data){
syncroit(function*(){
var args = yield buildit(data), code = args[0], output = args[1], message = args[2];
io.emit("process_complete",{code:code,output:output});
});
});
socket.on(LISTENERS["addgit"], function(data){
syncroit(function*() {
logit('gitadd', data);
if (data.passcode == SAC || data.sac == SAC) {
config.apps = include(CONFIG_PATH + 'craydent_deploy_config.json', true) || config.apps;
var appobj = config.apps.where({name: data.name})[0];
if (appobj) {
return io.emit("add_error", {code: '1', output: data.name + " already exists."});
}
var project_name = data.git_address.replace(/.*\/(.*?)\.git$/, '$1'),
repo_owner = data.git_address.replace(/.*?\.com[\/:](.*?)\/.*\.git$/, '$1');
yield _exec(shelldir + "git_script.sh " + data.git_address + " " + project_name + " " + data.name + " " + (data.key_name || "master_id_rsa").replace(/\.pub$/, ''));
var logFiles = [];
var servers = $c.isArray(data.servers) ? data.servers : [];
for (var i = 0, len = servers.length; i < len; i++) {
logFiles.push(LOG_BASE_PATH + data.name + "/" + servers[i]);
}
config.apps.push({
'git': data.git_address,
'name': data.name,
servers: servers,
logfile: logFiles,
size: {},
fd: {},
www: data.www || "",
nodejs: data.nodejs || "",
webdir: data.webdir || "",
"email":"",
"email2": "",
"autostart": false,
"email_interval": 3600000,
"health_check_interval": 30000
});
yield writeAppConfig(config.apps);
var dt = yield getsshkey(data.name);
var params = {
repo_owner: repo_owner,
project_name: project_name,
git_address: data.git_address,
git_user: data.git_user,
git_password: data.git_password,
name: data.name,
content: dt.content,
key_name: dt.name,
host: socket.handshake.headers.host.split(':')[0],
protocol: socket.handshake.headers.origin.contains('https') ? "https" : "http"
};
yield git.createDeployKey(params);
yield git.createWebhook(params, pconfig);
}
});
});
socket.on(LISTENERS["addssh"], function(data){
syncroit(function*() {
logit('sshkey', data);
if (data.passcode == SAC || data.sac == SAC) {
var args = yield _exec(shelldir + "sshkey_script.sh " + data.name + " " + data.email),
code = args[0], output = args[1], message = args[2];
logit(message);
var pubkey = data.name + '.pub';
var path = KEY_PATH + pubkey;
var exists = yield fsexists(path);
if (!exists) { return; }
args = yield fsread(path, 'utf8');
var err = args[0], data = args[1];
var obj = {error: true, message: err};
if (!err) {
config.keys.push(pubkey);
obj = {content: data, name: pubkey};
}
socket.emit("showsshkey", obj);
}
});
});
socket.on(LISTENERS["init"], function(data){
syncroit(function *() {
logit('initializing', data);
var eobj = {error: false, message: "already initialized"};
if (nconfig === false || data.passcode == SAC || data.sac == SAC) {
nconfig = true;
global.SOCKET_PORT = parseInt(data.ws_port);
global.HTTP_PORT = parseInt(data.http_port);
global.SAC = data.passcode || data.sac;
//global.HTTP_AUTH_USERNAME = data.http_username || "admin";
//global.HTTP_AUTH_PASSWORD = data.http_password || "admin";
global.HTTP_AUTH = global.HTTP_AUTH || {};
var usernames = (data.http_username || "admin").split(','),
passwords = (data.http_password || "admin").split(',');
for (var i = 0, p = 0, len = usernames.length; i < len; i++) {
global.HTTP_AUTH[usernames[i]] = global.HTTP_AUTH[usernames[i]] || { "access": ['*'] };
global.HTTP_AUTH[usernames[i]].password = encrypt_password(passwords[p++] || passwords[p--,--p]);
}
global.EMAIL = data.email;
global.ENV = data.environment;
yield writeNodeConfig(CONFIG_PATH);
var args = yield _exec("echo '" + data.password + "' | sudo -S bash " + shelldir + "initial_script.sh " + data.email + " " + (data.rootdir || "/var") + " $USER"),
code = args[0], output = args[1], message = args[2];
logit(message);
eobj = {error: false};
}
socket.emit("initialized", eobj);
});
});
socket.on(LISTENERS["getssh"],function(data){
syncroit(function *() {
if (data.passcode != SAC || data.sac != SAC) { return; }
var dt = yield getsshkey(data.name);
socket.emit("showsshkey", dt);
})
});
socket.on(LISTENERS["adduser"],function(data){
socket.emit("addadminuser", add_admin_user(data));
});
socket.on(LISTENERS["removeuser"],function(data){
socket.emit("removeadminuser", rm_admin_user(data));
});
socket.on(LISTENERS["updatepassword"],function(data){
socket.emit("updateadminpassword", update_admin(data));
});
});
init_webserver();
yield check_apps();
});
function send_email (details) {
return syncroit(function* () {
if ($c.isString(details)) { details = log_tracker[details]; }
else if (details.email2 || global.EMAIL2) {
details.cuid = cuid();
log_tracker[details.cuid] = details;
details.iteration = 0;
details.reviewed = false;
}
details.iteration++;
var rname = details.name,
rserver = details.server,
remail = details.email || global.EMAIL,
remail2 = details.email2 || global.EMAIL2;
var link = remail2 && "\n\nAcknowledge link: blah.com****" || "";
var body = rname + ":" + rserver + " has stopped running and is being restarted" + link + "\n\nLogs:\n\n\n" +
(yield fsread(details.log))[1];
flog(rname + ":" + rserver + " sending email to " + remail + ".");
var nodemailer = require('nodemailer');
var transporter;
if (global.mailer) {
var ses = require('nodemailer-ses-transport');
transporter = nodemailer.createTransport(ses({
accessKeyId: global.AWSACCESSKEY,
secretAccessKey: global.AWSSECRETKEY
}));
} else {
transporter = nodemailer.createTransport(global.SMTP || null);
}
var mailOptions = {
from: global.SENDER,
to: !remail2 || details.iteration <= 10 ? remail : remail2,
subject: "Craydent Deploy Error - " + rname + ":" + rserver,
text: body
//html: '<b>Hello world </b>' // html body
};
var mailer_response = yield (yieldable(transporter.sendMail,transporter)(mailOptions));
if (mailer_response[0]) { flog("failure - " + rname + ":" + rserver + " email sent to " + remail + "."); }
else { flog("successful - " + rname + ":" + rserver + " email sent to " + remail + ". " + mailer_response[1].response); }
if (remail2) {
if (details.iteration <= 10) {
var interv = details.email_interval || global.EMAIL_INTERVAL || 3600000;
details.timeout = setTimeout(eval("(function () { send_email('" + details.cuid + "'); })"), interv);
} else {
clearTimeout(details.timeout);
delete log_tracker[details.cuid];
}
}
});
}
function check_apps(appname, server) {
var app_list = appname ? $c.where(apps,{name: appname}) : apps;
return syncroit(function* () {
//if (app_list != apps && !$c.where(apps,{name:app_list[0].name})[0]) { return; }
var asyncs = [], result_match = [];
for (var i = 0, len = app_list.length; i < len; i++) {
if (!app_list[i].autostart) { continue; }
for (var j = 0, jlen = app_list[i].servers.length; j < jlen; j++) {
if (server && app_list[i].servers[j] != server) { continue; }
result_match.push({
name: app_list[i].name,
nodejs:app_list[i].nodejs,
server: app_list[i].servers[j],
log: app_list[i].logfile[j],
email: app_list[i].email,
email2: app_list[i].email2,
email_interval: app_list[i].email_interval,
health_check_interval: app_list[i].health_check_interval,
index:i
});
asyncs.push(CL.exec("ps aux | egrep \"node /var/craydent/nodejs/" + app_list[i].name + "/\".*|awk '{print $2}'"));
}
}
var results = yield $c.parallelEach(asyncs);
for (var i = 0, len = results.length; i < len; i++) {
var result = results[i].output,
rname = result_match[i].name,
rserver = result_match[i].server,
remail = result_match[i].email || global.EMAIL;
if (result.split('\n').length == 3) {
flog(rname + ":" + rserver + " has stopped and is being started.");
if (remail) {
//send email
yield send_email(result_match[i]);
//var body = rname + ":" + rserver + " has stopped running and is being restarted\n\nLogs:\n\n\n" +
// (yield fsread(result_match[i].log))[1];
//flog(rname + ":" + rserver + " email sent to " + remail + ".");
//
//var nodemailer = require('nodemailer');
//var transporter;
//if (global.mailer) {
// var ses = require('nodemailer-ses-transport');
// transporter = nodemailer.createTransport(ses({
// accessKeyId: global.AWSACCESSKEY,
// secretAccessKey: global.AWSSECRETKEY
// }));
//} else {
// transporter = nodemailer.createTransport(global.SMTP || null);
//}
//
//var mailOptions = {
// from: global.SENDER,
// to: remail,
// subject: "Craydent Deploy Error - " + rname + ":" + rserver,
// text: body
// //html: '<b>Hello world </b>' // html body
//};
//var mailer_response = yield (yieldable(transporter.sendMail,transporter)(mailOptions));
//if (mailer_response[0]) { flog("failure -" + rname + ":" + rserver + " email sent to " + remail + "."); }
//else { flog("successful - " + rname + ":" + rserver + " email sent to " + remail + ". " + mailer_response[1].response); }
}
yield _exec(shelldir + "deploy_script.sh " + rname + " start '' " + (result_match[i].nodejs || "''") + " '' '" + rserver + "'");
}
apptimeouts[rname + rserver] && clearInterval(apptimeouts[rname + rserver]);
apptimeouts[rname + rserver] = setTimeout(eval("(function () { check_apps('" + rname + "','" + rserver + "'); })"), result_match[i].health_check_interval || global.INTERVAL || 30000);
}
if (!i) {
apptimeouts["all"] && clearInterval(apptimeouts["all"]);
apptimeouts["all"] = setTimeout(check_apps, global.INTERVAL || 30000);
}
});
}
function flog () {
var mongojs, db;
if (global.MONGO_URI) {
mongojs = require('mongojs');
db = mongojs(global.MONGO_URI, ['log']);
}
var prefix = $c.now('M d H:i:s')+' PID[' + process.pid + ']: ';
for (var i = 0, len = arguments.length; i < len; i++) {
if ($c.isString(arguments[i])) { console.log(prefix + arguments[i]); }
else { console.log(prefix, arguments[i]); }
if (global.MONGO_URI) {
db.log.insert({pid:process.pid,created:$c.now('M d H:i:s'),message:$c.isString(arguments[i]) ? arguments[i] : JSON.stringifyAdvanced(arguments[i]) });
}
}
}
function _exec (process) {
return syncroit(function* (){
var func = function (code, output, message) {
flog({code:code,output:output});
io.emit("process_complete",{code:code,output:output});
return arguments;
};
var args = yield CL.exec(process);
return func.apply(this,args);
});
}
function buildit(data){
return syncroit(function*() {
logit('deploy', data);
config.apps = include(CONFIG_PATH + 'craydent_deploy_config.json', true);
var appobj = config.apps.where({name: data.name})[0] || {};
var name = appobj.name;
if (data.passcode == SAC && name && actions[data.action]) {
deploying[name] = true;
yield _exec("echo \"user is $USER\";");
var args = yield _exec(shelldir + "deploy_script.sh " + name + " " + actions[data.action] +
" " + (appobj.www || "''") +
" " + (appobj.nodejs || "''") +
" " + (appobj.webdir || "''") +
" '" + appobj.servers.join(" ") + "'" +
" '" + (global.ENV || "prod") + "'");
if ($c.startsWithAny(data.action,"build","pull","npm")) {
if (pconfig = include(CPROXY_PATH, true)) {
var p = include(GIT_BASE_PATH + name + '/package.json',true);
p = JSON.parseAdvanced(p,null,null,GIT_BASE_PATH + name);
var routes = $c.getProperty(p, 'cproxy.routes') || {};
for (var fqdn in routes) {
if (!routes.hasOwnProperty(fqdn)) { continue; }
pconfig.routes[fqdn] = pconfig.routes[fqdn] || [];
$c.upsert(pconfig.routes[fqdn], routes[fqdn], "name");
}
yield fswrite(CPROXY_PATH, JSON.stringify(pconfig, null, 2));
}
}
delete deploying[name];
logit('build complete.');
return args;
} else {
return [500,"Access Denied"];
}
});
}
function rest_action(self, action, params) {
return syncroit(function*(){
params.action = action;
if (params.webhook) {
buildit(params);
self.send(200, {message:"build request received."});
return;
}
var args = yield buildit(params),code = args[0], output = args[1];
self.send(!code ? 200 : 500, {code:code,output:output});
});
}
function add_admin_user (data) {
var auth = global.HTTP_AUTH;
if (auth[data.username]) { return {error:true,message:"user already exists."}; }
if (data.passcode != SAC || data.sac != SAC
|| (!~auth[data.username].access.indexOf('*') && !~auth[data.username].access.indexOf(LISTENERS["adduser"]))) {
return {error:true,message:"you do not have sufficient access."};
}
//if (!~global.HTTP_AUTH_USERNAME.indexOf(data.username)) { return {error:true,message:"user already exists."}; }
auth[data.username] = { "access": (data.access || "").split(','), "password": encrypt_password(data.password) };
writeNodeConfig(CONFIG_PATH);
return {error: false,message:"successfully added user."}
}
function rm_admin_user (data) {
var auth = global.HTTP_AUTH;
if (!auth[data.username]) { return {error:true,message:"user does not exist."}; }
if (data.passcode != SAC || data.sac != SAC
|| (!~auth[data.username].access.indexOf('*') && !~auth[data.username].access.indexOf(LISTENERS["removeuser"]))) {
return {error:true,message:"you do not have sufficient access."};
}
delete auth[data.username];
writeNodeConfig(CONFIG_PATH);
return {error: false,message:"successfully removed user."}
}
function update_admin (data) {
var auth = global.HTTP_AUTH;
if (!auth[data.username]) { return {error:true,message:"user does not exist."}; }
if (data.passcode != SAC || data.sac != SAC
|| (!~auth[data.username].access.indexOf('*') && !~auth[data.username].access.indexOf(LISTENERS["updateuser"]))) {
return {error:true,message:"you do not have sufficient access."};
}
if (!correct_password(data.old_password, auth[data.username])) { return {error:true,message:"password does not match"}}
auth[data.username].password = encrypt_password(data.password);
auth[data.username].access = (data.access ? data.access.split(',') : auth[data.username].access) || [];
writeNodeConfig(CONFIG_PATH);
return {error: false,message:"successfully updated password."}
}
// create http server
// the front facing files are in the public folder
function init_webserver() {
var server = createServer(function* (req, res) {
var self = this,
path = self.SERVER_PATH,
hauth = req.headers['authorization'],
auth_header = 'WWW-Authenticate: Basic realm="Deployer Secure Area"';
if (path.contains('?')) {
path = path.split('?')[0];
}
if (path.endsWith('/')) {
path += "index.html";
}
path = (path.startsWith('/') ? PROJECT_PATH + "public" : PROJECT_PATH + "public/") + path;
path.endsWith('.html') && self.header("Content-Type: text/html");
if (!self.SERVER_PATH.contains(global.SAC) && path.endsWith('.html')) {
if (!hauth) { // No Authorization header was passed in so it's the first time the browser hit us
self.header(auth_header);
return self.end(401, '<html><body>You are trying to access a secure area. Please login.</body></html>');
}
var encoded = hauth.split(' ')[1]; // Split on a space, the original auth looks like "Basic Y2hhcmxlczoxMjM0NQ==" and we need the 2nd part
var index, not_authorized = '<html><body>You are not authorized to access this page</body></html>';
if (!authorized(encoded)) {
self.header(auth_header);
self.end(401, not_authorized);
}
}
var exists = yield fsexists(path);
if (!exists) {
flog('missing file: ' + path, exists);
return self.end();
}
flog('file: ' + path);
var args = yield fsread(path, 'utf8'), err = args[0], data = args[1];
if (err) {
return self.end();
}
return self.end(fillTemplate(data, config));
}).listen(global.HTTP_PORT);
server.all("/acknowledge/${cuid}", function* (req, res, params) {
var lt = log_tracker[params.cuid];
if (lt) {
clearTimeout(lt.timeout);
delete log_tracker[lt.cuid];
return self.send(200, {message:"Acknowledgment received."});
}
return self.send(200, {message:"Acknowledgment does not exist or has already been reviewed."});
});
server.all("/build/${name}/${passcode}", function* (req, res, params) {
return yield rest_action(this, "build", params);
});
server.all("/backup/${name}/${passcode}", function* (req, res, params) {
return yield rest_action(this, "backup", params);
});
server.all("/npm/${command}/${name}/${passcode}", function* (req, res, params) {
return yield rest_action(this, "npm" + params.command, params);
});
server.all("/pull/${name}/${passcode}", function* (req, res, params) {
return yield rest_action(this, "pull", params);
});
server.all("/pull/${command}/${name}/${passcode}", function* (req, res, params) {
return yield rest_action(this, "pull" + params.command, params);
});
server.all("/restart/${name}/${passcode}", function* (req, res, params) {
return yield rest_action(this, "restart", params);
});
server.all("/start/${name}/${passcode}", function* (req, res, params) {
return yield rest_action(this, "start", params);
});
server.all("/stop/${name}/${passcode}", function* (req, res, params) {
return yield rest_action(this, "stop", params);
});
server.all("/sync/${name}/${passcode}", function* (req, res, params) {
return yield rest_action(this, "sync", params);
});
server.all("/admin/user/add/${passcode}/${username}/${password}", function* (req, res, params) {
return add_admin_user(params);
});
server.all("/admin/user/remove/${passcode}/${username}", function* (req, res, params) {
return rm_admin_user(params);
});
server.all("/admin/password/update/${passcode}/${username}/${old_password}/${password}", function* (req, res, params) {
return update_admin(params);
});
logit('http start on port: ' + global.HTTP_PORT);
}
// helper functions
function pollProcess(name) {
return syncroit(function*() {
if (!deploying[name]) {
flog(yield _exec("ps aux | grep " + name));
}
});
}
function start_app(obj) {
// do not proceed if there is no log file
if (!obj.logfile && !obj.logfile.length) { return; }
var files = obj.logfile;
// loop through each log file and start watching the logs
for (var i = 0, len = files.length; i < len; i++) {
var file = files[i];
(function(fname) {
if (!fs.existsSync(fname)) {
return;
}
obj.fd[fname] = fs.openSync(fname, 'r');
obj.size[fname] = fs.statSync(fname).size;
fs.watch(fname, function (action, filename) {
if (action != "change") { return; }
fs.stat(fname, function (err, stats) {
if (err) {
return io.emit('error', err);
}
var cfsize = stats.size,
size = obj.size[fname] || 0;
if (size && cfsize > size) {
fs.read(obj.fd[fname] || null, new Buffer(cfsize - size), 0, cfsize - size - 1, size, function (err, br, buffer) {
io.emit('line', {line: buffer.toString('utf8'), file: fname});
});
}
obj.size[fname] = cfsize;
});
});
})(file);
}
}
function getsshkey(name){
return syncroit(function*(){
var path = KEY_PATH + name;
var exists = yield fsexists(path);
if (!exists) { return; }
var args = yield fsreaddir(path, 'utf8'),
err = args[0], dt = args[1];
if (err) {
return {error: true, message: err};
}
return {content: dt,name:name};
});
}