vole
Clone
Read only, no credentials:
https://rodent.software/vole.git
Write over SSH with a registered key:
git clone ssh://git@rodent.software:2222/vole.git
A free and open-source forge that lives in your Git repo.
| 1 | #!/bin/sh |
| 2 | # Render a first-boot file for one machine, to paste into a provider's user-data |
| 3 | # field. |
| 4 | # |
| 5 | # ./render.sh > user-data.yaml # the forge |
| 6 | # ./render.sh runner > runner-user-data.yaml # a CI runner |
| 7 | # |
| 8 | # Values come from the environment. Anything unset falls back to the default |
| 9 | # below. The output goes into a cloud provider's "user data" field. See |
| 10 | # docs/deploy/vps.md and docs/deploy/runner.md. |
| 11 | set -eu |
| 12 | |
| 13 | here="$(cd "$(dirname "$0")" && pwd)" |
| 14 | what="${1:-vole}" |
| 15 | |
| 16 | if ! command -v envsubst >/dev/null 2>&1; then |
| 17 | echo "envsubst is missing; install gettext (Debian and Ubuntu: apt install gettext-base)" >&2 |
| 18 | exit 2 |
| 19 | fi |
| 20 | |
| 21 | # render <template> <placeholder names...> |
| 22 | # |
| 23 | # Only the named placeholders are substituted. A name outside the list is a typo, |
| 24 | # and envsubst would leave it in the output as literal text, so the list is the |
| 25 | # contract between this script and the template. |
| 26 | render() { |
| 27 | template="$1" |
| 28 | shift |
| 29 | list="" |
| 30 | for name in "$@"; do |
| 31 | list="$list\${$name} " |
| 32 | done |
| 33 | rendered="$(envsubst "$list" <"$here/$template")" |
| 34 | if printf '%s\n' "$rendered" | grep -q '\${'; then |
| 35 | echo "unsubstituted placeholder in $template:" >&2 |
| 36 | printf '%s\n' "$rendered" | grep -n '\${' >&2 |
| 37 | exit 1 |
| 38 | fi |
| 39 | printf '%s\n' "$rendered" |
| 40 | } |
| 41 | |
| 42 | case "$what" in |
| 43 | vole) |
| 44 | : "${HOSTNAME:?set HOSTNAME to the DNS name the instance will answer on}" |
| 45 | : "${ADMIN_ACCOUNT:?set ADMIN_ACCOUNT to the account name to create}" |
| 46 | : "${ADMIN_SSH_KEY:?set ADMIN_SSH_KEY to the public key of that account}" |
| 47 | : "${VOLE_PACKAGE_URL:?set VOLE_PACKAGE_URL to the .deb for this machine's architecture}" |
| 48 | : "${ADMIN_EMAIL:=}" |
| 49 | : "${INSTANCE_NAME:=Vole}" |
| 50 | : "${TLS_MODE:=acme}" |
| 51 | |
| 52 | case "$TLS_MODE" in |
| 53 | acme | proxy) ;; |
| 54 | *) |
| 55 | echo "TLS_MODE must be acme or proxy, got $TLS_MODE" >&2 |
| 56 | exit 2 |
| 57 | ;; |
| 58 | esac |
| 59 | |
| 60 | export hostname="$HOSTNAME" |
| 61 | export admin_account="$ADMIN_ACCOUNT" |
| 62 | export admin_ssh_key="$ADMIN_SSH_KEY" |
| 63 | export admin_email="$ADMIN_EMAIL" |
| 64 | export instance_name="$INSTANCE_NAME" |
| 65 | export tls_mode="$TLS_MODE" |
| 66 | export vole_package_url="$VOLE_PACKAGE_URL" |
| 67 | |
| 68 | render vole.yaml hostname admin_account admin_ssh_key admin_email instance_name tls_mode vole_package_url |
| 69 | ;; |
| 70 | runner) |
| 71 | : "${FORGE_HOST:?set FORGE_HOST to the instance's DNS name}" |
| 72 | : "${VOLE_PACKAGE_URL:?set VOLE_PACKAGE_URL to the .deb for this machine's architecture}" |
| 73 | : "${RUNNER_HOSTNAME:=vole-runner}" |
| 74 | : "${RUNNER_RUNTIME:=podman}" |
| 75 | : "${RUNNER_NETWORK:=bridge}" |
| 76 | : "${RUNNER_DIR:=/var/lib/vole-runner}" |
| 77 | # Labels a job's runs-on can ask for, space separated: "linux amd64". |
| 78 | : "${RUNNER_LABEL_NAMES:=linux}" |
| 79 | # How many jobs this machine runs at once. Each is a container, so the machine |
| 80 | # has to carry this many times the container limits. |
| 81 | : "${RUNNER_JOBS:=1}" |
| 82 | # What one job may take, and what the machine keeps for itself. The memory limit |
| 83 | # is the one to size for: RUNNER_JOBS times RUNNER_MEMORY is the runner at full |
| 84 | # stretch, and the unit's MemoryMax backstop is a percentage of the machine above |
| 85 | # it. RUNNER_DISK_RESERVE is free space kept under RUNNER_DIR: a job that takes |
| 86 | # the filesystem below it is stopped while it runs. |
| 87 | : "${RUNNER_MEMORY:=4G}" |
| 88 | : "${RUNNER_PIDS:=2048}" |
| 89 | : "${RUNNER_TMPFS:=1G}" |
| 90 | : "${RUNNER_DISK_RESERVE:=2G}" |
| 91 | |
| 92 | labels="" |
| 93 | for name in $RUNNER_LABEL_NAMES; do |
| 94 | labels="$labels--label $name " |
| 95 | done |
| 96 | |
| 97 | export runner_hostname="$RUNNER_HOSTNAME" |
| 98 | export forge_host="$FORGE_HOST" |
| 99 | export runner_runtime="$RUNNER_RUNTIME" |
| 100 | export runner_network="$RUNNER_NETWORK" |
| 101 | export runner_dir="$RUNNER_DIR" |
| 102 | export runner_jobs="--jobs $RUNNER_JOBS" |
| 103 | export runner_memory="$RUNNER_MEMORY" |
| 104 | export runner_pids="$RUNNER_PIDS" |
| 105 | export runner_tmpfs="$RUNNER_TMPFS" |
| 106 | export runner_disk_reserve="$RUNNER_DISK_RESERVE" |
| 107 | export runner_labels="$labels" |
| 108 | export vole_package_url="$VOLE_PACKAGE_URL" |
| 109 | |
| 110 | render runner.yaml runner_hostname forge_host runner_runtime runner_network runner_dir runner_jobs runner_labels runner_memory runner_pids runner_tmpfs runner_disk_reserve vole_package_url |
| 111 | ;; |
| 112 | *) |
| 113 | echo "unknown template $what; use vole or runner" >&2 |
| 114 | exit 2 |
| 115 | ;; |
| 116 | esac |
| 117 |