From 96eccc6b6719eec2e217f88d701ee2f44e280bb9 Mon Sep 17 00:00:00 2001 From: Bernd Worsch Date: Sat, 13 Sep 2025 01:32:19 +0200 Subject: [PATCH] feat: rails style bootkit bin/railiance with quickstart --- .gitignore | 2 +- QUICKSTART.md | 6 ++++ ansible/ansible.cfg | 11 ++++++ ansible/hosts.ini.example | 19 ++++++++++ bin/railiance | 76 +++++++++++++++++++++++++++++++++++++++ cloudinit/user-data.yaml | 12 +++++++ docs/first_host.md | 22 ++++++++++++ 7 files changed, 147 insertions(+), 1 deletion(-) create mode 100644 QUICKSTART.md create mode 100644 ansible/ansible.cfg create mode 100644 ansible/hosts.ini.example create mode 100644 bin/railiance create mode 100644 cloudinit/user-data.yaml create mode 100644 docs/first_host.md diff --git a/.gitignore b/.gitignore index b6f5f3f..a0ec474 100644 --- a/.gitignore +++ b/.gitignore @@ -28,7 +28,7 @@ yarn-error.log # Ansible *.retry # Local inventory (never commit host IPs/secrets) -inventory/ +ansible/hosts.ini hosts .secrets/ .vault_pass.txt diff --git a/QUICKSTART.md b/QUICKSTART.md new file mode 100644 index 0000000..bdd94d9 --- /dev/null +++ b/QUICKSTART.md @@ -0,0 +1,6 @@ +# Railiance Bootkit Quickstart +Run: + bin/railiance doctor + bin/railiance gen-ssh-key + bin/railiance cloudinit > user-data.yaml +Then rent VM, seed with tools/seed_node.sh, and bootstrap with Ansible. diff --git a/ansible/ansible.cfg b/ansible/ansible.cfg new file mode 100644 index 0000000..66667e3 --- /dev/null +++ b/ansible/ansible.cfg @@ -0,0 +1,11 @@ +[defaults] +inventory = ansible/hosts.ini +interpreter_python = auto +host_key_checking = False +retry_files_enabled = False +stdout_callback = yaml +timeout = 30 + +[ssh_connection] +pipelining = True + diff --git a/ansible/hosts.ini.example b/ansible/hosts.ini.example new file mode 100644 index 0000000..409f1ce --- /dev/null +++ b/ansible/hosts.ini.example @@ -0,0 +1,19 @@ +# Ansible inventory template for Railiance + +# Single seed host (first node) +[seed] +# 203.0.113.10 ansible_user=ubuntu ansible_become=true + +# Optional: control plane / workers (future multi-node) +#[k3s_master] +# 203.0.113.11 ansible_user=ubuntu ansible_become=true + +#[k3s_workers] +# 203.0.113.21 ansible_user=ubuntu ansible_become=true +# 203.0.113.22 ansible_user=ubuntu ansible_become=true + +# Combine groups for convenience +#[k3s:children] +#k3s_master +#k3s_workers + diff --git a/bin/railiance b/bin/railiance new file mode 100644 index 0000000..c1b38c0 --- /dev/null +++ b/bin/railiance @@ -0,0 +1,76 @@ +#!/usr/bin/env bash +# bin/railiance — Rails-style CLI entrypoint for Railiance +set -euo pipefail + +ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" + +usage() { + cat <<'EOF' +Usage: bin/railiance + +Commands: + next Show canonical first-time sequence + doctor Check local prerequisites (git, curl, jq, ansible) + plan-host Print provider-neutral host specs & checklist + gen-ssh-key Generate an SSH key (ed25519) and print pubkey + cloudinit Emit minimal cloud-init user-data + init-repo Idempotently furnish repo housekeeping + build-spore Build a distributable "Spore" bundle + seed-local Run the seed script on this machine + checklist Print a pre-VM checklist + help Show this help +EOF +} + +cmd="${1:-help}" + +need(){ command -v "$1" >/dev/null 2>&1 || { echo "Missing: $1" >&2; exit 1; }; } + +case "$cmd" in + help) usage ;; + next) cat "$ROOT/docs/first_host.md" ;; + doctor) + for c in git curl jq; do + command -v "$c" >/dev/null && echo "OK: $c" || { echo "Missing: $c"; exit 1; } + done + command -v ansible >/dev/null && echo "OK: ansible" || echo "Note: ansible not found (only needed for host bootstrap)" + ;; + plan-host) + sed -n '1,200p' "$ROOT/docs/first_host.md" | sed -n '/^## 2\) Choose/,/^## 3\)/p' + ;; + gen-ssh-key) + need ssh-keygen + key="${HOME}/.ssh/id_ed25519" + [[ -f "$key" ]] || ssh-keygen -t ed25519 -N "" -f "$key" + echo "Public key:" + cat "${key}.pub" + ;; + cloudinit) cat "$ROOT/cloudinit/user-data.yaml" ;; + init-repo) bash "$ROOT/tools/furnish_railiance_repo.sh" ;; + build-spore) bash "$ROOT/tools/build_spore.sh" ;; + seed-local) bash "$ROOT/tools/seed_node.sh" ;; + init-inventory) + if [[ -f "$ROOT/ansible/hosts.ini" ]]; then + echo "ansible/hosts.ini already exists." + else + cp "$ROOT/ansible/hosts.ini.example" "$ROOT/ansible/hosts.ini" + echo "Created ansible/hosts.ini from example." + fi + ;; + checklist) + cat <<'CK' +Rent-a-VM Checklist +------------------- +[ ] Provider account ready (billing set) +[ ] Region chosen (low latency to you/users) +[ ] Image: Ubuntu 24.04 LTS +[ ] Size: 2 vCPU / 4–8 GB RAM / 60+ GB SSD +[ ] SSH key uploaded (see gen-ssh-key) + - Run: bin/railiance gen-ssh-key +[ ] Cloud-init pasted (see: bin/railiance cloudinit) +[ ] Hostname set (e.g., railiance-seed-1) +[ ] Record public IP / DNS +CK + ;; + *) usage; exit 2 ;; +esac diff --git a/cloudinit/user-data.yaml b/cloudinit/user-data.yaml new file mode 100644 index 0000000..3b258af --- /dev/null +++ b/cloudinit/user-data.yaml @@ -0,0 +1,12 @@ +#cloud-config +package_update: true +package_upgrade: true +users: + - name: ubuntu + sudo: ALL=(ALL) NOPASSWD:ALL + groups: sudo + shell: /bin/bash + ssh_authorized_keys: + - ssh-ed25519 AAAA...replace_with_your_pubkey +runcmd: + - [ sh, -lc, 'echo Railiance seed host initialized' ] diff --git a/docs/first_host.md b/docs/first_host.md new file mode 100644 index 0000000..1e5838a --- /dev/null +++ b/docs/first_host.md @@ -0,0 +1,22 @@ +# First Railiance Host — Provider Guide + +## 1) Generate SSH key +``` +bin/railiance gen-ssh-key +``` + +## 2) Choose a VM +Ubuntu 24.04 LTS, 2 vCPU, 4–8GB RAM, 60+GB SSD, open 22/80/443. + +## 3) Cloud-init +``` +bin/railiance cloudinit > user-data.yaml +``` + +## 4) Seed +Copy Spore or clone directly, then run seed script on the host. + +## 5) Bootstrap (optional now) +``` +ansible-playbook -i ansible/inventory/hosts.ini ansible/bootstrap.yml +```