Sam Jeston
History
123 lines·
4.2 KB
·Bourne Again Shell (bash)
| 1 | #!/usr/bin/env bash |
| 2 | # Installs or updates openhub as a systemd service. Run it as root on the |
| 3 | # target machine (scripts/deploy-server.sh builds openhub there and runs this |
| 4 | # for you): |
| 5 | # |
| 6 | # sudo ./install.sh ./openhub [./openhub.service] |
| 7 | # |
| 8 | # Each run stops the service, snapshots the database into backups/ in the data |
| 9 | # directory (keeping the last 5), swaps the binary (the old one stays as |
| 10 | # openhub.prev) and starts the service again. If the new binary fails its |
| 11 | # health check, the previous one is put back. Repositories aren't snapshotted: |
| 12 | # upgrades only migrate the database. |
| 13 | set -euo pipefail |
| 14 | |
| 15 | bin=${1:?usage: install.sh BINARY [UNIT_FILE]} |
| 16 | unit=${2:-} |
| 17 | dest=/usr/local/bin/openhub |
| 18 | unit_dest=/etc/systemd/system/openhub.service |
| 19 | defaults=/etc/default/openhub |
| 20 | keep_backups=5 |
| 21 | |
| 22 | [ "$(id -u)" = 0 ] || { echo "install.sh must run as root, e.g. with sudo." >&2; exit 1; } |
| 23 | |
| 24 | # setting NAME DEFAULT: the value the service sees, honouring /etc/default/openhub. |
| 25 | setting() { |
| 26 | ( |
| 27 | [ -f "$defaults" ] && . "$defaults" |
| 28 | printf '%s\n' "${!1:-$2}" |
| 29 | ) |
| 30 | } |
| 31 | |
| 32 | # put SRC: replace the installed binary without writing into a running executable. |
| 33 | put() { |
| 34 | install -m 0755 "$1" "$dest.new" |
| 35 | mv -f "$dest.new" "$dest" |
| 36 | } |
| 37 | |
| 38 | # get URL: succeeds when URL answers without an HTTP error. |
| 39 | get() { |
| 40 | if command -v curl >/dev/null; then |
| 41 | curl -fs --max-time 2 -o /dev/null "$1" |
| 42 | else |
| 43 | wget -q -T 2 -O /dev/null "$1" |
| 44 | fi |
| 45 | } |
| 46 | |
| 47 | # Refuse a binary built for another architecture before touching the service. |
| 48 | new_version=$("$bin" --version) || { echo "$bin doesn't run on this machine. Build it for $(uname -m)." >&2; exit 1; } |
| 49 | git_bin=$(setting OPENHUB_GIT_BIN git) |
| 50 | command -v "$git_bin" >/dev/null || { echo "openhub needs git at runtime and can't find $git_bin. Install git first." >&2; exit 1; } |
| 51 | |
| 52 | data=$(setting OPENHUB_DATA_DIR /var/lib/openhub) |
| 53 | db=$data/openhub.db |
| 54 | addr=$(setting OPENHUB_HTTP_ADDR 127.0.0.1:3000) |
| 55 | case $addr in |
| 56 | 0.0.0.0:*) addr=127.0.0.1:${addr#*:} ;; |
| 57 | "[::]":*) addr=[::1]:${addr##*:} ;; |
| 58 | esac |
| 59 | url=http://$addr/ |
| 60 | |
| 61 | id openhub >/dev/null 2>&1 || useradd --system --user-group --home-dir /var/lib/openhub --no-create-home --shell /usr/sbin/nologin openhub |
| 62 | |
| 63 | if [ ! -f "$defaults" ]; then |
| 64 | cat >"$defaults" <<'EOF' |
| 65 | # Settings for the openhub service; see "Configuration" in the openhub README. |
| 66 | # Restart after editing: sudo systemctl restart openhub |
| 67 | #OPENHUB_PUBLIC_URL=https://git.example.com |
| 68 | #OPENHUB_SSH_HOST=git.example.com |
| 69 | #OPENHUB_SSH_PORT=2222 |
| 70 | #OPENHUB_DISABLE_REGISTRATION=true |
| 71 | EOF |
| 72 | echo "Wrote $defaults. Set OPENHUB_PUBLIC_URL there, then run: sudo systemctl restart openhub" |
| 73 | fi |
| 74 | |
| 75 | if [ -n "$unit" ] && ! cmp -s "$unit" "$unit_dest"; then |
| 76 | install -m 0644 "$unit" "$unit_dest" |
| 77 | systemctl daemon-reload |
| 78 | fi |
| 79 | [ -f "$unit_dest" ] || { echo "No openhub unit is installed yet. Pass the unit file as the second argument." >&2; exit 1; } |
| 80 | |
| 81 | systemctl stop openhub 2>/dev/null || true |
| 82 | |
| 83 | snap= |
| 84 | if [ -f "$db" ]; then |
| 85 | backups=$data/backups |
| 86 | snap=$backups/$(date +%Y%m%d-%H%M%S) |
| 87 | mkdir -p "$snap" |
| 88 | # The service is stopped, so the files are consistent; -wal/-shm only exist after an unclean stop. |
| 89 | for f in "$db" "$db-wal" "$db-shm"; do |
| 90 | if [ -f "$f" ]; then cp -p "$f" "$snap/"; fi |
| 91 | done |
| 92 | chown -R openhub:openhub "$backups" |
| 93 | ls -1d "$backups"/*/ | head -n -"$keep_backups" | xargs -r rm -rf -- |
| 94 | echo "Database snapshot: $snap" |
| 95 | fi |
| 96 | |
| 97 | if [ -f "$dest" ]; then cp -p "$dest" "$dest.prev"; fi |
| 98 | put "$bin" |
| 99 | systemctl enable --quiet openhub |
| 100 | started=$(date +%s) |
| 101 | systemctl start openhub |
| 102 | |
| 103 | for _ in $(seq 20); do |
| 104 | sleep 1 |
| 105 | if get "$url"; then |
| 106 | echo "$new_version is running ($url)." |
| 107 | fingerprint=$(journalctl -u openhub --since "@$started" -o cat --no-pager 2>/dev/null | grep -o 'SHA256:[A-Za-z0-9+/]*' | head -n 1 || true) |
| 108 | if [ -n "$fingerprint" ]; then echo "SSH host key fingerprint: $fingerprint"; fi |
| 109 | echo "Settings: $defaults" |
| 110 | echo "Logs: journalctl -u openhub -f" |
| 111 | exit 0 |
| 112 | fi |
| 113 | done |
| 114 | |
| 115 | echo "$new_version failed its health check at $url." >&2 |
| 116 | journalctl -u openhub -n 20 --no-pager >&2 || true |
| 117 | if [ -f "$dest.prev" ]; then |
| 118 | put "$dest.prev" |
| 119 | systemctl restart openhub |
| 120 | echo "Restored the previous binary ($("$dest" --version))." >&2 |
| 121 | if [ -n "$snap" ]; then echo "If it can't open the database, stop the service and copy $snap back to $data." >&2; fi |
| 122 | fi |
| 123 | exit 1 |