Skip to content
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

Further tweaks for #168 #169

Merged
merged 18 commits into from
Jun 4, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 0 additions & 31 deletions lib/slack-messages.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,37 +18,6 @@

var utils = require('./utils.js');

// Polyfill from:
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign
if (typeof Object.assign !== 'function') {
// Must be writable: true, enumerable: false, configurable: true
Object.defineProperty(Object, "assign", {
value: function assign(target, varArgs) { // .length of function is 2
if (target === null) { // TypeError if undefined or null
throw new TypeError('Cannot convert undefined or null to object');
}

var to = Object(target);

for (var index = 1; index < arguments.length; index++) {
var nextSource = arguments[index];

if (nextSource !== null) { // Skip over if undefined or null
for (var nextKey in nextSource) {
// Avoid bugs when hasOwnProperty is shadowed
if (Object.prototype.hasOwnProperty.call(nextSource, nextKey)) {
to[nextKey] = nextSource[nextKey];
}
}
}
}
return to;
},
writable: true,
configurable: true
});
}

var buildMessagesWithChunkedFieldValue = function (msg) {
var msgs;

Expand Down
12 changes: 12 additions & 0 deletions lib/slack_monkey_patch.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,18 @@ function patchSendMessage(robot) {
// formatted and parsed on the server side.
// NOTE / TODO: We can get rid of this nasty patch once our node-slack-client and hubot-slack pull
// requests are merged.
// This code was refactored in https://github.com/StackStorm/hubot-stackstorm/pull/6
// which was opened and merged by Kami on 2015-06-04.
// As of 2019-05-22, these were the PRs I could find for the node-slack-client
// hubot-slack repositories:
// * https://github.com/slackapi/node-slack-sdk/pull/42
// - which was closed during a refactor and converted into an issue:
// https://github.com/slackapi/node-slack-sdk/issues/138
// * https://github.com/slackapi/hubot-slack/pull/544
// - which was opened on 2018-11-14, which seems to be too late to actually
// apply to this code
// So...I'm not entirely sure this monkey patch is still necessary.
// End-to-end testing is required to figure out for sure.
if (robot.adapter && robot.adapter.constructor && robot.adapter.constructor.name === 'SlackBot') {
for (var channel in robot.adapter.client.channels) {
robot.adapter.client.channels[channel].sendMessage = sendMessageRaw.bind(robot.adapter.client.channels[channel]);
Expand Down
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
"devDependencies": {
"chai": "^4.2.0",
"chai-as-promised": "^7.1.1",
"chai-string": "^1.5.0",
"gulp": "^3.9.0",
"gulp-jshint": "^2.1.0",
"gulp-mocha": "^6.0.0",
Expand All @@ -46,6 +47,7 @@
"jshint": "^2.7.0",
"jshint-stylish": "^2.0.0",
"log": "1.4.0",
"mocked-env": "^1.2.4",
"nock": "^10.0.0",
"nyc": "^13.0.1",
"sinon": "^6.3.5",
Expand Down
138 changes: 61 additions & 77 deletions scripts/stackstorm.js
Original file line number Diff line number Diff line change
Expand Up @@ -100,22 +100,20 @@ var TWOFACTOR_MESSAGE = "This action requires two-factor auth! Waiting for your
module.exports = function(robot) {
slack_monkey_patch.patchSendMessage(robot);

var self = this;

var promise = Promise.resolve();

if (env.ST2_API) {
robot.logger.warning("ST2_API is deprecated and will be removed in a future releases. Instead, please use the ST2_API_URL environment variable.");
}
var url = utils.parseUrl(env.ST2_API_URL);

var opts = {
protocol: url.protocol,
host: url.hostname,
port: url.port,
prefix: url.path,
rejectUnauthorized: false
};
var _stream = null,
self = this,
promise = Promise.resolve(),
url = utils.parseUrl(env.ST2_API_URL),
opts = {
protocol: url.protocol,
host: url.hostname,
port: url.port,
prefix: url.path,
rejectUnauthorized: false
};

if (env.ST2_STREAM_URL) {
var stream_url = utils.parseUrl(env.ST2_STREAM_URL);
Expand All @@ -127,35 +125,30 @@ module.exports = function(robot) {
};
}

var api = st2client(opts);
var api_client = st2client(opts);

if (env.ST2_API_KEY) {
api.setKey({ key: env.ST2_API_KEY });
api_client.setKey({ key: env.ST2_API_KEY });
} else if (env.ST2_AUTH_TOKEN) {
api.setToken({ token: env.ST2_AUTH_TOKEN });
}

function hubotErrorCallback(error, res) {
// Hubot alrady logged the stack trace before call this callback function,
// only error message will be logged here
robot.logger.error("Caught error from hubot: " + error.message);

stop();
api_client.setToken({ token: env.ST2_AUTH_TOKEN });
}

function exitProcessWithLog(errorMsg, err) {
function logErrorAndExit(err, res) {
if (err) {
robot.logger.error(errorMsg + err.message);
robot.logger.error(err.stack);
} else if (errorMsg != "") {
robot.logger.error(errorMsg);
}
if (res) {
res.send(JSON.stringify({
"status": "failed",
"msg": "An error occurred trying to post the message:\n" + err
}));
}

stop();
}

function authenticate() {
api.removeListener('expiry', authenticate);
api_client.removeListener('expiry', authenticate);

// API key gets precedence 1
if (env.ST2_API_KEY) {
Expand All @@ -172,7 +165,7 @@ module.exports = function(robot) {

var url = utils.parseUrl(env.ST2_AUTH_URL);

var client = st2client({
var auth_client = st2client({
auth: {
protocol: url.protocol,
host: url.hostname,
Expand All @@ -181,25 +174,26 @@ module.exports = function(robot) {
}
});

return client.authenticate(env.ST2_AUTH_USERNAME, env.ST2_AUTH_PASSWORD)
return auth_client.authenticate(env.ST2_AUTH_USERNAME, env.ST2_AUTH_PASSWORD)
.then(function (token) {
robot.logger.info('Token received. Expiring ' + token.expiry);
api.setToken(token);
client.on('expiry', authenticate);
api_client.setToken(token);
auth_client.on('expiry', authenticate);
})
.catch(function (err) {
exitProcessWithLog('Failed to authenticate: ', err);
logErrorAndExit(err);
});
}

if (env.ST2_API_KEY || env.ST2_AUTH_TOKEN || env.ST2_AUTH_USERNAME || env.ST2_AUTH_PASSWORD) {
// If using username and password then all are required.
if ((env.ST2_AUTH_USERNAME || env.ST2_AUTH_PASSWORD) &&
!(env.ST2_AUTH_USERNAME && env.ST2_AUTH_PASSWORD && env.ST2_AUTH_URL)) {
var error_msg = 'Env variables ST2_AUTH_USERNAME, ST2_AUTH_PASSWORD and ST2_AUTH_URL should only be used together.';
exitProcessWithLog(error_msg, null);
robot.logger.error('Environment variables ST2_AUTH_USERNAME, ST2_AUTH_PASSWORD and ST2_AUTH_URL should only be used together.');
stop();
} else {
promise = authenticate();
}
promise = authenticate();
}

// Pending 2-factor auth commands
Expand All @@ -217,12 +211,10 @@ module.exports = function(robot) {
// handler to manage per adapter message post-ing.
var postDataHandler = postData.getDataPostHandler(robot.adapterName, robot, formatter);

var loadCommands = function(opts) {
robot.logger.info('Loading commands....');
var loadCommands = function() {
robot.logger.info('Loading commands...');

var opts = Object.assign({exitOnFailure: false}, opts);

api.actionAlias.list()
api_client.actionAlias.list()
.then(function (aliases) {
// Remove all the existing commands
command_factory.removeCommands();
Expand Down Expand Up @@ -256,10 +248,8 @@ module.exports = function(robot) {
robot.logger.info(command_factory.st2_hubot_commands.length + ' commands are loaded');
})
.catch(function (err) {
var error_msg = 'Failed to retrieve commands from ' + env.ST2_API_URL + ' ';
if (opts.exitOnFailure) {
exitProcessWithLog(error_msg, err);
}
robot.logger.error('Failed to retrieve commands from ' + env.ST2_API_URL);
logErrorAndExit(err);
});
};

Expand All @@ -286,7 +276,7 @@ module.exports = function(robot) {
var sendAliasExecutionRequest = function (msg, payload) {
robot.logger.debug('Sending command payload:', JSON.stringify(payload));

api.aliasExecution.create(payload)
api_client.aliasExecution.create(payload)
.then(function (res) { sendAck(msg, res); })
.catch(function (err) {
// Compatibility with older StackStorm versions
Expand Down Expand Up @@ -330,7 +320,7 @@ module.exports = function(robot) {
var twofactor_id = uuid.v4();
robot.logger.debug('Requested an action that requires 2FA. Guid: ' + twofactor_id);
msg.send(TWOFACTOR_MESSAGE);
api.executions.create({
api_client.executions.create({
'action': env.HUBOT_2FA,
'parameters': {
'uuid': twofactor_id,
Expand All @@ -349,7 +339,7 @@ module.exports = function(robot) {
};

robot.respond(/([\s\S]+?)$/i, function(msg) {
var command, result, command_name, format_string, action_alias;
var command, result;

// Normalize the command and remove special handling provided by the chat service.
// e.g. slack replace quote marks with left double quote which would break behavior.
Expand All @@ -362,9 +352,7 @@ module.exports = function(robot) {
return;
}

command_name = result[0];
format_string = result[1];
action_alias = result[2];
var [command_name, format_string, action_alias] = result;

executeCommand(msg, command_name, format_string, command, action_alias);
});
Expand All @@ -380,31 +368,26 @@ module.exports = function(robot) {
}
postDataHandler.postData(data);

res.send('{"status": "completed", "msg": "Message posted successfully"}');
} catch (e) {
robot.logger.error("Unable to decode JSON: " + e);
robot.logger.error(e.stack);
res.send('{"status": "failed", "msg": "An error occurred trying to post the message: ' + e + '"}');
res.send(JSON.stringify({
"status": "completed",
"msg": "Message posted successfully"
}));
} catch (err) {
logErrorAndExit(err, res)
}
});

var commands_load_interval;

function start() {
robot.error(hubotErrorCallback);
api.stream.listen().catch(function (err) {
exitProcessWithLog('Unable to connect to stream: ', err);
}).then(function (source) {
source.onerror = function (err) {
// TODO: squeeze a little bit more info out of evensource.js
if (err.status === 401) {
robot.logger.error('Stream error:', err);
} else {
var error_message = util.format('stream error: [type: %s; status: %s]', err.type, err.status);
exitProcessWithLog(error_message, null);
}
};
source.addEventListener('st2.announcement__chatops', function (e) {
robot.error(logErrorAndExit);

api_client.stream.listen().then(function (stream) {
_stream = stream; // save stream for use in stop()
stream.on('error', function (err) {
logErrorAndExit(err);
});
stream.addEventListener('st2.announcement__chatops', function (e) {
var data;

robot.logger.debug('Chatops message received:', e.data);
Expand All @@ -419,7 +402,7 @@ module.exports = function(robot) {
});

if (env.HUBOT_2FA) {
source.addEventListener('st2.announcement__2fa', function (e) {
stream.addEventListener('st2.announcement__2fa', function (e) {
var data;

robot.logger.debug('Successfull two-factor auth:', e.data);
Expand All @@ -438,7 +421,7 @@ module.exports = function(robot) {
});

// Initial command loading
loadCommands({exitOnFailure: true});
loadCommands();

// Add an interval which tries to re-load the commands
commands_load_interval = setInterval(loadCommands.bind(self), (env.ST2_COMMANDS_RELOAD_INTERVAL * 1000));
Expand All @@ -449,10 +432,11 @@ module.exports = function(robot) {

function stop() {
clearInterval(commands_load_interval);
api.stream.listen().then(function (source) {
source.removeAllListeners();
source.close();
});

if (_stream) {
_stream.removeAllListeners();
_stream.close();
}

robot.shutdown();
process.exit(1);
Expand Down
Loading