mirror of
https://github.com/dredx/prole.git
synced 2026-09-23 11:03:59 +00:00
Kong API Gateway (replacing prole nginx): - Add etc/init_kong.sh provisioning script (DB-less mode, prole-db namespace) - Add kong-deployment.yaml and kong-service.yaml manifests - Rewire ingress rules (svc/git/api.prole.org) to prole-db-kong:8000 - Update kustomization.yaml to reference kong manifests PostgREST & DB Manager in prole-db namespace: - Add etc/init_postgrest.sh and etc/init_db_manager.sh scripts - Add postgrest/db-manager deployment and service manifests - Add src/db-manager/ Node.js REST endpoint for backup triggers - Default NAMESPACE changed to prole-db in both scripts Docker image pre-load from PROLE_DATA/docker-import: - Add _preload_docker_images() to init_common_services.sh - Scan for .tar files exported by final_deployment.sh - Import via k3d image import (k3d) or ctr (k3s) before deployments - Increase rollout timeouts to 300s (configurable via ROLLOUT_TIMEOUT) in init_openbao.sh, init_opentofu.sh, init_garage_store.sh, init_registry.sh OpenTofu password resolution fix: - Add Kubernetes secret fallback in resolve_admin_password() - Change hard exit 1 to graceful return 1 with warning - Wrap call in if-guard so set -e doesn't abort the script chain Milestone fix (init scripts not running): - Add init_kong.sh, init_postgrest.sh, init_db_manager.sh to InitializationScriptsMilestone.execute() script list and arg branches - Previously only actions.py had these; milestones.py was missing them Installer integration: - Add Kong/PostgREST/DB Manager to silent installer _step_init_scripts - Add corresponding tabs and execution blocks in UI services.py
392 lines
12 KiB
Bash
Executable File
392 lines
12 KiB
Bash
Executable File
#!/bin/bash
|
|
|
|
# usage: etc/final_deployment.sh [-e|--docker-export] [-c|--helm-chart] [-k|--kustomize] [-p|--prepare-k3s-pipeline] [-o|--output-dir DIR]
|
|
#
|
|
# This script handles post-installation deployment tasks for Prole.
|
|
# 1st use case: -e|--docker-export
|
|
# Runs docker image export for each image required to deploy Prole.
|
|
# Artifacts are written to DOCKER_IMPORT_DIR.
|
|
# 2nd use case: -c|--helm-chart
|
|
# Creates a Helm chart from the current k8s manifests.
|
|
# Artifacts are written to HELM_CHART_DIR.
|
|
# 3rd use case: -k|--kustomize
|
|
# Creates kustomize deployments (one per component).
|
|
# Artifacts are written to KUSTOMIZE_DIR.
|
|
# 4th use case: -p|--prepare-k3s-pipeline
|
|
# Stages all artifacts for k3s delivery via OpenTofu + ArgoCD.
|
|
# Copies manifests, generates tfvars, and creates ArgoCD Application manifests.
|
|
|
|
usage() {
|
|
echo "Usage: $0 [options]"
|
|
echo ""
|
|
echo "Options:"
|
|
echo " -e, --docker-export Export required docker images to DOCKER_IMPORT_DIR"
|
|
echo " -c, --helm-chart Create Helm chart from k8s manifests"
|
|
echo " -k, --kustomize Create kustomize deployments from k8s manifests"
|
|
echo " -p, --prepare-k3s-pipeline Stage artifacts for k3s delivery (OpenTofu + ArgoCD)"
|
|
echo " -o, --output-dir DIR Base directory for docker-import/, helm-chart/, and kustomize/"
|
|
echo ""
|
|
}
|
|
|
|
do_docker_export=0
|
|
do_helm_chart=0
|
|
do_kustomize=0
|
|
do_k3s_pipeline=0
|
|
export_dir=""
|
|
|
|
if [[ $# -eq 0 ]]; then
|
|
usage
|
|
exit 1
|
|
fi
|
|
|
|
while [[ $# -gt 0 ]]; do
|
|
case "$1" in
|
|
-e|--docker-export)
|
|
do_docker_export=1
|
|
shift
|
|
;;
|
|
-c|--helm-chart)
|
|
do_helm_chart=1
|
|
shift
|
|
;;
|
|
-k|--kustomize)
|
|
do_kustomize=1
|
|
shift
|
|
;;
|
|
-p|--prepare-k3s-pipeline)
|
|
do_k3s_pipeline=1
|
|
shift
|
|
;;
|
|
-o|--output-dir)
|
|
if [[ -z "${2:-}" ]]; then
|
|
echo "Missing value for $1"
|
|
usage
|
|
exit 1
|
|
fi
|
|
export_dir="$2"
|
|
shift 2
|
|
;;
|
|
-h|--help)
|
|
usage
|
|
exit 0
|
|
;;
|
|
*)
|
|
echo "Unknown option: $1"
|
|
usage
|
|
exit 1
|
|
;;
|
|
esac
|
|
done
|
|
|
|
if [[ $do_docker_export -eq 0 && $do_helm_chart -eq 0 && $do_kustomize -eq 0 && $do_k3s_pipeline -eq 0 ]]; then
|
|
usage
|
|
exit 1
|
|
fi
|
|
|
|
PROJECT_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
|
export PROJECT_ROOT
|
|
|
|
# Load environment if env.sh exists
|
|
if [[ -f "${PROJECT_ROOT}/env.sh" ]]; then
|
|
source "${PROJECT_ROOT}/env.sh"
|
|
fi
|
|
|
|
default_owner="$(id -un 2>/dev/null || echo prole)"
|
|
prole_data="${PROLE_DATA:-/opt/prole/data/${default_owner}}"
|
|
prole_data="${prole_data%/}"
|
|
|
|
if [[ -n "$export_dir" ]]; then
|
|
export_dir="${export_dir%/}"
|
|
DOCKER_IMPORT_DIR="${export_dir}/docker-import"
|
|
HELM_CHART_DIR="${export_dir}/helm-chart"
|
|
KUSTOMIZE_DIR="${export_dir}/kustomize"
|
|
fi
|
|
|
|
DOCKER_IMPORT_DIR="${DOCKER_IMPORT_DIR:-${prole_data}/docker-import}"
|
|
HELM_CHART_DIR="${HELM_CHART_DIR:-${prole_data}/helm-chart}"
|
|
KUSTOMIZE_DIR="${KUSTOMIZE_DIR:-${prole_data}/kustomize}"
|
|
|
|
export_docker_images() {
|
|
echo "Exporting Docker images to: ${DOCKER_IMPORT_DIR}"
|
|
mkdir -p "${DOCKER_IMPORT_DIR}"
|
|
|
|
# Collect images from K8s manifests
|
|
# Robust extraction of image names from YAML files
|
|
find "${PROJECT_ROOT}/k8s/prole" "${PROJECT_ROOT}/k8s/openbao" "${PROJECT_ROOT}/k8s/opentofu" -name "*.yaml" -exec grep -h "image:" {} + | awk -F'image:' '{print $2}' | awk '{print $1}' | sed "s/['\"]//g" > /tmp/prole_images.txt
|
|
|
|
# Also check Supabase compose if it exists
|
|
if [[ -f "${PROJECT_ROOT}/supabase/docker/docker-compose.yml" ]]; then
|
|
grep -h "image:" "${PROJECT_ROOT}/supabase/docker/docker-compose.yml" | awk -F'image:' '{print $2}' | awk '{print $1}' | sed "s/['\"]//g" >> /tmp/prole_images.txt
|
|
fi
|
|
|
|
# Add Kerberos proxy image if defined
|
|
KRB_IMG="${KRB5_AD_PROXY_IMAGE:-alpine/socat}"
|
|
if [[ -n "$KRB_IMG" ]]; then
|
|
echo "$KRB_IMG" >> /tmp/prole_images.txt
|
|
fi
|
|
|
|
# Add Kerberos test image (used by init_kerberos_test.sh)
|
|
KRB_TEST_IMG="${KRB5_TEST_IMAGE:-${PROLE_KRB_TEST_IMAGE:-ubuntu:24.04}}"
|
|
if [[ -n "$KRB_TEST_IMG" ]]; then
|
|
echo "$KRB_TEST_IMG" >> /tmp/prole_images.txt
|
|
fi
|
|
|
|
# Unique images
|
|
sort -u /tmp/prole_images.txt > /tmp/prole_images_unique.txt
|
|
|
|
while read -r image; do
|
|
if [[ -z "$image" ]]; then continue; fi
|
|
|
|
# Ensure we have the image locally
|
|
echo "Checking image: $image"
|
|
if ! docker image inspect "$image" >/dev/null 2>&1; then
|
|
echo "Pulling $image (platform linux/arm64)..."
|
|
docker pull --platform linux/arm64 "$image"
|
|
fi
|
|
|
|
safe_name=$(echo "$image" | sed 's/\//_/g' | sed 's/:/_/g')
|
|
tar_path="${DOCKER_IMPORT_DIR}/${safe_name}.tar"
|
|
|
|
echo "Exporting $image to $tar_path..."
|
|
docker save "$image" -o "$tar_path"
|
|
if [[ $? -eq 0 ]]; then
|
|
echo "[OK] Exported $image"
|
|
else
|
|
echo "[ERROR] Failed to export $image"
|
|
fi
|
|
done < /tmp/prole_images_unique.txt
|
|
|
|
rm -f /tmp/prole_images.txt /tmp/prole_images_unique.txt
|
|
echo "Docker export complete."
|
|
}
|
|
|
|
create_helm_chart() {
|
|
local chart_dir="${HELM_CHART_DIR}"
|
|
local chart_name="prole"
|
|
local chart_version="0.1.0"
|
|
local app_version
|
|
app_version="$(date -u +%Y.%m.%d)"
|
|
|
|
echo "Creating Helm chart in: ${chart_dir}"
|
|
mkdir -p "${chart_dir}/templates"
|
|
|
|
# Clean managed template subdirs to avoid stale manifests.
|
|
rm -rf "${chart_dir}/templates/prole" "${chart_dir}/templates/openbao" "${chart_dir}/templates/opentofu"
|
|
|
|
cat > "${chart_dir}/Chart.yaml" <<EOF
|
|
apiVersion: v2
|
|
name: ${chart_name}
|
|
description: Prole deployment manifests
|
|
type: application
|
|
version: ${chart_version}
|
|
appVersion: "${app_version}"
|
|
EOF
|
|
|
|
cat > "${chart_dir}/values.yaml" <<'EOF'
|
|
# Values are unused by default. Manifests are installed as-is.
|
|
EOF
|
|
|
|
copy_manifests() {
|
|
local src_dir="$1"
|
|
local dest_subdir="$2"
|
|
if [[ ! -d "$src_dir" ]]; then
|
|
echo "Skipping missing manifest dir: $src_dir"
|
|
return
|
|
fi
|
|
local dest_dir="${chart_dir}/templates/${dest_subdir}"
|
|
mkdir -p "${dest_dir}"
|
|
local found=0
|
|
while IFS= read -r -d '' file; do
|
|
if [[ "$(basename "$file")" == "kustomization.yaml" ]]; then
|
|
continue
|
|
fi
|
|
cp "$file" "${dest_dir}/"
|
|
found=1
|
|
done < <(find "$src_dir" -maxdepth 1 -type f -name "*.yaml" -print0)
|
|
if [[ $found -eq 0 ]]; then
|
|
echo "No manifests found in $src_dir"
|
|
fi
|
|
}
|
|
|
|
copy_manifests "${PROJECT_ROOT}/k8s/prole" "prole"
|
|
copy_manifests "${PROJECT_ROOT}/k8s/openbao" "openbao"
|
|
copy_manifests "${PROJECT_ROOT}/k8s/opentofu" "opentofu"
|
|
|
|
echo "Helm chart creation complete."
|
|
}
|
|
|
|
create_kustomize_deployments() {
|
|
local base_dir="${KUSTOMIZE_DIR}"
|
|
echo "Creating kustomize deployments in: ${base_dir}"
|
|
mkdir -p "${base_dir}"
|
|
|
|
create_kustomize_package() {
|
|
local name="$1"
|
|
local src_dir="$2"
|
|
if [[ ! -d "$src_dir" ]]; then
|
|
echo "Skipping missing manifest dir: $src_dir"
|
|
return
|
|
fi
|
|
|
|
local dest_dir="${base_dir}/${name}"
|
|
mkdir -p "${dest_dir}"
|
|
|
|
# Copy manifests except kustomization.yaml
|
|
local files=()
|
|
while IFS= read -r -d '' file; do
|
|
if [[ "$(basename "$file")" == "kustomization.yaml" ]]; then
|
|
continue
|
|
fi
|
|
cp "$file" "${dest_dir}/"
|
|
files+=("$(basename "$file")")
|
|
done < <(find "$src_dir" -maxdepth 1 -type f -name "*.yaml" -print0)
|
|
|
|
if [[ ${#files[@]} -eq 0 ]]; then
|
|
echo "No manifests found in $src_dir"
|
|
return
|
|
fi
|
|
|
|
{
|
|
echo "apiVersion: kustomize.config.k8s.io/v1beta1"
|
|
echo "kind: Kustomization"
|
|
echo "resources:"
|
|
for f in "${files[@]}"; do
|
|
echo " - ${f}"
|
|
done
|
|
} > "${dest_dir}/kustomization.yaml"
|
|
}
|
|
|
|
create_kustomize_package "prole" "${PROJECT_ROOT}/k8s/prole"
|
|
create_kustomize_package "openbao" "${PROJECT_ROOT}/k8s/openbao"
|
|
create_kustomize_package "opentofu" "${PROJECT_ROOT}/k8s/opentofu"
|
|
|
|
echo "Kustomize deployments creation complete."
|
|
}
|
|
|
|
if [[ $do_docker_export -eq 1 ]]; then
|
|
export_docker_images
|
|
fi
|
|
|
|
if [[ $do_helm_chart -eq 1 ]]; then
|
|
create_helm_chart
|
|
fi
|
|
|
|
if [[ $do_kustomize -eq 1 ]]; then
|
|
create_kustomize_deployments
|
|
fi
|
|
|
|
prepare_k3s_pipeline() {
|
|
echo "========================================"
|
|
echo "Preparing k3s pipeline (OpenTofu + ArgoCD)"
|
|
echo "========================================"
|
|
echo ""
|
|
|
|
local pipeline_dir="${PROJECT_ROOT}/deploy/opentofu/k3s"
|
|
local manifest_root="${pipeline_dir}/manifests"
|
|
local argocd_dir="${pipeline_dir}/argocd"
|
|
mkdir -p "${manifest_root}" "${argocd_dir}"
|
|
|
|
echo "==> Staging k8s manifests to ${manifest_root}"
|
|
local total=0
|
|
for component in prole openbao opentofu; do
|
|
local src="${PROJECT_ROOT}/k8s/${component}"
|
|
if [[ ! -d "$src" ]]; then
|
|
echo " [SKIP] ${component}/ (not found)"
|
|
continue
|
|
fi
|
|
local dst="${manifest_root}/${component}"
|
|
mkdir -p "$dst"
|
|
local count=0
|
|
for f in "${src}"/*.yaml; do
|
|
[[ -f "$f" ]] || continue
|
|
cp "$f" "$dst/"
|
|
count=$((count + 1))
|
|
done
|
|
total=$((total + count))
|
|
echo " [OK] ${component}/ -> manifests/${component}/ (${count} files)"
|
|
done
|
|
echo " Total manifests staged: ${total}"
|
|
|
|
# Stage Supabase manifests if present
|
|
local supabase_k8s="${PROJECT_ROOT}/supabase/k8s"
|
|
if [[ -d "$supabase_k8s" ]]; then
|
|
local dst="${manifest_root}/supabase"
|
|
mkdir -p "$dst"
|
|
local count=0
|
|
for f in "${supabase_k8s}"/*.yaml; do
|
|
[[ -f "$f" ]] || continue
|
|
cp "$f" "$dst/"
|
|
count=$((count + 1))
|
|
done
|
|
if [[ $count -gt 0 ]]; then
|
|
echo " [OK] supabase/k8s/ -> manifests/supabase/ (${count} files)"
|
|
fi
|
|
fi
|
|
|
|
# Write tfvars
|
|
local k3s_server="${K3S_SERVER_URL:-}"
|
|
local k3s_token="${K3S_TOKEN:-}"
|
|
local namespace="${NAMESPACE:-default}"
|
|
|
|
echo ""
|
|
echo "==> Writing opentofu.auto.tfvars"
|
|
echo " k3s_server_url = ${k3s_server:-(not set)}"
|
|
echo " namespace = ${namespace}"
|
|
|
|
cat > "${pipeline_dir}/opentofu.auto.tfvars" <<EOF
|
|
k3s_server_url = "${k3s_server}"
|
|
k3s_token = "${k3s_token}"
|
|
namespace = "${namespace}"
|
|
EOF
|
|
|
|
# Generate ArgoCD Application manifests
|
|
echo ""
|
|
echo "==> Generating ArgoCD Application manifests in argocd/"
|
|
|
|
local repo_url="${PROLE_GIT_REPO:-}"
|
|
if [[ -z "$repo_url" ]]; then
|
|
repo_url=$(cd "${PROJECT_ROOT}" && git remote get-url origin 2>/dev/null || true)
|
|
fi
|
|
repo_url="${repo_url:-https://github.com/prole-dev/prole.git}"
|
|
local target_revision="${PROLE_GIT_BRANCH:-main}"
|
|
|
|
for component in prole openbao opentofu; do
|
|
cat > "${argocd_dir}/application-${component}.yaml" <<EOF
|
|
apiVersion: argoproj.io/v1alpha1
|
|
kind: Application
|
|
metadata:
|
|
name: prole-${component}
|
|
namespace: argocd
|
|
spec:
|
|
project: default
|
|
source:
|
|
repoURL: ${repo_url}
|
|
targetRevision: ${target_revision}
|
|
path: deploy/opentofu/k3s/manifests/${component}
|
|
destination:
|
|
server: ${k3s_server:-https://kubernetes.default.svc}
|
|
namespace: ${namespace}
|
|
syncPolicy:
|
|
automated:
|
|
prune: true
|
|
selfHeal: true
|
|
syncOptions:
|
|
- CreateNamespace=true
|
|
EOF
|
|
echo " [OK] application-${component}.yaml"
|
|
done
|
|
|
|
echo ""
|
|
echo "==> k3s pipeline preparation complete."
|
|
echo " Pipeline dir: ${pipeline_dir}"
|
|
echo " ArgoCD apps: ${argocd_dir}"
|
|
echo ""
|
|
echo "Next steps:"
|
|
echo " cd ${pipeline_dir} && tofu init && tofu plan && tofu apply"
|
|
echo " kubectl apply -f ${argocd_dir}/"
|
|
}
|
|
|
|
if [[ $do_k3s_pipeline -eq 1 ]]; then
|
|
prepare_k3s_pipeline
|
|
fi
|