Files
marvin-turnstone/start-turnstone.sh
T

71 lines
3.2 KiB
Bash
Executable File

#!/bin/bash
# VM entrypoint, exec'd as PID 1 by /boco/init (image runs as root).
# Starts sshd for ops access, prepares virtiofs share ownership, then
# drops to the marvin user and execs turnstone-server.
set -euo pipefail
export HOME=/home/marvin
# Set hostname here since podman prevents us from setting it during
# build.-time. Turnstone requires a hostname to be set.
python3 -c 'import socket; socket.sethostname("marvin-vm")' || true
# sshd: host keys baked per-boot, ops channel on guest port 22
ssh-keygen -A
mkdir -p /run/sshd
/usr/sbin/sshd
# virtiofs shares appear root-owned (host dir is owned by the host user,
# which maps to guest root) — hand them to marvin so the server and
# agent tools can write. Also ensure ~/.config stays marvin-owned:
# boco-init creates mount-point dirs as root, and rootless podman
# refuses to run when $HOME/.config is not owned by the user.
mkdir -p /var/lib/turnstone /home/marvin/.config
chown marvin:marvin /var/lib/turnstone /home/marvin/.config || true
chown -R marvin:marvin /home/marvin/work || true
# Rootless container networking (pasta/slirp4netns) needs TUN access;
# the guest has no udev, so devtmpfs leaves it root-only.
if [ ! -e /dev/net/tun ]; then
mkdir -p /dev/net
[ -c /dev/net/tun ] || mknod /dev/net/tun c 10 200
fi
chmod 666 /dev/net/tun || true
# Seed the admin account (no-op when the user already exists — password
# is ignored on promotion). Runs as marvin so DB files it creates are
# marvin-owned. Override via image env or boot cmd:
# boco boot ... --cmd 'ADMIN_PASSWORD=... start-turnstone.sh'
ADMIN_USER="${ADMIN_USER:-marvin}"
ADMIN_PASSWORD="${ADMIN_PASSWORD:-marvin-turnstone}"
if [ "$ADMIN_PASSWORD" = "marvin-turnstone" ]; then
echo "start-turnstone: WARNING — default admin password in use; set ADMIN_PASSWORD to change it"
fi
setpriv --reuid=marvin --regid=marvin --init-groups \
/usr/local/bin/turnstone-admin create-admin \
--username "$ADMIN_USER" \
--password "$ADMIN_PASSWORD" \
|| echo "start-turnstone: admin seeding failed (continuing)"
# Console (cluster dashboard + admin panel) as a background daemon under
# marvin — PID 1 stays the server, so if the server dies the VM halts.
# Shares the same config.toml/database as the server (WAL multi-writer).
setpriv --reuid=marvin --regid=marvin --init-groups \
/usr/local/bin/turnstone-console --host 0.0.0.0 --port 8080 &
echo "start-turnstone: console starting on :8080"
# NOTE: turnstone reads $HOME/.config/turnstone/config.toml as marvin.
#
# Stable node identity: node_id defaults to {hostname}_{random-per-boot},
# so every boot inserts a NEW services row and the console probes stale
# ones (409 node_id mismatch → "unreachable"). Pin both:
# - TURNSTONE_NODE_ID: one registry row, upserted every boot
# - TURNSTONE_ADVERTISE_URL: loopback — the console's collector probes
# the registered URL, and the guest's slirp IPv6 (fec0::/fe80::)
# lands in the SSRF guard's never-allowed lane, which got the node
# refused outright.
export TURNSTONE_NODE_ID="${TURNSTONE_NODE_ID:-turnstone-vm-main}"
export TURNSTONE_ADVERTISE_URL="${TURNSTONE_ADVERTISE_URL:-http://127.0.0.1:8081}"
exec setpriv --reuid=marvin --regid=marvin --init-groups \
/usr/local/bin/turnstone-server --host 0.0.0.0 --port 8081