Repository navigation
Expand file tree
/
Copy pathpiclock-apply
More file actions
executable file
·61 lines (54 loc) · 2.46 KB
/
Copy pathpiclock-apply
File metadata and controls
executable file
·61 lines (54 loc) · 2.46 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
#!/usr/bin/env bash
# Privileged half of a PiClock deploy. Invoked ONLY as:
#
# sudo /usr/local/sbin/piclock-apply
#
# by piclock-receive (see /etc/sudoers.d/piclock-deploy). It takes no arguments,
# so there is nothing for the caller to inject.
#
# Scope is deliberately narrow: it updates only the runtime clock bundle and venv
# under /opt/piclock and restarts the service if it is already running. It does
# NOT touch the systemd unit, the service account, sudoers, or these scripts --
# those are host config, set up once by the manual bootstrap. So the worst a
# leaked deploy key can do is ship code that runs as the unprivileged 'clocker';
# it cannot escalate to root.
set -euo pipefail
STAGING="/var/lib/piclock-deploy/staging"
APP_DIR="/opt/piclock"
SERVICE_USER="clocker"
# Serialize applies even when invoked outside the receiver.
exec 9>/run/piclock-apply.lock
flock -x 9
# Everything under the app directory is service-controlled. Never mutate it
# as root: symlinks and concurrent app writes must have only clocker's rights.
# Bootstrap must provide a traversable deploy home and readable staging tree.
test -f "$STAGING/main.py" || { echo "staging does not look like piclock" >&2; exit 1; }
echo ">> Syncing code to $APP_DIR"
# Preserve the venv and pip cache; --delete-excluded prunes anything outside the
# runtime bundle so old docs, tests, CI files, or operator notes do not linger.
sudo -u "$SERVICE_USER" rsync -rlt --delete \
--delete-excluded \
--filter 'P /venv/***' \
--filter 'P /.cache/***' \
--exclude '__pycache__/' \
--exclude '*.pyc' \
--include '/main.py' \
--include '/requirements.txt' \
--include '/requirements-homekit.txt' \
--include '/piclock/***' \
--exclude '*' \
"$STAGING"/ "$APP_DIR"/
echo ">> Updating dependencies"
if [ ! -d "$APP_DIR/venv" ]; then
sudo -u "$SERVICE_USER" python3 -m venv "$APP_DIR/venv"
fi
sudo -u "$SERVICE_USER" "$APP_DIR/venv/bin/pip" install -q -r "$APP_DIR/requirements.txt"
# Keep the optional dependency bundle current on installations using HomeKit.
if [ -f /etc/systemd/system/piclock.service.d/homekit.conf ]; then
sudo -u "$SERVICE_USER" "$APP_DIR/venv/bin/pip" install -q -r "$APP_DIR/requirements-homekit.txt"
fi
echo ">> Restarting service if running"
# try-restart restarts ONLY if the unit is already active, so a service that is
# intentionally stopped (e.g. before the display is connected) stays stopped.
systemctl try-restart piclock.service
echo ">> Apply complete"