#!/usr/bin/env bash set -euo pipefail # init_service_layer.sh # Purpose: # - Deploy the service layer (Garage, OpenBao, Kong; OpenTofu in non-k8s modes) # - Keep service-layer resources grouped in SERVICE_NAMESPACE # - Migrate service layer to a new namespace SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd) # Shared option parsing for common core scripts # shellcheck disable=SC1090 source "$SCRIPT_DIR/common_core_lib.sh" # Inject default config if not provided _has_config=0 for _arg in "$@"; do [[ "$_arg" == "-c" || "$_arg" == "--config" || "$_arg" == -c=* || "$_arg" == --config=* ]] && _has_config=1 done if [[ $_has_config -eq 0 ]]; then _default_cfg="$(common_core_default_config_path "$SCRIPT_DIR" || true)" if [[ -n "$_default_cfg" ]]; then set -- "-c" "$_default_cfg" "$@" fi fi unset _has_config _arg _default_cfg common_core_preparse_config "$@" # shellcheck disable=SC1090 source "$SCRIPT_DIR/knoe_cfg.sh" knoe_ensure_kubeconfig >/dev/null 2>&1 || true ensure_kube_context || exit 1 ACTION="" SERVICE_NAMESPACE_OVERRIDE="" FROM_NAMESPACE="" TO_NAMESPACE="" ENABLE_KERBEROS=0 ENABLE_ARGOCD=0 usage() { cat < EOF } while [[ $# -gt 0 ]]; do case "$1" in -c|--config) shift shift ;; -m|--mode) shift knoe_set_mode "${1:-}" shift ;; -m=*|--mode=*) knoe_set_mode "${1#*=}" shift ;; -n|--namespace) shift SERVICE_NAMESPACE_OVERRIDE="${1:-}" shift ;; -n=*|--namespace=*) SERVICE_NAMESPACE_OVERRIDE="${1#*=}" shift ;; -k|--kerberos) ENABLE_KERBEROS=1 shift ;; -a|--argocd) ENABLE_ARGOCD=1 shift ;; --from) shift FROM_NAMESPACE="${1:-}" shift ;; --from=*) FROM_NAMESPACE="${1#*=}" shift ;; --to) shift TO_NAMESPACE="${1:-}" shift ;; --to=*) TO_NAMESPACE="${1#*=}" shift ;; start|update|restart|status|stop|migrate|initialize|reload|repair) ACTION="$1" [[ "$ACTION" == "repair" ]] && ACTION="update" shift ;; -h|--help) usage exit 0 ;; *) usage exit 2 ;; esac done if [[ -n "$SERVICE_NAMESPACE_OVERRIDE" ]]; then SERVICE_NAMESPACE="$SERVICE_NAMESPACE_OVERRIDE" fi SERVICE_NAMESPACE="${SERVICE_NAMESPACE:-${NAMESPACE:-default}}" if [[ -n "$TO_NAMESPACE" ]]; then SERVICE_NAMESPACE="$TO_NAMESPACE" fi SERVICE_LAYER_NAMESPACE="$SERVICE_NAMESPACE" ARGOCD_NS="${ARGOCD_NAMESPACE:-argocd}" # Registry should live in the service-layer namespace unless explicitly overridden. REGISTRY_NS="${REGISTRY_NAMESPACE:-${SERVICE_NAMESPACE}}" STATE_DIR="" if [[ -n "${KNOE_SERVICE:-}" && -f "$KNOE_SERVICE/knoe_cfg.sh" ]]; then STATE_DIR="${KNOE_SERVICE}/secrets" else STATE_DIR="${SCRIPT_DIR}/secrets" fi STATE_FILE="${STATE_DIR}/service-layer.namespace" log() { printf '%s\n' "$*"; } err() { printf '%s\n' "$*" >&2; } ensure_tools() { command -v kubectl >/dev/null || { err "Missing required tool: kubectl"; exit 1; } } ensure_namespace() { local ns="$1" if ! kubectl get namespace "$ns" >/dev/null 2>&1; then log "Creating namespace '$ns' ..." kubectl create namespace "$ns" >/dev/null 2>&1 || true fi } label_namespace() { local ns="$1" kubectl label namespace "$ns" knoe.layer=service --overwrite >/dev/null 2>&1 || true } read_last_namespace() { if [[ -f "$STATE_FILE" ]]; then cat "$STATE_FILE" fi } write_last_namespace() { mkdir -p "$STATE_DIR" printf '%s' "$1" >"$STATE_FILE" } deploy_service_layer() { local action="$1" local ns="$2" local rc=0 local manage_opentofu=1 if [[ "${KNOE_MODE:-}" == "k8s" ]]; then manage_opentofu=0 fi ensure_namespace "$ns" label_namespace "$ns" local argocd_action opentofu_action garage_action kdc_action openbao_action redis_action kong_action registry_action case "$action" in start|initialize|update|reload) argocd_action="update" ;; restart) argocd_action="restart" ;; stop) argocd_action="stop" ;; status) argocd_action="status" ;; *) argocd_action="update" ;; esac if [[ "$manage_opentofu" == "1" ]]; then case "$action" in start|initialize|update|reload) opentofu_action="update" ;; restart) opentofu_action="restart" ;; stop) opentofu_action="stop" ;; status) opentofu_action="status" ;; *) opentofu_action="update" ;; esac fi case "$action" in start|initialize|update|reload) openbao_action="update" ;; restart) openbao_action="restart" ;; stop) openbao_action="stop" ;; status) openbao_action="status" ;; *) openbao_action="update" ;; esac case "$action" in start|initialize|update|reload) redis_action="update" ;; restart) redis_action="restart" ;; stop) redis_action="stop" ;; status) redis_action="status" ;; *) redis_action="update" ;; esac case "$action" in start|initialize|update|reload) garage_action="start" ;; restart) garage_action="restart" ;; stop) garage_action="stop" ;; status) garage_action="status" ;; *) garage_action="start" ;; esac case "$action" in start|initialize|update|reload) kong_action="update" ;; restart) kong_action="restart" ;; stop) kong_action="stop" ;; status) kong_action="status" ;; *) kong_action="update" ;; esac case "$action" in start|initialize|update|reload) registry_action="update" ;; restart) registry_action="restart" ;; stop) registry_action="stop" ;; status) registry_action="status" ;; *) registry_action="update" ;; esac case "$action" in stop) kdc_action="cleanup" ;; status) kdc_action="status" ;; *) kdc_action="update" ;; esac if [[ "$ENABLE_ARGOCD" == "1" ]]; then ARGOCD_NAMESPACE="$ARGOCD_NS" SERVICE_NAMESPACE="$ns" \ "$SCRIPT_DIR/init_argocd.sh" -n "$ARGOCD_NS" "$argocd_action" || rc=$? fi # ------------------------------------------------------------------------- # Deploy services in dependency order: # 1. Registry – no dependencies; other services pull images from it # 2. OpenBao – secrets vault; needed by downstream services # 3. Garage – object storage # 4. Kong – API gateway # 5. OpenTofu – IaC engine; depends on registry + secrets (non-k8s, last) # ------------------------------------------------------------------------- if [[ -x "$SCRIPT_DIR/init_registry.sh" ]]; then REGISTRY_NAMESPACE="$REGISTRY_NS" SERVICE_NAMESPACE="$ns" \ "$SCRIPT_DIR/init_registry.sh" -n "$REGISTRY_NS" "$registry_action" || rc=$? fi OPENBAO_NAMESPACE="$ns" SERVICE_NAMESPACE="$ns" \ "$SCRIPT_DIR/init_openbao.sh" -n "$ns" "$openbao_action" || rc=$? # Redis — shared pub/sub broker; deploy before Kong so GitLab and knoe services can reach it if [[ -x "$SCRIPT_DIR/init_redis.sh" ]]; then REDIS_NAMESPACE="$ns" SERVICE_NAMESPACE="$ns" \ "$SCRIPT_DIR/init_redis.sh" -n "$ns" "$redis_action" || rc=$? else log "[WARN] init_redis.sh not found; Redis deploy skipped." fi # cert-manager is cluster-scoped and managed independently via init_certmgr.sh # in its own dedicated 'cert-manager' namespace; it is not part of the service layer. NAMESPACE="$ns" SERVICE_NAMESPACE="$ns" GARAGE_NAMESPACE="$ns" \ "$SCRIPT_DIR/init_garage_store.sh" "$garage_action" || rc=$? KONG_NAMESPACE="$ns" SERVICE_NAMESPACE="$ns" \ "$SCRIPT_DIR/init_kong.sh" -n "$ns" "$kong_action" || rc=$? if [[ "$manage_opentofu" == "1" ]]; then OPENTOFU_NAMESPACE="$ns" OPENTOFU_SECRET_NAMESPACE="${NAMESPACE:-$ns}" OPENTOFU_OPENBAO_NAMESPACE="$ns" SERVICE_NAMESPACE="$ns" \ "$SCRIPT_DIR/init_opentofu.sh" -n "$ns" "$opentofu_action" || rc=$? else log "[INFO] k8s mode: skipping OpenTofu deploy." fi if [[ "$ENABLE_KERBEROS" == "1" ]]; then # KDC is embedded in `knoe-auth` by default. Only deploy standalone KDC when requested. if [[ "${PROLE_KDC_STANDALONE:-0}" == "1" ]]; then SERVICE_NAMESPACE="$ns" PROLE_KDC_NAMESPACE="$ns" \ "$SCRIPT_DIR/init_kdc.sh" "$kdc_action" || rc=$? else log "[INFO] Kerberos enabled: skipping standalone KDC deploy (KDC runs as sidecar in 'knoe-auth')." fi fi return "$rc" } cleanup_old_namespace() { local ns="$1" log "Cleaning up service layer in old namespace '$ns' ..." if [[ "$ENABLE_ARGOCD" == "1" ]]; then ARGOCD_NAMESPACE="$ARGOCD_NS" SERVICE_NAMESPACE="$ns" \ "$SCRIPT_DIR/init_argocd.sh" -n "$ARGOCD_NS" stop || true fi # Cleanup in reverse dependency order (OpenTofu first, Registry last) OPENTOFU_NAMESPACE="$ns" SERVICE_NAMESPACE="$ns" \ "$SCRIPT_DIR/init_opentofu.sh" -n "$ns" stop || true KONG_NAMESPACE="$ns" SERVICE_NAMESPACE="$ns" \ "$SCRIPT_DIR/init_kong.sh" -n "$ns" stop || true NAMESPACE="$ns" SERVICE_NAMESPACE="$ns" GARAGE_NAMESPACE="$ns" \ "$SCRIPT_DIR/init_garage_store.sh" stop || true OPENBAO_NAMESPACE="$ns" SERVICE_NAMESPACE="$ns" \ "$SCRIPT_DIR/init_openbao.sh" -n "$ns" stop || true if [[ -x "$SCRIPT_DIR/init_redis.sh" ]]; then REDIS_NAMESPACE="$ns" SERVICE_NAMESPACE="$ns" \ "$SCRIPT_DIR/init_redis.sh" -n "$ns" stop || true fi CERTMGR_NAMESPACE="$ns" SERVICE_NAMESPACE="$ns" \ "$SCRIPT_DIR/init_certmgr.sh" -n "$ns" stop || true if [[ -x "$SCRIPT_DIR/init_registry.sh" ]]; then REGISTRY_NAMESPACE="$REGISTRY_NS" SERVICE_NAMESPACE="$ns" \ "$SCRIPT_DIR/init_registry.sh" -n "$REGISTRY_NS" stop || true fi if [[ "$ENABLE_KERBEROS" == "1" && "${PROLE_KDC_STANDALONE:-0}" == "1" ]]; then SERVICE_NAMESPACE="$ns" PROLE_KDC_NAMESPACE="$ns" \ "$SCRIPT_DIR/init_kdc.sh" cleanup || true fi cleanup_openbao "$ns" } migrate_service_layer() { local from_ns="$FROM_NAMESPACE" local to_ns="$SERVICE_LAYER_NAMESPACE" if [[ -z "$from_ns" ]]; then from_ns="$(read_last_namespace || true)" fi if [[ -z "$to_ns" ]]; then err "Missing target SERVICE_NAMESPACE" exit 2 fi if [[ -z "$from_ns" || "$from_ns" == "$to_ns" ]]; then log "Deploying service layer in '$to_ns' ..." deploy_service_layer update "$to_ns" write_last_namespace "$to_ns" return 0 fi log "Migrating service layer from '$from_ns' to '$to_ns' ..." deploy_service_layer update "$to_ns" cleanup_old_namespace "$from_ns" write_last_namespace "$to_ns" } ensure_tools case "$ACTION" in start|update|restart|status|stop|initialize|reload) deploy_service_layer "$ACTION" "$SERVICE_LAYER_NAMESPACE" if [[ "$ACTION" != "status" && "$ACTION" != "stop" ]]; then write_last_namespace "$SERVICE_LAYER_NAMESPACE" fi ;; migrate) migrate_service_layer ;; *) usage exit 2 ;; esac