-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathinstall.sh
More file actions
executable file
·252 lines (237 loc) · 11.4 KB
/
Copy pathinstall.sh
File metadata and controls
executable file
·252 lines (237 loc) · 11.4 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
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
#!/usr/bin/env bash
# SPDX-License-Identifier: Apache-2.0
# SPDX-FileCopyrightText: Copyright the Vortex contributors
#
# One-time bootstrap of vortex-bench-server on a fresh EC2 host.
# Idempotent - safe to re-run after editing units or to recover from
# partial state. See ops/README.md for the full operator runbook.
#
# Run as a user with sudo (typically ec2-user). The script will:
# 1. Create state directories under /var/lib/vortex-bench, owned by
# $RUN_USER. Logs go to journalctl, not to a file.
# 2. Drop a sudoers fragment that lets $RUN_USER restart the server
# service without a password (so the deploy timer can run as the
# service user).
# 3. Copy /etc/vortex-bench.env from the template if missing (mode 0600).
# 4. Install the systemd units and reload systemd.
# 5. Symlink the ops/ directory into /var/lib/vortex-bench so the
# systemd units have a stable path (the repo can move).
# 6. Enable + start the server, deploy timer, and backup timer.
#
# Usage (run from this repo's checkout root — the ops scripts live at ./ops/):
# ./ops/install.sh
# REPO_DIR=$HOME/benchmarks-website ./ops/install.sh
#
# Only REPO_DIR is honored as an env override; the run user, state-dir,
# env-file, systemd-dir, and sudoers-file paths are pinned (they have
# to match the shipped systemd units, which hard-code these values).
set -euo pipefail
# The installed systemd units hard-code `User=ec2-user`,
# `EnvironmentFile=/etc/vortex-bench.env`, and the
# `/var/lib/vortex-bench` state-dir. Keep these values aligned with
# the units in `systemd/` and the runbook in `README.md`; the script
# does NOT template the units at install time. Anyone running on a
# different user / state-dir / env-file path needs to hand-edit the
# units before this script copies them into /etc/systemd/system.
RUN_USER="ec2-user"
RUN_GROUP="${RUN_USER}"
REPO_DIR="${REPO_DIR:-$HOME/benchmarks-website}"
STATE_DIR="/var/lib/vortex-bench"
ENV_FILE="/etc/vortex-bench.env"
SYSTEMD_DIR="/etc/systemd/system"
SUDOERS_FILE="/etc/sudoers.d/vortex-bench"
ops_dir="${REPO_DIR}/ops"
if [ ! -d "$ops_dir" ]; then
echo "ERROR: ${ops_dir} not found. Set REPO_DIR=<repo path>." >&2
exit 2
fi
# Preflight: every external command the autopilot will call from this
# point on. Fail loudly here with a one-line summary instead of producing
# systemd units that 5xx silently in the journal hours later.
missing=()
for cmd in git cargo openssl jq flock aws tar gzip curl; do
command -v "$cmd" >/dev/null 2>&1 || missing+=("$cmd")
done
if [ "${#missing[@]}" -gt 0 ]; then
echo "ERROR: missing required commands: ${missing[*]}" >&2
echo " (install per BOOTSTRAP.md Phase 2 before re-running install.sh)" >&2
exit 2
fi
# The deploy timer runs as ${RUN_USER} with no SSH agent, so an SSH
# remote fails with "Permission denied (publickey)" on every fire.
# Public-repo HTTPS reads need no auth - warn early so this is not the
# first surprise out of the gate.
if [ -d "${REPO_DIR}/.git" ]; then
origin_url="$(git -C "$REPO_DIR" remote get-url origin 2>/dev/null || true)"
case "$origin_url" in
git@*|ssh://*)
echo "WARNING: ${REPO_DIR}'s origin is ${origin_url}." >&2
echo " The deploy timer cannot fetch over SSH (no agent). Fix with:" >&2
echo " git -C ${REPO_DIR} remote set-url origin https://github.com/vortex-data/benchmarks-website.git" >&2
;;
esac
fi
log() { printf '[install] %s\n' "$*"; }
# --- 1. State directories ---
log "creating ${STATE_DIR} (owner ${RUN_USER}:${RUN_GROUP})"
sudo install -d -m 0755 -o "$RUN_USER" -g "$RUN_GROUP" \
"$STATE_DIR" \
"${STATE_DIR}/bin" \
"${STATE_DIR}/snapshots" \
"${STATE_DIR}/duckdb-extensions"
# --- 2. Sudoers fragment ---
# Let RUN_USER restart/start/stop/status the v3 systemd units without a
# password. Scope is intentionally tight: only the four units the
# autopilot owns, only the four verbs ops/migrate.sh and ops/deploy.sh
# call. The other v3 admin operations (editing /etc/vortex-bench.env,
# moving /var/lib/vortex-bench files) still require a full sudo session
# the operator can audit.
log "writing sudoers fragment to ${SUDOERS_FILE}"
# Write to a tempfile, validate with visudo, ONLY THEN move into place.
# A broken sudoers fragment in /etc/sudoers.d/ breaks sudo system-wide
# and removes the operator's repair path; the validate-before-rename
# pattern below makes a syntax error fail safely.
#
# Sudoers matches argv exactly. Each authorized invocation must be a
# SINGLE-unit `systemctl <verb> <unit>` call; multi-unit invocations
# (`stop A B C`) would NOT be authorized by these per-unit lines, so
# every caller (deploy.sh, restart.sh, migrate.sh, force-rebuild.sh)
# splits its stops/starts into one call per unit.
sudoers_tmp="$(sudo mktemp /etc/sudoers.d/.vortex-bench.XXXXXX)"
sudo tee "$sudoers_tmp" >/dev/null <<EOF
# Auto-deploy + manual migration helpers run as ${RUN_USER}; only the
# systemctl calls into the v3 units need root. Both /bin/ and /usr/bin/
# are listed because Amazon Linux 2023 ships systemctl at /usr/bin while
# Debian-style hosts keep the /bin compatibility symlink.
${RUN_USER} ALL=(root) NOPASSWD: \\
/bin/systemctl restart vortex-bench-server, \\
/bin/systemctl start vortex-bench-server, \\
/bin/systemctl stop vortex-bench-server, \\
/bin/systemctl status vortex-bench-server, \\
/usr/bin/systemctl restart vortex-bench-server, \\
/usr/bin/systemctl start vortex-bench-server, \\
/usr/bin/systemctl stop vortex-bench-server, \\
/usr/bin/systemctl status vortex-bench-server, \\
/bin/systemctl start vortex-bench-deploy.service, \\
/bin/systemctl start vortex-bench-deploy.timer, \\
/bin/systemctl stop vortex-bench-deploy.service, \\
/bin/systemctl stop vortex-bench-deploy.timer, \\
/usr/bin/systemctl start vortex-bench-deploy.service, \\
/usr/bin/systemctl start vortex-bench-deploy.timer, \\
/usr/bin/systemctl stop vortex-bench-deploy.service, \\
/usr/bin/systemctl stop vortex-bench-deploy.timer, \\
/bin/systemctl start vortex-bench-backup.service, \\
/bin/systemctl start vortex-bench-backup.timer, \\
/bin/systemctl stop vortex-bench-backup.service, \\
/bin/systemctl stop vortex-bench-backup.timer, \\
/usr/bin/systemctl start vortex-bench-backup.service, \\
/usr/bin/systemctl start vortex-bench-backup.timer, \\
/usr/bin/systemctl stop vortex-bench-backup.service, \\
/usr/bin/systemctl stop vortex-bench-backup.timer
EOF
sudo chmod 0440 "$sudoers_tmp"
if ! sudo visudo -cf "$sudoers_tmp" >/dev/null; then
sudo rm -f "$sudoers_tmp"
echo "ERROR: sudoers fragment failed visudo validation; refusing to install." >&2
exit 3
fi
sudo mv -f "$sudoers_tmp" "$SUDOERS_FILE"
# --- 3. Env file ---
if [ ! -f "$ENV_FILE" ]; then
log "creating ${ENV_FILE} from template (mode 0600 owned by ${RUN_USER})"
sudo install -m 0600 -o "$RUN_USER" -g "$RUN_GROUP" \
"${ops_dir}/config/vortex-bench.env.example" \
"$ENV_FILE"
log "EDIT ${ENV_FILE} to set INGEST_BEARER_TOKEN, ADMIN_BEARER_TOKEN, REPO_DIR"
else
log "${ENV_FILE} already present - leaving alone"
fi
# --- 4. Symlink ops/ into the state dir ---
# Gives systemd units a stable path that doesn't depend on the repo
# checkout location moving. Stage-and-rename so the symlink is never
# missing for a window where a concurrent timer fire's ExecStart could
# ENOENT (matches the atomic-symlink pattern in deploy.sh).
log "symlinking ${ops_dir} -> ${STATE_DIR}/ops"
sudo ln -snT "$ops_dir" "${STATE_DIR}/ops.new"
sudo mv -Tf "${STATE_DIR}/ops.new" "${STATE_DIR}/ops"
# --- 5. systemd units ---
log "installing systemd units to ${SYSTEMD_DIR}"
for unit in \
vortex-bench-server.service \
vortex-bench-deploy.service \
vortex-bench-deploy.timer \
vortex-bench-backup.service \
vortex-bench-backup.timer
do
sudo install -m 0644 -o root -g root \
"${ops_dir}/systemd/${unit}" \
"${SYSTEMD_DIR}/${unit}"
done
sudo systemctl daemon-reload
# --- 6. Enable (and start, if tokens are set) ---
# The server unit needs a binary at /var/lib/vortex-bench/bin/vortex-bench-server
# before it can start. If the symlink isn't there yet, the deploy timer
# will lay one down on its first run; until then the server will fail.
if [ ! -e "${STATE_DIR}/bin/vortex-bench-server" ]; then
log "no binary at ${STATE_DIR}/bin/vortex-bench-server yet"
log " → the first deploy-timer fire (after start) will build + install one."
log " → tail it with: journalctl -fu vortex-bench-deploy.service"
fi
# Detect whether the operator has filled in the bearer tokens. An empty
# INGEST_BEARER_TOKEN makes the server fail startup; an empty
# ADMIN_BEARER_TOKEN leaves the admin listener unbound. Both cases mean
# starting the units now would just produce noisy failures - enable but
# defer the start instead. Source the env file in a subshell and test
# the runtime values: the prior `grep '^X=.+'` heuristic matched
# explicitly-empty `X=""` lines (the two quote characters satisfy `.+`)
# and started units that immediately failed validate_bearer_token.
tokens_set=$(
set -a
# shellcheck disable=SC1090
. "$ENV_FILE"
set +a
if [ -n "${INGEST_BEARER_TOKEN:-}" ] && [ -n "${ADMIN_BEARER_TOKEN:-}" ]; then
echo yes
fi
)
if [ "$tokens_set" = "yes" ]; then
log "tokens present in ${ENV_FILE} - enabling + starting deploy/backup timers"
# NB: we do NOT start vortex-bench-server.service here. The binary
# at /var/lib/vortex-bench/bin/vortex-bench-server does not exist
# until the deploy timer's first fire builds and installs one; the
# server then comes up automatically when deploy.sh runs `systemctl
# restart vortex-bench-server` after the symlink swap. Starting
# the server unit before that would just produce a noisy failure.
sudo systemctl enable --now vortex-bench-deploy.timer
sudo systemctl enable --now vortex-bench-backup.timer
sudo systemctl enable vortex-bench-server.service
else
log "tokens not set in ${ENV_FILE} - timers enabled but not started"
sudo systemctl enable vortex-bench-deploy.timer
sudo systemctl enable vortex-bench-backup.timer
sudo systemctl enable vortex-bench-server.service
log "after editing ${ENV_FILE}, run:"
log " sudo systemctl start vortex-bench-deploy.timer"
log " sudo systemctl start vortex-bench-backup.timer"
log " (server starts automatically on the deploy timer's first fire)"
fi
log ""
log "install complete. Next steps:"
log " 1. Edit ${ENV_FILE} (chmod 0600, owned by ${RUN_USER}):"
log " - INGEST_BEARER_TOKEN=<run 'openssl rand -hex 32' and paste>"
log " - ADMIN_BEARER_TOKEN=<run 'openssl rand -hex 32' and paste>"
log " - confirm REPO_DIR points at the actual checkout"
log " 2. After starting the timers, watch the first deploy fire build the"
log " binary and bring the server up with an empty DuckDB:"
log " journalctl -fu vortex-bench-deploy.service"
log " curl http://127.0.0.1:3000/health"
log " 3. Populate the DB with the v2 to v3 migration (server is stopped"
log " and restarted automatically; see BOOTSTRAP.md Phase 7.A for the"
log " migrator's CLI flag set):"
log " ${STATE_DIR}/ops/migrate.sh run --help"
log " 4. (If preserving an existing \$HOME/bench.duckdb instead of"
log " re-migrating, copy it into place before step 3:"
log " sudo systemctl stop vortex-bench-server"
log " mv \$HOME/bench.duckdb ${STATE_DIR}/bench.duckdb"
log " sudo systemctl start vortex-bench-server"
log " and skip step 3.)"