a1a17e81a1
Includes updated JS challenge scripts with Claude-User whitelist, same-site referer bypass, Blackbox-Exporter allowed bot, and all new exporters, cheat sheets, and automation scripts.
653 lines
24 KiB
Bash
653 lines
24 KiB
Bash
#!/usr/bin/env bash
|
|
#########################################################################################
|
|
#### gitops-bootstrap.sh — Bootstrap GitOps on Kubernetes with Flux or ArgoCD ####
|
|
#### Install, configure git source, sync applications, and validate deployments ####
|
|
#### Requires: bash 4+, kubectl, git, flux CLI or argocd CLI ####
|
|
#### ####
|
|
#### Author: Phil Connor ####
|
|
#### Contact: contact@mylinux.work ####
|
|
#### License: MIT ####
|
|
#### Version 1.00 ####
|
|
#### ####
|
|
#### Usage: ####
|
|
#### ./gitops-bootstrap.sh --install flux --repo git@github.com:org/infra.git ####
|
|
#### ####
|
|
#### See --help for all options. ####
|
|
#########################################################################################
|
|
set -euo pipefail
|
|
|
|
VERSION="1.00"
|
|
|
|
# --- ANSI color variables (pre-initialized) ---
|
|
RED=""
|
|
GREEN=""
|
|
YELLOW=""
|
|
BLUE=""
|
|
CYAN=""
|
|
BOLD=""
|
|
DIM=""
|
|
RESET=""
|
|
|
|
# --- Defaults ---
|
|
RUN_MODE=""
|
|
GITOPS_TOOL="${GITOPS_TOOL:-flux}"
|
|
GIT_REPO="${GITOPS_REPO:-}"
|
|
GIT_BRANCH="${GITOPS_BRANCH:-main}"
|
|
GIT_PATH="${GITOPS_PATH:-./clusters/default}"
|
|
NAMESPACE="${GITOPS_NAMESPACE:-}"
|
|
KUBECONFIG_FILE="${KUBECONFIG:-}"
|
|
KUBE_CTX="${KUBE_CONTEXT:-}"
|
|
CONFIRM_YES=false
|
|
VERBOSE="${VERBOSE:-false}"
|
|
COLOR="${COLOR:-auto}"
|
|
|
|
# --- State ---
|
|
readonly SCRIPT_NAME="${0##*/}"
|
|
START_TIME=$(date +%s)
|
|
|
|
# --- Source name used for flux commands ---
|
|
SOURCE_NAME="main"
|
|
KUSTOMIZATION_NAME="default"
|
|
APP_NAME=""
|
|
|
|
# --- Color setup ---
|
|
setup_colors() {
|
|
if [[ "$COLOR" == "never" ]]; then
|
|
RED="" GREEN="" YELLOW="" BLUE="" CYAN="" BOLD="" DIM="" RESET=""
|
|
return
|
|
fi
|
|
if [[ "$COLOR" == "always" ]] || [[ -t 1 ]]; then
|
|
RED='\033[0;31m'
|
|
GREEN='\033[0;32m'
|
|
YELLOW='\033[1;33m'
|
|
BLUE='\033[0;34m'
|
|
CYAN='\033[0;36m'
|
|
BOLD='\033[1m'
|
|
DIM='\033[2m'
|
|
RESET='\033[0m'
|
|
fi
|
|
}
|
|
|
|
# --- Logging ---
|
|
log() { printf "%b\n" "${GREEN}✔${RESET} $*"; }
|
|
warn() { printf "%b\n" "${YELLOW}⚠${RESET} $*" >&2; }
|
|
err() { printf "%b\n" "${RED}✖${RESET} $*" >&2; }
|
|
verbose() { [[ "$VERBOSE" == "true" ]] && printf "%b\n" "${DIM}▸ $*${RESET}" >&2; return 0; }
|
|
die() { err "$*"; exit 1; }
|
|
|
|
section_header() {
|
|
printf "\n%b━━━ %s ━━━%b\n" "${BOLD}${BLUE}" "$1" "${RESET}"
|
|
}
|
|
|
|
field() {
|
|
printf " %-22s %s\n" "$1:" "$2"
|
|
}
|
|
|
|
field_color() {
|
|
printf " %-22s %b%s%b\n" "$1:" "$2" "$3" "${RESET}"
|
|
}
|
|
|
|
# --- Resolve namespace default based on tool ---
|
|
resolve_namespace() {
|
|
if [[ -z "$NAMESPACE" ]]; then
|
|
if [[ "$GITOPS_TOOL" == "argocd" ]]; then
|
|
NAMESPACE="argocd"
|
|
else
|
|
NAMESPACE="flux-system"
|
|
fi
|
|
fi
|
|
}
|
|
|
|
# --- kubectl wrapper ---
|
|
kubectl_cmd() {
|
|
local -a args=("kubectl")
|
|
[[ -n "$KUBECONFIG_FILE" ]] && args+=("--kubeconfig" "$KUBECONFIG_FILE")
|
|
[[ -n "$KUBE_CTX" ]] && args+=("--context" "$KUBE_CTX")
|
|
"${args[@]}" "$@"
|
|
}
|
|
|
|
# --- Dependency checks ---
|
|
require_kubectl() {
|
|
command -v kubectl >/dev/null 2>&1 || die "kubectl is required but not found in PATH"
|
|
}
|
|
|
|
require_flux() {
|
|
command -v flux >/dev/null 2>&1 || die "flux CLI is required but not found in PATH"
|
|
}
|
|
|
|
require_argocd() {
|
|
command -v argocd >/dev/null 2>&1 || die "argocd CLI is required but not found in PATH"
|
|
}
|
|
|
|
require_git() {
|
|
command -v git >/dev/null 2>&1 || die "git is required but not found in PATH"
|
|
}
|
|
|
|
# --- Confirm prompt ---
|
|
confirm_action() {
|
|
local prompt="${1:-Continue?}"
|
|
if [[ "$CONFIRM_YES" == "true" ]]; then
|
|
return 0
|
|
fi
|
|
printf "%s [y/N] " "$prompt"
|
|
read -r answer
|
|
[[ "$answer" =~ ^[Yy]$ ]] || die "Aborted"
|
|
}
|
|
|
|
# --- Wait for pods ready in namespace ---
|
|
wait_for_pods() {
|
|
local ns="$1"
|
|
local timeout="${2:-120}"
|
|
log "Waiting for pods in namespace ${CYAN}${ns}${RESET} (timeout ${timeout}s)"
|
|
|
|
local deadline=$(($(date +%s) + timeout))
|
|
while true; do
|
|
local not_ready
|
|
not_ready=$(kubectl_cmd get pods -n "$ns" --no-headers 2>/dev/null \
|
|
| grep -cvE 'Running|Completed|Succeeded' || true)
|
|
if [[ "$not_ready" -eq 0 ]]; then
|
|
local total
|
|
total=$(kubectl_cmd get pods -n "$ns" --no-headers 2>/dev/null | wc -l)
|
|
if [[ "$total" -gt 0 ]]; then
|
|
log "All ${total} pod(s) ready in ${ns}"
|
|
return 0
|
|
fi
|
|
fi
|
|
if [[ $(date +%s) -ge $deadline ]]; then
|
|
warn "Timeout waiting for pods in ${ns}"
|
|
kubectl_cmd get pods -n "$ns" --no-headers 2>/dev/null || true
|
|
return 1
|
|
fi
|
|
sleep 5
|
|
done
|
|
}
|
|
|
|
# ─────────────────────────────────────────────────────────────────────
|
|
# Install
|
|
# ─────────────────────────────────────────────────────────────────────
|
|
|
|
do_install_flux() {
|
|
section_header "Installing Flux"
|
|
require_kubectl
|
|
require_flux
|
|
|
|
log "Running pre-flight checks"
|
|
verbose "flux check --pre"
|
|
flux check --pre || die "Flux pre-flight checks failed"
|
|
|
|
log "Installing Flux components into namespace ${CYAN}${NAMESPACE}${RESET}"
|
|
verbose "flux install --namespace=${NAMESPACE}"
|
|
flux install --namespace="$NAMESPACE"
|
|
|
|
wait_for_pods "$NAMESPACE"
|
|
|
|
if [[ -n "$GIT_REPO" ]]; then
|
|
log "Configuring GitRepository source"
|
|
verbose "flux create source git ${SOURCE_NAME} --url=${GIT_REPO} --branch=${GIT_BRANCH} --namespace=${NAMESPACE}"
|
|
flux create source git "$SOURCE_NAME" \
|
|
--url="$GIT_REPO" \
|
|
--branch="$GIT_BRANCH" \
|
|
--namespace="$NAMESPACE"
|
|
|
|
log "Creating Kustomization"
|
|
verbose "flux create kustomization ${KUSTOMIZATION_NAME} --source=${SOURCE_NAME} --path=${GIT_PATH} --namespace=${NAMESPACE} --prune=true"
|
|
flux create kustomization "$KUSTOMIZATION_NAME" \
|
|
--source="$SOURCE_NAME" \
|
|
--path="$GIT_PATH" \
|
|
--namespace="$NAMESPACE" \
|
|
--prune=true
|
|
fi
|
|
|
|
section_header "Flux Installation Summary"
|
|
field "Namespace" "$NAMESPACE"
|
|
field "Git repository" "${GIT_REPO:-not configured}"
|
|
field "Branch" "$GIT_BRANCH"
|
|
field "Path" "$GIT_PATH"
|
|
log "Flux installation complete"
|
|
}
|
|
|
|
do_install_argocd() {
|
|
section_header "Installing Argo CD"
|
|
require_kubectl
|
|
|
|
local manifests_url="https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml"
|
|
|
|
log "Creating namespace ${CYAN}${NAMESPACE}${RESET}"
|
|
kubectl_cmd create namespace "$NAMESPACE" --dry-run=client -o yaml \
|
|
| kubectl_cmd apply -f -
|
|
|
|
log "Applying Argo CD manifests"
|
|
verbose "kubectl apply -n ${NAMESPACE} -f ${manifests_url}"
|
|
kubectl_cmd apply -n "$NAMESPACE" -f "$manifests_url"
|
|
|
|
wait_for_pods "$NAMESPACE"
|
|
|
|
section_header "Argo CD Installation Summary"
|
|
field "Namespace" "$NAMESPACE"
|
|
field "Manifests" "$manifests_url"
|
|
printf "\n"
|
|
log "Retrieve initial admin password:"
|
|
printf " %bkubectl -n %s get secret argocd-initial-admin-secret -o jsonpath='{.data.password}' | base64 -d%b\n" \
|
|
"${CYAN}" "$NAMESPACE" "${RESET}"
|
|
log "Argo CD installation complete"
|
|
}
|
|
|
|
do_install() {
|
|
case "$GITOPS_TOOL" in
|
|
flux) do_install_flux ;;
|
|
argocd) do_install_argocd ;;
|
|
*) die "Unknown GitOps tool: ${GITOPS_TOOL}. Use 'flux' or 'argocd'." ;;
|
|
esac
|
|
}
|
|
|
|
# ─────────────────────────────────────────────────────────────────────
|
|
# Status
|
|
# ─────────────────────────────────────────────────────────────────────
|
|
|
|
do_status_flux() {
|
|
section_header "Flux Status"
|
|
require_kubectl
|
|
require_flux
|
|
|
|
log "Sources"
|
|
flux get sources all --namespace="$NAMESPACE" 2>/dev/null || warn "No sources found"
|
|
|
|
printf "\n"
|
|
log "Kustomizations"
|
|
flux get kustomizations --namespace="$NAMESPACE" 2>/dev/null || warn "No kustomizations found"
|
|
|
|
printf "\n"
|
|
log "Helm releases"
|
|
flux get helmreleases --all-namespaces 2>/dev/null || verbose "No helm releases found"
|
|
}
|
|
|
|
do_status_argocd() {
|
|
section_header "Argo CD Status"
|
|
require_kubectl
|
|
|
|
log "Applications"
|
|
kubectl_cmd get applications -n "$NAMESPACE" -o wide 2>/dev/null || warn "No applications found"
|
|
|
|
printf "\n"
|
|
log "App Projects"
|
|
kubectl_cmd get appprojects -n "$NAMESPACE" -o wide 2>/dev/null || verbose "No app projects found"
|
|
}
|
|
|
|
do_status() {
|
|
case "$GITOPS_TOOL" in
|
|
flux) do_status_flux ;;
|
|
argocd) do_status_argocd ;;
|
|
*) die "Unknown GitOps tool: ${GITOPS_TOOL}" ;;
|
|
esac
|
|
|
|
section_header "Pod Status (${NAMESPACE})"
|
|
kubectl_cmd get pods -n "$NAMESPACE" -o wide 2>/dev/null || warn "No pods found"
|
|
}
|
|
|
|
# ─────────────────────────────────────────────────────────────────────
|
|
# Add Source
|
|
# ─────────────────────────────────────────────────────────────────────
|
|
|
|
do_add_source_flux() {
|
|
section_header "Adding Git Source (Flux)"
|
|
require_flux
|
|
|
|
[[ -z "$GIT_REPO" ]] && die "--repo is required to add a source"
|
|
|
|
log "Creating GitRepository source ${CYAN}${SOURCE_NAME}${RESET}"
|
|
verbose "flux create source git ${SOURCE_NAME} --url=${GIT_REPO} --branch=${GIT_BRANCH} --namespace=${NAMESPACE}"
|
|
flux create source git "$SOURCE_NAME" \
|
|
--url="$GIT_REPO" \
|
|
--branch="$GIT_BRANCH" \
|
|
--namespace="$NAMESPACE"
|
|
|
|
log "Source added successfully"
|
|
flux get sources git --namespace="$NAMESPACE"
|
|
}
|
|
|
|
do_add_source_argocd() {
|
|
section_header "Adding Git Source (Argo CD)"
|
|
require_argocd
|
|
|
|
[[ -z "$GIT_REPO" ]] && die "--repo is required to add a source"
|
|
|
|
log "Adding repository ${CYAN}${GIT_REPO}${RESET}"
|
|
verbose "argocd repo add ${GIT_REPO}"
|
|
argocd repo add "$GIT_REPO" || die "Failed to add repository"
|
|
|
|
log "Repository added successfully"
|
|
}
|
|
|
|
do_add_source() {
|
|
case "$GITOPS_TOOL" in
|
|
flux) do_add_source_flux ;;
|
|
argocd) do_add_source_argocd ;;
|
|
*) die "Unknown GitOps tool: ${GITOPS_TOOL}" ;;
|
|
esac
|
|
}
|
|
|
|
# ─────────────────────────────────────────────────────────────────────
|
|
# Sync / Reconcile
|
|
# ─────────────────────────────────────────────────────────────────────
|
|
|
|
do_sync_flux() {
|
|
section_header "Reconciling (Flux)"
|
|
require_flux
|
|
|
|
log "Reconciling source git/${SOURCE_NAME}"
|
|
verbose "flux reconcile source git ${SOURCE_NAME} --namespace=${NAMESPACE}"
|
|
flux reconcile source git "$SOURCE_NAME" --namespace="$NAMESPACE"
|
|
|
|
log "Reconciling kustomization ${KUSTOMIZATION_NAME}"
|
|
verbose "flux reconcile kustomization ${KUSTOMIZATION_NAME} --namespace=${NAMESPACE}"
|
|
flux reconcile kustomization "$KUSTOMIZATION_NAME" --namespace="$NAMESPACE"
|
|
|
|
log "Reconciliation triggered"
|
|
}
|
|
|
|
do_sync_argocd() {
|
|
section_header "Syncing (Argo CD)"
|
|
require_argocd
|
|
|
|
if [[ -n "$APP_NAME" ]]; then
|
|
log "Syncing application ${CYAN}${APP_NAME}${RESET}"
|
|
verbose "argocd app sync ${APP_NAME}"
|
|
argocd app sync "$APP_NAME"
|
|
else
|
|
log "Syncing all applications"
|
|
local apps
|
|
apps=$(kubectl_cmd get applications -n "$NAMESPACE" -o jsonpath='{range .items[*]}{.metadata.name}{"\n"}{end}' 2>/dev/null || true)
|
|
if [[ -z "$apps" ]]; then
|
|
warn "No applications found to sync"
|
|
return
|
|
fi
|
|
while IFS= read -r app; do
|
|
[[ -z "$app" ]] && continue
|
|
log "Syncing ${app}"
|
|
argocd app sync "$app" || warn "Failed to sync ${app}"
|
|
done <<< "$apps"
|
|
fi
|
|
|
|
log "Sync triggered"
|
|
}
|
|
|
|
do_sync() {
|
|
case "$GITOPS_TOOL" in
|
|
flux) do_sync_flux ;;
|
|
argocd) do_sync_argocd ;;
|
|
*) die "Unknown GitOps tool: ${GITOPS_TOOL}" ;;
|
|
esac
|
|
}
|
|
|
|
# ─────────────────────────────────────────────────────────────────────
|
|
# Validate (pre-flight)
|
|
# ─────────────────────────────────────────────────────────────────────
|
|
|
|
do_validate() {
|
|
section_header "Pre-flight Validation"
|
|
require_kubectl
|
|
|
|
local checks_passed=0
|
|
local checks_failed=0
|
|
|
|
# Check kubectl connectivity
|
|
log "Checking kubectl connectivity"
|
|
if kubectl_cmd cluster-info >/dev/null 2>&1; then
|
|
field_color "Cluster access" "${GREEN}" "OK"
|
|
checks_passed=$((checks_passed + 1))
|
|
else
|
|
field_color "Cluster access" "${RED}" "FAILED"
|
|
checks_failed=$((checks_failed + 1))
|
|
fi
|
|
|
|
# Check namespace exists
|
|
log "Checking namespace ${CYAN}${NAMESPACE}${RESET}"
|
|
if kubectl_cmd get namespace "$NAMESPACE" >/dev/null 2>&1; then
|
|
field_color "Namespace" "${GREEN}" "${NAMESPACE} exists"
|
|
checks_passed=$((checks_passed + 1))
|
|
else
|
|
field_color "Namespace" "${YELLOW}" "${NAMESPACE} does not exist (will be created)"
|
|
checks_passed=$((checks_passed + 1))
|
|
fi
|
|
|
|
# Check CRDs installed
|
|
log "Checking CRDs"
|
|
if [[ "$GITOPS_TOOL" == "flux" ]]; then
|
|
if kubectl_cmd get crd gitrepositories.source.toolkit.fluxcd.io >/dev/null 2>&1; then
|
|
field_color "Flux CRDs" "${GREEN}" "installed"
|
|
checks_passed=$((checks_passed + 1))
|
|
else
|
|
field_color "Flux CRDs" "${YELLOW}" "not installed"
|
|
checks_passed=$((checks_passed + 1))
|
|
fi
|
|
elif [[ "$GITOPS_TOOL" == "argocd" ]]; then
|
|
if kubectl_cmd get crd applications.argoproj.io >/dev/null 2>&1; then
|
|
field_color "ArgoCD CRDs" "${GREEN}" "installed"
|
|
checks_passed=$((checks_passed + 1))
|
|
else
|
|
field_color "ArgoCD CRDs" "${YELLOW}" "not installed"
|
|
checks_passed=$((checks_passed + 1))
|
|
fi
|
|
fi
|
|
|
|
# Check git repo accessible
|
|
if [[ -n "$GIT_REPO" ]]; then
|
|
log "Checking git repository accessibility"
|
|
require_git
|
|
if git ls-remote "$GIT_REPO" HEAD >/dev/null 2>&1; then
|
|
field_color "Git repository" "${GREEN}" "accessible"
|
|
checks_passed=$((checks_passed + 1))
|
|
else
|
|
field_color "Git repository" "${RED}" "not accessible"
|
|
checks_failed=$((checks_failed + 1))
|
|
fi
|
|
else
|
|
verbose "No git repository specified, skipping connectivity check"
|
|
fi
|
|
|
|
# Check tool CLI available
|
|
log "Checking CLI tools"
|
|
if [[ "$GITOPS_TOOL" == "flux" ]]; then
|
|
if command -v flux >/dev/null 2>&1; then
|
|
local flux_ver
|
|
flux_ver=$(flux version --client 2>/dev/null | head -1 || echo "unknown")
|
|
field_color "flux CLI" "${GREEN}" "$flux_ver"
|
|
checks_passed=$((checks_passed + 1))
|
|
else
|
|
field_color "flux CLI" "${RED}" "not found"
|
|
checks_failed=$((checks_failed + 1))
|
|
fi
|
|
elif [[ "$GITOPS_TOOL" == "argocd" ]]; then
|
|
if command -v argocd >/dev/null 2>&1; then
|
|
local argocd_ver
|
|
argocd_ver=$(argocd version --client --short 2>/dev/null || echo "unknown")
|
|
field_color "argocd CLI" "${GREEN}" "$argocd_ver"
|
|
checks_passed=$((checks_passed + 1))
|
|
else
|
|
field_color "argocd CLI" "${RED}" "not found"
|
|
checks_failed=$((checks_failed + 1))
|
|
fi
|
|
fi
|
|
|
|
section_header "Validation Summary"
|
|
field_color "Passed" "${GREEN}" "$checks_passed"
|
|
if [[ "$checks_failed" -gt 0 ]]; then
|
|
field_color "Failed" "${RED}" "$checks_failed"
|
|
die "Validation failed with ${checks_failed} error(s)"
|
|
else
|
|
field_color "Failed" "${GREEN}" "0"
|
|
log "All pre-flight checks passed"
|
|
fi
|
|
}
|
|
|
|
# ─────────────────────────────────────────────────────────────────────
|
|
# Teardown
|
|
# ─────────────────────────────────────────────────────────────────────
|
|
|
|
do_teardown_flux() {
|
|
section_header "Tearing Down Flux"
|
|
require_flux
|
|
|
|
confirm_action "Remove Flux from the cluster?"
|
|
|
|
log "Uninstalling Flux"
|
|
verbose "flux uninstall --namespace=${NAMESPACE} --silent"
|
|
flux uninstall --namespace="$NAMESPACE" --silent
|
|
|
|
log "Flux has been removed from the cluster"
|
|
}
|
|
|
|
do_teardown_argocd() {
|
|
section_header "Tearing Down Argo CD"
|
|
require_kubectl
|
|
|
|
confirm_action "Remove Argo CD from the cluster (delete namespace ${NAMESPACE})?"
|
|
|
|
log "Deleting namespace ${CYAN}${NAMESPACE}${RESET}"
|
|
kubectl_cmd delete namespace "$NAMESPACE" --wait=true
|
|
|
|
log "Argo CD has been removed from the cluster"
|
|
}
|
|
|
|
do_teardown() {
|
|
case "$GITOPS_TOOL" in
|
|
flux) do_teardown_flux ;;
|
|
argocd) do_teardown_argocd ;;
|
|
*) die "Unknown GitOps tool: ${GITOPS_TOOL}" ;;
|
|
esac
|
|
}
|
|
|
|
# ─────────────────────────────────────────────────────────────────────
|
|
# Help
|
|
# ─────────────────────────────────────────────────────────────────────
|
|
|
|
show_help() {
|
|
cat <<EOF
|
|
${BOLD}GitOps Bootstrap v${VERSION}${RESET}
|
|
Bootstrap GitOps (Flux or Argo CD) on a Kubernetes cluster.
|
|
|
|
${BOLD}MODES:${RESET}
|
|
--install TOOL Install GitOps tool on the cluster (flux or argocd)
|
|
--status Show GitOps deployment status
|
|
--add-source Add a git repository source
|
|
--sync Trigger reconciliation / sync
|
|
--validate Run pre-flight checks
|
|
--teardown Remove GitOps from the cluster
|
|
|
|
${BOLD}OPTIONS:${RESET}
|
|
--tool TOOL GitOps tool: flux (default) or argocd
|
|
--repo URL Git repository URL
|
|
--branch BRANCH Git branch (default: main)
|
|
--path PATH Path within the repo (default: ./clusters/default)
|
|
--namespace NS GitOps namespace (default: flux-system or argocd)
|
|
--source-name NAME Name for the git source (default: main)
|
|
--kustomization NAME Name for the kustomization (default: default)
|
|
--app NAME Application name (for argocd sync)
|
|
--kubeconfig FILE Path to kubeconfig file
|
|
--context CTX Kubernetes context name
|
|
--yes Skip confirmation prompts
|
|
--verbose Enable verbose output
|
|
--no-color Disable colored output
|
|
--help Show this help message
|
|
|
|
${BOLD}ENVIRONMENT VARIABLES:${RESET}
|
|
GITOPS_TOOL GitOps tool (flux or argocd)
|
|
GITOPS_REPO Git repository URL
|
|
GITOPS_BRANCH Git branch
|
|
GITOPS_PATH Path within the repo
|
|
GITOPS_NAMESPACE GitOps namespace
|
|
KUBECONFIG Path to kubeconfig file
|
|
KUBE_CONTEXT Kubernetes context name
|
|
VERBOSE Enable verbose output (true/false)
|
|
COLOR Color mode (auto, always, never)
|
|
|
|
${BOLD}EXAMPLES:${RESET}
|
|
${SCRIPT_NAME} --install flux --repo git@github.com:org/infra.git
|
|
${SCRIPT_NAME} --install argocd
|
|
${SCRIPT_NAME} --status --tool argocd
|
|
${SCRIPT_NAME} --add-source --repo git@github.com:org/infra.git
|
|
${SCRIPT_NAME} --sync --tool flux
|
|
${SCRIPT_NAME} --validate --repo git@github.com:org/infra.git
|
|
${SCRIPT_NAME} --teardown --tool flux --yes
|
|
EOF
|
|
exit 0
|
|
}
|
|
|
|
# ─────────────────────────────────────────────────────────────────────
|
|
# Parse arguments
|
|
# ─────────────────────────────────────────────────────────────────────
|
|
|
|
parse_args() {
|
|
while [[ $# -gt 0 ]]; do
|
|
case "$1" in
|
|
--install)
|
|
RUN_MODE="install"
|
|
if [[ "${2:-}" == "flux" || "${2:-}" == "argocd" ]]; then
|
|
GITOPS_TOOL="$2"; shift
|
|
fi
|
|
shift
|
|
;;
|
|
--status) RUN_MODE="status"; shift ;;
|
|
--add-source) RUN_MODE="add-source"; shift ;;
|
|
--sync) RUN_MODE="sync"; shift ;;
|
|
--validate) RUN_MODE="validate"; shift ;;
|
|
--teardown) RUN_MODE="teardown"; shift ;;
|
|
--tool) GITOPS_TOOL="${2:-}"; shift 2 || die "--tool requires a value" ;;
|
|
--repo) GIT_REPO="${2:-}"; shift 2 || die "--repo requires a URL" ;;
|
|
--branch) GIT_BRANCH="${2:-}"; shift 2 || die "--branch requires a value" ;;
|
|
--path) GIT_PATH="${2:-}"; shift 2 || die "--path requires a value" ;;
|
|
--namespace) NAMESPACE="${2:-}"; shift 2 || die "--namespace requires a value" ;;
|
|
--source-name) SOURCE_NAME="${2:-}"; shift 2 || die "--source-name requires a value" ;;
|
|
--kustomization) KUSTOMIZATION_NAME="${2:-}"; shift 2 || die "--kustomization requires a value" ;;
|
|
--app) APP_NAME="${2:-}"; shift 2 || die "--app requires a name" ;;
|
|
--kubeconfig) KUBECONFIG_FILE="${2:-}"; shift 2 || die "--kubeconfig requires a file" ;;
|
|
--context) KUBE_CTX="${2:-}"; shift 2 || die "--context requires a name" ;;
|
|
--yes) CONFIRM_YES=true; shift ;;
|
|
--verbose) VERBOSE="true"; shift ;;
|
|
--no-color) COLOR="never"; shift ;;
|
|
--help) setup_colors; show_help ;;
|
|
*) die "Unknown option: $1" ;;
|
|
esac
|
|
done
|
|
|
|
if [[ -z "$RUN_MODE" ]]; then err "No mode specified"; echo ""; show_help; exit 1; fi
|
|
|
|
case "$GITOPS_TOOL" in
|
|
flux|argocd) ;;
|
|
*) die "Invalid tool '${GITOPS_TOOL}'. Must be 'flux' or 'argocd'." ;;
|
|
esac
|
|
}
|
|
|
|
# ─────────────────────────────────────────────────────────────────────
|
|
# Main
|
|
# ─────────────────────────────────────────────────────────────────────
|
|
|
|
main() {
|
|
parse_args "$@"
|
|
setup_colors
|
|
resolve_namespace
|
|
|
|
verbose "Script: ${SCRIPT_NAME}"
|
|
verbose "Mode: ${RUN_MODE}"
|
|
verbose "Tool: ${GITOPS_TOOL}"
|
|
verbose "Namespace: ${NAMESPACE}"
|
|
[[ -n "$GIT_REPO" ]] && verbose "Repository: ${GIT_REPO}"
|
|
[[ -n "$KUBECONFIG_FILE" ]] && verbose "Kubeconfig: ${KUBECONFIG_FILE}"
|
|
[[ -n "$KUBE_CTX" ]] && verbose "Context: ${KUBE_CTX}"
|
|
|
|
case "$RUN_MODE" in
|
|
install) do_install ;;
|
|
status) do_status ;;
|
|
add-source) do_add_source ;;
|
|
sync) do_sync ;;
|
|
validate) do_validate ;;
|
|
teardown) do_teardown ;;
|
|
*) die "Unknown mode: ${RUN_MODE}" ;;
|
|
esac
|
|
|
|
local elapsed=$(( $(date +%s) - START_TIME ))
|
|
verbose "Completed in ${elapsed}s"
|
|
}
|
|
|
|
main "$@"
|