#!/usr/bin/env bash # Thin launch vehicle for the Knoe installer. # # Local execution (from a repo checkout): # ./install.sh [args...] # # Bootstrap via curl (first-time install): # curl -fsSL https://knoey.com/install.sh | bash # # --------------------------------------------------------------------------- # Dual-cluster GKE architecture (prod / k8s mode) # --------------------------------------------------------------------------- # knoe-dev-0 — Autopilot cluster: app workloads (GitLab, platform), service mesh knoe-0 # knoe-cnpg-0 — Standard GKE cluster: CloudNative-PG only (rw/ro/r pod separation) # 3 nodes × e2-standard-2, node pool: cnpg-db-pool # # GCP quota requirements (project: plenary-truck-485623-p7, region: us-west3): # pd-standard : node boot disks (3 × 50 GB = 150 GB — does NOT count against pd-ssd quota) # pd-ssd : PGDATA PVCs (3 × 50 Gi = 150 Gi) # WAL PVCs (3 × 50 Gi = 150 Gi) # Total pd-ssd = 300 Gi (requires 300 GB pd-ssd regional quota) # # To patch an existing knoe-cnpg-0 cluster with wrong boot disk type: # ./scripts/patch_clusters.sh # dry-run first: DRY_RUN=true ./scripts/patch_clusters.sh # --------------------------------------------------------------------------- set -euo pipefail # Repo URL used only during bootstrap (curl-pipe) installs. KNOE_REPO_URL="${KNOE_REPO_URL:-https://gitlab.knoey.com/knoe/knoe.git}" # Default install directory for bootstrap installs. _INSTALL_DIR="${KNOE_HOME:-$HOME/knoe}" _check_gcp_tools() { # gcloud is only required for GKE (k8s) deploys — skip for k3d, k3s, and min modes for arg in "$@"; do if [[ "$arg" == "--min" || "$arg" == "--k3d" || "$arg" == "--k3s" ]]; then return 0 fi done # Skip when a non-GKE config is explicitly passed (only gke.cfg needs gcloud) local prev="" for arg in "$@"; do if [[ ("$prev" == "-c" || "$prev" == "--config") && "$arg" != *gke* ]]; then return 0 fi prev="$arg" done local missing=0 if ! command -v gcloud >/dev/null 2>&1; then echo "Error: gcloud CLI is required for GKE cluster management." >&2 echo " Install: https://cloud.google.com/sdk/docs/install" >&2 missing=1 fi if ! command -v kubectl >/dev/null 2>&1; then echo "Error: kubectl is required for Kubernetes cluster operations." >&2 echo " Install: https://kubernetes.io/docs/tasks/tools/" >&2 missing=1 fi if [[ "$missing" -ne 0 ]]; then echo "" >&2 echo "Install missing tools and re-run install.sh." >&2 exit 1 fi } _bootstrap() { echo "==> Bootstrapping Knoe installer..." command -v git >/dev/null 2>&1 || { echo "Error: git is required." >&2; exit 1; } command -v python3 >/dev/null 2>&1 || { echo "Error: python3 is required." >&2; exit 1; } if [[ -d "${_INSTALL_DIR}/.git" ]]; then echo "==> Updating existing checkout at ${_INSTALL_DIR} ..." git -C "${_INSTALL_DIR}" pull --ff-only else echo "==> Cloning to ${_INSTALL_DIR} ..." git clone "${KNOE_REPO_URL}" "${_INSTALL_DIR}" fi exec "${_INSTALL_DIR}/install.sh" "$@" } # Resolve script directory; empty when running via curl pipe. _src="${BASH_SOURCE[0]:-}" _script_dir="$(cd "$(dirname "${_src:-/}")" 2>/dev/null && pwd || echo "")" if [[ -n "${_script_dir}" && -d "${_script_dir}/knoe" ]]; then # Local checkout: delegate to the Python installer module. cd "${_script_dir}" # kubectl-context notice. install.sh defers mode selection to the Python # TUI, so we can't strictly verify here — but printing the inherited # context up-front gives the user a chance to abort before the TUI # launches if it looks wrong (e.g. shell on GKE while planning a k3d # install). Filed against docs/TODO.md queue item #1 (drift R4); the # mode-aware strict guard runs in deploy.sh (which knows its config) and # should also run Python-side once the welcome screen records a mode. if [[ -f "${_script_dir}/etc/preflight_kubecontext.sh" ]]; then _is_min=0 for arg in "$@"; do if [[ "$arg" == "--min" ]]; then _is_min=1; break; fi done if [[ "$_is_min" -eq 0 ]]; then # shellcheck source=etc/preflight_kubecontext.sh source "${_script_dir}/etc/preflight_kubecontext.sh" print_kubecontext_notice fi unset _is_min fi # 1Password preflight — sign in, create 'knoey' vault, ensure 'administrator' item. # Skipped in --min mode (init_1password.sh handles the flag check itself). if [[ -f "${_script_dir}/etc/init_1password.sh" ]]; then bash "${_script_dir}/etc/init_1password.sh" "$@" || true fi # If a built binary exists, prefer it. if [[ -x "dist/knoe" ]]; then exec "./dist/knoe" "$@" fi # Prefer the venv Python at KNOE_HOME (or the repo root) when available; # it carries all knoe_requirements.txt dependencies. _VENV_PYTHON="${KNOE_HOME:-${_script_dir}}/bin/python3" _check_gcp_tools "$@" if [[ -x "${_VENV_PYTHON}" ]]; then exec "${_VENV_PYTHON}" -m knoe.ui.screens "$@" fi exec python3 -m knoe.ui.screens "$@" else # No local checkout found — bootstrap from the remote repo. _bootstrap "$@" fi