website

#astro#js#html#css

git clone https://git.pyrossh.dev/website

木 Personal website of pyrossh. Built with astrojs, shiki, vite.


src/posts/gopibot-to-the-rescue.md
2f32cac 1
---
2f32cac 2
title: Gopibot to the rescue
2f32cac 3
description: A slackbot for deploying your applications (chatops)
2f32cac 4
pubDate: 2017-04-19
2f32cac 5
tags:
2f32cac 6
  - nodejs
2f32cac 7
  - slack
2f32cac 8
  - bot
2f32cac 9
  - chatops
2f32cac 10
published: true
2f32cac 11
---
2f32cac 12
2f32cac 13
I was one of the developers who had access to our QA and Prod servers and the other person was the Head of Engineering and he is generally a busy guy.
2f32cac 14
So whenever there is a change that needs to be deployed everyone comes to me and tells me to deploy their microservice/frontend to the QA and blatantly
2f32cac 15
interrupts my awesome coding cycle.
2f32cac 16
2f32cac 17
Alright then, I break off from my flow, ssh into the server and start running the deploy command. And all of you jsdev wannabes who have worked with react and webpack will know the horrors about deploying frontend code right. It takes forever so I have to wait there looking at the console along with the dev who wanted me to deploy it (lets call him @kokill for now). So @kokill and I patiently wait for the webpack build to finish. 1m , 2m, 3m and WTH 15m. And then its built and the new frontend is deployed to QA. YES! Now I can continue with my work. But wait then some other dev comes likes call him (@D-Ne0) and he asks to deploy something else and again the same process of ssh’ing the server and another wait. This got repetitive and irritating.
2f32cac 18
2f32cac 19
Then I started searching for solutions to the problem and looked high and low and thought that CI/CD is the only thing that can solve this problem. But then I saw something new called ChatOps where developers have chatbots to talk to automate this manual work. Just like we have bots these days to help you out in your work like getting your laundry, grocery and making orders.
2f32cac 20
2f32cac 21
So I decided to take a shot at this in my free time. And it seems it was simpler than I thought and decided to use Slack our primary team communication platform. We used it daily for everything and I thought why not have a specific channel just where the bot resides and people could talk to the bot.
2f32cac 22
2f32cac 23
Since we are typically a nodejs shop I decided to find a way to send messages to a slack bot. And slack has this really great sdk for nodejs.
2f32cac 24
https://github.com/slackapi/node-slack-sdk  
2f32cac 25
First I went and created the bot in my slack team settings. And then wrote a script which would allow it to read messages from the channel it was added.
2f32cac 26
2f32cac 27
Here is the simple script,
2f32cac 28
2f32cac 29
```js
2f32cac 30
const RtmClient = require("@slack/client").RtmClient;
2f32cac 31
const RTM_EVENTS = require("@slack/client").RTM_EVENTS;
2f32cac 32
const CLIENT_EVENTS = require("@slack/client").CLIENT_EVENTS;
2f32cac 33
const bot_token = process.env.SLACK_BOT_TOKEN;
2f32cac 34
2f32cac 35
const rtm = new RtmClient(bot_token);
2f32cac 36
const COMMANDS = {
2f32cac 37
  web: "ssh -i qa.pem user@url docker pull image-name && docker rm -f container-id && docker run -d image-name",
2f32cac 38
};
2f32cac 39
let deploymentInProgress = false;
2f32cac 40
let counter = 0;
2f32cac 41
2f32cac 42
rtm.on(RTM_EVENTS.MESSAGE, (event) => {
2f32cac 43
  console.log("Got event", event);
2f32cac 44
  if (
2f32cac 45
    (event.subtype === "message_changed" || event.subtype === "message_deleted") &&
2f32cac 46
    event.text &&
2f32cac 47
    event.text.indexOf("$slackBotId") > -1
2f32cac 48
  ) {
2f32cac 49
    return rtm.sendMessage(
2f32cac 50
      "Please dont change the message and expect me to correct your past mistakes",
2f32cac 51
      event.channel,
2f32cac 52
    );
2f32cac 53
  }
2f32cac 54
  if (event.subtype) {
2f32cac 55
    return;
2f32cac 56
  }
2f32cac 57
  if (event.type === "message" && event.text && event.text.indexOf("$slackBotId") > -1) {
2f32cac 58
    if (deploymentInProgress === true) {
2f32cac 59
      counter = counter + 1;
2f32cac 60
      if (counter > 3) {
2f32cac 61
        counter = 0;
2f32cac 62
        return rtm.sendMessage(
2f32cac 63
          "Stop bugging me noob or I'll tell to raise you bugs",
2f32cac 64
          event.channel,
2f32cac 65
        );
2f32cac 66
      }
2f32cac 67
      return rtm.sendMessage("I am already processing a deploy request please wait", event.channel);
2f32cac 68
    }
2f32cac 69
    var input = event.text.trim().replace("$slackBotId ", "");
2f32cac 70
    console.log("Got input", input);
2f32cac 71
    const arr = input.split(" ");
2f32cac 72
    arr.forEach((word) => {
2f32cac 73
      word = word.replace(/\s/g, "");
2f32cac 74
    });
2f32cac 75
    const currCommand = arr[0];
2f32cac 76
    if (COMMANDS.indexOf(currCommand) > -1) {
2f32cac 77
      rtm.sendMessage("Starting to deploy ${currCommand}", event.channel);
2f32cac 78
      const ssh = spawn(COMMANDS[currCommand]);
2f32cac 79
      deploymentInProgress = true;
2f32cac 80
      ssh.stdout.on("data", (data) => {
2f32cac 81
        rtm.sendMessage(data, event.channel);
2f32cac 82
      });
2f32cac 83
      ssh.stderr.on("data", (data) => {
2f32cac 84
        rtm.sendMessage(data, event.channel);
2f32cac 85
      });
2f32cac 86
      ssh.on("close", (code) => {
2f32cac 87
        deploymentInProgress = false;
2f32cac 88
        if (code === 0) {
2f32cac 89
          console.log("Deployed Successfully", currCommand);
2f32cac 90
          rtm.sendMessage("Deployed Successfully " + currCommand, event.channel);
2f32cac 91
        } else {
2f32cac 92
          console.log("child process exited with code ", code);
2f32cac 93
          rtm.sendMessage("child process exited with code " + code);
2f32cac 94
        }
2f32cac 95
      });
2f32cac 96
      return;
2f32cac 97
    } else {
2f32cac 98
      counter = counter + 1;
2f32cac 99
      if (counter > 3) {
2f32cac 100
        counter = 0;
2f32cac 101
        return rtm.sendMessage(
2f32cac 102
          "Stop bugging me noob or I'll tell <@U30TXGLS1|gopi> to raise you bugs",
2f32cac 103
          event.channel,
2f32cac 104
        );
2f32cac 105
      }
2f32cac 106
      return rtm.sendMessage(
2f32cac 107
        `command '${event.text} ' not found.You need to specify one of these commands [${COMMANDS.map(
2f32cac 108
          (v, k) => k,
2f32cac 109
        ).join(",")} ]`,
2f32cac 110
        event.channel,
2f32cac 111
      );
2f32cac 112
    }
2f32cac 113
  }
2f32cac 114
});
2f32cac 115
console.log("Starting deploybot");
2f32cac 116
rtm.start();
2f32cac 117
```
2f32cac 118
2f32cac 119
So what the bot does is when someone mentions the bot with a command to run. It first checks if the command is defined in our COMMANDS map and then if
2f32cac 120
it is, it executes the corresponding shell command for it on our QA server and then gives back progress/error/finished messages back to the channel so
2f32cac 121
that everyone will be notified that someone had done a deployment. This is how it looks like,
2f32cac 122
2f32cac 123
Anyways to just have a boring bot that just runs boring commands was kinda boring. I thought of spicing up the bot interaction by making it say weird
2f32cac 124
things if you keep giving it invalid commands. Making it more of a life like bot.
2f32cac 125
2f32cac 126
Initially the bot was called deploybot and had a rocket icon but then there was our QA/Bug creator/Hell Raiser/Injoker in our team so I thought creating
2f32cac 127
a mini him would be better and give the bot a real person’s personality and it worked and people kind a started talking to bot some random stuff and
2f32cac 128
all.
2f32cac 129
2f32cac 130
![Gopibot 1](@/assets/images/gopibot.png)
2f32cac 131
2f32cac 132
Further on we can maybe introduce natural language processing and deep learning to make the bot learn from our messages and not just take a single
2f32cac 133
command. Like instead of me saying @gopibot cfm I can say @gopibot please deploy our cashflow server or please revert the deployment to the previous
2f32cac 134
version and things like that.