feat(tools): directed panspermia inspired colonization scripts
Some checks failed
railiance-tests / smoke (push) Has been cancelled
Some checks failed
railiance-tests / smoke (push) Has been cancelled
This commit is contained in:
62
tools/README_tools.md
Normal file
62
tools/README_tools.md
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
# 🌱 Railiance Tools — Directed Panspermia Model
|
||||||
|
|
||||||
|
Railiance bootstraps infrastructure in a way inspired by **directed panspermia** —
|
||||||
|
the idea of life being intentionally seeded across the cosmos.
|
||||||
|
Here, instead of biology, we seed **infrastructure-as-code** into blank environments.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🧬 Core Concepts
|
||||||
|
|
||||||
|
- **Parent Body** — an existing Railiance repo (the source of life).
|
||||||
|
- **Seed** — the minimal set of instructions/scripts to reproduce the repo in a new environment.
|
||||||
|
- **Spore** — a portable, bundled package of the Seed (self-contained, easy to transfer).
|
||||||
|
- **Target Environment** — a blank host (a sterile world waiting for life).
|
||||||
|
- **Biogenesis** — the process of unpacking a Spore and bootstrapping the environment.
|
||||||
|
- **Evolutionary Adaptation** — further provisioning, testing, and tuning specific to the host.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🛠️ Toolchain Overview
|
||||||
|
|
||||||
|
### `create_railiance_repo.sh`
|
||||||
|
- Creates a new Railiance repo in Gitea (under user or org).
|
||||||
|
- Acts like the *egg cell*: it defines the first container for life.
|
||||||
|
|
||||||
|
### `furnish_railiance_repo.sh`
|
||||||
|
- Idempotently sets up repo housekeeping files (LICENSE, README, .editorconfig, etc.).
|
||||||
|
- Brings the repo to a clean, opinionated state.
|
||||||
|
- Equivalent to providing the *genetic code*.
|
||||||
|
|
||||||
|
### `build_spore.sh`
|
||||||
|
- Packages the Seed into a **Spore bundle** (tar.gz).
|
||||||
|
- Includes creation/furnishing scripts, docs, and metadata.
|
||||||
|
- Like enclosing life into a *protective capsule* for travel.
|
||||||
|
|
||||||
|
### `seed_node.sh`
|
||||||
|
- Run on a blank host to unpack a Spore.
|
||||||
|
- Performs **Biogenesis**: installs prerequisites, clones the repo, and executes bootstrap steps.
|
||||||
|
- Like a *spore germinating* on a fertile planet.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🚀 Lifecycle
|
||||||
|
|
||||||
|
1. **Create** a repo with `create_railiance_repo.sh`.
|
||||||
|
2. **Furnish** it into a clean Railiance structure with `furnish_railiance_repo.sh`.
|
||||||
|
3. **Build** a distributable bundle with `build_spore.sh`.
|
||||||
|
4. **Seed** new environments with `seed_node.sh`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🌍 Why Panspermia?
|
||||||
|
|
||||||
|
This model emphasizes:
|
||||||
|
- **Reproducibility**: every host can be bootstrapped identically from a Spore.
|
||||||
|
- **Federation**: Spores can be sent to many environments (different orgs, clusters, or even air-gapped hosts).
|
||||||
|
- **Resilience**: infrastructure survives and adapts, no matter the environment.
|
||||||
|
- **Storytelling**: by using biological metaphors, we keep the process intuitive and memorable.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
✦ Railiance is not just code — it’s a way of letting infrastructure **colonize new worlds**.
|
||||||
29
tools/build_spore.sh
Normal file
29
tools/build_spore.sh
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# tools/build_spore.sh
|
||||||
|
# Package a "Spore" bundle: minimal bootstrap seed + furnishing scripts + metadata
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
repo_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||||
|
outdir="${repo_root}/dist"
|
||||||
|
mkdir -p "${outdir}"
|
||||||
|
|
||||||
|
timestamp="$(date -u +%Y%m%dT%H%M%SZ)"
|
||||||
|
spore_name="railiance_spore_${timestamp}.tar.gz"
|
||||||
|
spore_path="${outdir}/${spore_name}"
|
||||||
|
|
||||||
|
echo "[*] Building spore bundle → ${spore_path}"
|
||||||
|
|
||||||
|
# Metadata file
|
||||||
|
cat > "${outdir}/SPORE_METADATA.txt" <<META
|
||||||
|
Railiance Spore
|
||||||
|
---------------
|
||||||
|
Timestamp: ${timestamp}
|
||||||
|
Repo: $(basename "${repo_root}")
|
||||||
|
Commit: $(git -C "${repo_root}" rev-parse HEAD 2>/dev/null || echo "N/A")
|
||||||
|
META
|
||||||
|
|
||||||
|
# Bundle essential files
|
||||||
|
tar -czf "${spore_path}" -C "${repo_root}" tools/create_railiance_repo.sh tools/furnish_railiance_repo.sh tools/build_spore.sh tools/seed_node.sh LICENSE README.md .editorconfig .gitattributes .gitignore docs/ -C "${outdir}" SPORE_METADATA.txt
|
||||||
|
|
||||||
|
echo "[✓] Spore bundle created: ${spore_path}"
|
||||||
199
tools/furnish_railiance_repo.sh
Normal file
199
tools/furnish_railiance_repo.sh
Normal file
@@ -0,0 +1,199 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# tools/furnish_railiance_repo.sh
|
||||||
|
# Idempotently "furnishes" the repo with license, readmes, and housekeeping files.
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
repo_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||||
|
|
||||||
|
ensure_file() { # ensure_file <path> <here-doc label> [mode]
|
||||||
|
local path="$1"; shift
|
||||||
|
local label="$1"; shift
|
||||||
|
local mode="${1:-}"
|
||||||
|
if [[ -f "${path}" ]]; then
|
||||||
|
echo "[=] exists: ${path}"
|
||||||
|
else
|
||||||
|
echo "[+] create: ${path}"
|
||||||
|
mkdir -p "$(dirname "${path}")"
|
||||||
|
eval "cat <<'${label}' > '${path}'"
|
||||||
|
if [[ -n "${mode}" ]]; then chmod "${mode}" "${path}"; fi
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
append_once() { # append_once <path> <needle> <text>
|
||||||
|
local path="$1" needle="$2" text="$3"
|
||||||
|
grep -qF "${needle}" "${path}" 2>/dev/null || { echo "${text}" >> "${path}"; echo "[+] append → ${path}"; }
|
||||||
|
}
|
||||||
|
|
||||||
|
# LICENSE (MIT)
|
||||||
|
ensure_file "${repo_root}/LICENSE" LIC <<'LIC'
|
||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2025 Railiance Contributors
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
LIC
|
||||||
|
|
||||||
|
# Root README with badge (only if missing)
|
||||||
|
ensure_file "${repo_root}/README.md" RREAD <<'RREAD'
|
||||||
|
# Railiance Bootstrap
|
||||||
|
[](LICENSE)
|
||||||
|
|
||||||
|
Railiance is an opinionated **Infrastructure-as-Code framework** —
|
||||||
|
think *Rails for Ops*: convention over configuration, reproducibility first.
|
||||||
|
|
||||||
|
This repo (`railiance-bootstrap`) is the **entry point**:
|
||||||
|
from two bare Linux servers, a Git repo, and credentials, you can rebuild
|
||||||
|
a fully automated Kubernetes-based environment.
|
||||||
|
RREAD
|
||||||
|
|
||||||
|
# docs/README
|
||||||
|
ensure_file "${repo_root}/docs/README.md" DREAD <<'DREAD'
|
||||||
|
# Railiance Documentation
|
||||||
|
|
||||||
|
Welcome to **Railiance** — an opinionated framework for Infrastructure-as-Code.
|
||||||
|
Think of it as *Rails for Ops*: convention over configuration, productivity first.
|
||||||
|
DREAD
|
||||||
|
|
||||||
|
# CONTRIBUTING
|
||||||
|
ensure_file "${repo_root}/docs/CONTRIBUTING.md" CONTRIB <<'CONTRIB'
|
||||||
|
# Contributing to Railiance
|
||||||
|
(…short rules: no secrets, LF endings, PRs w/ tests…)
|
||||||
|
CONTRIB
|
||||||
|
|
||||||
|
# .editorconfig
|
||||||
|
ensure_file "${repo_root}/.editorconfig" ECONF <<'ECONF'
|
||||||
|
root = true
|
||||||
|
[*]
|
||||||
|
charset = utf-8
|
||||||
|
end_of_line = lf
|
||||||
|
insert_final_newline = true
|
||||||
|
trim_trailing_whitespace = true
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 2
|
||||||
|
|
||||||
|
[*.md]
|
||||||
|
trim_trailing_whitespace = false
|
||||||
|
|
||||||
|
[*.{yml,yaml}]
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 2
|
||||||
|
|
||||||
|
[*.sh]
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 2
|
||||||
|
|
||||||
|
[*.py]
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 4
|
||||||
|
ECONF
|
||||||
|
|
||||||
|
# .gitattributes
|
||||||
|
ensure_file "${repo_root}/.gitattributes" GATTR <<'GATTR'
|
||||||
|
* text=auto eol=lf
|
||||||
|
*.sh text eol=lf
|
||||||
|
*.yml text eol=lf
|
||||||
|
*.yaml text eol=lf
|
||||||
|
*.md text eol=lf
|
||||||
|
*.png binary
|
||||||
|
*.jpg binary
|
||||||
|
*.jpeg binary
|
||||||
|
*.gif binary
|
||||||
|
*.svg binary
|
||||||
|
*.ico binary
|
||||||
|
*.pdf binary
|
||||||
|
*.zip binary
|
||||||
|
*.tar.gz binary
|
||||||
|
*.tgz binary
|
||||||
|
.gitattributes text eol=lf
|
||||||
|
.editorconfig text eol=lf
|
||||||
|
GATTR
|
||||||
|
|
||||||
|
# .gitignore
|
||||||
|
ensure_file "${repo_root}/.gitignore" GIGN <<'GIGN'
|
||||||
|
.DS_Store
|
||||||
|
Thumbs.db
|
||||||
|
*.swp
|
||||||
|
*.swo
|
||||||
|
*.bak
|
||||||
|
*.tmp
|
||||||
|
*~
|
||||||
|
|
||||||
|
__pycache__/
|
||||||
|
*.pyc
|
||||||
|
*.pyo
|
||||||
|
*.pyd
|
||||||
|
*.egg-info/
|
||||||
|
.eggs/
|
||||||
|
.venv/
|
||||||
|
venv/
|
||||||
|
env/
|
||||||
|
|
||||||
|
node_modules/
|
||||||
|
npm-debug.log
|
||||||
|
yarn-debug.log
|
||||||
|
yarn-error.log
|
||||||
|
.pnpm-debug.log
|
||||||
|
|
||||||
|
*.retry
|
||||||
|
inventory/
|
||||||
|
hosts
|
||||||
|
.secrets/
|
||||||
|
.vault_pass.txt
|
||||||
|
|
||||||
|
charts/*.tgz
|
||||||
|
.helm/
|
||||||
|
kustomize-build/
|
||||||
|
.kube/
|
||||||
|
*.kubeconfig
|
||||||
|
|
||||||
|
.terraform/
|
||||||
|
terraform.tfstate
|
||||||
|
terraform.tfstate.backup
|
||||||
|
*.tfvars
|
||||||
|
|
||||||
|
logs/
|
||||||
|
*.log
|
||||||
|
.coverage
|
||||||
|
coverage.xml
|
||||||
|
htmlcov/
|
||||||
|
.junit/
|
||||||
|
*.out
|
||||||
|
*.err
|
||||||
|
|
||||||
|
.gitattributes.lock
|
||||||
|
.editorconfig.lock
|
||||||
|
|
||||||
|
.railiance_gitea.conf
|
||||||
|
|
||||||
|
.vscode/
|
||||||
|
.idea/
|
||||||
|
*.iml
|
||||||
|
GIGN
|
||||||
|
|
||||||
|
# tools/README
|
||||||
|
ensure_file "${repo_root}/tools/README.md" TREAD <<'TREAD'
|
||||||
|
# Railiance Tools
|
||||||
|
- `create_railiance_repo.sh` — create a Gitea repo (user/org).
|
||||||
|
- `furnish_railiance_repo.sh` — idempotently add license/housekeeping to this repo.
|
||||||
|
- `build_spore.sh` — produce a portable seed bundle (see panspermia model).
|
||||||
|
- `seed_node.sh` — run on a blank host to kick off biogenesis.
|
||||||
|
TREAD
|
||||||
|
|
||||||
|
echo "[✓] Furnishing complete."
|
||||||
136
tools/seed_node.sh
Normal file
136
tools/seed_node.sh
Normal file
@@ -0,0 +1,136 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# tools/seed_node.sh
|
||||||
|
# Railiance Seed — kick off biogenesis on a blank (or nearly blank) host.
|
||||||
|
#
|
||||||
|
# Responsibilities:
|
||||||
|
# - Ensure minimal prerequisites (curl, git, jq)
|
||||||
|
# - Discover metadata (panspermia.json or env vars)
|
||||||
|
# - Clone or update the parent repo (default: railiance-bootstrap)
|
||||||
|
# - Run furnishing (idempotent) to align housekeeping
|
||||||
|
# - (Optional) handoff to further bootstrap steps
|
||||||
|
#
|
||||||
|
# Usage examples:
|
||||||
|
# ./tools/seed_node.sh
|
||||||
|
# REPO_URL=https://git.example.com/org/railiance-bootstrap.git ./tools/seed_node.sh
|
||||||
|
# ./tools/seed_node.sh --repo-dir /srv/railiance --branch main
|
||||||
|
#
|
||||||
|
# Notes:
|
||||||
|
# - No secrets are written or echoed by this script.
|
||||||
|
# - Git authentication relies on your environment (SSH keys or credential helper).
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
# --------- defaults & flags ----------
|
||||||
|
REPO_DIR="${REPO_DIR:-railiance-bootstrap}"
|
||||||
|
BRANCH="${BRANCH:-main}"
|
||||||
|
META_PATH="${META_PATH:-}" # optional explicit path to panspermia.json
|
||||||
|
QUIET=false
|
||||||
|
|
||||||
|
while [[ $# -gt 0 ]]; do
|
||||||
|
case "$1" in
|
||||||
|
--repo-dir) REPO_DIR="${2:?}"; shift 2 ;;
|
||||||
|
--branch) BRANCH="${2:?}"; shift 2 ;;
|
||||||
|
--meta) META_PATH="${2:?}"; shift 2 ;;
|
||||||
|
-q|--quiet) QUIET=true; shift ;;
|
||||||
|
-h|--help)
|
||||||
|
sed -n '1,120p' "$0" | sed -n '1,/^set -euo pipefail/p'
|
||||||
|
exit 0 ;;
|
||||||
|
*) echo "Unknown arg: $1" >&2; exit 2 ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
log() { $QUIET || echo "$@"; }
|
||||||
|
|
||||||
|
need() {
|
||||||
|
command -v "$1" >/dev/null 2>&1 && return 0
|
||||||
|
log "[*] Installing $1 ..."
|
||||||
|
if command -v apt-get >/dev/null 2>&1; then
|
||||||
|
sudo apt-get update -y && sudo apt-get install -y "$1"
|
||||||
|
elif command -v dnf >/dev/null 2>&1; then
|
||||||
|
sudo dnf install -y "$1"
|
||||||
|
elif command -v yum >/dev/null 2>&1; then
|
||||||
|
sudo yum install -y "$1"
|
||||||
|
else
|
||||||
|
echo "ERROR: package manager not found to install $1" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# prerequisites
|
||||||
|
need curl
|
||||||
|
need git
|
||||||
|
command -v jq >/dev/null 2>&1 || need jq
|
||||||
|
|
||||||
|
# --------- discover metadata ----------
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
DEFAULT_META="${SCRIPT_DIR}/../panspermia.json"
|
||||||
|
|
||||||
|
REPO_URL="${REPO_URL:-}"
|
||||||
|
if [[ -z "${REPO_URL}" ]]; then
|
||||||
|
# read metadata file (explicit > default > none)
|
||||||
|
SRC_META=""
|
||||||
|
if [[ -n "${META_PATH}" && -f "${META_PATH}" ]]; then
|
||||||
|
SRC_META="${META_PATH}"
|
||||||
|
elif [[ -f "${DEFAULT_META}" ]]; then
|
||||||
|
SRC_META="${DEFAULT_META}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ -n "${SRC_META}" ]]; then
|
||||||
|
log "[=] Using metadata: ${SRC_META}"
|
||||||
|
REPO_URL="$(jq -r '.parent_body.repo_url // empty' "${SRC_META}")"
|
||||||
|
BRANCH_FROM_META="$(jq -r '.parent_body.branch // empty' "${SRC_META}")" || true
|
||||||
|
if [[ -n "${BRANCH_FROM_META}" ]]; then BRANCH="${BRANCH_FROM_META}"; fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ -z "${REPO_URL}" ]]; then
|
||||||
|
echo "ERROR: No REPO_URL provided and no panspermia metadata found." >&2
|
||||||
|
echo "Provide one of:" >&2
|
||||||
|
echo " - env REPO_URL=https://git.example.com/org/railiance-bootstrap.git" >&2
|
||||||
|
echo " - or a panspermia.json with .parent_body.repo_url" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
log "[*] Target repo: ${REPO_URL} (branch: ${BRANCH})"
|
||||||
|
log "[*] Local dir : ${REPO_DIR}"
|
||||||
|
|
||||||
|
# --------- clone or update ----------
|
||||||
|
if [[ -d "${REPO_DIR}/.git" ]]; then
|
||||||
|
log "[=] Repo dir exists. Fetching updates ..."
|
||||||
|
(
|
||||||
|
cd "${REPO_DIR}"
|
||||||
|
git remote -v
|
||||||
|
git fetch --all --tags
|
||||||
|
git checkout "${BRANCH}"
|
||||||
|
git pull --ff-only origin "${BRANCH}" || true
|
||||||
|
)
|
||||||
|
else
|
||||||
|
log "[+] Cloning repository ..."
|
||||||
|
git clone --branch "${BRANCH}" "${REPO_URL}" "${REPO_DIR}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# --------- furnishing ----------
|
||||||
|
if [[ -x "${REPO_DIR}/tools/furnish_railiance_repo.sh" ]]; then
|
||||||
|
log "[*] Running furnishing script (idempotent) ..."
|
||||||
|
bash "${REPO_DIR}/tools/furnish_railiance_repo.sh"
|
||||||
|
else
|
||||||
|
log "[!] Furnishing script not found at ${REPO_DIR}/tools/furnish_railiance_repo.sh — skipping."
|
||||||
|
fi
|
||||||
|
|
||||||
|
# --------- placeholder for next steps ----------
|
||||||
|
cat <<'NEXT'
|
||||||
|
|
||||||
|
[✓] Seed completed.
|
||||||
|
|
||||||
|
Next steps (manual, for now):
|
||||||
|
1) Review the repo at $REPO_DIR
|
||||||
|
2) Configure host inventory and credentials (kept local, never committed)
|
||||||
|
3) Run the initial bootstrap playbook (e.g., ansible/bootstrap.yml)
|
||||||
|
4) Prepare GitOps operator (ArgoCD/Flux) pointing to this repo
|
||||||
|
|
||||||
|
Hints:
|
||||||
|
- To use SSH instead of HTTPS, set REPO_URL=git@your-gitea:org/railiance-bootstrap.git
|
||||||
|
- If using HTTPS, set up 'git config --global credential.helper cache|store'
|
||||||
|
- For air-gapped: copy a Spore bundle, extract, then run this seed script
|
||||||
|
|
||||||
|
NEXT
|
||||||
Reference in New Issue
Block a user