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

Issue 1366 - Slack integrations [ Docker Events ] #1472

Closed
wants to merge 11 commits into from
Closed
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
11 changes: 11 additions & 0 deletions tools/autodeployment/env.example
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,14 @@ UNSPLASH_CLIENT_ID=

# Path to certificates
PATH_TO_CERTS=

# Slack "Incoming WebHook" to send messages to #telescope channel.
# For more information: https://api.slack.com/messaging/webhooks
# Example:
# await fetch(SLACK_SEND_MESSAGE, {
# method: 'post',
# headers: { 'Content-Type': 'application/json' },
# body: "text": "This is the message"
# });
# This will send the following message to our Slack channel: "This is the message"
SLACK_SEND_MESSAGE=
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's add an example of what this should look like in addition to the docs.

3 changes: 2 additions & 1 deletion tools/autodeployment/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,13 @@
"description": "A tool for automatic deployment",
"main": "server.js",
"dependencies": {
"node-fetch": "^2.6.1",
"date-fns": "^2.16.1",
"dotenv": "^8.2.0",
"github-webhook-handler": "^1.0.0",
"merge-stream": "^2.0.0",
"pm2": "^4.4.1",
"shelljs": "^0.8.3"
"shelljs": "^0.8.4"
},
"scripts": {
"start": "node server.js"
Expand Down
5 changes: 4 additions & 1 deletion tools/autodeployment/server.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ const mergeStream = require('merge-stream');
const fs = require('fs');

const { buildStart, buildStop, handleStatus } = require('./info');

const { dockerMonitor } = require('./src/docker_events');
// Current build process output stream (if any)
let out;
const {
Expand All @@ -27,6 +27,9 @@ const credentials = {
cert: certificate,
};

// Docker Monitor module:
dockerMonitor();

function handleError(req, res) {
res.statusCode = 404;
res.end('Not Found');
Expand Down
11 changes: 11 additions & 0 deletions tools/autodeployment/src/docker_events/docker-listener.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# This script listens to docker events and will report only the following events:
# START, UNPAUSE, RESTART, PAUSE, DIE and STOP.


#!/bin/bash

docker events --format '{{json .}}' --filter 'event=start' --filter 'event=unpause' --filter 'event=restart' --filter 'event=pause' --filter 'event=die' --filter 'event=stop'|
while read event;
do
echo ${event}
done
108 changes: 108 additions & 0 deletions tools/autodeployment/src/docker_events/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
/* eslint-disable no-unused-expressions */
const shell = require('shelljs');
const fetch = require('node-fetch');
const Events = require('events');

const { SLACK_SEND_MESSAGE } = process.env;

const dockerEvents = new Events.EventEmitter();

const server = process.DEPLOY_TYPE === 'production' ? 'PRODUCTION' : 'DEV';

const eventsDown = ['pause', 'die', 'stop'];
const eventsBack = ['start', 'unpause', 'restart'];

const containersUp = new Set();
const containersDown = new Set();

const message = (eventLog) => {
const {
status,
Action,
Actor: {
Attributes: { name },
},
} = eventLog;

const isDown = eventsDown.includes(Action);

const logo = isDown
? 'https://www.iconsdb.com/icons/preview/red/warning-xxl.png'
: 'https://www.iconsdb.com/icons/preview/green/up-circular-xxl.png';

return {
blocks: [
{
type: 'divider',
},
{
type: 'section',
text: {
type: 'mrkdwn',
text: `* ${server} DOCKER CONTAINER: ${
isDown ? 'DOWN' : 'UP'
}*\n\nContainer: ${name}\nAction: ${Action}\nCurrent Status: ${status}\n`,
},
accessory: {
type: 'image',
image_url: logo,
alt_text: 'alt text for image',
},
},
{
type: 'divider',
},
],
};
};

const sendMessage = async (containerEvent) => {
await fetch(SLACK_SEND_MESSAGE, {
method: 'post',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(message(containerEvent)),
});
};

const eventHandle = (containerEvent) => {
const {
Action,
Actor: {
Attributes: { name },
},
} = containerEvent;

if (
(containersDown.has(name) && eventsDown.includes(Action)) ||
(containersUp.has(name) && eventsBack.includes(Action))
)
return;

if (eventsDown.includes(Action)) {
containersUp.has(name) ? containersUp.delete(name) : null;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@humphd
How can I improve my coding style here?
I'm trying to avoid callbacks hell, and then I had to disable linter (/* eslint-disable no-unused-expressions */) to code these lines where I use a ternary operator with null.

containersDown.add(name);
} else {
containersDown.has(name) ? containersDown.delete(name) : null;
containersUp.add(name);
}
sendMessage(containerEvent);
};

const dockerListener = () => {
const event = shell.exec('./docker-listener.sh', {
silent: true,
async: true,
});
event.stdout.on('data', (data) => {
const containerEvent = JSON.parse(data);
if (containerEvent.Actor.Attributes.name.includes('telescope')) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@manekenpix, this line is for filter containers. Because we could have more than one project running Docker in the machine, let's think of how it would work on CDOT machines.
This line works on my local machine because all the docker's containers start with the word "telescope"; but I think this is different on CDOT machines.

eventHandle(containerEvent);
}
});
};

dockerEvents.on('start', dockerListener);

const dockerMonitor = () => dockerEvents.emit('start');

module.exports = { dockerMonitor };