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