Skip to content

Commit

Permalink
Dockerize event reminder module
Browse files Browse the repository at this point in the history
* Add Dockerfile for image build

* Add crontab autoregister

* Add GitHub Actions

* Use locally checked out repo

* Add DockerHub login

* Split GitHub Actions workflows for dev environment

* Add Docker image build workflow for stable releases

* Finalize workflows

* Use more reliable fetch_channel instead of get_channel to avoid cache miss errors

* Make env variables easily replaceable by sed

* Clean-up directories for use inside Docker

* Add README and docker-compose

* Rollback Dockerfile

* Use docker-compose secrets for Discord token

* Unversion discord-token.txt to use template file instead

* Read secrets from file instead of env

* Clean up template
  • Loading branch information
enrico-ghidoni authored Jun 22, 2024
1 parent 5d25c75 commit ba69964
Show file tree
Hide file tree
Showing 11 changed files with 158 additions and 10 deletions.
3 changes: 1 addition & 2 deletions .env.template
Original file line number Diff line number Diff line change
@@ -1,2 +1 @@
OWLBOT_SECRET=
OP_START_CHANNEL_ID=
OP_START_CHANNEL_ID=<OP_START_CHANNEL_ID>
31 changes: 31 additions & 0 deletions .github/workflows/dev-image-build.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
name: Build Owlbot DEV Docker image

on:
push:
branches: [ "dockerize", "dev" ]

jobs:

build:

runs-on: ubuntu-latest
environment: dev

steps:
-
name: Checkout repository
uses: actions/checkout@v4
with:
path: 'owlbot-repo'
-
name: Build the Docker image
run: docker build . --file owlbot-repo/Dockerfile --tag cntoarma/owlbot:dev
-
name: Authenticate to CNTO DockerHub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
-
name: Publish image to DockerHub
run: docker image push cntoarma/owlbot:dev
31 changes: 31 additions & 0 deletions .github/workflows/stable-image-build.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
name: Build Owlbot Docker image

on:
push:
branches: [ "main" ]

jobs:

build:

runs-on: ubuntu-latest
environment: stable

steps:
-
name: Checkout repository
uses: actions/checkout@v4
with:
path: 'owlbot-repo'
-
name: Build the Docker image
run: docker build . --file owlbot-repo/Dockerfile --tag cntoarma/owlbot:latest
-
name: Authenticate to CNTO DockerHub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
-
name: Publish image to DockerHub
run: docker image push cntoarma/owlbot:latest
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
# CNTO Custom
log
*.log
.env.local*
discord-token.txt

# Byte-compiled / optimized / DLL files
__pycache__/
Expand Down
10 changes: 10 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
FROM alpine:3.19

ADD owlbot-repo /owlbot
WORKDIR /owlbot

RUN apk add --no-cache python3 py3-pip
RUN pip install --break-system-packages -r requirements.txt
RUN crontab crontab.txt

CMD ["crond", "-f"]
51 changes: 51 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# CNTO Owlbot

## What is the Owlbot

Owlbot is CNTO's omnipresent assistant. It is currently implemented as a TeamSpeak user for populating our `stats` pages, and on Discord for automated member pings before our operations begin. R&D has plans to expand the Discord presence to enable staff members to carry out their tasks directly from our Discord, but this is a WIP.

## Installation guide

Owlbot is available as [a Docker image](https://hub.docker.com/repository/docker/cntoarma/owlbot/general), published on CNTO's DockerHub registry.

### 1. Create a Discord application from the Discord Developer Portal

You can follow [this guide](https://discordpy.readthedocs.io/en/stable/discord.html) to create a bot application. CNTO has two versions of the Owlbot managed by R&D: OWL and OWL Dev. The key takeaway from this step is to obtain the bot's secret, used to authenticate the bot against Discord's API.

### 2. Gather the required parameters

Within CNTO, the Owlbot is deployed on the `Tools Server`. It requires a few parameters as described in the `.env.template` file, namely:

```language=config
OWLBOT_SECRET=<OWLBOT_SECRET> # The bot's secret obtained on the Discord Developer Portal
OP_START_CHANNEL_ID=<OP_START_CHANNEL_ID> # The ID of the channel where operations reminders will be posted
```

These parameters can be passed to Owlbot in two different ways:

1. As system environment variables, for example `export OWLBOT_SECRET=1234`
2. As `.env` file in the same directory as the `.env.template`

Owlbot will try to load from a `.env` file, falling back to system variables. If both are present, system variables are used.

**Note** if you use the Owlbot Docker image from our public registry, the `.env` file is not yet created by the build process so you need to rely on environment variables. The `.env` file mechanism is supported for local development environments. We do not plan on adding `.env` file support for staging / production environments.

### 3. Run the Docker image

Launch a container based on the Owlbot Docker image, for example:

```bash
docker run -d -e OWLBOT_SECRET=<YOUR_SECRET_HERE> -e OP_START_CHANNEL_ID=<YOUR_CHANNEL_ID_HERE> cntoarma/owlbot:[stable|dev]
```

If you still want to use a `.env` you can avoid passing environment variables to the run command, for example:

```bash
docker run -d --env-file .env cntoarma/owlbot:[stable|dev]
```

**Note** using `docker-compose` is preferred in production environments as it can also handle container restarts, ensuring the Owlbot is operational all the time.

#### Update the crontab file

By default, the Owlbot will send join reminders 10 minutes before our events start (19:35 CET / CEST). This is configured in the `crontab.txt` file that gets installed inside the Owlbot container upon build. If you need to change the
1 change: 1 addition & 0 deletions crontab.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
35 19 * * 2,5 sh /owlbot/op-reminder.sh
1 change: 1 addition & 0 deletions discord-token.txt.template
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
DISCORD_TOKEN_HERE
13 changes: 13 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
version: "3"
services:
owlbot:
container_name: owlbot
# restart: unless-stopped
env_file: .env
image: cntoarma/owlbot:dev
secrets:
- discord_token

secrets:
discord_token:
file: ./discord-token.txt
4 changes: 1 addition & 3 deletions op-reminder.sh
Original file line number Diff line number Diff line change
@@ -1,3 +1 @@
source ~/miniconda3/etc/profile.d/conda.sh
conda activate discord-owlbot
python /home/carpenoctem/discord-owlbot/op-start-reminder.py
python /owlbot/op-start-reminder.py > /owlbot/cron.log 2>&1
21 changes: 16 additions & 5 deletions op-start-reminder.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,29 @@
import discord
from dotenv import load_dotenv
from dotenv import dotenv_values
import os

load_dotenv()
# Load from .env (for local dev environments) or override with environment variables (for production)
config = {
**dotenv_values('.env'),
**os.environ
}

CHANNEL_ID = os.enivon['OP_START_CHANNEL_ID']
BOT_SECRET = os.environ['OWLBOT_SECRET']
CHANNEL_ID = config['OP_START_CHANNEL_ID']

# Read bot token for Discord auth from docker-compose secrets
BOT_SECRET = None
with open('/run/secrets/discord_token', 'r') as f:
BOT_SECRET = f.read()

if BOT_SECRET is None:
raise ValueError("Unable to read Discord token")

class MyClient(discord.Client):
async def on_ready(self):
# async for guild in client.fetch_guilds(limit=150):
# print(guild.name)

channel = self.get_channel(CHANNEL_ID)
channel = await self.fetch_channel(CHANNEL_ID)
await channel.send("Tonight's OP is about to start, @here grab a drink and join us!")
await self.close()

Expand Down

0 comments on commit ba69964

Please sign in to comment.