fix(images): normalize shell scripts to LF line endings
CodeQL Advanced / Analyze (actions) (push) Canceled after 0s
CodeQL Advanced / Analyze (java-kotlin) (push) Canceled after 0s
CodeQL Advanced / Analyze (javascript-typescript) (push) Canceled after 0s
CodeQL Advanced / Analyze (python) (push) Canceled after 0s
Docker Image Build & Push / manifest (push) Canceled after 0s
Docker Image Build & Push / build-and-push-arm (push) Canceled after 0s
Docker Image Build & Push / build-and-push-amd (push) Canceled after 0s
Docker Image Build & Push / manifest (push) Canceled after 0s
Docker Image Build & Push / build-and-push-arm (push) Canceled after 0s
Docker Image Build & Push / build-and-push-amd (push) Canceled after 0s
Docker Image Build & Push / manifest (push) Canceled after 0s
Docker Image Build & Push / build-and-push-arm (push) Canceled after 0s
Docker Image Build & Push / build-and-push-amd (push) Canceled after 0s
Docker Image Build & Push / manifest (push) Canceled after 0s
Docker Image Build & Push / build-and-push-arm (push) Canceled after 0s
Docker Image Build & Push / build-and-push-amd (push) Canceled after 0s
Docker Image Build & Push / manifest (push) Canceled after 0s
Docker Image Build & Push / build-and-push-arm (push) Canceled after 0s
Docker Image Build & Push / build-and-push-amd (push) Canceled after 0s
Docker Image Build & Push / manifest (push) Canceled after 0s
Docker Image Build & Push / build-and-push-arm (push) Canceled after 0s
Docker Image Build & Push / build-and-push-amd (push) Canceled after 0s
Python Backend Docker Image CI / Build and Push Backend Python Docker Image (push) Canceled after 0s
Backend Docker Image CI / Build and Push Backend Docker Image (push) Canceled after 0s
Database Docker Image CI / Build and Push Database Docker Image (push) Canceled after 0s
Frontend Docker Image CI / Build and Push Frontend Docker Image (push) Canceled after 0s
Gateway Docker Image CI / Build and Push Gateway Docker Image (push) Canceled after 0s
Runtime Docker Image CI / Build and Push Runtime Docker Image (push) Canceled after 0s
CodeQL Advanced / Analyze (actions) (push) Canceled after 0s
CodeQL Advanced / Analyze (java-kotlin) (push) Canceled after 0s
CodeQL Advanced / Analyze (javascript-typescript) (push) Canceled after 0s
CodeQL Advanced / Analyze (python) (push) Canceled after 0s
Docker Image Build & Push / manifest (push) Canceled after 0s
Docker Image Build & Push / build-and-push-arm (push) Canceled after 0s
Docker Image Build & Push / build-and-push-amd (push) Canceled after 0s
Docker Image Build & Push / manifest (push) Canceled after 0s
Docker Image Build & Push / build-and-push-arm (push) Canceled after 0s
Docker Image Build & Push / build-and-push-amd (push) Canceled after 0s
Docker Image Build & Push / manifest (push) Canceled after 0s
Docker Image Build & Push / build-and-push-arm (push) Canceled after 0s
Docker Image Build & Push / build-and-push-amd (push) Canceled after 0s
Docker Image Build & Push / manifest (push) Canceled after 0s
Docker Image Build & Push / build-and-push-arm (push) Canceled after 0s
Docker Image Build & Push / build-and-push-amd (push) Canceled after 0s
Docker Image Build & Push / manifest (push) Canceled after 0s
Docker Image Build & Push / build-and-push-arm (push) Canceled after 0s
Docker Image Build & Push / build-and-push-amd (push) Canceled after 0s
Docker Image Build & Push / manifest (push) Canceled after 0s
Docker Image Build & Push / build-and-push-arm (push) Canceled after 0s
Docker Image Build & Push / build-and-push-amd (push) Canceled after 0s
Python Backend Docker Image CI / Build and Push Backend Python Docker Image (push) Canceled after 0s
Backend Docker Image CI / Build and Push Backend Docker Image (push) Canceled after 0s
Database Docker Image CI / Build and Push Database Docker Image (push) Canceled after 0s
Frontend Docker Image CI / Build and Push Frontend Docker Image (push) Canceled after 0s
Gateway Docker Image CI / Build and Push Gateway Docker Image (push) Canceled after 0s
Runtime Docker Image CI / Build and Push Runtime Docker Image (push) Canceled after 0s
database image crashed at start: CRLF shebang in start.sh made the kernel look for interpreter '/bin/bash\r'. Other image Dockerfiles mask this with dos2unix at build time, but scripts/images/database/Dockerfile does not. Convert all tracked .sh files to LF and pin eol=lf via .gitattributes.
This commit is contained in:
+248
-248
@@ -1,248 +1,248 @@
|
||||
#!/bin/bash
|
||||
### Collect secrets for DeepData installation.
|
||||
###
|
||||
### Usage:
|
||||
### scripts/k8s/collect-secrets.sh [--component deepdata|milvus] [--namespace <ns>]
|
||||
###
|
||||
### Modes (auto-detected):
|
||||
### 1. Sealed-secrets mode: controller running + kubeseal available → encrypt → apply SealedSecret
|
||||
### 2. Plain mode: no controller → Helm creates Secret with base64 (dev mode)
|
||||
###
|
||||
### Password priority: .env file values > interactive prompt > auto-generated
|
||||
###
|
||||
### Output: writes shell script variables to stdout (eval by caller)
|
||||
|
||||
# NOTE: NOT using 'set -e' because interactive prompts (read) can fail
|
||||
# when stdin is not a TTY. We validate critical values explicitly instead.
|
||||
|
||||
COMPONENT="${1:-deepdata}"
|
||||
NAMESPACE="${NAMESPACE:-deepdata}"
|
||||
ENV_FILE="${ENV_FILE:-.env}"
|
||||
|
||||
# Parse --component and --namespace from args if passed differently
|
||||
while [[ "$#" -gt 0 ]]; do
|
||||
case $1 in
|
||||
--component) COMPONENT="$2"; shift 2 ;;
|
||||
--namespace|-n) NAMESPACE="$2"; shift 2 ;;
|
||||
*) shift ;;
|
||||
esac
|
||||
done
|
||||
|
||||
TMP_DIR=$(mktemp -d)
|
||||
trap "rm -rf $TMP_DIR" EXIT
|
||||
|
||||
# ========== Detect Mode ==========
|
||||
detect_sealed_secrets() {
|
||||
kubectl get deployment -n "$NAMESPACE" sealed-secrets >/dev/null 2>&1 && return 0
|
||||
kubectl get deployment -n kube-system sealed-secrets >/dev/null 2>&1 && return 0
|
||||
kubectl get pod -n "$NAMESPACE" -l app.kubernetes.io/name=sealed-secrets --no-headers 2>/dev/null | grep -q Running && return 0
|
||||
return 1
|
||||
}
|
||||
|
||||
KUBESEAL="$(command -v kubeseal 2>/dev/null || echo "")"
|
||||
[ -z "$KUBESEAL" ] && KUBESEAL="$HOME/bin/kubeseal"
|
||||
[ ! -x "$KUBESEAL" ] && [ -x "./tools/bin/kubeseal" ] && KUBESEAL="./tools/bin/kubeseal"
|
||||
[ ! -x "$KUBESEAL" ] && [ -x "../tools/bin/kubeseal" ] && KUBESEAL="../tools/bin/kubeseal"
|
||||
|
||||
# Auto-download kubeseal if controller exists but binary is missing
|
||||
if detect_sealed_secrets && [ ! -x "$KUBESEAL" ]; then
|
||||
echo "[INFO] Sealed Secrets controller detected, but kubeseal not found. Downloading..." >&2
|
||||
KUBESEAL_URL="https://github.com/bitnami-labs/sealed-secrets/releases/download/v0.27.2/kubeseal-0.27.2-$(uname -s | tr '[:upper:]' '[:lower:]')-$(dpkg --print-architecture 2>/dev/null || uname -m | sed 's/x86_64/amd64/;s/aarch64/arm64/')"
|
||||
KUBESEAL_DIR="$HOME/bin"
|
||||
mkdir -p "$KUBESEAL_DIR"
|
||||
curl -sSL "$KUBESEAL_URL" -o "$KUBESEAL_DIR/kubeseal" && chmod +x "$KUBESEAL_DIR/kubeseal"
|
||||
KUBESEAL="$KUBESEAL_DIR/kubeseal"
|
||||
echo "[INFO] Installed kubeseal to $KUBESEAL" >&2
|
||||
fi
|
||||
|
||||
if detect_sealed_secrets && [ -x "$KUBESEAL" ]; then
|
||||
MODE="sealed"
|
||||
else
|
||||
MODE="plain"
|
||||
fi
|
||||
|
||||
echo "# DeepData secrets collection — component: $COMPONENT, mode: $MODE" >&2
|
||||
|
||||
# ========== Helper ==========
|
||||
random_hex() {
|
||||
openssl rand -hex 16 2>/dev/null || python3 -c "import secrets;print(secrets.token_hex(16))"
|
||||
}
|
||||
|
||||
seal_secret() {
|
||||
local name="$1" output="$2"
|
||||
shift 2
|
||||
local raw="${TMP_DIR}/${name}-raw.yaml"
|
||||
{
|
||||
echo "apiVersion: v1"
|
||||
echo "kind: Secret"
|
||||
echo "metadata:"
|
||||
echo " name: ${name}"
|
||||
echo " namespace: ${NAMESPACE}"
|
||||
echo "type: Opaque"
|
||||
echo "stringData:"
|
||||
for pair in "$@"; do
|
||||
key="${pair%%=*}"
|
||||
value="${pair#*=}"
|
||||
echo " ${key}: \"${value}\""
|
||||
done
|
||||
} > "$raw"
|
||||
"$KUBESEAL" --controller-name=sealed-secrets --namespace="${NAMESPACE}" -o yaml -f "$raw" > "$output"
|
||||
echo "[INFO] Created SealedSecret: $output" >&2
|
||||
}
|
||||
|
||||
# ========== Load .env (targeted: only reads known secret keys) ==========
|
||||
if [ -f "$ENV_FILE" ]; then
|
||||
echo "[INFO] Loading secrets from ${ENV_FILE}..." >&2
|
||||
|
||||
# Read .env line by line, only extract vars matching our known keys.
|
||||
# Ignores comments, blank lines, and unrelated vars like pgsql_host/shell vars.
|
||||
while IFS='=' read -r key value; do
|
||||
# Skip blank lines and comments
|
||||
[ -z "$key" ] && continue
|
||||
case "$key" in
|
||||
\#*) continue ;;
|
||||
esac
|
||||
# Strip leading/trailing whitespace from key
|
||||
key="$(echo "$key" | xargs)"
|
||||
|
||||
case "$key" in
|
||||
DB_PASSWORD|CERT_PASS|DOMAIN|HOME_PAGE_URL|JWT_SECRET|\
|
||||
LABEL_STUDIO_PASSWORD|LABEL_STUDIO_USER_TOKEN|POSTGRE_PASSWORD|\
|
||||
MINIO_ACCESS_KEY|MINIO_SECRET_KEY)
|
||||
val="$value"
|
||||
case "$val" in
|
||||
\'*|\"*) val="${val:1}" ;;
|
||||
esac
|
||||
case "$val" in
|
||||
*\'|*\") val="${val:0:-1}" ;;
|
||||
esac
|
||||
printf -v "$key" '%s' "$val"
|
||||
;;
|
||||
esac
|
||||
done < "$ENV_FILE"
|
||||
|
||||
[ -n "$DB_PASSWORD" ] && echo "[INFO] Loaded DB_PASSWORD from $ENV_FILE" >&2
|
||||
[ -n "$CERT_PASS" ] && echo "[INFO] Loaded CERT_PASS from $ENV_FILE" >&2
|
||||
[ -n "$JWT_SECRET" ] && echo "[INFO] Loaded JWT_SECRET from $ENV_FILE" >&2
|
||||
else
|
||||
echo "[WARN] No .env file found at $(pwd)/${ENV_FILE} — will prompt for secrets" >&2
|
||||
fi
|
||||
|
||||
# ========== DeepData ==========
|
||||
if [ "$COMPONENT" = "deepdata" ]; then
|
||||
# Collect
|
||||
[ -z "$DB_PASSWORD" ] && read -rsp "Enter DB_PASSWORD: " DB_PASSWORD && echo "" >&2
|
||||
[ -z "$JWT_SECRET" ] && JWT_SECRET=$(openssl rand -hex 32 2>/dev/null || python3 -c "import secrets;print(secrets.token_hex(32))") && echo "[INFO] Auto-generated JWT_SECRET" >&2
|
||||
[ -z "$DOMAIN" ] && read -rp "Enter DOMAIN (enter to skip): " DOMAIN >&2
|
||||
[ -z "$CERT_PASS" ] && read -rsp "Enter CERT_PASS (enter to skip): " CERT_PASS && echo "" >&2
|
||||
HOME_PAGE_URL="${HOME_PAGE_URL:-/data/management}"
|
||||
[ -z "$LABEL_STUDIO_PASSWORD" ] && read -rsp "Enter LABEL_STUDIO_PASSWORD (enter to skip): " LABEL_STUDIO_PASSWORD && echo "" >&2
|
||||
[ -z "$LABEL_STUDIO_USER_TOKEN" ] && LABEL_STUDIO_USER_TOKEN=$(random_hex)$(random_hex) && echo "[INFO] Auto-generated LABEL_STUDIO_USER_TOKEN" >&2
|
||||
|
||||
# ===== MANDATORY CHECK: DB_PASSWORD must not be empty =====
|
||||
if [ -z "$DB_PASSWORD" ]; then
|
||||
echo "[FATAL] DB_PASSWORD is empty! Cannot install without a database password." >&2
|
||||
echo "[FATAL] Set DB_PASSWORD in .env or ensure interactive prompts work." >&2
|
||||
echo "SECRETS_CREATE=SKIP"
|
||||
echo "HELM_VALUES_FILE="
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [ "$MODE" = "sealed" ]; then
|
||||
# Clean up any old stale Secret (prevents Helm conflict)
|
||||
if kubectl get secret deepdata-conf -n "$NAMESPACE" >/dev/null 2>&1; then
|
||||
echo "[INFO] Removing old deepdata-conf Secret..." >&2
|
||||
kubectl delete secret deepdata-conf -n "$NAMESPACE" --ignore-not-found >/dev/null 2>&1
|
||||
fi
|
||||
# Clean up old SealedSecret (apply is idempotent, but belt-and-suspenders)
|
||||
kubectl delete sealedsecret deepdata-conf -n "$NAMESPACE" --ignore-not-found >/dev/null 2>&1 || true
|
||||
|
||||
# DeepData-conf
|
||||
seal_secret "deepdata-conf" "${TMP_DIR}/deepdata-sealed.yaml" \
|
||||
"DB_PASSWORD=${DB_PASSWORD}" \
|
||||
"CERT_PASS=${CERT_PASS}" \
|
||||
"DOMAIN=${DOMAIN}" \
|
||||
"HOME_PAGE_URL=${HOME_PAGE_URL}" \
|
||||
"JWT_SECRET=${JWT_SECRET}" \
|
||||
"LABEL_STUDIO_PASSWORD=${LABEL_STUDIO_PASSWORD}" \
|
||||
"LABEL_STUDIO_USER_TOKEN=${LABEL_STUDIO_USER_TOKEN}"
|
||||
kubectl apply -f "${TMP_DIR}/deepdata-sealed.yaml" -n "$NAMESPACE" >/dev/null
|
||||
# Add Helm ownership labels so 'helm install --force' accepts the Secret
|
||||
kubectl wait --for=jsonpath='{.data.DB_PASSWORD}' --timeout=30s secret/deepdata-conf -n "$NAMESPACE" >/dev/null 2>&1 || true
|
||||
kubectl annotate secret deepdata-conf -n "$NAMESPACE" \
|
||||
meta.helm.sh/release-name=deepdata \
|
||||
meta.helm.sh/release-namespace="${NAMESPACE}" \
|
||||
--overwrite >/dev/null 2>&1
|
||||
kubectl label secret deepdata-conf -n "$NAMESPACE" \
|
||||
app.kubernetes.io/managed-by=Helm \
|
||||
--overwrite >/dev/null 2>&1
|
||||
|
||||
# Label Studio
|
||||
if [ -n "$LABEL_STUDIO_PASSWORD" ]; then
|
||||
POSTGRE_PASSWORD="${POSTGRE_PASSWORD:-$DB_PASSWORD}"
|
||||
seal_secret "label-studio-env" "${TMP_DIR}/label-studio-sealed.yaml" \
|
||||
"POSTGRE_PASSWORD=${POSTGRE_PASSWORD}" \
|
||||
"LABEL_STUDIO_PASSWORD=${LABEL_STUDIO_PASSWORD}" \
|
||||
"LABEL_STUDIO_USER_TOKEN=${LABEL_STUDIO_USER_TOKEN}"
|
||||
kubectl apply -f "${TMP_DIR}/label-studio-sealed.yaml" -n "$NAMESPACE" >/dev/null
|
||||
fi
|
||||
|
||||
echo "SECRETS_CREATE=false"
|
||||
echo "HELM_VALUES_FILE="
|
||||
else
|
||||
# Plain — delete any old SealedSecret and stale Secret first
|
||||
kubectl delete sealedsecret deepdata-conf -n "$NAMESPACE" --ignore-not-found >/dev/null 2>&1 || true
|
||||
if kubectl get secret deepdata-conf -n "$NAMESPACE" >/dev/null 2>&1; then
|
||||
echo "[INFO] Removing old deepdata-conf Secret..." >&2
|
||||
kubectl delete secret deepdata-conf -n "$NAMESPACE" --ignore-not-found >/dev/null 2>&1
|
||||
fi
|
||||
|
||||
# Write extra values to /tmp (survives script exit for Helm to read)
|
||||
values_file="/tmp/deepdata-secret-values-$$.yaml"
|
||||
cat > "$values_file" <<VALUES_EOF
|
||||
public:
|
||||
secrets:
|
||||
data:
|
||||
DB_PASSWORD: "${DB_PASSWORD}"
|
||||
JWT_SECRET: "${JWT_SECRET}"
|
||||
CERT_PASS: "${CERT_PASS}"
|
||||
DOMAIN: "${DOMAIN}"
|
||||
HOME_PAGE_URL: "${HOME_PAGE_URL}"
|
||||
LABEL_STUDIO_PASSWORD: "${LABEL_STUDIO_PASSWORD}"
|
||||
LABEL_STUDIO_USER_TOKEN: "${LABEL_STUDIO_USER_TOKEN}"
|
||||
VALUES_EOF
|
||||
|
||||
echo "[INFO] Wrote plain secret values to ${values_file}" >&2
|
||||
echo "SECRETS_CREATE=true"
|
||||
echo "HELM_VALUES_FILE=${values_file}"
|
||||
fi
|
||||
|
||||
# ========== Milvus ==========
|
||||
elif [ "$COMPONENT" = "milvus" ]; then
|
||||
# Only needed if secret doesn't already exist
|
||||
if kubectl get secret milvus-minio-secret -n "$NAMESPACE" >/dev/null 2>&1; then
|
||||
echo "# milvus-minio-secret already exists — skipping" >&2
|
||||
exit 0
|
||||
fi
|
||||
|
||||
[ -z "$MINIO_ACCESS_KEY" ] && MINIO_ACCESS_KEY=$(random_hex) && echo "[INFO] Auto-generated MINIO_ACCESS_KEY" >&2
|
||||
[ -z "$MINIO_SECRET_KEY" ] && MINIO_SECRET_KEY=$(random_hex)$(random_hex) && echo "[INFO] Auto-generated MINIO_SECRET_KEY" >&2
|
||||
|
||||
if [ "$MODE" = "sealed" ]; then
|
||||
seal_secret "milvus-minio-secret" "${TMP_DIR}/milvus-sealed.yaml" \
|
||||
"accesskey=${MINIO_ACCESS_KEY}" \
|
||||
"secretkey=${MINIO_SECRET_KEY}"
|
||||
kubectl apply -f "${TMP_DIR}/milvus-sealed.yaml" -n "$NAMESPACE" >/dev/null
|
||||
kubectl wait --for=jsonpath='{.data.accesskey}' --timeout=30s secret/milvus-minio-secret -n "$NAMESPACE" >/dev/null 2>&1 || true
|
||||
kubectl annotate secret milvus-minio-secret -n "$NAMESPACE" \
|
||||
meta.helm.sh/release-name=milvus-minio \
|
||||
meta.helm.sh/release-namespace="${NAMESPACE}" \
|
||||
--overwrite >/dev/null 2>&1
|
||||
else
|
||||
kubectl create secret generic milvus-minio-secret \
|
||||
--from-literal=accesskey="$MINIO_ACCESS_KEY" \
|
||||
--from-literal=secretkey="$MINIO_SECRET_KEY" \
|
||||
-n "$NAMESPACE" --dry-run=client -o yaml | kubectl apply -f - >/dev/null
|
||||
echo "[INFO] Created milvus-minio-secret (plain)" >&2
|
||||
fi
|
||||
fi
|
||||
#!/bin/bash
|
||||
### Collect secrets for DeepData installation.
|
||||
###
|
||||
### Usage:
|
||||
### scripts/k8s/collect-secrets.sh [--component deepdata|milvus] [--namespace <ns>]
|
||||
###
|
||||
### Modes (auto-detected):
|
||||
### 1. Sealed-secrets mode: controller running + kubeseal available → encrypt → apply SealedSecret
|
||||
### 2. Plain mode: no controller → Helm creates Secret with base64 (dev mode)
|
||||
###
|
||||
### Password priority: .env file values > interactive prompt > auto-generated
|
||||
###
|
||||
### Output: writes shell script variables to stdout (eval by caller)
|
||||
|
||||
# NOTE: NOT using 'set -e' because interactive prompts (read) can fail
|
||||
# when stdin is not a TTY. We validate critical values explicitly instead.
|
||||
|
||||
COMPONENT="${1:-deepdata}"
|
||||
NAMESPACE="${NAMESPACE:-deepdata}"
|
||||
ENV_FILE="${ENV_FILE:-.env}"
|
||||
|
||||
# Parse --component and --namespace from args if passed differently
|
||||
while [[ "$#" -gt 0 ]]; do
|
||||
case $1 in
|
||||
--component) COMPONENT="$2"; shift 2 ;;
|
||||
--namespace|-n) NAMESPACE="$2"; shift 2 ;;
|
||||
*) shift ;;
|
||||
esac
|
||||
done
|
||||
|
||||
TMP_DIR=$(mktemp -d)
|
||||
trap "rm -rf $TMP_DIR" EXIT
|
||||
|
||||
# ========== Detect Mode ==========
|
||||
detect_sealed_secrets() {
|
||||
kubectl get deployment -n "$NAMESPACE" sealed-secrets >/dev/null 2>&1 && return 0
|
||||
kubectl get deployment -n kube-system sealed-secrets >/dev/null 2>&1 && return 0
|
||||
kubectl get pod -n "$NAMESPACE" -l app.kubernetes.io/name=sealed-secrets --no-headers 2>/dev/null | grep -q Running && return 0
|
||||
return 1
|
||||
}
|
||||
|
||||
KUBESEAL="$(command -v kubeseal 2>/dev/null || echo "")"
|
||||
[ -z "$KUBESEAL" ] && KUBESEAL="$HOME/bin/kubeseal"
|
||||
[ ! -x "$KUBESEAL" ] && [ -x "./tools/bin/kubeseal" ] && KUBESEAL="./tools/bin/kubeseal"
|
||||
[ ! -x "$KUBESEAL" ] && [ -x "../tools/bin/kubeseal" ] && KUBESEAL="../tools/bin/kubeseal"
|
||||
|
||||
# Auto-download kubeseal if controller exists but binary is missing
|
||||
if detect_sealed_secrets && [ ! -x "$KUBESEAL" ]; then
|
||||
echo "[INFO] Sealed Secrets controller detected, but kubeseal not found. Downloading..." >&2
|
||||
KUBESEAL_URL="https://github.com/bitnami-labs/sealed-secrets/releases/download/v0.27.2/kubeseal-0.27.2-$(uname -s | tr '[:upper:]' '[:lower:]')-$(dpkg --print-architecture 2>/dev/null || uname -m | sed 's/x86_64/amd64/;s/aarch64/arm64/')"
|
||||
KUBESEAL_DIR="$HOME/bin"
|
||||
mkdir -p "$KUBESEAL_DIR"
|
||||
curl -sSL "$KUBESEAL_URL" -o "$KUBESEAL_DIR/kubeseal" && chmod +x "$KUBESEAL_DIR/kubeseal"
|
||||
KUBESEAL="$KUBESEAL_DIR/kubeseal"
|
||||
echo "[INFO] Installed kubeseal to $KUBESEAL" >&2
|
||||
fi
|
||||
|
||||
if detect_sealed_secrets && [ -x "$KUBESEAL" ]; then
|
||||
MODE="sealed"
|
||||
else
|
||||
MODE="plain"
|
||||
fi
|
||||
|
||||
echo "# DeepData secrets collection — component: $COMPONENT, mode: $MODE" >&2
|
||||
|
||||
# ========== Helper ==========
|
||||
random_hex() {
|
||||
openssl rand -hex 16 2>/dev/null || python3 -c "import secrets;print(secrets.token_hex(16))"
|
||||
}
|
||||
|
||||
seal_secret() {
|
||||
local name="$1" output="$2"
|
||||
shift 2
|
||||
local raw="${TMP_DIR}/${name}-raw.yaml"
|
||||
{
|
||||
echo "apiVersion: v1"
|
||||
echo "kind: Secret"
|
||||
echo "metadata:"
|
||||
echo " name: ${name}"
|
||||
echo " namespace: ${NAMESPACE}"
|
||||
echo "type: Opaque"
|
||||
echo "stringData:"
|
||||
for pair in "$@"; do
|
||||
key="${pair%%=*}"
|
||||
value="${pair#*=}"
|
||||
echo " ${key}: \"${value}\""
|
||||
done
|
||||
} > "$raw"
|
||||
"$KUBESEAL" --controller-name=sealed-secrets --namespace="${NAMESPACE}" -o yaml -f "$raw" > "$output"
|
||||
echo "[INFO] Created SealedSecret: $output" >&2
|
||||
}
|
||||
|
||||
# ========== Load .env (targeted: only reads known secret keys) ==========
|
||||
if [ -f "$ENV_FILE" ]; then
|
||||
echo "[INFO] Loading secrets from ${ENV_FILE}..." >&2
|
||||
|
||||
# Read .env line by line, only extract vars matching our known keys.
|
||||
# Ignores comments, blank lines, and unrelated vars like pgsql_host/shell vars.
|
||||
while IFS='=' read -r key value; do
|
||||
# Skip blank lines and comments
|
||||
[ -z "$key" ] && continue
|
||||
case "$key" in
|
||||
\#*) continue ;;
|
||||
esac
|
||||
# Strip leading/trailing whitespace from key
|
||||
key="$(echo "$key" | xargs)"
|
||||
|
||||
case "$key" in
|
||||
DB_PASSWORD|CERT_PASS|DOMAIN|HOME_PAGE_URL|JWT_SECRET|\
|
||||
LABEL_STUDIO_PASSWORD|LABEL_STUDIO_USER_TOKEN|POSTGRE_PASSWORD|\
|
||||
MINIO_ACCESS_KEY|MINIO_SECRET_KEY)
|
||||
val="$value"
|
||||
case "$val" in
|
||||
\'*|\"*) val="${val:1}" ;;
|
||||
esac
|
||||
case "$val" in
|
||||
*\'|*\") val="${val:0:-1}" ;;
|
||||
esac
|
||||
printf -v "$key" '%s' "$val"
|
||||
;;
|
||||
esac
|
||||
done < "$ENV_FILE"
|
||||
|
||||
[ -n "$DB_PASSWORD" ] && echo "[INFO] Loaded DB_PASSWORD from $ENV_FILE" >&2
|
||||
[ -n "$CERT_PASS" ] && echo "[INFO] Loaded CERT_PASS from $ENV_FILE" >&2
|
||||
[ -n "$JWT_SECRET" ] && echo "[INFO] Loaded JWT_SECRET from $ENV_FILE" >&2
|
||||
else
|
||||
echo "[WARN] No .env file found at $(pwd)/${ENV_FILE} — will prompt for secrets" >&2
|
||||
fi
|
||||
|
||||
# ========== DeepData ==========
|
||||
if [ "$COMPONENT" = "deepdata" ]; then
|
||||
# Collect
|
||||
[ -z "$DB_PASSWORD" ] && read -rsp "Enter DB_PASSWORD: " DB_PASSWORD && echo "" >&2
|
||||
[ -z "$JWT_SECRET" ] && JWT_SECRET=$(openssl rand -hex 32 2>/dev/null || python3 -c "import secrets;print(secrets.token_hex(32))") && echo "[INFO] Auto-generated JWT_SECRET" >&2
|
||||
[ -z "$DOMAIN" ] && read -rp "Enter DOMAIN (enter to skip): " DOMAIN >&2
|
||||
[ -z "$CERT_PASS" ] && read -rsp "Enter CERT_PASS (enter to skip): " CERT_PASS && echo "" >&2
|
||||
HOME_PAGE_URL="${HOME_PAGE_URL:-/data/management}"
|
||||
[ -z "$LABEL_STUDIO_PASSWORD" ] && read -rsp "Enter LABEL_STUDIO_PASSWORD (enter to skip): " LABEL_STUDIO_PASSWORD && echo "" >&2
|
||||
[ -z "$LABEL_STUDIO_USER_TOKEN" ] && LABEL_STUDIO_USER_TOKEN=$(random_hex)$(random_hex) && echo "[INFO] Auto-generated LABEL_STUDIO_USER_TOKEN" >&2
|
||||
|
||||
# ===== MANDATORY CHECK: DB_PASSWORD must not be empty =====
|
||||
if [ -z "$DB_PASSWORD" ]; then
|
||||
echo "[FATAL] DB_PASSWORD is empty! Cannot install without a database password." >&2
|
||||
echo "[FATAL] Set DB_PASSWORD in .env or ensure interactive prompts work." >&2
|
||||
echo "SECRETS_CREATE=SKIP"
|
||||
echo "HELM_VALUES_FILE="
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [ "$MODE" = "sealed" ]; then
|
||||
# Clean up any old stale Secret (prevents Helm conflict)
|
||||
if kubectl get secret deepdata-conf -n "$NAMESPACE" >/dev/null 2>&1; then
|
||||
echo "[INFO] Removing old deepdata-conf Secret..." >&2
|
||||
kubectl delete secret deepdata-conf -n "$NAMESPACE" --ignore-not-found >/dev/null 2>&1
|
||||
fi
|
||||
# Clean up old SealedSecret (apply is idempotent, but belt-and-suspenders)
|
||||
kubectl delete sealedsecret deepdata-conf -n "$NAMESPACE" --ignore-not-found >/dev/null 2>&1 || true
|
||||
|
||||
# DeepData-conf
|
||||
seal_secret "deepdata-conf" "${TMP_DIR}/deepdata-sealed.yaml" \
|
||||
"DB_PASSWORD=${DB_PASSWORD}" \
|
||||
"CERT_PASS=${CERT_PASS}" \
|
||||
"DOMAIN=${DOMAIN}" \
|
||||
"HOME_PAGE_URL=${HOME_PAGE_URL}" \
|
||||
"JWT_SECRET=${JWT_SECRET}" \
|
||||
"LABEL_STUDIO_PASSWORD=${LABEL_STUDIO_PASSWORD}" \
|
||||
"LABEL_STUDIO_USER_TOKEN=${LABEL_STUDIO_USER_TOKEN}"
|
||||
kubectl apply -f "${TMP_DIR}/deepdata-sealed.yaml" -n "$NAMESPACE" >/dev/null
|
||||
# Add Helm ownership labels so 'helm install --force' accepts the Secret
|
||||
kubectl wait --for=jsonpath='{.data.DB_PASSWORD}' --timeout=30s secret/deepdata-conf -n "$NAMESPACE" >/dev/null 2>&1 || true
|
||||
kubectl annotate secret deepdata-conf -n "$NAMESPACE" \
|
||||
meta.helm.sh/release-name=deepdata \
|
||||
meta.helm.sh/release-namespace="${NAMESPACE}" \
|
||||
--overwrite >/dev/null 2>&1
|
||||
kubectl label secret deepdata-conf -n "$NAMESPACE" \
|
||||
app.kubernetes.io/managed-by=Helm \
|
||||
--overwrite >/dev/null 2>&1
|
||||
|
||||
# Label Studio
|
||||
if [ -n "$LABEL_STUDIO_PASSWORD" ]; then
|
||||
POSTGRE_PASSWORD="${POSTGRE_PASSWORD:-$DB_PASSWORD}"
|
||||
seal_secret "label-studio-env" "${TMP_DIR}/label-studio-sealed.yaml" \
|
||||
"POSTGRE_PASSWORD=${POSTGRE_PASSWORD}" \
|
||||
"LABEL_STUDIO_PASSWORD=${LABEL_STUDIO_PASSWORD}" \
|
||||
"LABEL_STUDIO_USER_TOKEN=${LABEL_STUDIO_USER_TOKEN}"
|
||||
kubectl apply -f "${TMP_DIR}/label-studio-sealed.yaml" -n "$NAMESPACE" >/dev/null
|
||||
fi
|
||||
|
||||
echo "SECRETS_CREATE=false"
|
||||
echo "HELM_VALUES_FILE="
|
||||
else
|
||||
# Plain — delete any old SealedSecret and stale Secret first
|
||||
kubectl delete sealedsecret deepdata-conf -n "$NAMESPACE" --ignore-not-found >/dev/null 2>&1 || true
|
||||
if kubectl get secret deepdata-conf -n "$NAMESPACE" >/dev/null 2>&1; then
|
||||
echo "[INFO] Removing old deepdata-conf Secret..." >&2
|
||||
kubectl delete secret deepdata-conf -n "$NAMESPACE" --ignore-not-found >/dev/null 2>&1
|
||||
fi
|
||||
|
||||
# Write extra values to /tmp (survives script exit for Helm to read)
|
||||
values_file="/tmp/deepdata-secret-values-$$.yaml"
|
||||
cat > "$values_file" <<VALUES_EOF
|
||||
public:
|
||||
secrets:
|
||||
data:
|
||||
DB_PASSWORD: "${DB_PASSWORD}"
|
||||
JWT_SECRET: "${JWT_SECRET}"
|
||||
CERT_PASS: "${CERT_PASS}"
|
||||
DOMAIN: "${DOMAIN}"
|
||||
HOME_PAGE_URL: "${HOME_PAGE_URL}"
|
||||
LABEL_STUDIO_PASSWORD: "${LABEL_STUDIO_PASSWORD}"
|
||||
LABEL_STUDIO_USER_TOKEN: "${LABEL_STUDIO_USER_TOKEN}"
|
||||
VALUES_EOF
|
||||
|
||||
echo "[INFO] Wrote plain secret values to ${values_file}" >&2
|
||||
echo "SECRETS_CREATE=true"
|
||||
echo "HELM_VALUES_FILE=${values_file}"
|
||||
fi
|
||||
|
||||
# ========== Milvus ==========
|
||||
elif [ "$COMPONENT" = "milvus" ]; then
|
||||
# Only needed if secret doesn't already exist
|
||||
if kubectl get secret milvus-minio-secret -n "$NAMESPACE" >/dev/null 2>&1; then
|
||||
echo "# milvus-minio-secret already exists — skipping" >&2
|
||||
exit 0
|
||||
fi
|
||||
|
||||
[ -z "$MINIO_ACCESS_KEY" ] && MINIO_ACCESS_KEY=$(random_hex) && echo "[INFO] Auto-generated MINIO_ACCESS_KEY" >&2
|
||||
[ -z "$MINIO_SECRET_KEY" ] && MINIO_SECRET_KEY=$(random_hex)$(random_hex) && echo "[INFO] Auto-generated MINIO_SECRET_KEY" >&2
|
||||
|
||||
if [ "$MODE" = "sealed" ]; then
|
||||
seal_secret "milvus-minio-secret" "${TMP_DIR}/milvus-sealed.yaml" \
|
||||
"accesskey=${MINIO_ACCESS_KEY}" \
|
||||
"secretkey=${MINIO_SECRET_KEY}"
|
||||
kubectl apply -f "${TMP_DIR}/milvus-sealed.yaml" -n "$NAMESPACE" >/dev/null
|
||||
kubectl wait --for=jsonpath='{.data.accesskey}' --timeout=30s secret/milvus-minio-secret -n "$NAMESPACE" >/dev/null 2>&1 || true
|
||||
kubectl annotate secret milvus-minio-secret -n "$NAMESPACE" \
|
||||
meta.helm.sh/release-name=milvus-minio \
|
||||
meta.helm.sh/release-namespace="${NAMESPACE}" \
|
||||
--overwrite >/dev/null 2>&1
|
||||
else
|
||||
kubectl create secret generic milvus-minio-secret \
|
||||
--from-literal=accesskey="$MINIO_ACCESS_KEY" \
|
||||
--from-literal=secretkey="$MINIO_SECRET_KEY" \
|
||||
-n "$NAMESPACE" --dry-run=client -o yaml | kubectl apply -f - >/dev/null
|
||||
echo "[INFO] Created milvus-minio-secret (plain)" >&2
|
||||
fi
|
||||
fi
|
||||
|
||||
+167
-167
@@ -1,167 +1,167 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# DeepData Node Cleanup Script
|
||||
# Remove labels and taints from nodes that were configured for DeepData deployment
|
||||
#
|
||||
# Usage: ./node-cleanup.sh [--dry-run] [--nodes NODE1,NODE2]
|
||||
#
|
||||
|
||||
set -e
|
||||
|
||||
# Colors for output
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
BLUE='\033[0;34m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
# Default values
|
||||
DRY_RUN=false
|
||||
NAMESPACE="deepdata"
|
||||
LABEL_KEY="node-role.kubernetes.io/deepdata"
|
||||
LABEL_VALUE="true"
|
||||
TAINT_EFFECT="NoSchedule"
|
||||
|
||||
# Parse arguments
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case $1 in
|
||||
--namespace)
|
||||
NAMESPACE="$2"
|
||||
shift 2
|
||||
;;
|
||||
--dry-run)
|
||||
DRY_RUN=true
|
||||
shift
|
||||
;;
|
||||
--nodes)
|
||||
PROVIDED_NODES="$2"
|
||||
shift 2
|
||||
;;
|
||||
--label-key)
|
||||
LABEL_KEY="$2"
|
||||
shift 2
|
||||
;;
|
||||
*)
|
||||
echo "Unknown option: $1"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
echo -e "${BLUE}=====================================${NC}"
|
||||
echo -e "${BLUE} DeepData Node Cleanup${NC}"
|
||||
echo -e "${BLUE}=====================================${NC}"
|
||||
echo ""
|
||||
|
||||
# Check if kubectl is available
|
||||
if ! command -v kubectl &> /dev/null; then
|
||||
echo -e "${RED}Error: kubectl is not installed${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check if connected to cluster
|
||||
if ! kubectl cluster-info &> /dev/null; then
|
||||
echo -e "${RED}Error: Cannot connect to Kubernetes cluster${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Determine nodes to clean up
|
||||
if [ "$PROVIDED_NODES" != "" ]; then
|
||||
# Use provided nodes
|
||||
IFS=',' read -ra SELECTED_NODES <<< "$PROVIDED_NODES"
|
||||
else
|
||||
# Find nodes with the deepdata label directly from Kubernetes
|
||||
echo -e "${YELLOW}Finding nodes with $LABEL_KEY=$LABEL_VALUE label...${NC}"
|
||||
NODES=$(kubectl get nodes -l "$LABEL_KEY=$LABEL_VALUE" -o jsonpath='{range .items[*]}{.metadata.name}{"\n"}{end}')
|
||||
|
||||
if [ -z "$NODES" ]; then
|
||||
echo -e "${GREEN}No nodes found with $LABEL_KEY=$LABEL_VALUE label.${NC}"
|
||||
echo -e "${YELLOW}Cleanup not needed - no nodes were labeled.${NC}"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
SELECTED_NODES=()
|
||||
while IFS= read -r NODE; do
|
||||
if [ -n "$NODE" ]; then
|
||||
SELECTED_NODES+=("$NODE")
|
||||
fi
|
||||
done <<< "$NODES"
|
||||
fi
|
||||
|
||||
if [ ${#SELECTED_NODES[@]} -eq 0 ]; then
|
||||
echo -e "${YELLOW}No nodes to clean up.${NC}"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo -e "${GREEN}Nodes to clean up:${NC}"
|
||||
for NODE in "${SELECTED_NODES[@]}"; do
|
||||
echo " - $NODE"
|
||||
done
|
||||
|
||||
echo ""
|
||||
echo -e "${BLUE}Summary:${NC}"
|
||||
echo " Label to remove: $LABEL_KEY"
|
||||
|
||||
# Check if any node has the taint
|
||||
HAS_TAINTS=false
|
||||
for NODE in "${SELECTED_NODES[@]}"; do
|
||||
TAINT_COUNT=$(kubectl get node "$NODE" -o jsonpath='{range .spec.taints[*]}{.key}{"\n"}{end}' | grep -c "^${LABEL_KEY}$" || echo "0")
|
||||
if [ "$TAINT_COUNT" -gt 0 ]; then
|
||||
HAS_TAINTS=true
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
if [ "$HAS_TAINTS" = true ]; then
|
||||
echo " Taint to remove: $LABEL_KEY=$LABEL_VALUE:$TAINT_EFFECT"
|
||||
fi
|
||||
echo ""
|
||||
|
||||
read -p "Remove labels and taints? (y/n) [y]: " CONFIRM
|
||||
CONFIRM=${CONFIRM:-y}
|
||||
|
||||
if [ "$CONFIRM" != "y" ] && [ "$CONFIRM" != "Y" ]; then
|
||||
echo -e "${YELLOW}Cancelled.${NC}"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo -e "${GREEN}Removing configuration...${NC}"
|
||||
|
||||
# Remove labels from selected nodes
|
||||
for NODE in "${SELECTED_NODES[@]}"; do
|
||||
if [ "$DRY_RUN" = true ]; then
|
||||
echo "[DRY-RUN] kubectl label node $NODE $LABEL_KEY-"
|
||||
else
|
||||
kubectl label node "$NODE" "$LABEL_KEY-" --overwrite
|
||||
echo -e " ${GREEN}✓${NC} Removed label from $NODE"
|
||||
fi
|
||||
done
|
||||
|
||||
# Remove taints (check if node has the taint)
|
||||
for NODE in "${SELECTED_NODES[@]}"; do
|
||||
# Check if node has the taint
|
||||
HAS_TAINT=$(kubectl get node "$NODE" -o jsonpath='{range .spec.taints[*]}{.key}{"\n"}{end}' | grep -c "^${LABEL_KEY}$" || echo "0")
|
||||
|
||||
if [ "$HAS_TAINT" -gt 0 ]; then
|
||||
if [ "$DRY_RUN" = true ]; then
|
||||
echo "[DRY-RUN] kubectl taint node $NODE $LABEL_KEY=$LABEL_VALUE:$TAINT_EFFECT-"
|
||||
else
|
||||
kubectl taint node "$NODE" "$LABEL_KEY=$LABEL_VALUE:$TAINT_EFFECT-" --overwrite || true
|
||||
echo -e " ${GREEN}✓${NC} Removed taint from $NODE"
|
||||
fi
|
||||
else
|
||||
echo -e " ${YELLOW}○${NC} No taint to remove from $NODE"
|
||||
fi
|
||||
done
|
||||
|
||||
echo ""
|
||||
echo -e "${GREEN}Cleanup complete!${NC}"
|
||||
|
||||
# Clean up Helm args temp file if it exists
|
||||
if [ -f /tmp/deepdata-helm-args.sh ]; then
|
||||
rm /tmp/deepdata-helm-args.sh
|
||||
echo -e "${GREEN}Removed /tmp/deepdata-helm-args.sh${NC}"
|
||||
fi
|
||||
|
||||
exit 0
|
||||
#!/bin/bash
|
||||
#
|
||||
# DeepData Node Cleanup Script
|
||||
# Remove labels and taints from nodes that were configured for DeepData deployment
|
||||
#
|
||||
# Usage: ./node-cleanup.sh [--dry-run] [--nodes NODE1,NODE2]
|
||||
#
|
||||
|
||||
set -e
|
||||
|
||||
# Colors for output
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
BLUE='\033[0;34m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
# Default values
|
||||
DRY_RUN=false
|
||||
NAMESPACE="deepdata"
|
||||
LABEL_KEY="node-role.kubernetes.io/deepdata"
|
||||
LABEL_VALUE="true"
|
||||
TAINT_EFFECT="NoSchedule"
|
||||
|
||||
# Parse arguments
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case $1 in
|
||||
--namespace)
|
||||
NAMESPACE="$2"
|
||||
shift 2
|
||||
;;
|
||||
--dry-run)
|
||||
DRY_RUN=true
|
||||
shift
|
||||
;;
|
||||
--nodes)
|
||||
PROVIDED_NODES="$2"
|
||||
shift 2
|
||||
;;
|
||||
--label-key)
|
||||
LABEL_KEY="$2"
|
||||
shift 2
|
||||
;;
|
||||
*)
|
||||
echo "Unknown option: $1"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
echo -e "${BLUE}=====================================${NC}"
|
||||
echo -e "${BLUE} DeepData Node Cleanup${NC}"
|
||||
echo -e "${BLUE}=====================================${NC}"
|
||||
echo ""
|
||||
|
||||
# Check if kubectl is available
|
||||
if ! command -v kubectl &> /dev/null; then
|
||||
echo -e "${RED}Error: kubectl is not installed${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check if connected to cluster
|
||||
if ! kubectl cluster-info &> /dev/null; then
|
||||
echo -e "${RED}Error: Cannot connect to Kubernetes cluster${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Determine nodes to clean up
|
||||
if [ "$PROVIDED_NODES" != "" ]; then
|
||||
# Use provided nodes
|
||||
IFS=',' read -ra SELECTED_NODES <<< "$PROVIDED_NODES"
|
||||
else
|
||||
# Find nodes with the deepdata label directly from Kubernetes
|
||||
echo -e "${YELLOW}Finding nodes with $LABEL_KEY=$LABEL_VALUE label...${NC}"
|
||||
NODES=$(kubectl get nodes -l "$LABEL_KEY=$LABEL_VALUE" -o jsonpath='{range .items[*]}{.metadata.name}{"\n"}{end}')
|
||||
|
||||
if [ -z "$NODES" ]; then
|
||||
echo -e "${GREEN}No nodes found with $LABEL_KEY=$LABEL_VALUE label.${NC}"
|
||||
echo -e "${YELLOW}Cleanup not needed - no nodes were labeled.${NC}"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
SELECTED_NODES=()
|
||||
while IFS= read -r NODE; do
|
||||
if [ -n "$NODE" ]; then
|
||||
SELECTED_NODES+=("$NODE")
|
||||
fi
|
||||
done <<< "$NODES"
|
||||
fi
|
||||
|
||||
if [ ${#SELECTED_NODES[@]} -eq 0 ]; then
|
||||
echo -e "${YELLOW}No nodes to clean up.${NC}"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo -e "${GREEN}Nodes to clean up:${NC}"
|
||||
for NODE in "${SELECTED_NODES[@]}"; do
|
||||
echo " - $NODE"
|
||||
done
|
||||
|
||||
echo ""
|
||||
echo -e "${BLUE}Summary:${NC}"
|
||||
echo " Label to remove: $LABEL_KEY"
|
||||
|
||||
# Check if any node has the taint
|
||||
HAS_TAINTS=false
|
||||
for NODE in "${SELECTED_NODES[@]}"; do
|
||||
TAINT_COUNT=$(kubectl get node "$NODE" -o jsonpath='{range .spec.taints[*]}{.key}{"\n"}{end}' | grep -c "^${LABEL_KEY}$" || echo "0")
|
||||
if [ "$TAINT_COUNT" -gt 0 ]; then
|
||||
HAS_TAINTS=true
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
if [ "$HAS_TAINTS" = true ]; then
|
||||
echo " Taint to remove: $LABEL_KEY=$LABEL_VALUE:$TAINT_EFFECT"
|
||||
fi
|
||||
echo ""
|
||||
|
||||
read -p "Remove labels and taints? (y/n) [y]: " CONFIRM
|
||||
CONFIRM=${CONFIRM:-y}
|
||||
|
||||
if [ "$CONFIRM" != "y" ] && [ "$CONFIRM" != "Y" ]; then
|
||||
echo -e "${YELLOW}Cancelled.${NC}"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo -e "${GREEN}Removing configuration...${NC}"
|
||||
|
||||
# Remove labels from selected nodes
|
||||
for NODE in "${SELECTED_NODES[@]}"; do
|
||||
if [ "$DRY_RUN" = true ]; then
|
||||
echo "[DRY-RUN] kubectl label node $NODE $LABEL_KEY-"
|
||||
else
|
||||
kubectl label node "$NODE" "$LABEL_KEY-" --overwrite
|
||||
echo -e " ${GREEN}✓${NC} Removed label from $NODE"
|
||||
fi
|
||||
done
|
||||
|
||||
# Remove taints (check if node has the taint)
|
||||
for NODE in "${SELECTED_NODES[@]}"; do
|
||||
# Check if node has the taint
|
||||
HAS_TAINT=$(kubectl get node "$NODE" -o jsonpath='{range .spec.taints[*]}{.key}{"\n"}{end}' | grep -c "^${LABEL_KEY}$" || echo "0")
|
||||
|
||||
if [ "$HAS_TAINT" -gt 0 ]; then
|
||||
if [ "$DRY_RUN" = true ]; then
|
||||
echo "[DRY-RUN] kubectl taint node $NODE $LABEL_KEY=$LABEL_VALUE:$TAINT_EFFECT-"
|
||||
else
|
||||
kubectl taint node "$NODE" "$LABEL_KEY=$LABEL_VALUE:$TAINT_EFFECT-" --overwrite || true
|
||||
echo -e " ${GREEN}✓${NC} Removed taint from $NODE"
|
||||
fi
|
||||
else
|
||||
echo -e " ${YELLOW}○${NC} No taint to remove from $NODE"
|
||||
fi
|
||||
done
|
||||
|
||||
echo ""
|
||||
echo -e "${GREEN}Cleanup complete!${NC}"
|
||||
|
||||
# Clean up Helm args temp file if it exists
|
||||
if [ -f /tmp/deepdata-helm-args.sh ]; then
|
||||
rm /tmp/deepdata-helm-args.sh
|
||||
echo -e "${GREEN}Removed /tmp/deepdata-helm-args.sh${NC}"
|
||||
fi
|
||||
|
||||
exit 0
|
||||
|
||||
+504
-504
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user