mecano
Version:
Common functions for system deployment.
244 lines (238 loc) • 7.1 kB
JavaScript
// Generated by CoffeeScript 1.11.1
var exec, misc, path, string;
module.exports = function(options, callback) {
var current_username, result, stds;
options.log({
message: "Entering execute",
level: 'DEBUG',
module: 'mecano/lib/execute'
});
stds = options.user_args;
if (typeof options.argument === 'string') {
options.cmd = options.argument;
}
if (options.code == null) {
options.code = [0];
}
if (!Array.isArray(options.code)) {
options.code = [options.code];
}
if (options.code_skipped == null) {
options.code_skipped = [];
}
if (!Array.isArray(options.code_skipped)) {
options.code_skipped = [options.code_skipped];
}
if (options.stdin_log == null) {
options.stdin_log = true;
}
if (options.stdout_callback === void 0) {
options.stdout_callback = true;
}
if (options.stderr_callback === void 0) {
options.stderr_callback = true;
}
options.stdout_log = options.hasOwnProperty('stdout_log') ? options.stdout_log : true;
options.stderr_log = options.hasOwnProperty('stderr_log') ? options.stderr_log : true;
if (typeof options.cmd === 'function') {
options.cmd = options.cmd.call(this, options);
}
if (options.cmd == null) {
throw Error("Missing cmd: " + options.cmd);
}
if (options.trap) {
options.cmd = "set -e\n" + options.cmd;
}
if (options.stdin_log) {
options.log({
message: options.cmd,
type: 'stdin',
module: 'mecano/lib/execute'
});
}
result = {
stdout: null,
stderr: null,
code: null
};
current_username = options.ssh ? options.ssh.config.username : /^win/.test(process.platform) ? process.env['USERPROFILE'].split(path.sep)[2] : process.env['USER'];
this.call({
shy: true
}, function(_, callback) {
var obj;
if (options.target) {
return callback(null, true);
}
if (current_username === 'root') {
return callback(null, false);
}
if (!options.uid) {
return callback(null, false);
}
if (!/\d/.test("" + options.uid)) {
return callback(null, options.uid !== current_username);
}
return this.execute((
obj = {},
obj["awk -v val=" + options.uid + " -F "] = " '$3==val{print $1}' /etc/passwd`",
obj
), function(err, _, stdout) {
if (!err) {
options.uid = stdout.trim();
}
return callback(err, options.uid !== current_username);
});
});
this.call({
"if": function() {
return this.status(-1);
},
handler: function() {
options.cmd = "#!/bin/bash\n\n" + options.cmd;
if (options.target == null) {
options.target = "/tmp/mecano_" + (string.hash(options.cmd));
}
options.log({
message: 'Writing bash script to #{JSON.stringify options.target}',
level: 'INFO'
});
options.cmd = "su - " + options.uid + " -c 'bash /tmp/mecano_" + (string.hash(options.cmd)) + "'";
return this.file({
target: options.target
});
}
});
this.call(function(_, callback) {
var child, stderr_stream_open, stdout_stream_open;
child = exec(options);
result.stdout = [];
result.stderr = [];
if (options.stdout) {
child.stdout.pipe(options.stdout, {
end: false
});
}
if (options.stderr) {
child.stderr.pipe(options.stderr, {
end: false
});
}
stdout_stream_open = stderr_stream_open = false;
if (options.stdout_callback || options.stdout_log) {
child.stdout.on('data', function(data) {
if (options.stdout_log) {
stdout_stream_open = true;
}
if (options.stdout_log) {
options.log({
message: data,
type: 'stdout_stream',
module: 'mecano/lib/execute'
});
}
if (options.stdout_callback) {
if (Array.isArray(result.stdout)) {
return result.stdout.push(data);
} else {
return console.log('stdout coming after child exit');
}
}
});
}
if (options.stderr_callback || options.stderr_log) {
child.stderr.on('data', function(data) {
if (options.stderr_log) {
stderr_stream_open = true;
}
if (options.stderr_log) {
options.log({
message: data,
type: 'stderr_stream',
module: 'mecano/lib/execute'
});
}
if (options.stderr_callback) {
if (Array.isArray(result.stderr)) {
return result.stderr.push(data);
} else {
return console.log('stderr coming after child exit');
}
}
});
}
return child.on("exit", function(code) {
result.code = code;
return setTimeout(function() {
var err, status;
if (stdout_stream_open && options.stdout_log) {
options.log({
message: null,
type: 'stdout_stream',
module: 'mecano/lib/execute'
});
}
if (stderr_stream_open && options.stderr_log) {
options.log({
message: null,
type: 'stderr_stream',
module: 'mecano/lib/execute'
});
}
result.stdout = result.stdout.map(function(d) {
return d.toString();
}).join('');
if (options.trim || options.stdout_trim) {
result.stdout = result.stdout.trim();
}
result.stderr = result.stderr.map(function(d) {
return d.toString();
}).join('');
if (options.trim || options.stderr_trim) {
result.stderr = result.stderr.trim();
}
if (result.stdout && result.stdout !== '' && options.stdout_log) {
options.log({
message: result.stdout,
type: 'stdout',
module: 'mecano/lib/execute'
});
}
if (result.stderr && result.stderr !== '' && options.stderr_log) {
options.log({
message: result.stderr,
type: 'stderr',
module: 'mecano/lib/execute'
});
}
if (options.stdout) {
child.stdout.unpipe(options.stdout);
}
if (options.stderr) {
child.stderr.unpipe(options.stderr);
}
if (options.code.indexOf(code) === -1 && options.code_skipped.indexOf(code) === -1) {
err = new Error("Invalid Exit Code: " + code);
err.code = code;
return callback(err, null);
}
if (options.code_skipped.indexOf(code) === -1) {
status = true;
} else {
options.log({
message: "Skip exit code \"" + code + "\"",
level: 'INFO',
module: 'mecano/lib/execute'
});
}
return callback(null, status);
}, 1);
});
});
return this.then(function(err, status) {
return callback(err, status, result.stdout, result.stderr, result.code);
});
};
path = require('path');
exec = require('ssh2-exec');
misc = require('../misc');
string = require('../misc/string');