ircu2/tools/linesync/linesync-entrypoint.sh

290 lines
9.2 KiB
Bash
Executable File

#!/bin/bash
# Linesync Sidecar Entrypoint
# Supports multiple modes of operation for configuration synchronization
set -e
# =============================================================================
# UID/GID Auto-Detection and Privilege Dropping
# =============================================================================
# If running as root, detect the UID/GID from mounted directories and drop
# privileges to match. This allows bind mounts to work without manual -u flags.
if [ "$(id -u)" = "0" ]; then
# Detect UID/GID from mounted directories (in order of preference)
TARGET_UID=""
TARGET_GID=""
for detect_path in /home/linesync/ircd/ircd.conf ; do
if [ -d "$detect_path" ]; then
TARGET_UID=$(stat -c %u "$detect_path")
TARGET_GID=$(stat -c %g "$detect_path")
# Skip if owned by root (probably not a bind mount)
if [ "$TARGET_UID" != "0" ]; then
break
fi
fi
done
# Default to 1000:1000 if detection failed or got root
: "${TARGET_UID:=1000}"
: "${TARGET_GID:=1000}"
# Get current linesync UID/GID
CURRENT_UID=$(id -u linesync)
CURRENT_GID=$(id -g linesync)
# Modify user/group if needed
if [ "$TARGET_GID" != "$CURRENT_GID" ]; then
groupmod -g "$TARGET_GID" linesync 2>/dev/null || true
fi
if [ "$TARGET_UID" != "$CURRENT_UID" ]; then
usermod -u "$TARGET_UID" linesync 2>/dev/null || true
fi
# Fix ownership of home directory
chown -R linesync:linesync /home/linesync 2>/dev/null || true
# Ensure SSH config exists
if [ ! -f /home/linesync/.ssh/config ]; then
mkdir -p /home/linesync/.ssh
echo -e "Host *\n StrictHostKeyChecking accept-new\n UserKnownHostsFile /home/linesync/.ssh/known_hosts" > /home/linesync/.ssh/config
chmod 700 /home/linesync/.ssh
chmod 600 /home/linesync/.ssh/config
chown -R linesync:linesync /home/linesync/.ssh
fi
# Re-exec this script as linesync user
exec gosu linesync "$0" "$@"
fi
# =============================================================================
# Main Entrypoint (running as linesync user)
# =============================================================================
# Configuration with defaults
: "${SYNC_INTERVAL:=300}" # Sync interval in seconds (default: 5 minutes)
: "${IRCD_CONF:=/home/linesync/ircd/ircd.conf}"
: "${IRCD_PID:=/home/linesync/ircd/ircd.pid}"
: "${SSH_KEY:=/home/linesync/.ssh/id_ed25519}"
: "${NEFARIOUS_CONTAINER:=nefarious}"
: "${GIT_REPOSITORY:=}"
: "${CERT_TAG:=}"
: "${CERT_FILE:=}" # Output path for certificate (default: fullchain.pem in conf dir)
GITSYNC="/home/linesync/gitsync.sh"
show_help() {
echo "Linesync Sidecar Container"
echo ""
echo "Modes:"
echo " keygen Generate a new SSH keypair for git authentication"
echo " setup Clone the linesync git repository (initial setup)"
echo " sync Run continuous sync loop (default)"
echo " once Run sync once and exit"
echo " shell Start an interactive shell"
echo " help Show this help message"
echo ""
echo "Environment Variables:"
echo " SYNC_INTERVAL Seconds between sync attempts (default: 300)"
echo " IRCD_CONF Path to ircd.conf (default: /home/linesync/ircd/ircd.conf)"
echo " IRCD_PID Path to ircd.pid (default: /home/linesync/ircd/ircd.pid)"
echo " SSH_KEY Path to SSH private key (default: /home/linesync/.ssh/id_ed25519)"
echo " NEFARIOUS_CONTAINER Name of nefarious container to signal (default: nefarious)"
echo " GIT_REPOSITORY Git repository URL (required for setup mode)"
echo " CERT_TAG Git tag for SSL certificate (optional)"
echo " CERT_FILE Output path for certificate (default: fullchain.pem in conf dir)"
echo ""
echo "Volume Mounts:"
echo " /home/linesync/.ssh SSH keys directory"
echo " /home/linesync/ircd IRCd config directory (shared with nefarious)"
echo " /var/run/docker.sock Docker socket (for sending SIGHUP)"
echo ""
}
# Generate SSH keypair
do_keygen() {
local keytype="${1:-ed25519}"
local sshdir="/home/linesync/.ssh"
local keyfile="${sshdir}/id_${keytype}"
# Check if .ssh directory exists
if [ ! -d "$sshdir" ]; then
echo "Error: SSH directory $sshdir does not exist"
echo "Create the directory on the host first: mkdir -p ./linesync-ssh"
exit 1
fi
# Check if directory is writable
if [ ! -w "$sshdir" ]; then
echo "Error: SSH directory $sshdir is not writable"
echo "Check that the directory exists and has correct permissions"
exit 1
fi
# Ensure proper directory permissions
chmod 700 "$sshdir" 2>/dev/null || true
if [ -f "$keyfile" ]; then
echo "Key already exists at $keyfile"
echo "Public key:"
cat "${keyfile}.pub"
return 0
fi
echo "Generating ${keytype} keypair..."
ssh-keygen -t "$keytype" -f "$keyfile" -N "" -C "linesync@$(hostname)"
# Set proper permissions on the key files
chmod 600 "$keyfile"
chmod 644 "${keyfile}.pub"
echo ""
echo "Key generated successfully!"
echo ""
echo "Public key (add this to your git repository's deploy keys):"
echo "================================================================"
cat "${keyfile}.pub"
echo "================================================================"
}
# Initial repository setup
do_setup() {
if [ -z "$GIT_REPOSITORY" ]; then
echo "Error: GIT_REPOSITORY environment variable is required for setup"
exit 1
fi
if [ ! -f "$SSH_KEY" ]; then
echo "Error: SSH key not found at $SSH_KEY"
echo "Run 'keygen' mode first to create a keypair"
exit 1
fi
echo "Setting up linesync repository..."
echo "Repository: $GIT_REPOSITORY"
echo "SSH Key: $SSH_KEY"
echo "Config: $IRCD_CONF"
# Run gitsync.sh in setup mode
"$GITSYNC" -s "$SSH_KEY" -i "$GIT_REPOSITORY" "$IRCD_CONF" "$IRCD_PID"
}
# Signal nefarious container to reload config
signal_reload() {
if [ -S /var/run/docker.sock ]; then
echo "Sending SIGHUP to container: $NEFARIOUS_CONTAINER"
docker kill --signal=SIGHUP "$NEFARIOUS_CONTAINER" 2>/dev/null || \
echo "Warning: Could not signal container (may not be running)"
else
echo "Warning: Docker socket not available, cannot signal container"
echo "Config changes will take effect on next ircd restart"
fi
}
# Run a single sync
do_sync_once() {
local sync_args="-s $SSH_KEY"
if [ -n "$CERT_TAG" ]; then
sync_args="$sync_args -c $CERT_TAG"
if [ -n "$CERT_FILE" ]; then
sync_args="$sync_args -C $CERT_FILE"
fi
fi
echo "[$(date '+%Y-%m-%d %H:%M:%S')] Running sync..."
# Create a wrapper that signals via docker instead of using PID file
# We'll run gitsync.sh but handle the signaling ourselves
local tmp_pid="/tmp/fake.pid"
echo "99999" > "$tmp_pid"
# Capture gitsync output to check if changes were made
local before_md5=""
local after_md5=""
if [ -f "$IRCD_CONF" ]; then
before_md5=$(md5sum "$IRCD_CONF" 2>/dev/null | cut -d' ' -f1)
fi
# Run gitsync (it will try to HUP pid 99999 which will fail silently)
"$GITSYNC" $sync_args "$IRCD_CONF" "$tmp_pid" 2>&1 || true
if [ -f "$IRCD_CONF" ]; then
after_md5=$(md5sum "$IRCD_CONF" 2>/dev/null | cut -d' ' -f1)
fi
# If config changed, signal the container
if [ "$before_md5" != "$after_md5" ] && [ -n "$after_md5" ]; then
echo "Configuration changed, signaling reload..."
signal_reload
fi
rm -f "$tmp_pid"
}
# Continuous sync loop
do_sync_loop() {
# Handle shutdown signals gracefully
trap 'echo "[$(date "+%Y-%m-%d %H:%M:%S")] Shutting down..."; exit 0' SIGTERM SIGINT
echo "Starting linesync daemon"
echo "Sync interval: ${SYNC_INTERVAL}s"
echo "Config: $IRCD_CONF"
echo "Container: $NEFARIOUS_CONTAINER"
echo ""
# Check prerequisites
if [ ! -f "$SSH_KEY" ]; then
echo "Error: SSH key not found at $SSH_KEY"
echo "Run 'keygen' mode first, or mount your key"
exit 1
fi
local linesync_dir
linesync_dir=$(dirname "$IRCD_CONF")/linesync
if [ ! -d "$linesync_dir" ]; then
echo "Error: Linesync repository not found at $linesync_dir"
echo "Run 'setup' mode first to clone the repository"
exit 1
fi
# Main loop
while true; do
do_sync_once
echo "[$(date '+%Y-%m-%d %H:%M:%S')] Sleeping ${SYNC_INTERVAL}s..."
# Sleep in background so trap can interrupt
sleep "$SYNC_INTERVAL" &
wait $!
done
}
# Main entrypoint
case "${1:-sync}" in
keygen)
do_keygen "${2:-ed25519}"
;;
setup)
do_setup
;;
sync)
do_sync_loop
;;
once)
do_sync_once
;;
shell|bash|sh)
exec /bin/bash
;;
help|--help|-h)
show_help
;;
*)
echo "Unknown command: $1"
show_help
exit 1
;;
esac