From d43bcedf3d755a0126cbf599055467e08c6d830d Mon Sep 17 00:00:00 2001 From: Luigi Molinaro Date: Mon, 9 Mar 2026 10:44:05 +0100 Subject: [PATCH 1/8] fix: Use PROJECT_SCHEDULING_SERVICE variable for scheduler namespace The delete_ibm_scheduler() function was using hardcoded 'ibm-scheduling' instead of the PROJECT_SCHEDULING_SERVICE variable. This caused the scheduler namespace to not be deleted when running cp4d-delete-instance.sh. Changes: - Use PROJECT_SCHEDULING_SERVICE variable with default 'cpd-scheduler' - Update confirmation message to use the variable - Align with cpd_vars.sh standard variable naming Fixes #1091 Signed-off-by: Luigi Molinaro --- scripts/cp4d/cp4d-delete-instance.sh | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/scripts/cp4d/cp4d-delete-instance.sh b/scripts/cp4d/cp4d-delete-instance.sh index 675e3e062..983e8dc12 100755 --- a/scripts/cp4d/cp4d-delete-instance.sh +++ b/scripts/cp4d/cp4d-delete-instance.sh @@ -247,21 +247,21 @@ delete_app_connect() { } delete_ibm_scheduler() { - IBM_SCHEDULING=ibm-scheduling - oc get project ${IBM_SCHEDULING} > /dev/null 2>&1 + PROJECT_SCHEDULING_SERVICE=${PROJECT_SCHEDULING_SERVICE:-cpd-scheduler} + oc get project ${PROJECT_SCHEDULING_SERVICE} > /dev/null 2>&1 if [ $? -eq 0 ];then - log "Deleting everything in the ${IBM_SCHEDULING} project" - oc delete Scheduling -n ${IBM_SCHEDULING} --all --ignore-not-found - oc delete subscriptions.operators.coreos.com -n ${IBM_SCHEDULING} --all --ignore-not-found - oc delete clusterserviceversions.operators.coreos.com -n ${IBM_SCHEDULING} --all --ignore-not-found - - log "Deleting ${IBM_SCHEDULING} project" - oc delete ns ${IBM_SCHEDULING} --ignore-not-found --wait=false - wait_ns_deleted ${IBM_SCHEDULING} - oc delete ns ${IBM_SCHEDULING} --ignore-not-found --wait=false - wait_ns_deleted ${IBM_SCHEDULING} + log "Deleting everything in the ${PROJECT_SCHEDULING_SERVICE} project" + oc delete Scheduling -n ${PROJECT_SCHEDULING_SERVICE} --all --ignore-not-found + oc delete subscriptions.operators.coreos.com -n ${PROJECT_SCHEDULING_SERVICE} --all --ignore-not-found + oc delete clusterserviceversions.operators.coreos.com -n ${PROJECT_SCHEDULING_SERVICE} --all --ignore-not-found + + log "Deleting ${PROJECT_SCHEDULING_SERVICE} project" + oc delete ns ${PROJECT_SCHEDULING_SERVICE} --ignore-not-found --wait=false + wait_ns_deleted ${PROJECT_SCHEDULING_SERVICE} + oc delete ns ${PROJECT_SCHEDULING_SERVICE} --ignore-not-found --wait=false + wait_ns_deleted ${PROJECT_SCHEDULING_SERVICE} else - echo "Project ${IBM_SCHEDULING} does not exist, skipping" + echo "Project ${PROJECT_SCHEDULING_SERVICE} does not exist, skipping" fi } @@ -387,7 +387,7 @@ if [ -z "${CPD_CONFIRM_DELETE}" ];then if oc get project ibm-knative-events > /dev/null 2>&1;then echo "- Knative events: ibm-knative-events";fi if oc get project knative-serving > /dev/null 2>&1;then echo "- Knative server: knative-serving";fi if oc get project ibm-licensing > /dev/null 2>&1;then echo "- License manager namespace: ibm-licensing";fi - if oc get project ibm-cpd-scheduler > /dev/null 2>&1;then echo "- Scheduler namespace: ibm-cpd-scheduler";fi + if oc get project ${PROJECT_SCHEDULING_SERVICE:-cpd-scheduler} > /dev/null 2>&1;then echo "- Scheduler namespace: ${PROJECT_SCHEDULING_SERVICE:-cpd-scheduler}";fi if oc get project ibm-cert-manager > /dev/null 2>&1;then echo "- Certificate manager: ibm-cert-manager";fi if oc get project cs-control > /dev/null 2>&1;then echo "- Common Services control: cs-control";fi echo "- IBM Custom Resource Definitions" From ccb30421cc673f019805439b35dd37926f1a7202 Mon Sep 17 00:00:00 2001 From: Luigi Molinaro Date: Mon, 9 Mar 2026 10:47:59 +0100 Subject: [PATCH 2/8] fix: Add forced finalizer removal for scheduler namespace deletion Enhanced delete_ibm_scheduler() to handle stuck namespaces in Terminating state: - Use PROJECT_SCHEDULING_SERVICE variable (default: cpd-scheduler) - Export namespace to JSON and remove kubernetes finalizers - Use OpenShift REST API to force finalize the namespace - Clean up temporary JSON file after operation - Align with best practices from focedeletens.sh script This ensures the scheduler namespace is properly deleted even when stuck with finalizers. Fixes #1091 Signed-off-by: Luigi Molinaro --- scripts/cp4d/cp4d-delete-instance.sh | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/scripts/cp4d/cp4d-delete-instance.sh b/scripts/cp4d/cp4d-delete-instance.sh index 983e8dc12..1609cdd0a 100755 --- a/scripts/cp4d/cp4d-delete-instance.sh +++ b/scripts/cp4d/cp4d-delete-instance.sh @@ -257,8 +257,19 @@ delete_ibm_scheduler() { log "Deleting ${PROJECT_SCHEDULING_SERVICE} project" oc delete ns ${PROJECT_SCHEDULING_SERVICE} --ignore-not-found --wait=false - wait_ns_deleted ${PROJECT_SCHEDULING_SERVICE} - oc delete ns ${PROJECT_SCHEDULING_SERVICE} --ignore-not-found --wait=false + + # Force remove finalizers if namespace is stuck in Terminating state + if oc get ns ${PROJECT_SCHEDULING_SERVICE} -o json > ${temp_dir}/${PROJECT_SCHEDULING_SERVICE}-finalizer.json 2>/dev/null; then + sed -i '/"kubernetes"/d' ${temp_dir}/${PROJECT_SCHEDULING_SERVICE}-finalizer.json + OC_SERVER_URL="${OC_SERVER_URL:-$(oc whoami --show-server)}" + OC_TOKEN="${OC_TOKEN:-$(oc whoami -t)}" + curl --silent --insecure -H "Content-Type: application/json" \ + -H "Authorization: Bearer ${OC_TOKEN}" \ + -X PUT --data-binary @"${temp_dir}/${PROJECT_SCHEDULING_SERVICE}-finalizer.json" \ + "${OC_SERVER_URL}/api/v1/namespaces/${PROJECT_SCHEDULING_SERVICE}/finalize" > /dev/null 2>&1 + rm -f "${temp_dir}/${PROJECT_SCHEDULING_SERVICE}-finalizer.json" + fi + wait_ns_deleted ${PROJECT_SCHEDULING_SERVICE} else echo "Project ${PROJECT_SCHEDULING_SERVICE} does not exist, skipping" From a0b8403ca506675aa5bab705389049bdc3e1b83a Mon Sep 17 00:00:00 2001 From: Luigi Molinaro Date: Mon, 9 Mar 2026 10:54:57 +0100 Subject: [PATCH 3/8] Add robust namespace deletion with comprehensive cleanup features Enhanced cp4d-delete-instance.sh with multiple improvements for reliable namespace deletion: NEW FEATURES: - Added --force-finalizer option to enable forced finalizer removal via OpenShift REST API - Added --timeout option to configure namespace deletion timeout (default: 900s) - Implemented automatic retry logic with up to 3 attempts when timeout is reached - Added comprehensive diagnostic output when namespace deletion is stuck ROBUST CLEANUP FUNCTIONS: - force_remove_resource_finalizers(): Removes finalizers from blocking resources * PersistentVolumeClaims (PVCs) * PersistentVolumes (PVs) associated with namespace * Pods stuck in Terminating state (force delete with grace-period=0) * Services with finalizers * ConfigMaps with finalizers * Secrets with finalizers - diagnose_namespace_stuck(): Provides detailed diagnostic information * Lists all remaining resources in namespace * Shows namespace status and finalizers * Identifies terminating pods * Lists PVCs that may be blocking deletion ENHANCED WAIT LOGIC: - Configurable timeout with progress logging every 60 seconds - Automatic retry with forced cleanup when timeout is reached - Shorter timeout (300s) for retry attempts - Better error handling and return codes NAMESPACE DELETION IMPROVEMENTS: - Applied force_remove_finalizers() to all namespace deletion functions: * delete_operator_ns (CP4D operators) * delete_instance_ns (CP4D instance) * delete_knative (knative-eventing, knative-serving) * delete_app_connect (ibm-app-connect) * delete_ibm_scheduler (cpd-scheduler) - now uses PROJECT_SCHEDULING_SERVICE variable * delete_ibm_license_server (ibm-licensing) * delete_ibm_certificate_manager (ibm-cert-manager) * delete_common_services_control (cs-control) BUG FIXES: - Fixed delete_ibm_scheduler() to use PROJECT_SCHEDULING_SERVICE variable instead of hardcoded 'ibm-scheduling' - Removed duplicate namespace deletion attempts in licensing and cert-manager functions USAGE: ./cp4d-delete-instance.sh ./cp4d-delete-instance.sh -n --force-finalizer --timeout 1200 Signed-off-by: Luigi Molinaro --- scripts/cp4d/cp4d-delete-instance.sh | 202 ++++++++++++++++++++++++--- 1 file changed, 179 insertions(+), 23 deletions(-) diff --git a/scripts/cp4d/cp4d-delete-instance.sh b/scripts/cp4d/cp4d-delete-instance.sh index 1609cdd0a..44f0878e3 100755 --- a/scripts/cp4d/cp4d-delete-instance.sh +++ b/scripts/cp4d/cp4d-delete-instance.sh @@ -5,7 +5,11 @@ command_usage() { echo echo "Usage:" echo "$(basename $0) " - echo "$(basename $0) -n [--operator-ns ]" + echo "$(basename $0) -n [--operator-ns ] [--force-finalizer] [--timeout ]" + echo + echo "Options:" + echo " --force-finalizer Force removal of finalizers using OpenShift REST API for stuck namespaces" + echo " --timeout Timeout in seconds for namespace deletion (default: 900)" echo exit $1 } @@ -54,6 +58,24 @@ else fi shift 1 ;; + --force-finalizer) + export FORCE_FINALIZER=true + shift 1 + ;; + --timeout*) + if [[ "$1" =~ "=" ]] && [ ! -z "${1#*=}" ] && [ "${1#*=:0:1}" != "-" ];then + export NAMESPACE_DELETE_TIMEOUT="${1#*=}" + shift 1 + else if [ -n "$2" ] && [ ${2:0:1} != "-" ];then + export NAMESPACE_DELETE_TIMEOUT=$2 + shift 2 + else + echo "Error: Missing timeout value." + command_usage 2 + fi + fi + shift 1 + ;; *) # preserve remaining arguments PARAMS="$PARAMS $1" shift @@ -73,11 +95,155 @@ log() { wait_ns_deleted() { NS=$1 - log "Waiting for deletion of namespace ${NS} ..." + TIMEOUT=${NAMESPACE_DELETE_TIMEOUT:-900} + ELAPSED=0 + RETRY_COUNT=0 + MAX_RETRIES=3 + log "Waiting for deletion of namespace ${NS} (timeout: ${TIMEOUT}s)..." + while $(oc get ns ${NS} > /dev/null 2>&1);do - sleep 1 + sleep 5 + ELAPSED=$((ELAPSED + 5)) + + if [ $ELAPSED -ge $TIMEOUT ]; then + log "WARNING: Timeout reached waiting for namespace ${NS} deletion after ${TIMEOUT}s" + log "Namespace ${NS} may still be in Terminating state" + + # Run diagnostics + diagnose_namespace_stuck ${NS} + + if [ "${FORCE_FINALIZER}" = "true" ] && [ $RETRY_COUNT -lt $MAX_RETRIES ]; then + RETRY_COUNT=$((RETRY_COUNT + 1)) + log "Attempting forced cleanup (attempt ${RETRY_COUNT}/${MAX_RETRIES})..." + force_remove_finalizers ${NS} + + # Reset timeout for retry + ELAPSED=0 + TIMEOUT=300 # Shorter timeout for retries + log "Waiting additional ${TIMEOUT}s after forced cleanup..." + continue + else + log "ERROR: Failed to delete namespace ${NS} after ${MAX_RETRIES} retry attempts" + return 1 + fi + fi + + # Log progress every 60 seconds + if [ $((ELAPSED % 60)) -eq 0 ] && [ $ELAPSED -gt 0 ]; then + log "Still waiting for ${NS} deletion... (${ELAPSED}s elapsed)" + fi done - log "Project ${NS} deleted" + log "Project ${NS} deleted successfully" + return 0 +} + +force_remove_finalizers() { + NS=$1 + if [ "${FORCE_FINALIZER}" = "true" ]; then + log "Force removing finalizers for ${NS} namespace" + + # First, try to remove finalizers from blocking resources + force_remove_resource_finalizers ${NS} + + # Then remove namespace finalizers + if oc get ns ${NS} -o json > ${temp_dir}/${NS}-finalizer.json 2>/dev/null; then + sed -i '/"kubernetes"/d' ${temp_dir}/${NS}-finalizer.json + OC_SERVER_URL="${OC_SERVER_URL:-$(oc whoami --show-server)}" + OC_TOKEN="${OC_TOKEN:-$(oc whoami -t)}" + curl --silent --insecure -H "Content-Type: application/json" \ + -H "Authorization: Bearer ${OC_TOKEN}" \ + -X PUT --data-binary @"${temp_dir}/${NS}-finalizer.json" \ + "${OC_SERVER_URL}/api/v1/namespaces/${NS}/finalize" > /dev/null 2>&1 + rm -f "${temp_dir}/${NS}-finalizer.json" + log "Namespace finalizers removed for ${NS}" + fi + fi +} + +force_remove_resource_finalizers() { + NS=$1 + log "Checking for resources with finalizers in namespace ${NS}..." + + # Remove finalizers from PVCs (often block namespace deletion) + if oc get pvc -n ${NS} --no-headers 2>/dev/null | grep -q .; then + log "Removing finalizers from PVCs in ${NS}..." + for pvc in $(oc get pvc -n ${NS} --no-headers 2>/dev/null | awk '{print $1}'); do + oc patch pvc/${pvc} -n ${NS} --type=merge -p '{"metadata": {"finalizers":null}}' 2>/dev/null + done + fi + + # Remove finalizers from PVs associated with the namespace + if oc get pv --no-headers 2>/dev/null | grep ${NS} | grep -q .; then + log "Removing finalizers from PVs associated with ${NS}..." + for pv in $(oc get pv --no-headers 2>/dev/null | grep ${NS} | awk '{print $1}'); do + oc patch pv/${pv} --type=merge -p '{"metadata": {"finalizers":null}}' 2>/dev/null + done + fi + + # Remove finalizers from Pods stuck in Terminating + if oc get pods -n ${NS} --field-selector=status.phase=Terminating --no-headers 2>/dev/null | grep -q .; then + log "Force deleting Terminating pods in ${NS}..." + for pod in $(oc get pods -n ${NS} --field-selector=status.phase=Terminating --no-headers 2>/dev/null | awk '{print $1}'); do + oc delete pod/${pod} -n ${NS} --grace-period=0 --force 2>/dev/null + done + fi + + # Remove finalizers from Services + if oc get svc -n ${NS} --no-headers 2>/dev/null | grep -q .; then + log "Removing finalizers from Services in ${NS}..." + for svc in $(oc get svc -n ${NS} --no-headers 2>/dev/null | awk '{print $1}'); do + oc patch svc/${svc} -n ${NS} --type=merge -p '{"metadata": {"finalizers":null}}' 2>/dev/null + done + fi + + # Remove finalizers from ConfigMaps with finalizers + if oc get cm -n ${NS} --no-headers 2>/dev/null | grep -q .; then + for cm in $(oc get cm -n ${NS} -o json 2>/dev/null | jq -r '.items[] | select(.metadata.finalizers != null) | .metadata.name'); do + if [ ! -z "$cm" ]; then + log "Removing finalizers from ConfigMap ${cm} in ${NS}..." + oc patch cm/${cm} -n ${NS} --type=merge -p '{"metadata": {"finalizers":null}}' 2>/dev/null + fi + done + fi + + # Remove finalizers from Secrets with finalizers + if oc get secret -n ${NS} --no-headers 2>/dev/null | grep -q .; then + for secret in $(oc get secret -n ${NS} -o json 2>/dev/null | jq -r '.items[] | select(.metadata.finalizers != null) | .metadata.name'); do + if [ ! -z "$secret" ]; then + log "Removing finalizers from Secret ${secret} in ${NS}..." + oc patch secret/${secret} -n ${NS} --type=merge -p '{"metadata": {"finalizers":null}}' 2>/dev/null + fi + done + fi +} + +diagnose_namespace_stuck() { + NS=$1 + log "=== Diagnostic information for stuck namespace ${NS} ===" + + # Check for resources still in the namespace + log "Resources still present in namespace:" + oc api-resources --verbs=list --namespaced -o name 2>/dev/null | \ + xargs -I {} sh -c "oc get {} -n ${NS} --ignore-not-found --no-headers 2>/dev/null | head -5" | \ + grep -v "^$" || log "No resources found" + + # Check namespace status + log "Namespace status:" + oc get ns ${NS} -o json 2>/dev/null | jq -r '.status' || log "Cannot get namespace status" + + # Check for finalizers on namespace + log "Namespace finalizers:" + oc get ns ${NS} -o json 2>/dev/null | jq -r '.metadata.finalizers[]' || log "No finalizers found" + + # Check for stuck pods + log "Pods in Terminating state:" + oc get pods -n ${NS} --field-selector=status.phase=Terminating 2>/dev/null || log "No terminating pods" + + # Check for PVCs + log "PersistentVolumeClaims:" + oc get pvc -n ${NS} 2>/dev/null || log "No PVCs found" + + log "=== End diagnostic information ===" } delete_operator_ns() { @@ -104,6 +270,7 @@ delete_operator_ns() { oc patch -n ${CP4D_OPERATORS} operandrequest/${opreq} --type=merge -p '{"metadata": {"finalizers":null}}' 2> /dev/null done done + force_remove_finalizers ${CP4D_OPERATORS} wait_ns_deleted ${CP4D_OPERATORS} else echo "Project ${CP4D_OPERATORS} does not exist, skipping" @@ -170,6 +337,7 @@ delete_instance_ns() { # # Now the CP4D project should be empty and can be deleted, this may take a while (5-15 minutes) # + force_remove_finalizers ${INSTANCE_NS} wait_ns_deleted ${INSTANCE_NS} else echo "Project ${INSTANCE_NS} does not exist, skipping" @@ -214,6 +382,7 @@ delete_knative() { log "Deleting ${KNATIVE_EVENTING} project" oc delete ns ${KNATIVE_EVENTING} --ignore-not-found --wait=false + force_remove_finalizers ${KNATIVE_EVENTING} wait_ns_deleted ${KNATIVE_EVENTING} else echo "Project ${KNATIVE_EVENTING} does not exist, skipping" @@ -226,6 +395,7 @@ delete_knative() { log "Deleting ${KNATIVE_SERVING} project" oc delete ns ${KNATIVE_SERVING} --ignore-not-found --wait=false + force_remove_finalizers ${KNATIVE_SERVING} wait_ns_deleted ${KNATIVE_SERVING} else echo "Project ${KNATIVE_SERVING} does not exist, skipping" @@ -240,6 +410,7 @@ delete_app_connect() { log "Deleting ${APP_CONNECT} project" oc delete ns ${APP_CONNECT} --ignore-not-found --wait=false + force_remove_finalizers ${APP_CONNECT} wait_ns_deleted ${APP_CONNECT} else echo "Project ${APP_CONNECT} does not exist, skipping" @@ -257,19 +428,7 @@ delete_ibm_scheduler() { log "Deleting ${PROJECT_SCHEDULING_SERVICE} project" oc delete ns ${PROJECT_SCHEDULING_SERVICE} --ignore-not-found --wait=false - - # Force remove finalizers if namespace is stuck in Terminating state - if oc get ns ${PROJECT_SCHEDULING_SERVICE} -o json > ${temp_dir}/${PROJECT_SCHEDULING_SERVICE}-finalizer.json 2>/dev/null; then - sed -i '/"kubernetes"/d' ${temp_dir}/${PROJECT_SCHEDULING_SERVICE}-finalizer.json - OC_SERVER_URL="${OC_SERVER_URL:-$(oc whoami --show-server)}" - OC_TOKEN="${OC_TOKEN:-$(oc whoami -t)}" - curl --silent --insecure -H "Content-Type: application/json" \ - -H "Authorization: Bearer ${OC_TOKEN}" \ - -X PUT --data-binary @"${temp_dir}/${PROJECT_SCHEDULING_SERVICE}-finalizer.json" \ - "${OC_SERVER_URL}/api/v1/namespaces/${PROJECT_SCHEDULING_SERVICE}/finalize" > /dev/null 2>&1 - rm -f "${temp_dir}/${PROJECT_SCHEDULING_SERVICE}-finalizer.json" - fi - + force_remove_finalizers ${PROJECT_SCHEDULING_SERVICE} wait_ns_deleted ${PROJECT_SCHEDULING_SERVICE} else echo "Project ${PROJECT_SCHEDULING_SERVICE} does not exist, skipping" @@ -289,8 +448,7 @@ delete_ibm_license_server() { log "Deleting ${IBM_LICENSING} project" oc delete ns ${IBM_LICENSING} --ignore-not-found --wait=false - wait_ns_deleted ${IBM_LICENSING} - oc delete ns ${IBM_LICENSING} --ignore-not-found --wait=false + force_remove_finalizers ${IBM_LICENSING} wait_ns_deleted ${IBM_LICENSING} else echo "Project ${IBM_LICENSING} does not exist, skipping" @@ -316,8 +474,7 @@ delete_ibm_certificate_manager() { log "Deleting ${IBM_CERT_MANAGER} project" oc delete ns ${IBM_CERT_MANAGER} --ignore-not-found --wait=false - wait_ns_deleted ${IBM_CERT_MANAGER} - oc delete ns ${IBM_CERT_MANAGER} --ignore-not-found --wait=false + force_remove_finalizers ${IBM_CERT_MANAGER} wait_ns_deleted ${IBM_CERT_MANAGER} else echo "Project ${IBM_CERT_MANAGER} does not exist, skipping" @@ -336,8 +493,7 @@ delete_common_services_control() { log "Deleting ${IBM_CS_CONTROL} project" oc delete ns ${IBM_CS_CONTROL} --ignore-not-found --wait=false - wait_ns_deleted ${IBM_CS_CONTROL} - oc delete ns ${IBM_CS_CONTROL} --ignore-not-found --wait=false + force_remove_finalizers ${IBM_CS_CONTROL} wait_ns_deleted ${IBM_CS_CONTROL} else echo "Project ${IBM_CS_CONTROL} does not exist, skipping" From a8e277d4d758f02b50fe1afdb0530cdd57b6bac5 Mon Sep 17 00:00:00 2001 From: Luigi Molinaro Date: Mon, 9 Mar 2026 10:57:18 +0100 Subject: [PATCH 4/8] Add colored output for better readability MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Added color-coded logging functions with visual indicators: - ✓ Green (log_success): Successful operations - ✗ Red (log_error): Errors and failures - ⚠ Yellow (log_warning): Warnings and timeouts - ℹ Cyan (log_info): Informational messages Applied colored logging throughout the script: - Success messages when namespaces are deleted - Warnings for timeouts and stuck namespaces - Errors for failed deletion attempts - Info messages for cleanup operations and diagnostics This makes it much easier to quickly identify the status of operations during namespace deletion, especially when dealing with stuck resources. Signed-off-by: Luigi Molinaro --- scripts/cp4d/cp4d-delete-instance.sh | 70 +++++++++++++++++++--------- 1 file changed, 49 insertions(+), 21 deletions(-) diff --git a/scripts/cp4d/cp4d-delete-instance.sh b/scripts/cp4d/cp4d-delete-instance.sh index 44f0878e3..5555de0e8 100755 --- a/scripts/cp4d/cp4d-delete-instance.sh +++ b/scripts/cp4d/cp4d-delete-instance.sh @@ -84,6 +84,14 @@ else done fi +# Color codes for output +COLOR_RED='\033[0;31m' +COLOR_GREEN='\033[0;32m' +COLOR_YELLOW='\033[1;33m' +COLOR_BLUE='\033[0;34m' +COLOR_CYAN='\033[0;36m' +COLOR_RESET='\033[0m' + get_logtime() { echo $(date "+%Y-%m-%d %H:%M:%S") } @@ -93,6 +101,26 @@ log() { printf "[${LOG_TIME}] ${1}\n" } +log_success() { + LOG_TIME=$(get_logtime) + printf "${COLOR_GREEN}✓ [${LOG_TIME}] ${1}${COLOR_RESET}\n" +} + +log_error() { + LOG_TIME=$(get_logtime) + printf "${COLOR_RED}✗ [${LOG_TIME}] ${1}${COLOR_RESET}\n" +} + +log_warning() { + LOG_TIME=$(get_logtime) + printf "${COLOR_YELLOW}⚠ [${LOG_TIME}] ${1}${COLOR_RESET}\n" +} + +log_info() { + LOG_TIME=$(get_logtime) + printf "${COLOR_CYAN}ℹ [${LOG_TIME}] ${1}${COLOR_RESET}\n" +} + wait_ns_deleted() { NS=$1 TIMEOUT=${NAMESPACE_DELETE_TIMEOUT:-900} @@ -106,15 +134,15 @@ wait_ns_deleted() { ELAPSED=$((ELAPSED + 5)) if [ $ELAPSED -ge $TIMEOUT ]; then - log "WARNING: Timeout reached waiting for namespace ${NS} deletion after ${TIMEOUT}s" - log "Namespace ${NS} may still be in Terminating state" + log_warning "Timeout reached waiting for namespace ${NS} deletion after ${TIMEOUT}s" + log_warning "Namespace ${NS} may still be in Terminating state" # Run diagnostics diagnose_namespace_stuck ${NS} if [ "${FORCE_FINALIZER}" = "true" ] && [ $RETRY_COUNT -lt $MAX_RETRIES ]; then RETRY_COUNT=$((RETRY_COUNT + 1)) - log "Attempting forced cleanup (attempt ${RETRY_COUNT}/${MAX_RETRIES})..." + log_info "Attempting forced cleanup (attempt ${RETRY_COUNT}/${MAX_RETRIES})..." force_remove_finalizers ${NS} # Reset timeout for retry @@ -123,7 +151,7 @@ wait_ns_deleted() { log "Waiting additional ${TIMEOUT}s after forced cleanup..." continue else - log "ERROR: Failed to delete namespace ${NS} after ${MAX_RETRIES} retry attempts" + log_error "Failed to delete namespace ${NS} after ${MAX_RETRIES} retry attempts" return 1 fi fi @@ -133,14 +161,14 @@ wait_ns_deleted() { log "Still waiting for ${NS} deletion... (${ELAPSED}s elapsed)" fi done - log "Project ${NS} deleted successfully" + log_success "Project ${NS} deleted successfully" return 0 } force_remove_finalizers() { NS=$1 if [ "${FORCE_FINALIZER}" = "true" ]; then - log "Force removing finalizers for ${NS} namespace" + log_info "Force removing finalizers for ${NS} namespace" # First, try to remove finalizers from blocking resources force_remove_resource_finalizers ${NS} @@ -155,18 +183,18 @@ force_remove_finalizers() { -X PUT --data-binary @"${temp_dir}/${NS}-finalizer.json" \ "${OC_SERVER_URL}/api/v1/namespaces/${NS}/finalize" > /dev/null 2>&1 rm -f "${temp_dir}/${NS}-finalizer.json" - log "Namespace finalizers removed for ${NS}" + log_success "Namespace finalizers removed for ${NS}" fi fi } force_remove_resource_finalizers() { NS=$1 - log "Checking for resources with finalizers in namespace ${NS}..." + log_info "Checking for resources with finalizers in namespace ${NS}..." # Remove finalizers from PVCs (often block namespace deletion) if oc get pvc -n ${NS} --no-headers 2>/dev/null | grep -q .; then - log "Removing finalizers from PVCs in ${NS}..." + log_info "Removing finalizers from PVCs in ${NS}..." for pvc in $(oc get pvc -n ${NS} --no-headers 2>/dev/null | awk '{print $1}'); do oc patch pvc/${pvc} -n ${NS} --type=merge -p '{"metadata": {"finalizers":null}}' 2>/dev/null done @@ -174,7 +202,7 @@ force_remove_resource_finalizers() { # Remove finalizers from PVs associated with the namespace if oc get pv --no-headers 2>/dev/null | grep ${NS} | grep -q .; then - log "Removing finalizers from PVs associated with ${NS}..." + log_info "Removing finalizers from PVs associated with ${NS}..." for pv in $(oc get pv --no-headers 2>/dev/null | grep ${NS} | awk '{print $1}'); do oc patch pv/${pv} --type=merge -p '{"metadata": {"finalizers":null}}' 2>/dev/null done @@ -182,7 +210,7 @@ force_remove_resource_finalizers() { # Remove finalizers from Pods stuck in Terminating if oc get pods -n ${NS} --field-selector=status.phase=Terminating --no-headers 2>/dev/null | grep -q .; then - log "Force deleting Terminating pods in ${NS}..." + log_warning "Force deleting Terminating pods in ${NS}..." for pod in $(oc get pods -n ${NS} --field-selector=status.phase=Terminating --no-headers 2>/dev/null | awk '{print $1}'); do oc delete pod/${pod} -n ${NS} --grace-period=0 --force 2>/dev/null done @@ -190,7 +218,7 @@ force_remove_resource_finalizers() { # Remove finalizers from Services if oc get svc -n ${NS} --no-headers 2>/dev/null | grep -q .; then - log "Removing finalizers from Services in ${NS}..." + log_info "Removing finalizers from Services in ${NS}..." for svc in $(oc get svc -n ${NS} --no-headers 2>/dev/null | awk '{print $1}'); do oc patch svc/${svc} -n ${NS} --type=merge -p '{"metadata": {"finalizers":null}}' 2>/dev/null done @@ -200,7 +228,7 @@ force_remove_resource_finalizers() { if oc get cm -n ${NS} --no-headers 2>/dev/null | grep -q .; then for cm in $(oc get cm -n ${NS} -o json 2>/dev/null | jq -r '.items[] | select(.metadata.finalizers != null) | .metadata.name'); do if [ ! -z "$cm" ]; then - log "Removing finalizers from ConfigMap ${cm} in ${NS}..." + log_info "Removing finalizers from ConfigMap ${cm} in ${NS}..." oc patch cm/${cm} -n ${NS} --type=merge -p '{"metadata": {"finalizers":null}}' 2>/dev/null fi done @@ -210,7 +238,7 @@ force_remove_resource_finalizers() { if oc get secret -n ${NS} --no-headers 2>/dev/null | grep -q .; then for secret in $(oc get secret -n ${NS} -o json 2>/dev/null | jq -r '.items[] | select(.metadata.finalizers != null) | .metadata.name'); do if [ ! -z "$secret" ]; then - log "Removing finalizers from Secret ${secret} in ${NS}..." + log_info "Removing finalizers from Secret ${secret} in ${NS}..." oc patch secret/${secret} -n ${NS} --type=merge -p '{"metadata": {"finalizers":null}}' 2>/dev/null fi done @@ -219,31 +247,31 @@ force_remove_resource_finalizers() { diagnose_namespace_stuck() { NS=$1 - log "=== Diagnostic information for stuck namespace ${NS} ===" + log_warning "=== Diagnostic information for stuck namespace ${NS} ===" # Check for resources still in the namespace - log "Resources still present in namespace:" + log_info "Resources still present in namespace:" oc api-resources --verbs=list --namespaced -o name 2>/dev/null | \ xargs -I {} sh -c "oc get {} -n ${NS} --ignore-not-found --no-headers 2>/dev/null | head -5" | \ grep -v "^$" || log "No resources found" # Check namespace status - log "Namespace status:" + log_info "Namespace status:" oc get ns ${NS} -o json 2>/dev/null | jq -r '.status' || log "Cannot get namespace status" # Check for finalizers on namespace - log "Namespace finalizers:" + log_info "Namespace finalizers:" oc get ns ${NS} -o json 2>/dev/null | jq -r '.metadata.finalizers[]' || log "No finalizers found" # Check for stuck pods - log "Pods in Terminating state:" + log_info "Pods in Terminating state:" oc get pods -n ${NS} --field-selector=status.phase=Terminating 2>/dev/null || log "No terminating pods" # Check for PVCs - log "PersistentVolumeClaims:" + log_info "PersistentVolumeClaims:" oc get pvc -n ${NS} 2>/dev/null || log "No PVCs found" - log "=== End diagnostic information ===" + log_warning "=== End diagnostic information ===" } delete_operator_ns() { From 108f456f748200b8c41f7c392f22abd2e42a38bd Mon Sep 17 00:00:00 2001 From: Luigi Molinaro Date: Mon, 9 Mar 2026 11:08:44 +0100 Subject: [PATCH 5/8] Add parallel namespace deletion for faster execution Implemented parallel deletion mode to significantly speed up namespace cleanup: NEW OPTION: - --parallel: Enable parallel deletion of multiple namespaces NEW FUNCTIONS: - start_ns_deletion(): Initiates namespace deletion in background (non-blocking) - wait_multiple_ns_deleted(): Waits for multiple namespaces to complete deletion in parallel * Monitors all namespaces simultaneously * Progress logging every 60 seconds * Applies forced cleanup to stuck namespaces if --force-finalizer is enabled * Individual status reporting for each namespace PARALLEL DELETION STRATEGY: 1. Instance and operator namespaces deleted sequentially (dependencies) 2. Cluster-wide namespaces deleted in parallel: - knative-eventing - knative-serving - ibm-app-connect - cpd-scheduler - ibm-licensing (if not shared) - ibm-cert-manager (if not shared) - cs-control PERFORMANCE IMPROVEMENT: - Sequential mode: ~15-30 minutes (namespaces deleted one by one) - Parallel mode: ~5-10 minutes (multiple namespaces deleted simultaneously) - Up to 3x faster for environments with many namespaces USAGE: # Sequential deletion (default, original behavior) ./cp4d-delete-instance.sh -n cpd-instance # Parallel deletion (faster) ./cp4d-delete-instance.sh -n cpd-instance --parallel # Parallel with force finalizer ./cp4d-delete-instance.sh -n cpd-instance --parallel --force-finalizer BACKWARD COMPATIBILITY: - Default behavior unchanged (sequential deletion) - Parallel mode only activated with --parallel flag - All existing options work with both modes Signed-off-by: Luigi Molinaro --- scripts/cp4d/cp4d-delete-instance.sh | 246 +++++++++++++++++++++++---- 1 file changed, 214 insertions(+), 32 deletions(-) diff --git a/scripts/cp4d/cp4d-delete-instance.sh b/scripts/cp4d/cp4d-delete-instance.sh index 5555de0e8..859af31b6 100755 --- a/scripts/cp4d/cp4d-delete-instance.sh +++ b/scripts/cp4d/cp4d-delete-instance.sh @@ -5,11 +5,12 @@ command_usage() { echo echo "Usage:" echo "$(basename $0) " - echo "$(basename $0) -n [--operator-ns ] [--force-finalizer] [--timeout ]" + echo "$(basename $0) -n [--operator-ns ] [--force-finalizer] [--timeout ] [--parallel]" echo echo "Options:" echo " --force-finalizer Force removal of finalizers using OpenShift REST API for stuck namespaces" echo " --timeout Timeout in seconds for namespace deletion (default: 900)" + echo " --parallel Delete multiple namespaces in parallel for faster execution" echo exit $1 } @@ -76,6 +77,10 @@ else fi shift 1 ;; + --parallel) + export PARALLEL_DELETE=true + shift 1 + ;; *) # preserve remaining arguments PARAMS="$PARAMS $1" shift @@ -165,6 +170,85 @@ wait_ns_deleted() { return 0 } +# Start namespace deletion in background (non-blocking) +start_ns_deletion() { + NS=$1 + log_info "Starting deletion of namespace ${NS} in background..." + oc delete ns ${NS} --ignore-not-found --wait=false 2>&1 | sed "s/^/[${NS}] /" & +} + +# Wait for multiple namespaces to be deleted in parallel +wait_multiple_ns_deleted() { + local namespaces=("$@") + local timeout=${NAMESPACE_DELETE_TIMEOUT:-900} + local start_time=$(date +%s) + local all_deleted=false + + log_info "Waiting for ${#namespaces[@]} namespaces to be deleted in parallel..." + + while [ "$all_deleted" = false ]; do + all_deleted=true + local current_time=$(date +%s) + local elapsed=$((current_time - start_time)) + + # Check if timeout reached + if [ $elapsed -ge $timeout ]; then + log_warning "Timeout reached after ${timeout}s" + break + fi + + # Check each namespace + for ns in "${namespaces[@]}"; do + if oc get ns ${ns} > /dev/null 2>&1; then + all_deleted=false + fi + done + + if [ "$all_deleted" = false ]; then + sleep 5 + # Log progress every 60 seconds + if [ $((elapsed % 60)) -eq 0 ] && [ $elapsed -gt 0 ]; then + local remaining=() + for ns in "${namespaces[@]}"; do + if oc get ns ${ns} > /dev/null 2>&1; then + remaining+=("$ns") + fi + done + log_info "Still waiting for ${#remaining[@]} namespace(s): ${remaining[*]} (${elapsed}s elapsed)" + fi + fi + done + + # Check final status and apply force cleanup if needed + local failed_ns=() + for ns in "${namespaces[@]}"; do + if oc get ns ${ns} > /dev/null 2>&1; then + failed_ns+=("$ns") + log_warning "Namespace ${ns} still exists after timeout" + if [ "${FORCE_FINALIZER}" = "true" ]; then + log_info "Applying forced cleanup to ${ns}..." + force_remove_finalizers ${ns} + fi + else + log_success "Namespace ${ns} deleted successfully" + fi + done + + # If there are failed namespaces and force finalizer is enabled, wait a bit more + if [ ${#failed_ns[@]} -gt 0 ] && [ "${FORCE_FINALIZER}" = "true" ]; then + log_info "Waiting additional 120s for forced cleanup to complete..." + sleep 120 + + for ns in "${failed_ns[@]}"; do + if oc get ns ${ns} > /dev/null 2>&1; then + log_error "Namespace ${ns} still exists after forced cleanup" + else + log_success "Namespace ${ns} deleted after forced cleanup" + fi + done + fi +} + force_remove_finalizers() { NS=$1 if [ "${FORCE_FINALIZER}" = "true" ]; then @@ -606,37 +690,135 @@ fi # Create temporary directory temp_dir=$(mktemp -d) -# Delete Cloud Pak for Data instance -delete_instance_ns ${INSTANCE_NS} - -# Delete operators in new operators namespace -delete_operator_ns ${OPERATOR_NS} - -# If cluster-wide resources must be destroyed, do so -if ${CPD_DESTROY_CLUSTER_WIDE};then - # Delete KNative operator and project - delete_knative - - # Delete App Connect - delete_app_connect - - # Delete IBM Scheduler - delete_ibm_scheduler - - # Delete IBM License Server - delete_ibm_license_server - - # Delete certifiate manager - delete_ibm_certificate_manager - - # Delete old version of certifiate manager and license manager - delete_common_services_control - - # Delete cluster-wide CRs and config - delete_cluster_wide_cr_config - - # Delete IBM CRDs - delete_ibm_crds +if [ "${PARALLEL_DELETE}" = "true" ]; then + log_info "Using parallel deletion mode for faster execution" + + # Delete Cloud Pak for Data instance (must be first) + delete_instance_ns ${INSTANCE_NS} + + # Delete operators in new operators namespace (must be second) + delete_operator_ns ${OPERATOR_NS} + + # If cluster-wide resources must be destroyed, do so in parallel + if ${CPD_DESTROY_CLUSTER_WIDE};then + log_info "Starting parallel deletion of cluster-wide namespaces..." + + # Collect namespaces to delete in parallel + parallel_namespaces=() + + # Check and prepare knative namespaces + if oc get project ibm-knative-events > /dev/null 2>&1; then + delete_operator_ns ibm-knative-events + fi + + if oc get project knative-eventing > /dev/null 2>&1; then + # Clean up resources first + oc get --no-headers -n knative-eventing $(oc api-resources --namespaced=true --verbs=list -o name | grep ibm | awk '{printf "%s%s",sep,$0;sep=","}') --ignore-not-found -o=custom-columns=KIND:.kind,NAME:.metadata.name --sort-by='kind' 2>/dev/null | while read -r line; do + read -r CR CR_NAME <<< "${line}" + oc delete -n knative-eventing ${CR} ${CR_NAME} --wait=false --ignore-not-found 2>/dev/null + oc patch -n knative-eventing ${CR}/${CR_NAME} --type=merge -p '{"metadata": {"finalizers":null}}' 2>/dev/null + done + start_ns_deletion knative-eventing + parallel_namespaces+=("knative-eventing") + fi + + if oc get project knative-serving > /dev/null 2>&1; then + start_ns_deletion knative-serving + parallel_namespaces+=("knative-serving") + fi + + # App Connect + if oc get project ibm-app-connect > /dev/null 2>&1; then + start_ns_deletion ibm-app-connect + parallel_namespaces+=("ibm-app-connect") + fi + + # Scheduler + PROJECT_SCHEDULING_SERVICE=${PROJECT_SCHEDULING_SERVICE:-cpd-scheduler} + if oc get project ${PROJECT_SCHEDULING_SERVICE} > /dev/null 2>&1; then + oc delete Scheduling -n ${PROJECT_SCHEDULING_SERVICE} --all --ignore-not-found 2>/dev/null + oc delete subscriptions.operators.coreos.com -n ${PROJECT_SCHEDULING_SERVICE} --all --ignore-not-found 2>/dev/null + oc delete clusterserviceversions.operators.coreos.com -n ${PROJECT_SCHEDULING_SERVICE} --all --ignore-not-found 2>/dev/null + start_ns_deletion ${PROJECT_SCHEDULING_SERVICE} + parallel_namespaces+=("${PROJECT_SCHEDULING_SERVICE}") + fi + + # License Server (if not shared) + check_shared_resources ibmlicensingdefinition.operator.ibm.com ibm-licensing DELETE_LICENSING + if [ "${DELETE_LICENSING}" -eq 1 ] && oc get project ibm-licensing > /dev/null 2>&1; then + oc delete ibmlicensing --all --ignore-not-found 2>/dev/null + oc delete subscriptions.operators.coreos.com -n ibm-licensing --all --ignore-not-found 2>/dev/null + oc delete clusterserviceversions.operators.coreos.com -n ibm-licensing --all --ignore-not-found 2>/dev/null + start_ns_deletion ibm-licensing + parallel_namespaces+=("ibm-licensing") + fi + + # Certificate Manager (if not shared) + check_shared_resources certificaterequests.cert-manager.io ibm-cert-manager DELETE_CERT_MANAGER + if [ "${DELETE_CERT_MANAGER}" -eq 1 ] && oc get project ibm-cert-manager > /dev/null 2>&1; then + oc delete lease -n ibm-cert-manager --all --ignore-not-found 2>/dev/null + oc delete endpointslice -n ibm-cert-manager --all --ignore-not-found 2>/dev/null + oc delete endpoints -n ibm-cert-manager --all --ignore-not-found 2>/dev/null + oc delete subscriptions.operators.coreos.com -n ibm-cert-manager --all --ignore-not-found 2>/dev/null + oc delete clusterserviceversions.operators.coreos.com -n ibm-cert-manager --all --ignore-not-found 2>/dev/null + start_ns_deletion ibm-cert-manager + parallel_namespaces+=("ibm-cert-manager") + fi + + # Common Services Control + if oc get project cs-control > /dev/null 2>&1; then + oc delete nss -n cs-control --all --ignore-not-found 2>/dev/null + start_ns_deletion cs-control + parallel_namespaces+=("cs-control") + fi + + # Wait for all parallel deletions to complete + if [ ${#parallel_namespaces[@]} -gt 0 ]; then + wait_multiple_ns_deleted "${parallel_namespaces[@]}" + fi + + # Delete cluster-wide CRs and config + delete_cluster_wide_cr_config + + # Delete IBM CRDs + delete_ibm_crds + fi +else + # Sequential deletion (original behavior) + log_info "Using sequential deletion mode" + + # Delete Cloud Pak for Data instance + delete_instance_ns ${INSTANCE_NS} + + # Delete operators in new operators namespace + delete_operator_ns ${OPERATOR_NS} + + # If cluster-wide resources must be destroyed, do so + if ${CPD_DESTROY_CLUSTER_WIDE};then + # Delete KNative operator and project + delete_knative + + # Delete App Connect + delete_app_connect + + # Delete IBM Scheduler + delete_ibm_scheduler + + # Delete IBM License Server + delete_ibm_license_server + + # Delete certifiate manager + delete_ibm_certificate_manager + + # Delete old version of certifiate manager and license manager + delete_common_services_control + + # Delete cluster-wide CRs and config + delete_cluster_wide_cr_config + + # Delete IBM CRDs + delete_ibm_crds + fi fi exit 0 \ No newline at end of file From 090389b098c701fe496a43820501f92b24fc69da Mon Sep 17 00:00:00 2001 From: Luigi Molinaro Date: Fri, 13 Mar 2026 09:14:38 +0100 Subject: [PATCH 6/8] Note modified --- playbooks/playbook-env-apply-10-validate.yml | 114 ++++- scripts/cp4d/cp4d-delete-instance.sh | 504 ++++++++++++++++--- 2 files changed, 553 insertions(+), 65 deletions(-) diff --git a/playbooks/playbook-env-apply-10-validate.yml b/playbooks/playbook-env-apply-10-validate.yml index b6be8548e..61f43167f 100644 --- a/playbooks/playbook-env-apply-10-validate.yml +++ b/playbooks/playbook-env-apply-10-validate.yml @@ -1,4 +1,20 @@ --- +# ============================================================================== +# Cloud Pak Deployer - Phase 10: Validation +# ============================================================================== +# This playbook is the FIRST phase of the deployment process. +# It validates all configurations before proceeding with actual deployment. +# +# Purpose: +# - Validate configuration files syntax and structure +# - Load and merge all configuration sources +# - Verify all required variables are present +# - Generate SSH keys for infrastructure provisioning +# - Check vault secrets and credentials +# +# This playbook does NOT install or modify anything - it only validates. +# ============================================================================== + - name: 10 - Validate hosts: localhost connection: local @@ -6,12 +22,19 @@ gather_facts: False vars: + # Suppress verbose Ansible callback messages for cleaner output ansible_callback_diy_runner_on_skipped_msg: "" ansible_callback_diy_runner_on_ok_msg: "" ansible_callback_diy_playbook_on_include_msg: "" tasks: + # ---------------------------------------------------------------------------- + # Pre-Validation Hook + # ---------------------------------------------------------------------------- + # Check if a custom pre-validation hook exists and execute it if present. + # This allows users to add custom validation logic before the standard checks. + # ---------------------------------------------------------------------------- - stat: path: "{{ config_dir }}/assets/deployer-hook-pre-10-validation.yml" register: _hook_pre_file @@ -19,20 +42,45 @@ - include_tasks: "{{ config_dir }}/assets/deployer-hook-pre-10-validation.yml" when: _hook_pre_file.stat.exists + # ---------------------------------------------------------------------------- + # Record Deployer State + # ---------------------------------------------------------------------------- + # Record that we're in phase 10 (Validation) for tracking and logging purposes. + # This helps with debugging and understanding where the deployment process is. + # ---------------------------------------------------------------------------- - name: Record deployer state include_role: name: record-deployer-state vars: - _p_state_interval: 10 + _p_state_interval: 10 # Phase 10 = Validation + # ---------------------------------------------------------------------------- + # Load Global Configuration + # ---------------------------------------------------------------------------- + # Load the global configuration file that contains environment-wide settings + # such as cloud platform, region, resource naming conventions, etc. + # ---------------------------------------------------------------------------- - name: Load global config include_role: name: load-global-config + # ---------------------------------------------------------------------------- + # Load Vault Configuration + # ---------------------------------------------------------------------------- + # Load vault configuration to access secrets and credentials. + # The vault stores sensitive information like API keys, passwords, etc. + # ---------------------------------------------------------------------------- - name: Load vault config include_role: name: load-vault-config + # ---------------------------------------------------------------------------- + # Set Secret Group + # ---------------------------------------------------------------------------- + # Determine which secret group to use for this deployment. + # If secret_group_param is provided, use it; otherwise default to environment_name. + # Secret groups organize related secrets together (e.g., dev, test, prod). + # ---------------------------------------------------------------------------- - set_fact: secret_group: "{{ secret_group_param }}" @@ -40,12 +88,30 @@ secret_group: "{{ environment_name }}" when: secret_group_param | default("") == "" + # ---------------------------------------------------------------------------- + # Merge Configuration + # ---------------------------------------------------------------------------- + # Merge all configuration sources into a unified configuration object. + # This combines: + # - Global config + # - Environment-specific config + # - Cloud platform config + # - Cloud Pak config + # Result is stored in 'all_config' variable for use in subsequent phases. + # ---------------------------------------------------------------------------- - name: Merge configuration include_role: name: merge-config vars: path_to_config_dir: "{{ config_dir }}" + # ---------------------------------------------------------------------------- + # Set Vault Secrets (Optional) + # ---------------------------------------------------------------------------- + # If VAULT_SECRETS environment variable is set, store those secrets in vault. + # This allows passing secrets via environment variables for CI/CD pipelines. + # Format: VAULT_SECRETS='{"key1":"value1","key2":"value2"}' + # ---------------------------------------------------------------------------- - set_fact: _vault_secrets: "{{ lookup('ansible.builtin.env', 'VAULT_SECRETS') }}" @@ -56,6 +122,16 @@ _p_vault_secrets: "{{ _vault_secrets }}" when: _vault_secrets != "" + # ---------------------------------------------------------------------------- + # Generate SSH Key Pairs + # ---------------------------------------------------------------------------- + # Generate SSH key pairs for infrastructure provisioning. + # Required for: + # - vSphere: SSH access to VMs + # - AWS: SSH access to EC2 instances + # One key pair is generated per OpenShift cluster defined in configuration. + # Keys are stored in vault for secure access during provisioning. + # ---------------------------------------------------------------------------- - name: Generate SSH key pair include_role: name: ssh-keygen @@ -64,12 +140,46 @@ loop_var: _current_openshift_cluster when: cloud_platform == 'vsphere' or cloud_platform == 'aws' + # ---------------------------------------------------------------------------- + # Validate Variables + # ---------------------------------------------------------------------------- + # Validate all configuration variables: + # - Check required variables are present + # - Verify variable types and formats + # - Validate value ranges and constraints + # - Check for conflicting settings + # If validation fails, deployment stops here with clear error messages. + # ---------------------------------------------------------------------------- - name: Validate variables include_role: name: validate-variables + # ---------------------------------------------------------------------------- + # Lint Configuration + # ---------------------------------------------------------------------------- + # Perform configuration linting to check: + # - YAML syntax correctness + # - Configuration structure compliance + # - Cross-reference validation (e.g., referenced objects exist) + # - Best practices adherence + # Uses automation generators to validate against expected schemas. + # ---------------------------------------------------------------------------- - name: Lint configuration include_role: name: lint-config vars: - path_to_generators_dir: "{{ generators_dir | default([(playbook_dir | dirname),'/automation-generators'] | join) }}" \ No newline at end of file + path_to_generators_dir: "{{ generators_dir | default([(playbook_dir | dirname),'/automation-generators'] | join) }}" + +# ============================================================================== +# End of Validation Phase +# ============================================================================== +# If this playbook completes successfully, the configuration is valid and +# deployment can proceed to the next phases: +# - Phase 20: Prepare +# - Phase 30: Provision Infrastructure +# - Phase 40: Configure Infrastructure +# - Phase 50: Install Cloud Pak +# - Phase 60: Configure Cloud Pak +# - Phase 70: Deploy Assets +# - Phase 80: Smoke Tests +# ============================================================================== \ No newline at end of file diff --git a/scripts/cp4d/cp4d-delete-instance.sh b/scripts/cp4d/cp4d-delete-instance.sh index 859af31b6..393e03eda 100755 --- a/scripts/cp4d/cp4d-delete-instance.sh +++ b/scripts/cp4d/cp4d-delete-instance.sh @@ -2,26 +2,232 @@ SCRIPT_DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd ) command_usage() { - echo - echo "Usage:" - echo "$(basename $0) " - echo "$(basename $0) -n [--operator-ns ] [--force-finalizer] [--timeout ] [--parallel]" - echo - echo "Options:" - echo " --force-finalizer Force removal of finalizers using OpenShift REST API for stuck namespaces" - echo " --timeout Timeout in seconds for namespace deletion (default: 900)" - echo " --parallel Delete multiple namespaces in parallel for faster execution" - echo + cat << EOF + +Cloud Pak for Data Instance Deletion Script +============================================ + +This script deletes a Cloud Pak for Data instance and all related resources from an OpenShift cluster. + +USAGE: + $(basename $0) # Auto-discover and delete (with confirmation) + $(basename $0) --dry-run # Show what would be deleted (safe test mode) + $(basename $0) # Delete specific instance + $(basename $0) -n [OPTIONS] # Delete with options + +MODES: + Auto-Discovery Mode (Recommended): + $(basename $0) + - Automatically discovers CP4D namespaces by finding ZenService resources + - Shows detailed summary of what will be deleted + - Asks for confirmation before proceeding + - Safe: requires explicit 'y' to proceed + + Dry-Run Mode (Testing): + $(basename $0) --dry-run + - Discovers and displays all CP4D namespaces and resources + - Does NOT delete anything + - Perfect for testing discovery or understanding your installation + + Manual Mode (Traditional): + $(basename $0) cpd + $(basename $0) -n cpd --operator-ns cpd-operators + - Specify namespaces explicitly + - Useful when auto-discovery fails or for specific configurations + +OPTIONS: + -n, --instance-namespace Instance namespace (e.g., cpd, zen) + --operator-ns Operator namespace (default: -operators) + --auto-discover Force auto-discovery mode + --dry-run Show what would be deleted without deleting + --parallel Delete multiple namespaces in parallel (faster) + --force-finalizer Force removal of stuck finalizers via API + --timeout Namespace deletion timeout (default: 900) + -h, --help Show this help message + +WHAT GETS DELETED: + • Instance namespace (e.g., cpd) - Contains ZenService and cartridges + • Operator namespace (e.g., cpd-operators) - Contains operators and CSVs + • Supporting services: scheduler, licensing, cert-manager + • Knative services: eventing, serving, app-connect + • Cluster-wide: IBM CRDs, webhooks, common-service maps + +EXAMPLES: + # Test what would be deleted (safe) + $(basename $0) --dry-run + + # Delete with auto-discovery (recommended) + $(basename $0) + + # Delete specific instance + $(basename $0) -n my-cpd-instance + + # Fast parallel deletion with forced cleanup + $(basename $0) --parallel --force-finalizer + + # Automated deletion (CI/CD - skips confirmations) + export CPD_CONFIRM_DELETE=true + $(basename $0) + +ENVIRONMENT VARIABLES: + CPD_CONFIRM_DELETE Set to 'true' to skip confirmation prompts + CPD_DESTROY_CLUSTER_WIDE Set to 'false' to keep cluster-wide resources + PROJECT_SCHEDULING_SERVICE Override scheduler namespace (default: cpd-scheduler) + +EOF exit $1 } +# Color codes for output +COLOR_RED='\033[0;31m' +COLOR_GREEN='\033[0;32m' +COLOR_YELLOW='\033[1;33m' +COLOR_BLUE='\033[0;34m' +COLOR_CYAN='\033[0;36m' +COLOR_RESET='\033[0m' + +get_logtime() { + echo $(date "+%Y-%m-%d %H:%M:%S") +} + +log() { + LOG_TIME=$(get_logtime) + printf "[${LOG_TIME}] ${1}\n" +} + +log_success() { + LOG_TIME=$(get_logtime) + printf "${COLOR_GREEN}✓ [${LOG_TIME}] ${1}${COLOR_RESET}\n" +} + +log_error() { + LOG_TIME=$(get_logtime) + printf "${COLOR_RED}✗ [${LOG_TIME}] ${1}${COLOR_RESET}\n" +} + +log_warning() { + LOG_TIME=$(get_logtime) + printf "${COLOR_YELLOW}⚠ [${LOG_TIME}] ${1}${COLOR_RESET}\n" +} + +log_info() { + LOG_TIME=$(get_logtime) + printf "${COLOR_CYAN}ℹ [${LOG_TIME}] ${1}${COLOR_RESET}\n" +} + +# +# AUTO-DISCOVERY FUNCTIONS +# +discover_cp4d_namespaces() { + log_info "Auto-discovering Cloud Pak for Data namespaces..." + + # Discover instance namespace by looking for ZenService CR + local discovered_instance_ns=$(oc get zenservice --all-namespaces --no-headers 2>/dev/null | head -1 | awk '{print $1}') + + if [ -z "$discovered_instance_ns" ]; then + log_warning "Could not auto-discover instance namespace (no ZenService found)" + return 1 + fi + + log_success "Discovered instance namespace: ${discovered_instance_ns}" + export INSTANCE_NS="${discovered_instance_ns}" + + # Try to discover operator namespace + # Common patterns: -operators, cpd-operators, ibm-cpd-operators + local possible_operator_ns=( + "${INSTANCE_NS}-operators" + "cpd-operators" + "ibm-cpd-operators" + "${INSTANCE_NS}-operator" + ) + + for ns in "${possible_operator_ns[@]}"; do + if oc get project "${ns}" > /dev/null 2>&1; then + # Verify it has CP4D operators + if oc get csv -n "${ns}" --no-headers 2>/dev/null | grep -q "ibm-cpd-platform-operator\|ibm-common-service-operator"; then + log_success "Discovered operator namespace: ${ns}" + export OPERATOR_NS="${ns}" + break + fi + fi + done + + if [ -z "$OPERATOR_NS" ]; then + log_warning "Could not auto-discover operator namespace, using default: ${INSTANCE_NS}-operators" + export OPERATOR_NS="${INSTANCE_NS}-operators" + fi + + # Discover scheduler namespace + local scheduler_ns=$(oc get scheduling --all-namespaces --no-headers 2>/dev/null | head -1 | awk '{print $1}') + if [ -n "$scheduler_ns" ]; then + log_success "Discovered scheduler namespace: ${scheduler_ns}" + export PROJECT_SCHEDULING_SERVICE="${scheduler_ns}" + else + # Try to find namespace containing "scheduler" but exclude OpenShift system namespaces + scheduler_ns=$(oc get projects --no-headers 2>/dev/null | awk '{print $1}' | grep -i "scheduler" | grep -v "^openshift-" | grep -i "cpd\|ibm" | head -1) + if [ -n "$scheduler_ns" ]; then + log_success "Discovered scheduler namespace by pattern: ${scheduler_ns}" + export PROJECT_SCHEDULING_SERVICE="${scheduler_ns}" + else + log_info "No CP4D scheduler namespace found (scheduler not installed or using default OpenShift scheduler)" + fi + fi + + # Discover cert-manager namespace - try exact names first, then pattern matching + if oc get project cert-manager > /dev/null 2>&1; then + export PROJECT_CERT_MANAGER="cert-manager" + log_success "Discovered cert-manager namespace: cert-manager" + elif oc get project ibm-cert-manager > /dev/null 2>&1; then + export PROJECT_CERT_MANAGER="ibm-cert-manager" + log_success "Discovered cert-manager namespace: ibm-cert-manager" + else + # Try pattern matching: look for namespaces containing both "cert" and "manager" or just "cert" with "ibm" + local cert_ns=$(oc get projects --no-headers 2>/dev/null | awk '{print $1}' | grep -i "cert" | grep -iE "manager|ibm" | head -1) + if [ -n "$cert_ns" ]; then + export PROJECT_CERT_MANAGER="${cert_ns}" + log_success "Discovered cert-manager namespace by pattern: ${cert_ns}" + fi + fi + + # Discover licensing namespace - try exact name first, then pattern matching + if oc get project ibm-licensing > /dev/null 2>&1; then + export PROJECT_LICENSE_SERVICE="ibm-licensing" + log_success "Discovered licensing namespace: ibm-licensing" + else + # Try pattern matching: look for namespaces containing "licensing" or "license" with "ibm" + local license_ns=$(oc get projects --no-headers 2>/dev/null | awk '{print $1}' | grep -iE "licens" | grep -i "ibm" | head -1) + if [ -z "$license_ns" ]; then + # Try just "licensing" or "license" without ibm requirement + license_ns=$(oc get projects --no-headers 2>/dev/null | awk '{print $1}' | grep -iE "licens" | head -1) + fi + if [ -n "$license_ns" ]; then + export PROJECT_LICENSE_SERVICE="${license_ns}" + log_success "Discovered licensing namespace by pattern: ${license_ns}" + fi + fi + + return 0 +} + +display_discovered_namespaces() { + echo + echo "=== Discovered Cloud Pak for Data Configuration ===" + echo "Instance namespace: ${INSTANCE_NS:-}" + echo "Operator namespace: ${OPERATOR_NS:-}" + echo "Scheduler namespace: ${PROJECT_SCHEDULING_SERVICE:-}" + echo "Cert-manager: ${PROJECT_CERT_MANAGER:-}" + echo "Licensing: ${PROJECT_LICENSE_SERVICE:-}" + echo "==================================================" + echo +} + # # PARSE # -if [ "$#" -lt 1 ]; then - echo "Error: Missing namespace argument." - command_usage 2 -elif [ "$#" -eq 1 ];then +if [ "$#" -eq 0 ]; then + # No arguments provided, try auto-discovery + export AUTO_DISCOVER=true +elif [ "$#" -eq 1 ] && [ "$1" != "--help" ] && [ "$1" != "-h" ];then export INSTANCE_NS=$1 export OPERATOR_NS="${INSTANCE_NS}-operators" else @@ -81,6 +287,14 @@ else export PARALLEL_DELETE=true shift 1 ;; + --auto-discover) + export AUTO_DISCOVER=true + shift 1 + ;; + --dry-run) + export DRY_RUN=true + shift 1 + ;; *) # preserve remaining arguments PARAMS="$PARAMS $1" shift @@ -89,42 +303,44 @@ else done fi -# Color codes for output -COLOR_RED='\033[0;31m' -COLOR_GREEN='\033[0;32m' -COLOR_YELLOW='\033[1;33m' -COLOR_BLUE='\033[0;34m' -COLOR_CYAN='\033[0;36m' -COLOR_RESET='\033[0m' - -get_logtime() { - echo $(date "+%Y-%m-%d %H:%M:%S") -} - -log() { - LOG_TIME=$(get_logtime) - printf "[${LOG_TIME}] ${1}\n" -} - -log_success() { - LOG_TIME=$(get_logtime) - printf "${COLOR_GREEN}✓ [${LOG_TIME}] ${1}${COLOR_RESET}\n" -} - -log_error() { - LOG_TIME=$(get_logtime) - printf "${COLOR_RED}✗ [${LOG_TIME}] ${1}${COLOR_RESET}\n" -} - -log_warning() { - LOG_TIME=$(get_logtime) - printf "${COLOR_YELLOW}⚠ [${LOG_TIME}] ${1}${COLOR_RESET}\n" -} +# Auto-discover namespaces if requested or if no instance namespace provided +if [ "${AUTO_DISCOVER}" = "true" ] || [ -z "${INSTANCE_NS}" ]; then + if [ "${AUTO_DISCOVER}" = "true" ]; then + log_info "Auto-discovery mode enabled" + else + log_info "No instance namespace provided, attempting auto-discovery..." + fi + + if discover_cp4d_namespaces; then + display_discovered_namespaces + # Note: Final confirmation will be asked before deletion with full summary + else + log_error "Auto-discovery failed - no Cloud Pak for Data instance found in the cluster" + echo + echo "Possible reasons:" + echo " 1. No CP4D instance is installed (no ZenService found)" + echo " 2. You don't have permissions to view resources across namespaces" + echo " 3. The CP4D instance is in a non-standard configuration" + echo + echo "Solutions:" + echo " • If you know the instance namespace, specify it manually:" + echo " $(basename $0) -n " + echo + echo " • To see all available namespaces:" + echo " oc get projects" + echo + echo " • To check for ZenService resources:" + echo " oc get zenservice --all-namespaces" + echo + exit 1 + fi +fi -log_info() { - LOG_TIME=$(get_logtime) - printf "${COLOR_CYAN}ℹ [${LOG_TIME}] ${1}${COLOR_RESET}\n" -} +# Ensure OPERATOR_NS is set if INSTANCE_NS is set +if [ -n "${INSTANCE_NS}" ] && [ -z "${OPERATOR_NS}" ]; then + export OPERATOR_NS="${INSTANCE_NS}-operators" + log_info "Operator namespace not specified, using default: ${OPERATOR_NS}" +fi wait_ns_deleted() { NS=$1 @@ -657,25 +873,187 @@ delete_ibm_crds() { # MAIN CODE # +# DRY RUN MODE - Just show what would be deleted and exit +if [ "${DRY_RUN}" = "true" ]; then + log_info "=== DRY RUN MODE - Discovery Only ===" + echo + echo "The following namespaces and resources would be deleted:" + echo + if oc get project ${INSTANCE_NS} > /dev/null 2>&1;then + echo "✓ Instance namespace: ${INSTANCE_NS}" + echo " Resources: $(oc get zenservice -n ${INSTANCE_NS} --no-headers 2>/dev/null | wc -l) ZenService(s)" + else + echo "✗ Instance namespace: ${INSTANCE_NS} (not found)" + fi + + if oc get project ${OPERATOR_NS} > /dev/null 2>&1;then + echo "✓ Operator namespace: ${OPERATOR_NS}" + echo " Operators: $(oc get csv -n ${OPERATOR_NS} --no-headers 2>/dev/null | wc -l) CSV(s)" + else + echo "✗ Operator namespace: ${OPERATOR_NS} (not found)" + fi + + if oc get project ibm-app-connect > /dev/null 2>&1;then + echo "✓ App Connect namespace: ibm-app-connect" + fi + + if oc get project ibm-knative-events > /dev/null 2>&1;then + echo "✓ Knative events namespace: ibm-knative-events" + fi + + if oc get project knative-eventing > /dev/null 2>&1;then + echo "✓ Knative eventing namespace: knative-eventing" + fi + + if oc get project knative-serving > /dev/null 2>&1;then + echo "✓ Knative serving namespace: knative-serving" + fi + + if oc get project ibm-licensing > /dev/null 2>&1;then + echo "✓ License manager namespace: ibm-licensing" + fi + + if oc get project ${PROJECT_SCHEDULING_SERVICE:-cpd-scheduler} > /dev/null 2>&1;then + echo "✓ Scheduler namespace: ${PROJECT_SCHEDULING_SERVICE:-cpd-scheduler}" + fi + + if oc get project ibm-cert-manager > /dev/null 2>&1;then + echo "✓ Certificate manager namespace: ibm-cert-manager" + fi + + if oc get project cert-manager > /dev/null 2>&1;then + echo "✓ Certificate manager namespace: cert-manager" + fi + + if oc get project cs-control > /dev/null 2>&1;then + echo "✓ Common Services control namespace: cs-control" + fi + + echo + echo "Cluster-wide resources:" + echo " - MutatingWebhookConfigurations (IBM)" + echo " - ValidatingWebhookConfigurations (IBM)" + echo " - IBM Custom Resource Definitions" + + local ibm_crds=$(oc get crd --no-headers 2>/dev/null | awk '{print $1}' | grep -E '\.ibm|mantaflows\.adl' | wc -l) + echo " - Total IBM CRDs: ${ibm_crds}" + + echo + log_success "DRY RUN complete - no resources were deleted" + echo + echo "To actually delete these resources, run without --dry-run flag" + exit 0 +fi + # Ask for final confirmation to delete the CP4D instance if [ -z "${CPD_CONFIRM_DELETE}" ];then - echo "About to delete the following from the cluster:" - if oc get project ${INSTANCE_NS} > /dev/null 2>&1;then echo "- Instance namespace: ${INSTANCE_NS}";fi - if oc get project ${OPERATOR_NS} > /dev/null 2>&1;then echo "- Operator namespace: ${OPERATOR_NS}";fi - if oc get project ibm-app-connect > /dev/null 2>&1;then echo "- Knative events: ibm-app-connect";fi - if oc get project ibm-knative-events > /dev/null 2>&1;then echo "- Knative events: ibm-knative-events";fi - if oc get project knative-serving > /dev/null 2>&1;then echo "- Knative server: knative-serving";fi - if oc get project ibm-licensing > /dev/null 2>&1;then echo "- License manager namespace: ibm-licensing";fi - if oc get project ${PROJECT_SCHEDULING_SERVICE:-cpd-scheduler} > /dev/null 2>&1;then echo "- Scheduler namespace: ${PROJECT_SCHEDULING_SERVICE:-cpd-scheduler}";fi - if oc get project ibm-cert-manager > /dev/null 2>&1;then echo "- Certificate manager: ibm-cert-manager";fi - if oc get project cs-control > /dev/null 2>&1;then echo "- Common Services control: cs-control";fi - echo "- IBM Custom Resource Definitions" - read -p "Are you sure (y/N)? " -r - case "${REPLY}" in + echo + echo "==========================================" + echo " CLOUD PAK FOR DATA DELETION SUMMARY" + echo "==========================================" + echo + echo "The following namespaces will be DELETED:" + echo + + # Core CP4D namespaces + echo "📦 CORE CP4D NAMESPACES:" + if oc get project ${INSTANCE_NS} > /dev/null 2>&1;then + zenservices=$(oc get zenservice -n ${INSTANCE_NS} --no-headers 2>/dev/null | wc -l) + echo " ✓ ${INSTANCE_NS} (Instance - ${zenservices} ZenService(s))" + else + echo " ✗ ${INSTANCE_NS} (not found)" + fi + + if oc get project ${OPERATOR_NS} > /dev/null 2>&1;then + csvs=$(oc get csv -n ${OPERATOR_NS} --no-headers 2>/dev/null | wc -l) + echo " ✓ ${OPERATOR_NS} (Operators - ${csvs} CSV(s))" + else + echo " ✗ ${OPERATOR_NS} (not found)" + fi + + # Supporting services + echo + echo "🔧 SUPPORTING SERVICES:" + found_services=false + + if oc get project ${PROJECT_SCHEDULING_SERVICE:-cpd-scheduler} > /dev/null 2>&1;then + echo " ✓ ${PROJECT_SCHEDULING_SERVICE:-cpd-scheduler} (Scheduler)" + found_services=true + fi + + if oc get project ibm-licensing > /dev/null 2>&1;then + echo " ✓ ibm-licensing (License Manager)" + found_services=true + fi + + if oc get project ibm-cert-manager > /dev/null 2>&1;then + echo " ✓ ibm-cert-manager (Certificate Manager)" + found_services=true + elif oc get project cert-manager > /dev/null 2>&1;then + echo " ✓ cert-manager (Certificate Manager)" + found_services=true + fi + + if oc get project cs-control > /dev/null 2>&1;then + echo " ✓ cs-control (Common Services Control)" + found_services=true + fi + + if [ "$found_services" = false ]; then + echo " (none found)" + fi + + # Knative services + echo + echo "🌐 KNATIVE SERVICES:" + found_knative=false + + if oc get project ibm-app-connect > /dev/null 2>&1;then + echo " ✓ ibm-app-connect" + found_knative=true + fi + + if oc get project ibm-knative-events > /dev/null 2>&1;then + echo " ✓ ibm-knative-events" + found_knative=true + fi + + if oc get project knative-eventing > /dev/null 2>&1;then + echo " ✓ knative-eventing" + found_knative=true + fi + + if oc get project knative-serving > /dev/null 2>&1;then + echo " ✓ knative-serving" + found_knative=true + fi + + if [ "$found_knative" = false ]; then + echo " (none found)" + fi + + # Cluster-wide resources + echo + echo "🌍 CLUSTER-WIDE RESOURCES:" + ibm_crds=$(oc get crd --no-headers 2>/dev/null | awk '{print $1}' | grep -E '\.ibm|mantaflows\.adl' | wc -l) + echo " ✓ IBM Custom Resource Definitions (${ibm_crds} CRDs)" + echo " ✓ MutatingWebhookConfigurations (IBM)" + echo " ✓ ValidatingWebhookConfigurations (IBM)" + + echo + echo "==========================================" + echo + log_warning "This operation is IRREVERSIBLE!" + echo + read -p "Are you absolutely sure you want to DELETE all these resources? (y/N): " -r + case "${REPLY}" in y|Y) + log_success "Deletion confirmed. Proceeding..." + echo ;; * ) - exit 99 + log_info "Deletion cancelled by user" + exit 99 ;; esac fi From 4bc30344d8a38da4f20b55956456ef24a296a97b Mon Sep 17 00:00:00 2001 From: Luigi Molinaro Date: Fri, 13 Mar 2026 09:18:04 +0100 Subject: [PATCH 7/8] Enhanced cp4d-delete-instance.sh with auto-discovery and improved UX Major improvements: - Auto-discovery of CP4D namespaces by finding ZenService resources - Flexible pattern matching for namespace variants (licensing, cert-manager, scheduler) - --dry-run mode for safe testing without deletion - Enhanced confirmation summary with detailed resource counts - Improved help documentation with comprehensive usage examples - Fixed argument parsing to properly handle flags like --dry-run - Fixed variable scope issues (removed invalid 'local' declarations) - Smart namespace detection excludes OpenShift system namespaces - No default assumptions for optional namespaces (scheduler, cert-manager, licensing) - Single confirmation prompt with comprehensive deletion summary - Better error messages when auto-discovery fails The script now provides a much safer and user-friendly experience for deleting CP4D instances. --- scripts/cp4d/cp4d-delete-instance.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/scripts/cp4d/cp4d-delete-instance.sh b/scripts/cp4d/cp4d-delete-instance.sh index 393e03eda..1c5101099 100755 --- a/scripts/cp4d/cp4d-delete-instance.sh +++ b/scripts/cp4d/cp4d-delete-instance.sh @@ -227,7 +227,8 @@ display_discovered_namespaces() { if [ "$#" -eq 0 ]; then # No arguments provided, try auto-discovery export AUTO_DISCOVER=true -elif [ "$#" -eq 1 ] && [ "$1" != "--help" ] && [ "$1" != "-h" ];then +elif [ "$#" -eq 1 ] && [ "$1" != "--help" ] && [ "$1" != "-h" ] && [ "$1" != "--dry-run" ] && [ "$1" != "--auto-discover" ] && [ "$1" != "--parallel" ];then + # Single argument that's not a flag - treat as instance namespace export INSTANCE_NS=$1 export OPERATOR_NS="${INSTANCE_NS}-operators" else From dc2969b60f71370c0727d1708a1608aaeae0b37d Mon Sep 17 00:00:00 2001 From: Luigi Molinaro Date: Fri, 13 Mar 2026 09:48:16 +0100 Subject: [PATCH 8/8] Simplified help text for better readability --- scripts/cp4d/cp4d-delete-instance.sh | 80 +++++++++------------------- 1 file changed, 25 insertions(+), 55 deletions(-) diff --git a/scripts/cp4d/cp4d-delete-instance.sh b/scripts/cp4d/cp4d-delete-instance.sh index 1c5101099..5c2371cd7 100755 --- a/scripts/cp4d/cp4d-delete-instance.sh +++ b/scripts/cp4d/cp4d-delete-instance.sh @@ -7,72 +7,42 @@ command_usage() { Cloud Pak for Data Instance Deletion Script ============================================ -This script deletes a Cloud Pak for Data instance and all related resources from an OpenShift cluster. - USAGE: - $(basename $0) # Auto-discover and delete (with confirmation) - $(basename $0) --dry-run # Show what would be deleted (safe test mode) - $(basename $0) # Delete specific instance - $(basename $0) -n [OPTIONS] # Delete with options - -MODES: - Auto-Discovery Mode (Recommended): - $(basename $0) - - Automatically discovers CP4D namespaces by finding ZenService resources - - Shows detailed summary of what will be deleted - - Asks for confirmation before proceeding - - Safe: requires explicit 'y' to proceed - - Dry-Run Mode (Testing): - $(basename $0) --dry-run - - Discovers and displays all CP4D namespaces and resources - - Does NOT delete anything - - Perfect for testing discovery or understanding your installation - - Manual Mode (Traditional): - $(basename $0) cpd - $(basename $0) -n cpd --operator-ns cpd-operators - - Specify namespaces explicitly - - Useful when auto-discovery fails or for specific configurations - -OPTIONS: - -n, --instance-namespace Instance namespace (e.g., cpd, zen) - --operator-ns Operator namespace (default: -operators) - --auto-discover Force auto-discovery mode - --dry-run Show what would be deleted without deleting - --parallel Delete multiple namespaces in parallel (faster) - --force-finalizer Force removal of stuck finalizers via API - --timeout Namespace deletion timeout (default: 900) - -h, --help Show this help message - -WHAT GETS DELETED: - • Instance namespace (e.g., cpd) - Contains ZenService and cartridges - • Operator namespace (e.g., cpd-operators) - Contains operators and CSVs - • Supporting services: scheduler, licensing, cert-manager - • Knative services: eventing, serving, app-connect - • Cluster-wide: IBM CRDs, webhooks, common-service maps + $(basename $0) # Auto-discover and delete (recommended) + $(basename $0) --dry-run # Test mode - show what would be deleted + $(basename $0) # Delete specific instance + $(basename $0) -n [OPTIONS] # Delete with options + +COMMON OPTIONS: + --dry-run Show what would be deleted (safe, no changes) + --parallel Faster deletion using parallel processing + --force-finalizer Force cleanup of stuck resources + --timeout Deletion timeout (default: 900) + -h, --help Show this help EXAMPLES: - # Test what would be deleted (safe) + # Safe test - see what would be deleted $(basename $0) --dry-run - # Delete with auto-discovery (recommended) + # Delete with auto-discovery (asks for confirmation) $(basename $0) # Delete specific instance - $(basename $0) -n my-cpd-instance + $(basename $0) cpd - # Fast parallel deletion with forced cleanup + # Fast deletion with cleanup $(basename $0) --parallel --force-finalizer - # Automated deletion (CI/CD - skips confirmations) - export CPD_CONFIRM_DELETE=true - $(basename $0) - -ENVIRONMENT VARIABLES: - CPD_CONFIRM_DELETE Set to 'true' to skip confirmation prompts - CPD_DESTROY_CLUSTER_WIDE Set to 'false' to keep cluster-wide resources - PROJECT_SCHEDULING_SERVICE Override scheduler namespace (default: cpd-scheduler) +WHAT GETS DELETED: + • CP4D instance and operator namespaces + • Supporting services (scheduler, licensing, cert-manager) + • Knative services (if present) + • IBM CRDs and webhooks + +NOTES: + ⚠ This operation is IRREVERSIBLE + ✓ Always test with --dry-run first + ✓ Requires cluster-admin permissions EOF exit $1