Skip to content
Merged
55 changes: 46 additions & 9 deletions collection-scripts/gather_namespace-inspect
Original file line number Diff line number Diff line change
Expand Up @@ -77,12 +77,6 @@ else
# Combine and deduplicate
all_namespaces=$(echo -e "${helm_namespaces}\n${standalone_namespaces}\n${cr_namespaces}\n${operator_namespaces}" | grep -v '^$' | sort | uniq || echo "")

if [[ -z "$all_namespaces" ]]; then
log_warn "No RHDH deployments found in cluster"
echo "No RHDH namespaces detected" > "$inspect_dir/no-namespaces.txt"
exit 0
fi

# Convert to array
while IFS= read -r ns; do
[[ -n "$ns" ]] && namespaces_to_inspect+=("$ns")
Expand All @@ -94,10 +88,53 @@ else
fi
fi

# Trim whitespace from namespace names
for i in "${!namespaces_to_inspect[@]}"; do
namespaces_to_inspect[$i]=$(echo "${namespaces_to_inspect[$i]}" | xargs)
# Add orchestrator-related namespaces when auto-detecting (not when user specifies --namespaces)
if [[ -z "${RHDH_TARGET_NAMESPACES:-}" ]]; then
orch_ns_file="$BASE_COLLECTION_PATH/orchestrator/detected-namespaces.txt"
if [[ -s "$orch_ns_file" ]]; then
log_info "Adding orchestrator-related namespaces to inspection..."
while IFS= read -r orch_ns; do
orch_ns=$(echo "$orch_ns" | xargs)
[[ -z "$orch_ns" ]] && continue
already_included=false
for existing_ns in "${namespaces_to_inspect[@]:-}"; do
existing_ns=$(echo "$existing_ns" | xargs)
if [[ "$existing_ns" == "$orch_ns" ]]; then
already_included=true
break
fi
done
if [[ "$already_included" != "true" ]]; then
namespaces_to_inspect+=("$orch_ns")
log_info "Added orchestrator namespace: $orch_ns"
fi
done < "$orch_ns_file"
fi
fi

if [[ ${#namespaces_to_inspect[@]} -eq 0 ]]; then
log_warn "No RHDH deployments or orchestrator components found in cluster"
echo "No namespaces detected" > "$inspect_dir/no-namespaces.txt"
exit 0
fi

# Trim whitespace, remove empty entries, and deduplicate
declare -a cleaned_namespaces=()
for ns in "${namespaces_to_inspect[@]}"; do
ns=$(echo "$ns" | xargs)
[[ -z "$ns" ]] && continue
already_present=false
for existing in "${cleaned_namespaces[@]:-}"; do
if [[ "$existing" == "$ns" ]]; then
already_present=true
break
fi
done
if [[ "$already_present" != "true" ]]; then
cleaned_namespaces+=("$ns")
fi
done
namespaces_to_inspect=("${cleaned_namespaces[@]:-}")

log_info "Found ${#namespaces_to_inspect[@]} namespace(s) to inspect: ${namespaces_to_inspect[*]}"

Expand Down
19 changes: 19 additions & 0 deletions collection-scripts/gather_orchestrator
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ ensure_directory "$orchestrator_dir"
# Flag to track if any Orchestrator components were found
orchestrator_detected=false

# File to track orchestrator-related namespaces for gather_namespace-inspect
# Created lazily on first write; gather_namespace-inspect uses [[ -s file ]] so absence is fine
ORCH_NAMESPACES_FILE="$orchestrator_dir/detected-namespaces.txt"

# ============================================================================
# Serverless Operators Detection and Collection
# ============================================================================
Expand All @@ -33,6 +37,7 @@ function gather_serverless_operators() {
if $KUBECTL_CMD get namespace "$serverless_ns" >/dev/null 2>&1; then
log_info "\tFound OpenShift Serverless namespace: $serverless_ns"
orchestrator_detected=true
echo "$serverless_ns" >> "$ORCH_NAMESPACES_FILE"

local serverless_ns_dir="$serverless_dir/ns=$serverless_ns"
ensure_directory "$serverless_ns_dir"
Expand Down Expand Up @@ -72,6 +77,7 @@ function gather_serverless_operators() {
if $KUBECTL_CMD get namespace "$logic_ns" >/dev/null 2>&1; then
log_info "\tFound OpenShift Serverless Logic namespace: $logic_ns"
orchestrator_detected=true
echo "$logic_ns" >> "$ORCH_NAMESPACES_FILE"

local logic_ns_dir="$serverless_dir/ns=$logic_ns"
ensure_directory "$logic_ns_dir"
Expand Down Expand Up @@ -194,6 +200,8 @@ function gather_sonataflow_platforms() {
sfp_name=$(echo "$sfp_info" | cut -d'/' -f2)
fi

[[ -n "$sfp_ns" ]] && echo "$sfp_ns" >> "$ORCH_NAMESPACES_FILE"

log_info "--> Processing SonataFlowPlatform $sfp_name in namespace $sfp_ns"

local sfp_cr_dir="$sfp_dir/ns=$sfp_ns/$sfp_name"
Expand Down Expand Up @@ -264,6 +272,8 @@ function gather_sonataflow_workflows() {
wf_name=$(echo "$wf_info" | cut -d'/' -f2)
fi

[[ -n "$wf_ns" ]] && echo "$wf_ns" >> "$ORCH_NAMESPACES_FILE"

local ns_dir="$sfw_dir/ns=$wf_ns"

# Collect per-namespace workflow list once
Expand Down Expand Up @@ -320,6 +330,7 @@ function gather_knative_resources() {
# Check knative-serving namespace for resources
if $KUBECTL_CMD get namespace knative-serving >/dev/null 2>&1; then
orchestrator_detected=true
echo "knative-serving" >> "$ORCH_NAMESPACES_FILE"
local serving_dir="$knative_dir/knative-serving"
ensure_directory "$serving_dir"

Expand All @@ -337,6 +348,7 @@ function gather_knative_resources() {
# Check knative-eventing namespace for resources
if $KUBECTL_CMD get namespace knative-eventing >/dev/null 2>&1; then
orchestrator_detected=true
echo "knative-eventing" >> "$ORCH_NAMESPACES_FILE"
local eventing_dir="$knative_dir/knative-eventing"
ensure_directory "$eventing_dir"

Expand Down Expand Up @@ -422,6 +434,13 @@ gather_orchestrator_crds
gather_sonataflow_platforms
gather_sonataflow_workflows
gather_knative_resources

# Deduplicate the detected namespaces file
if [[ -s "$ORCH_NAMESPACES_FILE" ]]; then
sort -u -o "$ORCH_NAMESPACES_FILE" "$ORCH_NAMESPACES_FILE"
log_info "Orchestrator namespaces for namespace-inspect: $(tr '\n' ',' < "$ORCH_NAMESPACES_FILE" | sed 's/,$//')"
fi

generate_orchestrator_summary

if [[ "$orchestrator_detected" == "true" ]]; then
Expand Down
217 changes: 217 additions & 0 deletions tests/namespace-inspect.bats
Original file line number Diff line number Diff line change
@@ -0,0 +1,217 @@
#!/usr/bin/env bats
# Tests for gather_namespace-inspect script

load 'test_helper'

setup() {
setup_test_environment
export BASE_COLLECTION_PATH="${TEST_TMPDIR}"

# Create a mock bin directory and prepend it to PATH
export MOCK_BIN="${TEST_TMPDIR}/mock-bin"
mkdir -p "$MOCK_BIN"

# File where mock oc captures inspect arguments
export OC_INSPECT_ARGS="${TEST_TMPDIR}/oc-inspect-args.txt"

# Mock oc: captures "adm inspect" args, no-ops everything else
cat > "$MOCK_BIN/oc" << 'MOCK_OC'
#!/usr/bin/env bash
if [[ "${1:-}" == "adm" && "${2:-}" == "inspect" ]]; then
shift 2
echo "$@" > "$OC_INSPECT_ARGS"
exit 0
fi
if [[ "${1:-}" == "version" ]]; then
echo "Client Version: v4.15.0"
exit 0
fi
echo ""
exit 0
MOCK_OC
chmod +x "$MOCK_BIN/oc"

# Mock kubectl: returns empty results for all queries
# Distinguishes "-o json" (needs valid JSON for jq) from "-o jsonpath=..." (needs empty string)
cat > "$MOCK_BIN/kubectl" << 'MOCK_KUBECTL'
#!/usr/bin/env bash
if [[ "${1:-}" == "version" ]]; then
echo "Client Version: v1.30.0"
exit 0
fi
for arg in "$@"; do
case "$arg" in
json) echo '{"items":[]}'; exit 0 ;;
jsonpath=*) exit 0 ;;
esac
done
exit 0
MOCK_KUBECTL
chmod +x "$MOCK_BIN/kubectl"

# Mock helm: returns empty JSON array
cat > "$MOCK_BIN/helm" << 'MOCK_HELM'
#!/usr/bin/env bash
echo "[]"
exit 0
MOCK_HELM
chmod +x "$MOCK_BIN/helm"

# Mock jq: use real jq if available, otherwise provide minimal stub
if command -v jq &>/dev/null; then
ln -sf "$(command -v jq)" "$MOCK_BIN/jq"
else
cat > "$MOCK_BIN/jq" << 'MOCK_JQ'
#!/usr/bin/env bash
echo ""
exit 0
MOCK_JQ
chmod +x "$MOCK_BIN/jq"
fi

export PATH="$MOCK_BIN:$PATH"
export KUBECTL_CMD="kubectl"
}

teardown() {
teardown_test_environment
}

# ============================================================================
# Script existence and basic tests
# ============================================================================

@test "gather_namespace-inspect script exists" {
[ -f "${SCRIPTS_DIR}/gather_namespace-inspect" ]
}

@test "gather_namespace-inspect script is executable" {
[ -x "${SCRIPTS_DIR}/gather_namespace-inspect" ]
}

@test "gather_namespace-inspect sources common.sh" {
run grep -q "source.*common.sh" "${SCRIPTS_DIR}/gather_namespace-inspect"
[ "$status" -eq 0 ]
}

# ============================================================================
# Orchestrator namespace integration tests (runtime behavior)
# ============================================================================

@test "gather_namespace-inspect auto-detect deduplicates orchestrator namespaces with whitespace variants" {
mkdir -p "$BASE_COLLECTION_PATH/orchestrator"
# Write duplicates, whitespace variants, and blank lines
cat > "$BASE_COLLECTION_PATH/orchestrator/detected-namespaces.txt" << 'EOF'
orch-ns1
orch-ns1
orch-ns2

orch-ns2
orch-ns1
EOF

run "${SCRIPTS_DIR}/gather_namespace-inspect"
[ "$status" -eq 0 ]

# oc adm inspect should have been called
[ -f "$OC_INSPECT_ARGS" ]

# Each namespace should appear exactly once
local args
args=$(cat "$OC_INSPECT_ARGS")
local count_ns1 count_ns2
count_ns1=$(echo "$args" | grep -o 'namespace/orch-ns1' | wc -l)
count_ns2=$(echo "$args" | grep -o 'namespace/orch-ns2' | wc -l)
[ "$count_ns1" -eq 1 ]
[ "$count_ns2" -eq 1 ]
}

@test "gather_namespace-inspect explicit namespaces mode ignores orchestrator namespaces" {
export RHDH_TARGET_NAMESPACES="explicit-ns1,explicit-ns2"

mkdir -p "$BASE_COLLECTION_PATH/orchestrator"
echo "orch-ns1" > "$BASE_COLLECTION_PATH/orchestrator/detected-namespaces.txt"

run "${SCRIPTS_DIR}/gather_namespace-inspect"
[ "$status" -eq 0 ]
[ -f "$OC_INSPECT_ARGS" ]

local args
args=$(cat "$OC_INSPECT_ARGS")
[[ "$args" == *"namespace/explicit-ns1"* ]]
[[ "$args" == *"namespace/explicit-ns2"* ]]
[[ "$args" != *"namespace/orch-ns1"* ]]
}

@test "gather_namespace-inspect empty detected-namespaces.txt does not add namespaces" {
mkdir -p "$BASE_COLLECTION_PATH/orchestrator"
: > "$BASE_COLLECTION_PATH/orchestrator/detected-namespaces.txt"

run "${SCRIPTS_DIR}/gather_namespace-inspect"
[ "$status" -eq 0 ]

# With no helm/operator/CR results and an empty orch file, no namespaces are detected
[ -f "$BASE_COLLECTION_PATH/namespace-inspect/no-namespaces.txt" ]
[[ ! -f "$OC_INSPECT_ARGS" ]]
}

@test "gather_namespace-inspect absent detected-namespaces.txt does not add namespaces" {
# Don't create the orchestrator directory at all
run "${SCRIPTS_DIR}/gather_namespace-inspect"
[ "$status" -eq 0 ]

[ -f "$BASE_COLLECTION_PATH/namespace-inspect/no-namespaces.txt" ]
[[ ! -f "$OC_INSPECT_ARGS" ]]
}

@test "gather_namespace-inspect merges auto-detected and orchestrator namespaces without duplicates" {
# Make kubectl return a namespace for the operator detection query
cat > "$MOCK_BIN/kubectl" << 'MOCK_KUBECTL'
#!/usr/bin/env bash
if [[ "${1:-}" == "version" ]]; then
echo "Client Version: v1.30.0"
exit 0
fi
if [[ "$*" == *"app=rhdh-operator"* ]]; then
echo "operator-ns"
exit 0
fi
for arg in "$@"; do
case "$arg" in
json) echo '{"items":[]}'; exit 0 ;;
jsonpath=*) exit 0 ;;
esac
done
exit 0
MOCK_KUBECTL
chmod +x "$MOCK_BIN/kubectl"

mkdir -p "$BASE_COLLECTION_PATH/orchestrator"
# Include operator-ns as a duplicate and a new orch-only namespace
printf '%s\n' "operator-ns" "orch-ns1" > "$BASE_COLLECTION_PATH/orchestrator/detected-namespaces.txt"

run "${SCRIPTS_DIR}/gather_namespace-inspect"
[ "$status" -eq 0 ]
[ -f "$OC_INSPECT_ARGS" ]

local args
args=$(cat "$OC_INSPECT_ARGS")
local count_operator count_orch
count_operator=$(echo "$args" | grep -o 'namespace/operator-ns' | wc -l)
count_orch=$(echo "$args" | grep -o 'namespace/orch-ns1' | wc -l)
[ "$count_operator" -eq 1 ]
[ "$count_orch" -eq 1 ]
}

@test "gather_namespace-inspect whitespace-only lines in detected-namespaces.txt are ignored" {
mkdir -p "$BASE_COLLECTION_PATH/orchestrator"
# File with only whitespace lines
printf ' \n\t\n \n' > "$BASE_COLLECTION_PATH/orchestrator/detected-namespaces.txt"

run "${SCRIPTS_DIR}/gather_namespace-inspect"
[ "$status" -eq 0 ]

# No valid namespaces, so no inspect should run
[ -f "$BASE_COLLECTION_PATH/namespace-inspect/no-namespaces.txt" ]
[[ ! -f "$OC_INSPECT_ARGS" ]]
}
Loading
Loading