From 20e03dd686f2708e0ff08e76e3932f01f3f0a8c6 Mon Sep 17 00:00:00 2001 From: Colin Powell Date: Sat, 1 Aug 2026 21:26:14 -0400 Subject: [PATCH] [rc.d] Fix FreeBSD service scripts and switch deploy tooling to service(8) --- .drone.yml | 2 +- .gitea/workflows/ci.yml | 2 +- Makefile | 2 +- rc.d/vrobbler | 58 ++++++++++++++++++++++++++++++++++++++++ rc.d/vrobbler_celery | 54 +++++++++++++++++++++++++++++++++++++ rc.d/vrobbler_celerybeat | 56 ++++++++++++++++++++++++++++++++++++++ 6 files changed, 171 insertions(+), 3 deletions(-) create mode 100755 rc.d/vrobbler create mode 100755 rc.d/vrobbler_celery create mode 100755 rc.d/vrobbler_celerybeat diff --git a/.drone.yml b/.drone.yml index 011f32c..97bb61d 100644 --- a/.drone.yml +++ b/.drone.yml @@ -37,7 +37,7 @@ steps: - pip install git+https://code.lab.unbl.ink/secstate/vrobbler.git@main - vrobbler migrate - vrobbler collectstatic --noinput - - immortalctl restart celery && immortalctl restart vrobbler + - service vrobbler_celery restart && service vrobbler_celerybeat restart && service vrobbler restart when: ref: - refs/tags/* diff --git a/.gitea/workflows/ci.yml b/.gitea/workflows/ci.yml index 5817277..7e3ca9f 100644 --- a/.gitea/workflows/ci.yml +++ b/.gitea/workflows/ci.yml @@ -137,7 +137,7 @@ jobs: python3 -c "import vrobbler; print(f'vrobbler {vrobbler.__version__} installed OK')" vrobbler migrate vrobbler collectstatic --noinput - immortalctl restart vrobbler-celery && immortalctl restart vrobbler-celerybeat && immortalctl restart vrobbler + service vrobbler_celery restart && service vrobbler_celerybeat restart && service vrobbler restart - name: Notify deploy success (ntfy) if: success() diff --git a/Makefile b/Makefile index 8f48cfd..47e42f9 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ deploy: - ssh vrobbler.service "pip uninstall vrobbler && pip install git+https://code.lab.unbl.ink/secstate/vrobbler.git && immortalctl restart vrobbler && immortalctl restart vrobbler-celery && vrobbler migrate" + ssh vrobbler.service "pip uninstall vrobbler && pip install git+https://code.lab.unbl.ink/secstate/vrobbler.git && service vrobbler restart && service vrobbler_celery restart && service vrobbler_celerybeat restart && vrobbler migrate" logs: ssh life.unbl.ink tail -n 100 -f /var/log/vrobbler.json test: diff --git a/rc.d/vrobbler b/rc.d/vrobbler new file mode 100755 index 0000000..119c87c --- /dev/null +++ b/rc.d/vrobbler @@ -0,0 +1,58 @@ +#!/bin/sh +# +# rc.d script for the vrobbler Django web app, served by gunicorn. +# +# PROVIDE: vrobbler +# REQUIRE: NETWORKING postgresql redis +# KEYWORD: shutdown +# +# Installation (on the FreeBSD jail): +# +# install -m 0555 rc.d/vrobbler /usr/local/etc/rc.d/vrobbler +# sysrc vrobbler_enable="YES" +# service vrobbler start +# +# Configuration (via sysrc or /etc/rc.conf): +# +# vrobbler_bind - gunicorn bind address (default: 0.0.0.0:8014) +# vrobbler_workers - number of gunicorn workers (default: 4) +# vrobbler_gunicorn - path to gunicorn (default: /usr/local/bin/gunicorn) +# vrobbler_user - user to run as (default: root) +# vrobbler_flags - extra daemon(8) flags +# +# NOTE: do not name this knob "${name}_program" (e.g. vrobbler_program). +# FreeBSD's rc.subr(8) overrides $command with ${name}_program whenever it +# is set, which would replace our daemon(8) wrapper with gunicorn itself. +# +# The command is run under daemon(8) with a supervisor pidfile (-P) and +# restart-on-crash (-R), so gunicorn is automatically restarted if it dies, +# in the same way immortal used to. Sending SIGTERM to the supervisor (which +# is what `service vrobbler stop` does) forwards the signal to gunicorn and +# lets it shut down gracefully. +# +# Environment variables (database URL, Redis URL, API keys, ...) are read by +# Django itself from /usr/local/etc/vrobbler.conf, so no shell env is needed. +# +# If you run gunicorn as a non-root user, make sure it can write its pidfile +# and log files (e.g. chown /var/run/vrobbler.pid's directory and the +# /var/log/vrobbler_*.log files). +# +. /etc/rc.subr + +name="vrobbler" +rcvar="vrobbler_enable" + +load_rc_config ${name} + +: ${vrobbler_enable:="NO"} +: ${vrobbler_bind:="0.0.0.0:8014"} +: ${vrobbler_workers:="4"} +: ${vrobbler_gunicorn:="/usr/local/bin/gunicorn"} +: ${vrobbler_log_dir:="/var/log"} + +pidfile="/var/run/${name}.pid" + +command="/usr/sbin/daemon" +command_args="-f -P ${pidfile} -R 5 -t ${name} ${vrobbler_gunicorn} vrobbler.wsgi:application --bind ${vrobbler_bind} --workers ${vrobbler_workers} --access-logfile ${vrobbler_log_dir}/${name}_access.log --error-logfile ${vrobbler_log_dir}/${name}_error.log" + +run_rc_command "$1" diff --git a/rc.d/vrobbler_celery b/rc.d/vrobbler_celery new file mode 100755 index 0000000..90ad283 --- /dev/null +++ b/rc.d/vrobbler_celery @@ -0,0 +1,54 @@ +#!/bin/sh +# +# rc.d script for the vrobbler Celery worker. +# +# PROVIDE: vrobbler_celery +# REQUIRE: NETWORKING postgresql redis +# KEYWORD: shutdown +# +# Installation (on the FreeBSD jail): +# +# install -m 0555 rc.d/vrobbler_celery /usr/local/etc/rc.d/vrobbler_celery +# sysrc vrobbler_celery_enable="YES" +# service vrobbler_celery start +# +# Configuration (via sysrc or /etc/rc.conf): +# +# vrobbler_celery_queues - queues to consume (default: default,charts) +# vrobbler_celery_bin - path to celery (default: /usr/local/bin/celery) +# vrobbler_celery_user - user to run as (default: root) +# vrobbler_celery_flags - extra daemon(8) flags +# +# NOTE: do not name the celery path knob "${name}_program". FreeBSD's +# rc.subr(8) overrides $command with ${name}_program whenever it is set, +# which would replace the daemon(8) wrapper with celery itself. +# +# The command is run under daemon(8) with a supervisor pidfile (-P) and +# restart-on-crash (-R), so the worker is automatically restarted if it dies, +# in the same way immortal used to. Sending SIGTERM to the supervisor (which +# is what `service vrobbler_celery stop` does) forwards the signal to celery, +# which shuts the worker down gracefully. +# +# The queues match the old immortal/Procfile setup. If you ever run more than +# one worker instance, give each a unique nodename via -n (celery@%h is the +# hostname default). +# +. /etc/rc.subr + +name="vrobbler_celery" +rcvar="vrobbler_celery_enable" + +load_rc_config ${name} + +: ${vrobbler_celery_enable:="NO"} +: ${vrobbler_celery_queues:="default,charts"} +: ${vrobbler_celery_bin:="/usr/local/bin/celery"} +: ${vrobbler_celery_autoscale:="2,6"} +: ${vrobbler_log_dir:="/var/log"} + +pidfile="/var/run/${name}.pid" + +command="/usr/sbin/daemon" +command_args="-f -P ${pidfile} -R 5 -t ${name} ${vrobbler_celery_bin} -A vrobbler worker -Q ${vrobbler_celery_queues} -n celery@%h -l info --logfile ${vrobbler_log_dir}/${name}.log" + +run_rc_command "$1" diff --git a/rc.d/vrobbler_celerybeat b/rc.d/vrobbler_celerybeat new file mode 100755 index 0000000..4faa977 --- /dev/null +++ b/rc.d/vrobbler_celerybeat @@ -0,0 +1,56 @@ +#!/bin/sh +# +# rc.d script for the vrobbler Celery beat scheduler. +# +# PROVIDE: vrobbler_celerybeat +# REQUIRE: NETWORKING postgresql redis +# KEYWORD: shutdown +# +# Installation (on the FreeBSD jail): +# +# install -m 0555 rc.d/vrobbler_celerybeat /usr/local/etc/rc.d/vrobbler_celerybeat +# sysrc vrobbler_celerybeat_enable="YES" +# service vrobbler_celerybeat start +# +# Configuration (via sysrc or /etc/rc.conf): +# +# vrobbler_celerybeat_bin - path to celery (default: /usr/local/bin/celery) +# vrobbler_celerybeat_user - user to run as (default: root) +# vrobbler_celerybeat_flags - extra daemon(8) flags +# +# NOTE: do not name the celery path knob "${name}_program". FreeBSD's +# rc.subr(8) overrides $command with ${name}_program whenever it is set, +# which would replace the daemon(8) wrapper with celery itself. +# +# The command is run under daemon(8) with a supervisor pidfile (-P) and +# restart-on-crash (-R), so beat is automatically restarted if it dies. +# +# The schedule state is persisted to /var/db/vrobbler/celerybeat-schedule so it +# survives restarts (beat picks up the CELERY_BEAT_SCHEDULE entries in +# settings.py). If you run beat as a non-root user, make sure it can write +# /var/db/vrobbler and /var/log/vrobbler_celerybeat.log. Rotate the log with +# newsyslog(8). +# +. /etc/rc.subr + +name="vrobbler_celerybeat" +rcvar="vrobbler_celerybeat_enable" + +load_rc_config ${name} + +: ${vrobbler_celerybeat_enable:="NO"} +: ${vrobbler_celerybeat_bin:="/usr/local/bin/celery"} + +pidfile="/var/run/${name}.pid" + +command="/usr/sbin/daemon" +command_args="-f -P ${pidfile} -R 5 -t ${name} ${vrobbler_celerybeat_bin} -A vrobbler beat -n beat@%h -l info --schedule /var/db/vrobbler/celerybeat-schedule --logfile /var/log/${name}.log" + +start_precmd="vrobbler_celerybeat_prestart" + +vrobbler_celerybeat_prestart() +{ + mkdir -p /var/db/vrobbler +} + +run_rc_command "$1"