Starting Captain Hook
NOTE: Captain Hook can be run by itself, but is designed to run as part of the pod-webhooks docker pod. Instructions below are not guaranteed to work outside of the docker pod.
Captain Hook Docker "Pod"
To run Captain Hook, we utilize a Docker compose file to run the container that runs Captain Hook and mounts the correct directories in the correct locations.
See docker-compose.yml in the Captain Hook repository.
This is a one-container pod.
To start/stop/build it,
docker-compose up -d # start in background
docker-compose down
docker-compose build
To rebuild from scratch,
docker-compose build --no-cache
Startup Service: Captain Hook Docker Pod
In order to start the Captain Hook docker pod automatically
at startup, and automatically restart the pod if it crashes or
is stopped, we install a startup service called dockerpod-captainhook
:
[Unit]
Description=captain hook webhook server docker pod
Requires=docker.service
After=docker.service
[Service]
Restart=always
ExecStart=/usr/local/bin/docker-compose -f /home/charles/codes/bots/b-captain-hook/docker-compose.yml up
ExecStop=/usr/local/bin/docker-compose -f /home/charles/codes/bots/b-captain-hook/docker-compose.yml down
[Install]
WantedBy=default.target
This startup service runs docker-compose
with the -f
flag to specify
an absolute path to the Captain Hook docker-compose.yml
file.
Startup Service: Captain Hook Canary
Captain Hook listens for incoming web hooks and (optionally) runs a script in the hooks/
folder, based on the type of action, the name of the repository, and the
name of the branch.
However, there is one tricky task: Captain Hook must be able update itself when there are changes pushed to the Captain Hook repository.
To resolve this, we run a "canary" startup service for Captain Hook.
This canary startup service runs a shell script that checks (every 10 seconds)
for the presence of a file at /tmp/triggers/
. If this file is present, the
host copy of Captain Hook is updated, the Captain Hook docker pod is restarted,
and the trigger file is removed.
This allows webhooks received by Captain Hook (which occur inside of a Docker
container) to trigger an event on the host machine by bind-mounting
/tmp/triggers/
and adding a file to this directory.
captain-hook-canary.service
:
[Unit]
Description=captain hook canary script
Requires=dockerpod-captainhook.service
After=dockerpod-captainhook.service
[Service]
Restart=always
ExecStart=/home/charles/blackbeard_scripts/captain_hook_canary.sh
ExecStop=/usr/bin/pgrep -f captain_hook_canary | /usr/bin/xargs /bin/kill
[Install]
WantedBy=default.target
Also see captain-hook-canary.service in https://git.charlesreid1.com/dotfiles/debian.
This script calls the Captain Hook canary script, which is given below:
captain_hook_canary.sh
:
#!/bin/bash
: '
Captain Hook Canary Script
Note: this needs an associated systemd service.
See the services directory of the dotfiles repo.
(snip comments)
'
while true
do
# bootstrap-pull captain hook
if [ -f "/tmp/triggers/push-b-captain-hook-master" ]; then
echo "CAPTAIN HOOK'S CANARY:"
echo "Running trigger to update Captain Hook on the host machine (user charles)"
sudo -H -u charles python /home/charles/blackbeard_scripts/captain_hook_pull_host.py
echo "All done."
rm -f "/tmp/triggers/push-b-captain-hook-master"
fi
sleep 10;
done
Also see captain_hook_canary.sh
in the dotfiles/blackbeard_scripts
folder of
https://git.charlesreid1.com/dotfiles/debian.
When this canary script for Captain Hook is triggered by the presence of
a file at /tmp/triggers/push-b-captain-hook-master
(which is mounted
inside the container at th same location as outside the container), it will
run a script to pull Captain Hook:
captain_hook_pull_host.py
:
#!/usr/bin/env python3
import subprocess
import os
import time
"""
Captain Hook: Pull Captain Hook on the Host
This script is called by the host machine
(blackbeard) running the Captain Hook container.
This is triggered by push actions to the
master branch of b-captain-hook.
The action is to update (git pull) the copy
of captain hook running on the host, and
restart the container pod.
"""
work_dir = os.path.join('/home','charles','codes','bots','b-captain-hook')
# Step 1:
# Update Captain Hook
pull_cmd = ['git','pull','origin','master']
subprocess.call(pull_cmd, cwd=work_dir)
time.sleep(5)
# Step 2:
# Restart Captain Hook pod
pod_restart = ['docker-compose','restart']
subprocess.call(pod_restart, cwd=work_dir)