#!/usr/bin/env bash set -euo pipefail # init_argocd.sh # Deploy and manage ArgoCD as part of the common core stack. 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" common_core_preparse_config "$@" # shellcheck disable=SC1090 source "$SCRIPT_DIR/knoe_cfg.sh" set -- "${COMMON_CORE_ARGS[@]}" common_core_parse_args "$@" if [[ "${COMMON_CORE_HELP:-0}" == 1 ]]; then common_core_usage "$0" exit 0 fi if [[ -n "${COMMON_CORE_PARSE_ERROR:-}" ]]; then echo "ERROR: ${COMMON_CORE_PARSE_ERROR}" >&2 common_core_usage "$0" exit 2 fi ACTION="$COMMON_CORE_ACTION" REPO_ROOT="${KNOE_HOME:-$(cd "$SCRIPT_DIR/.." && pwd)}" GKE_MANIFEST_DIR="${GKE_MANIFEST_DIR:-$REPO_ROOT/deploy/gcp/gke}" if [[ -d "$SCRIPT_DIR/../k8s/argocd" ]]; then ARGOCD_MANIFEST_DIR="$SCRIPT_DIR/../k8s/argocd" elif [[ -n "${KNOE_HOME:-}" && -d "$KNOE_HOME/k8s/argocd" ]]; then ARGOCD_MANIFEST_DIR="$KNOE_HOME/k8s/argocd" else ARGOCD_MANIFEST_DIR="$SCRIPT_DIR/../k8s/argocd" fi ARGOCD_MANIFEST_FILE=${ARGOCD_MANIFEST_FILE:-"$ARGOCD_MANIFEST_DIR/install.yaml"} ARGOCD_NAMESPACE_DEFAULT="${ARGOCD_NAMESPACE:-argocd}" ARGOCD_NAMESPACE="$(common_core_resolve_namespace "$ARGOCD_NAMESPACE_DEFAULT")" common_core_apply_namespace "$ARGOCD_NAMESPACE" export ARGOCD_NAMESPACE ARGOCD_LABEL_SELECTOR=${ARGOCD_LABEL_SELECTOR:-"app.kubernetes.io/part-of=argocd"} ARGOCD_SERVER_SERVICE=${ARGOCD_SERVER_SERVICE:-argocd-server} ARGOCD_PORT_FORWARD_LOCAL=${ARGOCD_PORT_FORWARD_LOCAL:-8081} ARGOCD_PORT_FORWARD_REMOTE=${ARGOCD_PORT_FORWARD_REMOTE:-80} ARGOCD_NODE_SELECTOR=${ARGOCD_NODE_SELECTOR:-} # ── Google Workspace OIDC (applied when all three vars are set) ─────────────── PLATFORM_DOMAIN="${PLATFORM_DOMAIN:-}" FRONTDOOR_HOST="${FRONTDOOR_HOST:-}" BOOTSTRAP_ADMIN_EMAIL="${BOOTSTRAP_ADMIN_EMAIL:-}" ensure_tools() { command -v kubectl >/dev/null || { echo "Missing required tool: kubectl" >&2; exit 1; } } ensure_namespace() { if ! kubectl get namespace "$ARGOCD_NAMESPACE" >/dev/null 2>&1; then echo "Creating namespace '$ARGOCD_NAMESPACE' ..." kubectl create namespace "$ARGOCD_NAMESPACE" >/dev/null 2>&1 || true fi } render_manifest() { if [[ ! -f "$ARGOCD_MANIFEST_FILE" ]]; then echo "ERROR: ArgoCD manifest not found: $ARGOCD_MANIFEST_FILE" >&2 exit 1 fi knoe_render_manifest "$ARGOCD_MANIFEST_FILE" | sed "s|\\${ARGOCD_NAMESPACE}|$ARGOCD_NAMESPACE|g" } resolve_argocd_node_selector() { if [[ -n "$ARGOCD_NODE_SELECTOR" ]]; then printf '%s' "$ARGOCD_NODE_SELECTOR" return 0 fi local node="" node=$(kubectl get nodes -l 'node-role.kubernetes.io/control-plane' -o jsonpath='{.items[0].metadata.name}' 2>/dev/null || true) if [[ -n "$node" ]]; then printf 'kubernetes.io/hostname=%s' "$node" fi } apply_argocd_node_selector() { local selector selector="$(resolve_argocd_node_selector)" if [[ -z "$selector" ]]; then return 0 fi local key="${selector%%=*}" local val="${selector#*=}" if [[ -z "$key" || -z "$val" ]]; then echo "WARN: invalid ARGOCD_NODE_SELECTOR '$selector' (expected key=value); skipping." >&2 return 0 fi for target in \ deployment/argocd-applicationset-controller \ deployment/argocd-dex-server \ deployment/argocd-notifications-controller \ deployment/argocd-repo-server \ deployment/argocd-server \ deployment/argocd-redis \ statefulset/argocd-application-controller; do kubectl -n "$ARGOCD_NAMESPACE" patch "$target" \ --type merge \ -p "{\"spec\":{\"template\":{\"spec\":{\"nodeSelector\":{\"$key\":\"$val\"}}}}}" >/dev/null 2>&1 || true done } apply_argocd() { echo "Applying ArgoCD manifest to namespace '$ARGOCD_NAMESPACE' ..." render_manifest | kubectl apply --server-side --force-conflicts --field-manager=knoe-installer --validate=false -n "$ARGOCD_NAMESPACE" -f - apply_argocd_node_selector kubectl rollout status deploy/argocd-server -n "$ARGOCD_NAMESPACE" --timeout=${ROLLOUT_TIMEOUT:-300s} || true kubectl rollout status deploy/argocd-repo-server -n "$ARGOCD_NAMESPACE" --timeout=${ROLLOUT_TIMEOUT:-300s} || true kubectl rollout status deploy/argocd-dex-server -n "$ARGOCD_NAMESPACE" --timeout=${ROLLOUT_TIMEOUT:-300s} || true kubectl rollout status deploy/argocd-applicationset-controller -n "$ARGOCD_NAMESPACE" --timeout=${ROLLOUT_TIMEOUT:-300s} || true kubectl rollout status deploy/argocd-notifications-controller -n "$ARGOCD_NAMESPACE" --timeout=${ROLLOUT_TIMEOUT:-300s} || true kubectl rollout status deploy/argocd-redis -n "$ARGOCD_NAMESPACE" --timeout=${ROLLOUT_TIMEOUT:-300s} || true kubectl rollout status statefulset/argocd-application-controller -n "$ARGOCD_NAMESPACE" --timeout=${ROLLOUT_TIMEOUT:-300s} || true } apply_argocd_oidc_config() { local cm_file="$GKE_MANIFEST_DIR/argocd-oidc-cm.yaml" if [[ -z "$PLATFORM_DOMAIN" || -z "$FRONTDOOR_HOST" || -z "$BOOTSTRAP_ADMIN_EMAIL" ]]; then return 0 fi if [[ ! -f "$cm_file" ]]; then echo "WARN: ArgoCD OIDC config not found at $cm_file; skipping OIDC patch." >&2 return 0 fi echo "Applying ArgoCD OIDC config (issuer=https://${FRONTDOOR_HOST}/auth) ..." PLATFORM_DOMAIN="$PLATFORM_DOMAIN" \ FRONTDOOR_HOST="$FRONTDOOR_HOST" \ BOOTSTRAP_ADMIN_EMAIL="$BOOTSTRAP_ADMIN_EMAIL" \ envsubst < "$cm_file" \ | kubectl apply --server-side --force-conflicts \ --field-manager=knoe-installer -f - } rollout_restart_argocd() { kubectl -n "$ARGOCD_NAMESPACE" rollout restart deploy/argocd-server deploy/argocd-repo-server \ deploy/argocd-dex-server deploy/argocd-applicationset-controller deploy/argocd-notifications-controller \ deploy/argocd-redis >/dev/null 2>&1 || true kubectl -n "$ARGOCD_NAMESPACE" rollout restart statefulset/argocd-application-controller >/dev/null 2>&1 || true } delete_argocd() { echo "Removing ArgoCD resources from namespace '$ARGOCD_NAMESPACE' ..." render_manifest | kubectl delete -n "$ARGOCD_NAMESPACE" -f - --ignore-not-found } status_argocd() { kubectl -n "$ARGOCD_NAMESPACE" get deploy,statefulset,svc -l "$ARGOCD_LABEL_SELECTOR" 2>/dev/null || true kubectl -n "$ARGOCD_NAMESPACE" get pods -l "$ARGOCD_LABEL_SELECTOR" 2>/dev/null || true } case "$ACTION" in start|initialize|update|reload) ensure_tools ensure_namespace apply_argocd apply_argocd_oidc_config knoe_register_port_forward "argocd" "$ARGOCD_NAMESPACE" "svc/${ARGOCD_SERVER_SERVICE}" \ "$ARGOCD_PORT_FORWARD_LOCAL" "$ARGOCD_PORT_FORWARD_REMOTE" "0.0.0.0" "TCP" "ArgoCD" ;; restart) ensure_tools ensure_namespace apply_argocd rollout_restart_argocd apply_argocd_oidc_config knoe_register_port_forward "argocd" "$ARGOCD_NAMESPACE" "svc/${ARGOCD_SERVER_SERVICE}" \ "$ARGOCD_PORT_FORWARD_LOCAL" "$ARGOCD_PORT_FORWARD_REMOTE" "0.0.0.0" "TCP" "ArgoCD" ;; stop) ensure_tools delete_argocd ;; status) ensure_tools status_argocd ;; *) common_core_usage "$0" exit 1 ;; esac