-
Notifications
You must be signed in to change notification settings - Fork 116
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Inconsistent return code #150
Comments
This is odd. Is this also happening when the |
Unfortunately, I'm not able to reproduce this. Could you please replace var util = require('util')
, extend = require('util-extend')
, Fiber = require('fibers')
, Connection = require('ssh2').Client
, byline = require('byline')
, Transport = require('./index')
, errors = require('../errors')
, fs = require('fs');
function SSH(context) {
SSH.super_.call(this, context);
var config = extend({}, context.remote); // clone
if(config.tryKeyboard !== false) {
config.tryKeyboard = true;
config.readyTimeout = config.readyTimeout || 30000;
}
if(config.privateKey) {
config.privateKey = fs.readFileSync(config.privateKey, { encoding: 'utf8' });
}
var self = this;
var fiber = Fiber.current;
this._connection = new Connection();
this._connection.on('keyboard-interactive', function next(name, instructions,
instructionsLang, prompts, finish, answers) {
answers = answers || [];
var currentPrompt = prompts[answers.length];
if(answers.length < prompts.length) {
new Fiber(function() {
var answer = self.prompt(currentPrompt.prompt, { hidden: !currentPrompt.echo });
answers.push(answer);
next(name, instructions, instructionsLang, prompts, finish, answers);
}).run();
} else {
finish(answers);
}
});
this._connection.on('ready', function() {
fiber.run();
});
this._connection.on('error', function(err) {
return fiber.throwInto(err);
});
this._connection.connect(config);
return Fiber.yield();
}
util.inherits(SSH, Transport);
SSH.prototype._exec = function(command, options) {
options = options || {};
var self = this;
options = extend(extend({}, self._options), options); // clone and extend
var result = {
code: 0,
stdout: null,
stderr: null
};
self._logger.command(command);
var fiber = Fiber.current;
self._connection.exec(command, options.exec || {}, function(err, stream) {
stream.on('data', function(data) {
result.stdout = (result.stdout || '') + data;
});
stream.stderr.on('data', function(data) {
result.stderr = (result.stderr || '') + data;
});
byline(stream, { keepEmptyLines: true }).on('data', function(data) {
if(!options.silent) {
self._logger.stdout(data);
}
});
byline(stream.stderr, { keepEmptyLines: true }).on('data', function(data) {
self._logger[options.failsafe ? 'stdwarn' : 'stderr'](data);
});
stream.on('exit', function(code) {
self._logger.warn('DEBUG: exit-start ' + code);
result.code = code;
self._logger.warn('DEBUG: exit-end ' + code);
});
stream.on('end', function() {
self._logger.warn('DEBUG: end-start ' + result.code);
if(result.code === 0) {
self._logger.success('ok');
} else if(options.failsafe) {
self._logger.warn('failed safely (' + result.code + ')');
} else {
self._logger.error('failed (' + result.code + ')');
var error = new errors.CommandExitedAbnormallyError(
'Command exited abnormally on ' + self._context.remote.host);
return fiber.throwInto(error);
}
self._logger.warn('DEBUG: end-end ' + result.code);
fiber.run(result);
});
});
return Fiber.yield();
};
SSH.prototype.close = function() {
this._connection.end();
};
module.exports = SSH; |
Expected output: x.x.x.x $ which bar
x.x.x.x > bar not found
x.x.x.x ● DEBUG: exit-start 1
x.x.x.x ● DEBUG: exit-end 1
x.x.x.x >
x.x.x.x ● DEBUG: end-start 1
x.x.x.x ● failed safely (1)
x.x.x.x ● DEBUG: end-end 1
x.x.x.x $ which baz
x.x.x.x > baz not found
x.x.x.x ● DEBUG: exit-start 1
x.x.x.x ● DEBUG: exit-end 1
x.x.x.x >
x.x.x.x ● DEBUG: end-start 1
x.x.x.x ● failed safely (1)
x.x.x.x ● DEBUG: end-end 1 |
There you go: Code: plan.remote(function (transport) {
['bar','baz'].forEach(function(str){
var hasWPCLI = transport.exec('which ' + str, {
failsafe: true
});
console.log(hasWPCLI.code);
});
}); Output:
Using another target (multiple executions):
|
Thank you, this is incredibly helpful. It really seems like there's a race condition where the exit event is not thrown, or simply too late. |
I tried multiple workarounds. Before continuing, it would be great if you could replace var util = require('util')
, extend = require('util-extend')
, Fiber = require('fibers')
, Connection = require('ssh2').Client
, byline = require('byline')
, Transport = require('./index')
, errors = require('../errors')
, fs = require('fs');
function SSH(context) {
SSH.super_.call(this, context);
var config = extend({}, context.remote); // clone
if(config.tryKeyboard !== false) {
config.tryKeyboard = true;
config.readyTimeout = config.readyTimeout || 30000;
}
if(config.privateKey) {
config.privateKey = fs.readFileSync(config.privateKey, { encoding: 'utf8' });
}
var self = this;
var fiber = Fiber.current;
this._connection = new Connection();
this._connection.on('keyboard-interactive', function next(name, instructions,
instructionsLang, prompts, finish, answers) {
answers = answers || [];
var currentPrompt = prompts[answers.length];
if(answers.length < prompts.length) {
new Fiber(function() {
var answer = self.prompt(currentPrompt.prompt, { hidden: !currentPrompt.echo });
answers.push(answer);
next(name, instructions, instructionsLang, prompts, finish, answers);
}).run();
} else {
finish(answers);
}
});
this._connection.on('ready', function() {
fiber.run();
});
this._connection.on('error', function(err) {
return fiber.throwInto(err);
});
this._connection.connect(config);
return Fiber.yield();
}
util.inherits(SSH, Transport);
SSH.prototype._exec = function(command, options) {
options = options || {};
var self = this;
options = extend(extend({}, self._options), options); // clone and extend
var result = {
code: 0,
stdout: null,
stderr: null
};
self._logger.command(command);
var fiber = Fiber.current;
self._connection.exec(command, options.exec || {}, function(err, stream) {
stream.on('data', function(data) {
result.stdout = (result.stdout || '') + data;
});
stream.stderr.on('data', function(data) {
result.stderr = (result.stderr || '') + data;
});
byline(stream, { keepEmptyLines: true }).on('data', function(data) {
if(!options.silent) {
self._logger.stdout(data);
}
});
byline(stream.stderr, { keepEmptyLines: true }).on('data', function(data) {
self._logger[options.failsafe ? 'stdwarn' : 'stderr'](data);
});
stream.on('exit', function(code) {
result.code = code;
});
stream.on('end', function() {
setImmediate(function() {
if(result.code === 0) {
self._logger.success('ok');
} else if(options.failsafe) {
self._logger.warn('failed safely (' + result.code + ')');
} else {
self._logger.error('failed (' + result.code + ')');
var error = new errors.CommandExitedAbnormallyError(
'Command exited abnormally on ' + self._context.remote.host);
return fiber.throwInto(error);
}
fiber.run(result);
});
});
});
return Fiber.yield();
};
SSH.prototype.close = function() {
this._connection.end();
};
module.exports = SSH; |
Sorry for the delay! My flightplan.js: var plan = require('flightplan');
plan.target('staging', {
host: 'pepperoni',
username: 'user',
agent: process.env.SSH_AUTH_SOCK
});
plan.remote(function (transport) {
['bar','baz'].forEach(function(str){
var returnCode = transport.exec('which ' + str, {
failsafe: true
});
console.log(returnCode.code);
});
}); The output (executed multiple times):
|
I'm trying to check if my remote machine has a specific command by using
which
and checking its return code.However, I'm getting some strange results as sometimes it is returned '1' and sometimes '0'.
Returning 0:
Returning 1:
Both calls were made seconds apart from each other.
Any thoughts on what's happening? Thanks!
The text was updated successfully, but these errors were encountered: