A Slack bot to help faciliate better productivity, especially when working with Jira and/or Gerrit.
Currently Angel Bot has the following skills:
- Looking up words in the dictionary (Merriam-Webster. Requires API key)
- Providing links to Blue Jeans conference rooms
- Translating Jira numbers to Jira ticket links
- Translating gerrit notation to gerrit links
- Conducting raffles
- Add your slack token to
slackbot-frd.conf
in the provided spot (or set it as an env var, which is recommended for production environments). For more information see the slackbot_frd documentation - Add your Merriam Webster dictionary keys to
slackbot-frd.conf
(or the env var) if you want to use the dictionary bot - run
bundle install
- run
slackbot-frd start
from the top-level directory
Please do!
Angel bot uses slackbot_frd
Any VM service provider will do. Angelbot runs in docker, and has been hosted on Digital Ocean and AWS EC2 at various times. The important part is that you install docker on your base image. Once docker is installed, clone this repo:
git clone https://github.com/FreedomBen/angelbot.git
You will also probably want to install some additional tools on the system, such as tmux
(which is useful for maintaining the session after the SSH connection is closed.
Instructions in this guide will assume you are using tmux, with the provided tmux.conf
file installed at $HOME/.tmux.conf
(you can use the script ./dotfiles/update-dot-files.sh
to do this for you, but be advised it will stomp on existing files (which you probably don't
want to do on your dev machine, only on the angelbot server)).
There is a handy script located at scripts/build.sh
that will build you an image of angelbot that you can then run with the other script (see Starting). Call it from the root of the project like this:
./scripts/build.sh
Alternatively you can build it manually from the project root by running:
docker build -t angelbot .
This builds an image named "angelbot". If you give it a different name, you'll need to make note of that for when you run the image as a container.
NOTE: The tmux portion is optional, but recommended
If you're not in a tmux
session yet, kick one off:
tmux
Or if one already exists, find it and attach to it:
tmux ls # list current sessions
tmux at -t <num> # attach to session <num> e.g: 0
Check out the tmux section for a quick rundown of common tmux things that are handy.
Once the image is built, you can run it with the handy script:
./scripts/run-container.sh
or manually using:
docker run -it --rm --name angelbot angelbot bash
NOTE: The reason we are calling bash
in the container is because currently the decryption key to unlock the secrets must be typed in manually.
Once the container is running, use the start
alias to kick things off. It will prompt you for the decryption key (password) which you will need to enter:
$ start
Enter password:
Angel bot should now be running! If you're curious about implementation, read on for some explanation.
The start
alias is defined in the Dockerfile
as a shortcut to calling:
/app/scripts/start-bots.sh
The scripts/start-bots.sh
script will call aescrypt
to decrypt the secrets file and source the contents into the current shell, then start slackbot-frd
for you. All it does is call:
. <(aescrypt -d angelbot.aes -o -) || echo 'Doh password was wrong'
slackbot-frd start
The underlying slackbot_frd library uses ping/pong signals to ensure that the connection is still up. This is good because every once in a while slack will stop responding on the other end, but the socket is never closed. Without a ping/pong check, angelbot will happily continue running thinking everything is fine, when in fact it is not.
If the slack server fails to answer the "ping" message with a "pong" after a few seconds, slackbot_frd will tear down the connection and restart it. This has successfully been done for years now in production.
Occasionally however, something strange will happen and you will need to manually restart angelbot.
When this occurs, simply navigate to the running window (in tmux for example) and Ctrl+C the instance,
then restart it with normal procedure of running start
Deploying changes is as simple as SSHing in to the VM, then change to the code directory and run:
git pull --rebase
./scripts/build.sh
Then attach to the tmux session and restart the container:
tmux at # if not already attached
# <Ctrl+c> in running window
./scripts/run-container.sh
start
# Enter password
Start a new session:
tmux
Attach to existing session:
tmux ls # list current sessions
tmux at -t <num> # attach to session <num> e.g: 0
Detach from session:
<Ctrl+b> d
Split current pane horizontally:
<Ctrl+b><Ctrl+d>
Split current pane vertically:
<Ctrl+b><Ctrl+s>
Navigate panes:
<Ctrl+b> h # h, j, k, l for left, up, down, or right (like vim)
If you need to add, update, or delete a value in the secrets file, this is not hard. It does require aescrypt CLI tool to be installed on your machine. You can peek at the Dockerfile
for hints on how to install it. On Fedora, you just need to install dependencies:
sudo dnf install unzip glibc glibc-devel glibc-static
Then pull down, build, and install:
cd ~ # or wherever you prefer
wget https://github.com/FreedomBen/aescrypt/archive/master.zip
unzip master.zip
cd aescrypt-master/linux/src
make
sudo make install
Now decrypt the secrets file
aescrypt -d angelbot.aes
Enter the decryption key when prompted for the password. Once decrypted open the new file angelbot
in the editor of your choice and make your modifications.
IMPORTANT: You must stick to legal bash syntax since the contents of this file are sourced into a bash shell in the angelbot container
Now re-encrypt the file, being very careful not to fat-finger the key:
aescrypt -e angelbot
rm
the plaintext file and commit your updated version to the repo.
TIP: If you just want to view the contents of the file, you can print it to the terminal with:
aescrypt -d -o - angelbot.aes
Keep in mind tho that the contents will stick around in the tmux buffer so be discriminating about where you do this.
If running on Amazon Linux, Red Hat, CentOS, or other related distro, use:
sudo yum update
NOTE: If the update installs a new docker engine (which it does from time to time), it will kill all running docker containers which includes angelbot, and she'll need to be restarted again
Periodically, after starting/stopping docker containers, you may want to clean up artifacts left by docker. This will prevent the disk from filling up. There are a few things you should do:
- Cleanup unlabeled images (often build artifacts)
docker rmi $(docker images | grep -iE '^<none>' | awk '{print $3}' | xargs)
- Cleanup old containers (angelbot containers shouldn't accumulate, but still good to check)
Note: This is a glimpse into the distant future and isn't relevant now, but might be at some point, so I've included it here as part of my brain dump
Currently a single angel bot instance more than meets the demand at Instructure. In the future it's possible that this may change. Due to underlying libraries, angel runs on a single thread, and there isn't really a vertical scaling option. Fortunately I foresee a few strategies for scalining horizontally, which is the better way to scale anyway.
- Multiple instances of angelbot on the same EC2 instance
- Multiple EC2 instances running one or more instances of angelbot
The way it is currently, running n instances of angel bot will result in n responses to every trigger. This is obviously terrible. To correct this, there are a couple strategies to choose from (ordered by what sound like the best options to me currently):
- Have each instance only answer some non-intersecting subset of channels: E.g.: Instance 0 is listening in channels a, b, and c (busy channels) while Instance 1 listens in all other channels
- To accomplish this, you will need to modify the bot code to check for the appropriate channel. There a couple of ways to do this. See
greeting-bot.rb
for a good example (it uses slackbot_frd to do the filtering rather than checkingchannel == 'mychannel'
. If using a subset tho, I don't think currently works with slackbot_frd so you might need to do something likeif %w[c1, c2].include?(channel)
- To accomplish this, you will need to modify the bot code to check for the appropriate channel. There a couple of ways to do this. See
- Have each instance run a non-intersecting subset of bots. E.g. Instance 0 runs the gerrit-jira translator (main source of traffic) and instance 1 runs all the others
NOTE: The scripts in scripts/*
will need to be modified to use different container name based on the instance, because currently if starting multiple instances on the same docker daemon, there will be a name conflict