diff --git a/scripts/backup-mariadb.sh b/scripts/backup-mariadb.sh index e8e02773e..69e40c19e 100755 --- a/scripts/backup-mariadb.sh +++ b/scripts/backup-mariadb.sh @@ -1,3 +1,13 @@ +# ----------------------------------------------- +# _ _ +# | | | | +# __ _ ___ _ __ ___ ___| |_ __ _ ___| | __ +# / _` |/ _ \ '_ \ / _ \/ __| __/ _` |/ __| |/ / +# | (_| | __/ | | | __/\__ \ || (_| | (__| < +# \__, |\___|_| |_|\___||___/\__\__,_|\___|_|\_\ +# __/ | ops scripts +# |___/ +# ----------------------------------------------- #!/bin/bash # shellcheck disable=SC2124,SC2145,SC2294,SC2086 diff --git a/scripts/cleanup-openstack-completed-jobs.sh b/scripts/cleanup-openstack-completed-jobs.sh index 85dae556a..f9244e941 100755 --- a/scripts/cleanup-openstack-completed-jobs.sh +++ b/scripts/cleanup-openstack-completed-jobs.sh @@ -1,3 +1,13 @@ +# ----------------------------------------------- +# _ _ +# | | | | +# __ _ ___ _ __ ___ ___| |_ __ _ ___| | __ +# / _` |/ _ \ '_ \ / _ \/ __| __/ _` |/ __| |/ / +# | (_| | __/ | | | __/\__ \ || (_| | (__| < +# \__, |\___|_| |_|\___||___/\__\__,_|\___|_|\_\ +# __/ | ops scripts +# |___/ +# ----------------------------------------------- #!/bin/bash NAMESPACE="openstack" TTL=180 diff --git a/scripts/convert_osa_inventory.py b/scripts/convert-osa-inventory.py similarity index 93% rename from scripts/convert_osa_inventory.py rename to scripts/convert-osa-inventory.py index 1698d8b16..ee2f6739c 100755 --- a/scripts/convert_osa_inventory.py +++ b/scripts/convert-osa-inventory.py @@ -1,3 +1,13 @@ +# ----------------------------------------------- +# _ _ +# | | | | +# __ _ ___ _ __ ___ ___| |_ __ _ ___| | __ +# / _` |/ _ \ '_ \ / _ \/ __| __/ _` |/ __| |/ / +# | (_| | __/ | | | __/\__ \ || (_| | (__| < +# \__, |\___|_| |_|\___||___/\__\__,_|\___|_|\_\ +# __/ | ops scripts +# |___/ +# ----------------------------------------------- #!/usr/bin/python3 # Copyright 2019-Present, Rackspace Technology, Inc. diff --git a/scripts/create-manila-secrets.sh b/scripts/create-manila-secrets.sh index bf08b6126..d4eb950d0 100755 --- a/scripts/create-manila-secrets.sh +++ b/scripts/create-manila-secrets.sh @@ -1,3 +1,13 @@ +# ----------------------------------------------- +# _ _ +# | | | | +# __ _ ___ _ __ ___ ___| |_ __ _ ___| | __ +# / _` |/ _ \ '_ \ / _ \/ __| __/ _` |/ __| |/ / +# | (_| | __/ | | | __/\__ \ || (_| | (__| < +# \__, |\___|_| |_|\___||___/\__\__,_|\___|_|\_\ +# __/ | ops scripts +# |___/ +# ----------------------------------------------- #!/bin/bash # shellcheck disable=SC2086 diff --git a/scripts/find_ovn_duplicate_ip.sh b/scripts/find-ovn-duplicate-ip.sh similarity index 86% rename from scripts/find_ovn_duplicate_ip.sh rename to scripts/find-ovn-duplicate-ip.sh index f4494a9e3..49539868b 100755 --- a/scripts/find_ovn_duplicate_ip.sh +++ b/scripts/find-ovn-duplicate-ip.sh @@ -1,3 +1,13 @@ +# ----------------------------------------------- +# _ _ +# | | | | +# __ _ ___ _ __ ___ ___| |_ __ _ ___| | __ +# / _` |/ _ \ '_ \ / _ \/ __| __/ _` |/ __| |/ / +# | (_| | __/ | | | __/\__ \ || (_| | (__| < +# \__, |\___|_| |_|\___||___/\__\__,_|\___|_|\_\ +# __/ | ops scripts +# |___/ +# ----------------------------------------------- #!/bin/bash # Script to use 'kubectl get ip' to list all Kube-OVN allocated IP records diff --git a/scripts/find_ovn_stale_ip_crd.sh b/scripts/find-ovn-stale-ip-crd.sh similarity index 88% rename from scripts/find_ovn_stale_ip_crd.sh rename to scripts/find-ovn-stale-ip-crd.sh index 7d11cbf63..9e0fc575a 100755 --- a/scripts/find_ovn_stale_ip_crd.sh +++ b/scripts/find-ovn-stale-ip-crd.sh @@ -1,3 +1,13 @@ +# ----------------------------------------------- +# _ _ +# | | | | +# __ _ ___ _ __ ___ ___| |_ __ _ ___| | __ +# / _` |/ _ \ '_ \ / _ \/ __| __/ _` |/ __| |/ / +# | (_| | __/ | | | __/\__ \ || (_| | (__| < +# \__, |\___|_| |_|\___||___/\__\__,_|\___|_|\_\ +# __/ | ops scripts +# |___/ +# ----------------------------------------------- #!/bin/bash # Configuration Defaults diff --git a/scripts/import-external-cluster.sh b/scripts/import-external-cluster.sh index 802ad1549..540155291 100755 --- a/scripts/import-external-cluster.sh +++ b/scripts/import-external-cluster.sh @@ -1,3 +1,13 @@ +# ----------------------------------------------- +# _ _ +# | | | | +# __ _ ___ _ __ ___ ___| |_ __ _ ___| | __ +# / _` |/ _ \ '_ \ / _ \/ __| __/ _` |/ __| |/ / +# | (_| | __/ | | | __/\__ \ || (_| | (__| < +# \__, |\___|_| |_|\___||___/\__\__,_|\___|_|\_\ +# __/ | ops scripts +# |___/ +# ----------------------------------------------- #!/usr/bin/env -S bash set -e diff --git a/scripts/install_kubectl.sh b/scripts/install-kubectl.sh similarity index 100% rename from scripts/install_kubectl.sh rename to scripts/install-kubectl.sh diff --git a/scripts/kube-ovn-convert.sh b/scripts/kube-ovn-convert.sh index 6b3a5b137..5518924df 100755 --- a/scripts/kube-ovn-convert.sh +++ b/scripts/kube-ovn-convert.sh @@ -1,3 +1,13 @@ +# ----------------------------------------------- +# _ _ +# | | | | +# __ _ ___ _ __ ___ ___| |_ __ _ ___| | __ +# / _` |/ _ \ '_ \ / _ \/ __| __/ _` |/ __| |/ / +# | (_| | __/ | | | __/\__ \ || (_| | (__| < +# \__, |\___|_| |_|\___||___/\__\__,_|\___|_|\_\ +# __/ | ops scripts +# |___/ +# ----------------------------------------------- #!/usr/bin/env -S bash set -e diff --git a/scripts/lib/functions.sh b/scripts/lib/functions.sh index 79e9a4f3f..992ffcc0b 100644 --- a/scripts/lib/functions.sh +++ b/scripts/lib/functions.sh @@ -1,3 +1,13 @@ +# ----------------------------------------------- +# _ _ +# | | | | +# __ _ ___ _ __ ___ ___| |_ __ _ ___| | __ +# / _` |/ _ \ '_ \ / _ \/ __| __/ _` |/ __| |/ / +# | (_| | __/ | | | __/\__ \ || (_| | (__| < +# \__, |\___|_| |_|\___||___/\__\__,_|\___|_|\_\ +# __/ | ops scripts +# |___/ +# ----------------------------------------------- #!/usr/bin/env bash # Copyright 2024-Present, Rackspace Technology, Inc. diff --git a/scripts/manage_hpa.sh b/scripts/manage-hpa.sh similarity index 94% rename from scripts/manage_hpa.sh rename to scripts/manage-hpa.sh index 168cac36c..572d6ccc1 100755 --- a/scripts/manage_hpa.sh +++ b/scripts/manage-hpa.sh @@ -1,3 +1,13 @@ +# ----------------------------------------------- +# _ _ +# | | | | +# __ _ ___ _ __ ___ ___| |_ __ _ ___| | __ +# / _` |/ _ \ '_ \ / _ \/ __| __/ _` |/ __| |/ / +# | (_| | __/ | | | __/\__ \ || (_| | (__| < +# \__, |\___|_| |_|\___||___/\__\__,_|\___|_|\_\ +# __/ | ops scripts +# |___/ +# ----------------------------------------------- #!/bin/bash # --- Configuration --- diff --git a/scripts/ovn-compare-neutron-fips-with-ovn-nat.sh b/scripts/ovn-compare-neutron-fips-with-ovn-nat.sh new file mode 100755 index 000000000..dbaed0763 --- /dev/null +++ b/scripts/ovn-compare-neutron-fips-with-ovn-nat.sh @@ -0,0 +1,239 @@ +# ----------------------------------------------- +# _ _ +# | | | | +# __ _ ___ _ __ ___ ___| |_ __ _ ___| | __ +# / _` |/ _ \ '_ \ / _ \/ __| __/ _` |/ __| |/ / +# | (_| | __/ | | | __/\__ \ || (_| | (__| < +# \__, |\___|_| |_|\___||___/\__\__,_|\___|_|\_\ +# __/ | ops scripts +# |___/ +# ----------------------------------------------- +#!/bin/bash + +# SCRIPT FOCUS: Validate Neutron Floating IPs (FIPs) against OVN Logical_Router NAT rules. +# This check ensures that all active FIPs have a corresponding dnat_and_snat rule in OVN. + +KO_NBCTL_CMD="kubectl ko nbctl" + +# --- Dependency Check --- +if [ "${BASH_VERSINFO[0]}" -lt 4 ]; then + echo "ERROR: DEPENDENCY MISSING: Bash version 4.0 or higher is required for associative array support." + echo "Current version: $BASH_VERSION" + exit 2 +fi + +if ! command -v openstack &> /dev/null; then + echo "ERROR: DEPENDENCY MISSING: 'openstack' client command not found." + echo "Please ensure the OpenStack CLI is installed and configured correctly (source openrc)." + exit 2 +fi + +if ! command -v kubectl &> /dev/null; then + echo "ERROR: DEPENDENCY MISSING: 'kubectl' command not found." + echo "Please ensure kubectl is installed and in your PATH." + exit 2 +fi + +if ! command -v awk &> /dev/null; then + echo "ERROR: DEPENDENCY MISSING: 'awk' command not found. This is needed for data parsing." + exit 2 +fi + +if ! command -v grep &> /dev/null; then + echo "ERROR: DEPENDENCY MISSING: 'grep' command not found. This is needed for filtering and comparison." + exit 2 +fi + +if ! $KO_NBCTL_CMD show &> /dev/null; then + echo "ERROR: FAILED CONNECTION: Failed to connect to OVN NBDB using '$KO_NBCTL_CMD show'." + echo "Please check your 'kubectl ko' configuration/alias and OVN controller status." + exit 2 +fi +# --- End Dependency Check --- + +FIX_MODE=false +SCAN_MODE=false +HELP_MODE=false +STALE_FOUND=0 + +for arg in "$@"; do + case "$arg" in + --scan) + SCAN_MODE=true + ;; + --fix) + FIX_MODE=true + SCAN_MODE=true + ;; + --help) + HELP_MODE=true + ;; + *) + if [[ "$arg" != "--scan" && "$arg" != "--fix" ]]; then + HELP_MODE=true + fi + ;; + esac +done + +show_help() { + echo "Usage: $0 [OPTION]" + echo "" + echo "Compares Neutron Floating IPs (FIPs) with OVN Logical_Router NAT rules." + echo "Identifies missing or stale FIP-related NAT entries." + echo "" + echo "Options:" + echo " --scan Execute the comparison and diagnostic scan (read-only)." + echo " --fix Execute the scan AND automatically deletes stale OVN NAT rules associated with FIPs." + echo " --help Display this help message and exit." + echo "" + echo "Exit Codes for Automation (CronJobs):" + echo " 0: Script completed successfully (Fix mode) OR Scan mode found no stale resources." + echo " 1: Scan mode found stale resources (Signals a cleanup action is required)." + echo " 2: Fatal error during dependency check or OVN DB query." + echo "" +} + +if [ "$#" -eq 0 ] || [ "$HELP_MODE" = true ]; then + show_help + exit 0 +fi + +if [ "$SCAN_MODE" = true ]; then + + if [ "$FIX_MODE" = true ]; then + echo "==================================================================================" + echo " WARNING: FIX MODE IS ACTIVE! Stale FIP NAT rules will be DELETED." + echo "==================================================================================" + echo "" + else + echo "========================================================" + echo " SCAN MODE ACTIVE (Read-Only). Use --fix to apply changes." + echo "========================================================" + echo "" + fi + + echo "## 1. Extracting Neutron Floating IP IDs and their associated OVN keys..." + + # Extract ID, FIP Address, and Fixed IP Address (for filtering unassigned) + NEUTRON_FIP_DATA=$( + openstack floating ip list -f value -c ID -c "Floating IP Address" -c "Fixed IP Address" + ) + + declare -A NEUTRON_FIP_MAP + NEUTRON_FIP_SET=" " + + # Neutron FIP Map: Key=FIP_IP_Address, Value=Neutron_FIP_UUID + while read -r id fip_ip fixed_ip; do + if [[ -n "$id" && -n "$fip_ip" && "$fixed_ip" != "None" ]]; then + NEUTRON_FIP_MAP["$fip_ip"]="$id" + NEUTRON_FIP_SET="${NEUTRON_FIP_SET}${fip_ip} " + fi + done <<< "$NEUTRON_FIP_DATA" + + NEUTRON_FIP_COUNT=${#NEUTRON_FIP_MAP[@]} + echo " -> Found $NEUTRON_FIP_COUNT ASSIGNED Neutron Floating IPs to check." + echo "" + + echo "## 2. OVN Logical_Router NAT Comparison" + + declare -A NAT_RULE_MAP + STALE_NAT_UUIDS=() + + # Get NAT rules that are of type dnat_and_snat, which is used for FIPs + # Columns: _uuid, type, external_ip, external_ids + # Note: We query all LRs to get all NAT rules managed by OVN. + OVN_NAT_DATA=$($KO_NBCTL_CMD --columns=_uuid,type,external_ip,external_ids --bare --format=csv find NAT type=dnat_and_snat) + + if [ $? -ne 0 ]; then + echo " [FATAL ERROR] Failed to execute 'ovn-nbctl find NAT' command." + exit 2 + fi + + # NAT_RULE_MAP uses Floating IP Address (Key) to OVN NAT UUID (Value) + eval "$( + echo "$OVN_NAT_DATA" | + awk ' + BEGIN { FS="," } + NF>=3 { + ovn_uuid = $1 + nat_type = $2 + # The external_ip is the Floating IP Address + fip_ip = $3 + + # Strip all whitespace from the IP address + gsub(/^[ \t]+|[ \t]+$/, "", fip_ip) + + # Check for a valid IP format and ensure it is the correct type + if (nat_type == "dnat_and_snat" && fip_ip ~ /^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$/) { + # Output a Bash assignment statement for direct eval + print "NAT_RULE_MAP[\"" fip_ip "\"]=\"" ovn_uuid "\"" + } + } + ' + )" + + OVN_NAT_COUNT=${#NAT_RULE_MAP[@]} + echo " -> Successfully mapped $OVN_NAT_COUNT unique FIP addresses to OVN NAT Rules." + echo "" + + echo "## 3. Comparison Report" + echo "------------------------------------------" + + echo "### A. Missing FIP NAT Rules in OVN NBDB (FIP Provisioning Failure)" + MISSING_FIPS=0 + for fip_ip in "${!NEUTRON_FIP_MAP[@]}"; do + if [[ ! ${NAT_RULE_MAP["$fip_ip"]} ]]; then + fip_id="${NEUTRON_FIP_MAP["$fip_ip"]}" + echo " [MISSING] Neutron FIP ID: $fip_id (FIP Address: $fip_ip)" + MISSING_FIPS=$((MISSING_FIPS + 1)) + fi + done + if [ $MISSING_FIPS -eq 0 ]; then + echo " [OK] All $NEUTRON_FIP_COUNT Neutron FIPs found as OVN NAT rules." + else + echo " [ERROR] Total Missing FIP NAT Rules: $MISSING_FIPS" + fi + echo "" + + echo "### B. Stale FIP NAT Rules in OVN NBDB (FIP Cleanup Failure)" + STALE_NAT_RULES=0 + for fip_ip in "${!NAT_RULE_MAP[@]}"; do + if ! echo "$NEUTRON_FIP_SET" | grep -q " ${fip_ip} "; then + ovn_uuid="${NAT_RULE_MAP["$fip_ip"]}" + echo " [STALE] FIP Address: $fip_ip (OVN NAT UUID: $ovn_uuid)" + STALE_NAT_UUIDS+=("$ovn_uuid") + STALE_NAT_RULES=$((STALE_NAT_RULES + 1)) + fi + done + + if [ $STALE_NAT_RULES -eq 0 ]; then + echo " [OK] No stale FIP-related NAT rules found in OVN NBDB." + else + echo " [CLEANUP NEEDED] Total Stale FIP NAT Rules: $STALE_NAT_RULES" + STALE_FOUND=1 + fi + echo "" + + if [ "$FIX_MODE" = true ] && [ "$STALE_FOUND" -eq 1 ]; then + echo "## 4. Remediation: Deleting Stale NAT Rules from OVN NBDB" + + NAT_CLEANUP_COUNT=0 + NAT_TOTAL_TO_CLEANUP=${#STALE_NAT_UUIDS[@]} + for nat_uuid in "${STALE_NAT_UUIDS[@]}"; do + NAT_CLEANUP_COUNT=$((NAT_CLEANUP_COUNT + 1)) + echo " -> [NAT $NAT_CLEANUP_COUNT/$NAT_TOTAL_TO_CLEANUP] Attempting to destroy STALE NAT UUID: $nat_uuid" + $KO_NBCTL_CMD destroy NAT "$nat_uuid" || echo " -> WARNING: Failed to destroy NAT $nat_uuid. May require manual cleanup." + done + + echo " [COMPLETE] Remediation attempt finished." + exit 0 + elif [ "$FIX_MODE" = true ] && [ "$STALE_FOUND" -eq 0 ]; then + echo "## 4. Remediation" + echo " [SKIP] Fix mode enabled, but no stale resources found to delete." + exit 0 + fi + + exit "$STALE_FOUND" + +fi diff --git a/scripts/ovn-compare-neutron-ports-with-ovn-ports.sh b/scripts/ovn-compare-neutron-ports-with-ovn-ports.sh new file mode 100755 index 000000000..de1932ee1 --- /dev/null +++ b/scripts/ovn-compare-neutron-ports-with-ovn-ports.sh @@ -0,0 +1,243 @@ +# ----------------------------------------------- +# _ _ +# | | | | +# __ _ ___ _ __ ___ ___| |_ __ _ ___| | __ +# / _` |/ _ \ '_ \ / _ \/ __| __/ _` |/ __| |/ / +# | (_| | __/ | | | __/\__ \ || (_| | (__| < +# \__, |\___|_| |_|\___||___/\__\__,_|\___|_|\_\ +# __/ | ops scripts +# |___/ +# ----------------------------------------------- +#!/bin/bash + +# SCRIPT FOCUS: Validate Neutron Ports against OVN Logical_Switch_Ports (LSPs). + +KO_NBCTL_CMD="kubectl ko nbctl" + +# --- Dependency Check --- +if [ "${BASH_VERSINFO[0]}" -lt 4 ]; then + echo "ERROR: DEPENDENCY MISSING: Bash version 4.0 or higher is required for mapfile/readarray support." + echo "Current version: $BASH_VERSION" + exit 2 +fi + +if ! command -v openstack &> /dev/null; then + echo "ERROR: DEPENDENCY MISSING: 'openstack' client command not found." + echo "Please ensure the OpenStack CLI is installed and configured correctly (source openrc)." + exit 2 +fi + +if ! command -v kubectl &> /dev/null; then + echo "ERROR: DEPENDENCY MISSING: 'kubectl' command not found." + echo "Please ensure kubectl is installed and in your PATH." + exit 2 +fi + +if ! command -v awk &> /dev/null; then + echo "ERROR: DEPENDENCY MISSING: 'awk' command not found. This is needed for data parsing." + exit 2 +fi + +if ! command -v grep &> /dev/null; then + echo "ERROR: DEPENDENCY MISSING: 'grep' command not found. This is needed for filtering and comparison." + exit 2 +fi + +if ! $KO_NBCTL_CMD show &> /dev/null; then + echo "ERROR: FAILED CONNECTION: Failed to connect to OVN NBDB using '$KO_NBCTL_CMD show'." + echo "Please check your 'kubectl ko' configuration/alias and OVN controller status." + exit 2 +fi +# --- End Dependency Check --- + + +FIX_MODE=false +SCAN_MODE=false +HELP_MODE=false +STALE_FOUND=0 + +for arg in "$@"; do + case "$arg" in + --scan) + SCAN_MODE=true + ;; + --fix) + FIX_MODE=true + SCAN_MODE=true + ;; + --help) + HELP_MODE=true + ;; + *) + if [[ "$arg" != "--scan" && "$arg" != "--fix" ]]; then + HELP_MODE=true + fi + ;; + esac +done + +show_help() { + echo "Usage: $0 [OPTION]" + echo "" + echo "Compares standard Neutron Ports (excluding floating IPs) against OVN NBDB Logical_Switch_Ports (LSPs)." + echo "Mapping is done by comparing Neutron Port UUIDs with the OVN LSP 'name' column." + echo "" + echo "Options:" + echo " --scan Execute the comparison and diagnostic scan (read-only)." + echo " --fix Execute the scan AND automatically deletes stale OVN LSPs from the OVN NBDB." + echo " --help Display this help message and exit." + echo "" + echo "Exit Codes for Automation (CronJobs):" + echo " 0: Script completed successfully (Fix mode) OR Scan mode found no stale resources." + echo " 1: Scan mode found stale resources (Signals a cleanup action is required)." + echo " 2: Fatal error during dependency check or OVN DB query." + echo "" +} + +if [ "$#" -eq 0 ] || [ "$HELP_MODE" = true ]; then + show_help + exit 0 +fi + +if [ "$SCAN_MODE" = true ]; then + + if [ "$FIX_MODE" = true ]; then + echo "==================================================================================" + echo " WARNING: FIX MODE IS ACTIVE! Stale Logical Switch Ports will be DELETED." + echo "==================================================================================" + echo "" + else + echo "========================================================" + echo " SCAN MODE ACTIVE (Read-Only). Use --fix to apply changes." + echo "========================================================" + echo "" + fi + + echo "## 1. Extracting Neutron Port IDs (Excluding Floating IPs)..." + + # Get Neutron Port UUIDs, explicitly excluding ports with device_owner=network:floatingip + NEUTRON_ALL_PORTS_DATA=$(openstack port list --long -f value -c ID -c device_owner) + + NEUTRON_LSP_IDS=$( + echo "$NEUTRON_ALL_PORTS_DATA" | + grep -v "network:floatingip" | + awk '{print $1}' | + sort + ) + + NEUTRON_PORT_COUNT=$(echo "$NEUTRON_LSP_IDS" | wc -l) + + if [ $NEUTRON_PORT_COUNT -lt 1 ]; then + echo " [INFO] Found 0 Neutron Ports (excluding FIPs). Skipping comparison." + exit 0 + fi + echo " -> Found $NEUTRON_PORT_COUNT Neutron Standard Ports (LSPs expected)." + + echo "" + + NEUTRON_LSP_ID_SET=" " + for id in $NEUTRON_LSP_IDS; do + NEUTRON_LSP_ID_SET="${NEUTRON_LSP_ID_SET}${id} " + done + + echo "## 2. OVN Logical_Switch_Port Comparison" + + declare -A LSP_UUIDS_MAP + STALE_LSP_UUIDS=() + + # Get LSP UUID and its name (which contains the Neutron Port UUID) + OVN_LSP_DATA=$($KO_NBCTL_CMD --columns=_uuid,name --bare --format=csv find Logical_Switch_Port) + + if [ $? -ne 0 ]; then + echo " [FATAL ERROR] Failed to execute 'ovn-nbctl find Logical_Switch_Port' command." + exit 2 + fi + + # LSP_UUIDS_MAP uses Neutron UUID (from LSP name) as key, OVN LSP UUID as value + eval "$( + echo "$OVN_LSP_DATA" | + awk ' + BEGIN { FS="," } + NF==2 { + ovn_uuid = $1 + neutron_id = $2 + + # Check for UUID format to identify Neutron ports + if (neutron_id ~ /[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}/) { + # Output a Bash assignment statement for direct eval + print "LSP_UUIDS_MAP[\"" neutron_id "\"]=\"" ovn_uuid "\"" + } + } + ' + )" + + OVN_LSP_COUNT=${#LSP_UUIDS_MAP[@]} + echo " -> Mapped $OVN_LSP_COUNT unique OVN LSPs believed to be Neutron ports." + echo "" + + echo "## 3. Comparison Report (Standard Ports)" + echo "----------------------------------------" + + echo "### A. Missing Standard Ports (LSPs) in OVN NBDB" + MISSING_PORTS=0 + + for id in $NEUTRON_LSP_IDS; do + # Check if the Neutron UUID exists as a key in our LSP map + if [[ ! ${LSP_UUIDS_MAP["$id"]} ]]; then + echo " [MISSING] Neutron Port ID (LSP): $id" + MISSING_PORTS=$((MISSING_PORTS + 1)) + fi + done + + if [ $MISSING_PORTS -eq 0 ]; then + echo " [OK] All $NEUTRON_PORT_COUNT Neutron Standard Ports found as OVN LSPs." + else + echo " [ERROR] Total Missing Standard Ports: $MISSING_PORTS" + fi + echo "" + + echo "### B. Stale Logical Switch Ports (LSPs) in OVN NBDB" + STALE_PORTS=0 + + for neutron_id in "${!LSP_UUIDS_MAP[@]}"; do + ovn_uuid="${LSP_UUIDS_MAP["$neutron_id"]}" + + # Check if the Neutron UUID (from OVN LSP name) is NOT in the current Neutron LSP ID set + if ! echo "$NEUTRON_LSP_ID_SET" | grep -q " ${neutron_id} "; then + # If the ID is not in the Neutron set, the LSP is stale + echo " [STALE] Port ID (LSP): $neutron_id (OVN LSP UUID: $ovn_uuid)" + STALE_LSP_UUIDS+=("$ovn_uuid") + STALE_PORTS=$((STALE_PORTS + 1)) + fi + done + + if [ $STALE_PORTS -eq 0 ]; then + echo " [OK] No stale Neutron-managed LSPs found in OVN NBDB." + else + echo " [CLEANUP NEEDED] Total Stale Standard Ports: $STALE_PORTS" + STALE_FOUND=1 + fi + echo "" + + if [ "$FIX_MODE" = true ] && [ "$STALE_FOUND" -eq 1 ]; then + echo "## 4. Remediation: Deleting Stale Resources from OVN NBDB" + + LSP_CLEANUP_COUNT=0 + LSP_TOTAL_TO_CLEANUP=${#STALE_LSP_UUIDS[@]} + for lsp_uuid in "${STALE_LSP_UUIDS[@]}"; do + LSP_CLEANUP_COUNT=$((LSP_CLEANUP_COUNT + 1)) + echo " -> [LSP $LSP_CLEANUP_COUNT/$LSP_TOTAL_TO_CLEANUP] Attempting to destroy STALE Logical_Switch_Port UUID: $lsp_uuid" + $KO_NBCTL_CMD destroy Logical_Switch_Port "$lsp_uuid" || echo " -> WARNING: Failed to destroy Logical_Switch_Port $lsp_uuid. May require manual cleanup." + done + + echo " [COMPLETE] Remediation attempt finished." + exit 0 + elif [ "$FIX_MODE" = true ] && [ "$STALE_FOUND" -eq 0 ]; then + echo "## 4. Remediation" + echo " [SKIP] Fix mode enabled, but no stale resources found to delete." + exit 0 + fi + + exit "$STALE_FOUND" + +fi diff --git a/scripts/ovn-compare-neutron-routers-with-logical-routers.sh b/scripts/ovn-compare-neutron-routers-with-logical-routers.sh new file mode 100755 index 000000000..6e319f660 --- /dev/null +++ b/scripts/ovn-compare-neutron-routers-with-logical-routers.sh @@ -0,0 +1,315 @@ +# ----------------------------------------------- +# _ _ +# | | | | +# __ _ ___ _ __ ___ ___| |_ __ _ ___| | __ +# / _` |/ _ \ '_ \ / _ \/ __| __/ _` |/ __| |/ / +# | (_| | __/ | | | __/\__ \ || (_| | (__| < +# \__, |\___|_| |_|\___||___/\__\__,_|\___|_|\_\ +# __/ | ops scripts +# |___/ +# ----------------------------------------------- +#!/bin/bash + +# SCRIPT FOCUS: Validate Neutron Routers and Router Ports against OVN Logical_Router and Logical_Router_Port. + +KO_NBCTL_CMD="kubectl ko nbctl" + +# --- Dependency Check --- +if [ "${BASH_VERSINFO[0]}" -lt 4 ]; then + echo "ERROR: DEPENDENCY MISSING: Bash version 4.0 or higher is required for associative array support." + echo "Current version: $BASH_VERSION" + exit 2 +fi + +if ! command -v openstack &> /dev/null; then + echo "ERROR: DEPENDENCY MISSING: 'openstack' client command not found." + echo "Please ensure the OpenStack CLI is installed and configured correctly (source openrc)." + exit 2 +fi + +if ! command -v kubectl &> /dev/null; then + echo "ERROR: DEPENDENCY MISSING: 'kubectl' command not found." + echo "Please ensure kubectl is installed and in your PATH." + exit 2 +fi + +if ! command -v awk &> /dev/null; then + echo "ERROR: DEPENDENCY MISSING: 'awk' command not found. This is needed for data parsing." + exit 2 +fi + +if ! command -v grep &> /dev/null; then + echo "ERROR: DEPENDENCY MISSING: 'grep' command not found. This is needed for filtering and comparison." + exit 2 +fi + +if ! $KO_NBCTL_CMD show &> /dev/null; then + echo "ERROR: FAILED CONNECTION: Failed to connect to OVN NBDB using '$KO_NBCTL_CMD show'." + echo "Please check your 'kubectl ko' configuration/alias and OVN controller status." + exit 2 +fi +# --- End Dependency Check --- + +FIX_MODE=false +SCAN_MODE=false +HELP_MODE=false +STALE_FOUND=0 + +for arg in "$@"; do + case "$arg" in + --scan) + SCAN_MODE=true + ;; + --fix) + FIX_MODE=true + SCAN_MODE=true + ;; + --help) + HELP_MODE=true + ;; + *) + if [[ "$arg" != "--scan" && "$arg" != "--fix" ]]; then + HELP_MODE=true + fi + ;; + esac +done + +show_help() { + echo "Usage: $0 [OPTION]" + echo "" + echo "Compares Neutron Routers and Router Ports with OVN NBDB Logical_Router and Logical_Router_Port." + echo "Identifies missing or stale router and port entities managed by Neutron." + echo "" + echo "Options:" + echo " --scan Execute the comparison and diagnostic scan (read-only)." + echo " --fix Execute the scan AND automatically deletes stale OVN Routers and Router Ports." + echo " --help Display this help message and exit." + echo "" + echo "Exit Codes for Automation (CronJobs):" + echo " 0: Script completed successfully (Fix mode) OR Scan mode found no stale resources." + echo " 1: Scan mode found stale resources (Signals a cleanup action is required)." + echo " 2: Fatal error during dependency check or OVN DB query." + echo "" +} + +if [ "$#" -eq 0 ] || [ "$HELP_MODE" = true ]; then + show_help + exit 0 +fi + +if [ "$SCAN_MODE" = true ]; then + + if [ "$FIX_MODE" = true ]; then + echo "==================================================================================" + echo " WARNING: FIX MODE IS ACTIVE! Stale Logical Routers/Router Ports will be DELETED." + echo "==================================================================================" + echo "" + else + echo "========================================================" + echo " SCAN MODE ACTIVE (Read-Only). Use --fix to apply changes." + echo "========================================================" + echo "" + fi + + echo "## 1. Extracting Neutron Router and Router Port IDs..." + + NEUTRON_ROUTER_IDS=$(openstack router list -f value -c ID | awk '{print $1}' | sort) + NEUTRON_ROUTER_COUNT=$(echo "$NEUTRON_ROUTER_IDS" | wc -l) + echo " -> Found $NEUTRON_ROUTER_COUNT Neutron Routers." + + NEUTRON_RPORT_DATA=$( + openstack port list --device-owner network:router_interface --long -f value -c ID; + openstack port list --device-owner network:router_gateway --long -f value -c ID + ) + NEUTRON_RPORT_IDS=$(echo "$NEUTRON_RPORT_DATA" | awk '{print $1}' | sort | uniq) + NEUTRON_RPORT_COUNT=$(echo "$NEUTRON_RPORT_IDS" | wc -l) + echo " -> Found $NEUTRON_RPORT_COUNT Neutron Router Ports (Interfaces/Gateways)." + echo "" + + NEUTRON_ROUTER_SET=" " + for id in $NEUTRON_ROUTER_IDS; do + NEUTRON_ROUTER_SET="${NEUTRON_ROUTER_SET}${id} " + done + + + NEUTRON_RPORT_SET=" " + for id in $NEUTRON_RPORT_IDS; do + NEUTRON_RPORT_SET="${NEUTRON_RPORT_SET}${id} " + done + + echo "## 2. OVN Logical_Router Comparison (Neutron Routers)" + + declare -A LR_UUIDS_MAP + STALE_LR_UUIDS=() + + OVN_LR_DATA=$($KO_NBCTL_CMD --columns=_uuid,name --bare --format=csv find Logical_Router) + + if [ $? -ne 0 ]; then + echo " [FATAL ERROR] Failed to execute 'ovn-nbctl find Logical_Router' command." + exit 2 + fi + + eval "$( + echo "$OVN_LR_DATA" | + awk ' + BEGIN { FS="," } + NF==2 { + ovn_uuid = $1 + if (match($2, /neutron-([a-f0-9-]+)/, arr)) { + neutron_id = arr[1] + + gsub(/^[ \t]+|[ \t]+$/, "", neutron_id) + + if (neutron_id ~ /[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}/) { + print "LR_UUIDS_MAP[\"" neutron_id "\"]=\"" ovn_uuid "\"" + } + } + } + ' + )" + + OVN_LR_COUNT=${#LR_UUIDS_MAP[@]} + echo " -> Successfully mapped $OVN_LR_COUNT unique Neutron Router IDs to OVN Logical_Routers." + echo "" + + echo "## 3. OVN Logical_Router_Port Comparison (Neutron Router Ports)" + + declare -A LRP_UUIDS_MAP + STALE_LRP_UUIDS=() + + OVN_LRP_DATA=$($KO_NBCTL_CMD --columns=_uuid,name --bare --format=csv find Logical_Router_Port) + + if [ $? -ne 0 ]; then + echo " [FATAL ERROR] Failed to execute 'ovn-nbctl find Logical_Router_Port' command." + exit 2 + fi + + eval "$( + echo "$OVN_LRP_DATA" | + awk ' + BEGIN { FS="," } + NF==2 { + ovn_uuid = $1 + neutron_id = $2 + + # Check for either 'UUID' or 'lrp-UUID' format. Capture group 2 is the UUID. + if (match(neutron_id, /^(lrp-)?([a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12})/, arr)) { + neutron_id = arr[2] + + gsub(/^[ \t]+|[ \t]+$/, "", neutron_id) + + if (neutron_id != "") { + print "LRP_UUIDS_MAP[\"" neutron_id "\"]=\"" ovn_uuid "\"" + } + } + } + ' + )" + + OVN_LRP_COUNT=${#LRP_UUIDS_MAP[@]} + echo " -> Successfully mapped $OVN_LRP_COUNT unique Neutron Router Port IDs to OVN Logical_Router_Ports." + echo "" + + echo "## 4. Comparison Report" + echo "------------------------------------------" + + echo "### A. Missing Logical Routers in OVN NBDB" + MISSING_ROUTERS=0 + for id in $NEUTRON_ROUTER_IDS; do + if [[ ! ${LR_UUIDS_MAP["$id"]} ]]; then + echo " [MISSING] Neutron Router ID: $id" + MISSING_ROUTERS=$((MISSING_ROUTERS + 1)) + fi + done + if [ $MISSING_ROUTERS -eq 0 ]; then + echo " [OK] All $NEUTRON_ROUTER_COUNT Neutron Routers found as OVN Logical_Routers." + else + echo " [ERROR] Total Missing Routers: $MISSING_ROUTERS" + fi + echo "" + + echo "### B. Stale Logical Routers in OVN NBDB" + STALE_ROUTERS=0 + for neutron_id in "${!LR_UUIDS_MAP[@]}"; do + if ! echo "$NEUTRON_ROUTER_SET" | grep -q " ${neutron_id} "; then + ovn_uuid="${LR_UUIDS_MAP["$neutron_id"]}" + echo " [STALE] Router ID: $neutron_id (OVN LR UUID: $ovn_uuid)" + STALE_LR_UUIDS+=("$ovn_uuid") + STALE_ROUTERS=$((STALE_ROUTERS + 1)) + fi + done + + if [ $STALE_ROUTERS -eq 0 ]; then + echo " [OK] No stale Logical_Routers found in OVN NBDB." + else + echo " [CLEANUP NEEDED] Total Stale Logical_Routers: $STALE_ROUTERS" + STALE_FOUND=1 + fi + echo "" + + echo "### C. Missing Logical_Router_Ports in OVN NBDB" + MISSING_RPORTS=0 + for id in $NEUTRON_RPORT_IDS; do + if [[ ! ${LRP_UUIDS_MAP["$id"]} ]]; then + echo " [MISSING] Neutron Router Port ID: $id" + MISSING_RPORTS=$((MISSING_RPORTS + 1)) + fi + done + if [ $MISSING_RPORTS -eq 0 ]; then + echo " [OK] All $NEUTRON_RPORT_COUNT Neutron Router Ports found as OVN Logical_Router_Ports." + else + echo " [ERROR] Total Missing Router Ports: $MISSING_RPORTS" + fi + echo "" + + echo "### D. Stale Logical_Router_Ports in OVN NBDB" + STALE_RPORTS=0 + for neutron_id in "${!LRP_UUIDS_MAP[@]}"; do + if ! echo "$NEUTRON_RPORT_SET" | grep -q " ${neutron_id} "; then + ovn_uuid="${LRP_UUIDS_MAP["$neutron_id"]}" + echo " [STALE] Router Port ID: $neutron_id (OVN LRP UUID: $ovn_uuid)" + STALE_LRP_UUIDS+=("$ovn_uuid") + STALE_RPORTS=$((STALE_RPORTS + 1)) + fi + done + + if [ $STALE_RPORTS -eq 0 ]; then + echo " [OK] No stale Logical_Router_Ports found in OVN NBDB." + else + echo " [CLEANUP NEEDED] Total Stale Logical_Router_Ports: $STALE_RPORTS" + STALE_FOUND=1 + fi + echo "" + + + if [ "$FIX_MODE" = true ] && [ "$STALE_FOUND" -eq 1 ]; then + echo "## 5. Remediation: Deleting Stale Resources from OVN NBDB" + + LRP_CLEANUP_COUNT=0 + LRP_TOTAL_TO_CLEANUP=${#STALE_LRP_UUIDS[@]} + for lrp_uuid in "${STALE_LRP_UUIDS[@]}"; do + LRP_CLEANUP_COUNT=$((LRP_CLEANUP_COUNT + 1)) + echo " -> [LRP $LRP_CLEANUP_COUNT/$LRP_TOTAL_TO_CLEANUP] Attempting to destroy STALE Logical_Router_Port UUID: $lrp_uuid" + $KO_NBCTL_CMD destroy Logical_Router_Port "$lrp_uuid" || echo " -> WARNING: Failed to destroy Logical_Router_Port $lrp_uuid. May require manual cleanup." + done + + LR_CLEANUP_COUNT=0 + LR_TOTAL_TO_CLEANUP=${#STALE_LR_UUIDS[@]} + for lr_uuid in "${STALE_LR_UUIDS[@]}"; do + LR_CLEANUP_COUNT=$((LR_CLEANUP_COUNT + 1)) + echo " -> [LR $LR_CLEANUP_COUNT/$LR_TOTAL_TO_CLEANUP] Attempting to destroy STALE Logical_Router UUID: $lr_uuid" + $KO_NBCTL_CMD destroy Logical_Router "$lr_uuid" || echo " -> WARNING: Failed to destroy Logical_Router $lr_uuid. May require manual cleanup." + done + + echo " [COMPLETE] Remediation attempt finished." + exit 0 + elif [ "$FIX_MODE" = true ] && [ "$STALE_FOUND" -eq 0 ]; then + echo "## 5. Remediation" + echo " [SKIP] Fix mode enabled, but no stale resources found to delete." + exit 0 + fi + + exit "$STALE_FOUND" + +fi diff --git a/scripts/ovn-compare-neutron-security-groups-with-acl.sh b/scripts/ovn-compare-neutron-security-groups-with-acl.sh new file mode 100755 index 000000000..8138dfcb3 --- /dev/null +++ b/scripts/ovn-compare-neutron-security-groups-with-acl.sh @@ -0,0 +1,318 @@ +# ----------------------------------------------- +# _ _ +# | | | | +# __ _ ___ _ __ ___ ___| |_ __ _ ___| | __ +# / _` |/ _ \ '_ \ / _ \/ __| __/ _` |/ __| |/ / +# | (_| | __/ | | | __/\__ \ || (_| | (__| < +# \__, |\___|_| |_|\___||___/\__\__,_|\___|_|\_\ +# __/ | ops scripts +# |___/ +# ----------------------------------------------- +#!/bin/bash + +# SCRIPT FOCUS: Validate Neutron Security Groups (SG) and Rules against OVN Port_Groups and ACLs. + +KO_NBCTL_CMD="kubectl ko nbctl" + +# --- Dependency Check --- +if [ "${BASH_VERSINFO[0]}" -lt 4 ]; then + echo "ERROR: DEPENDENCY MISSING: Bash version 4.0 or higher is required for associative array support." + echo "Current version: $BASH_VERSION" + exit 2 +fi + +if ! command -v openstack &> /dev/null; then + echo "ERROR: DEPENDENCY MISSING: 'openstack' client command not found." + echo "Please ensure the OpenStack CLI is installed and configured correctly (source openrc)." + exit 2 +fi + +if ! command -v kubectl &> /dev/null; then + echo "ERROR: DEPENDENCY MISSING: 'kubectl' command not found." + echo "Please ensure kubectl is installed and in your PATH." + exit 2 +fi + +if ! command -v awk &> /dev/null; then + echo "ERROR: DEPENDENCY MISSING: 'awk' command not found. This is needed for data parsing." + exit 2 +fi + +if ! command -v grep &> /dev/null; then + echo "ERROR: DEPENDENCY MISSING: 'grep' command not found. This is needed for filtering and comparison." + exit 2 +fi + +if ! $KO_NBCTL_CMD show &> /dev/null; then + echo "ERROR: FAILED CONNECTION: Failed to connect to OVN NBDB using '$KO_NBCTL_CMD show'." + echo "Please check your 'kubectl ko' configuration/alias and OVN controller status." + exit 2 +fi +# --- End Dependency Check --- + +FIX_MODE=false +SCAN_MODE=false +HELP_MODE=false +STALE_FOUND=0 + +for arg in "$@"; do + case "$arg" in + --scan) + SCAN_MODE=true + ;; + --fix) + FIX_MODE=true + SCAN_MODE=true + ;; + --help) + HELP_MODE=true + ;; + *) + if [[ "$arg" != "--scan" && "$arg" != "--fix" ]]; then + HELP_MODE=true + fi + ;; + esac +done + +show_help() { + echo "Usage: $0 [OPTION]" + echo "" + echo "Compares Neutron Security Groups and Rules with OVN NBDB Port_Groups and ACLs." + echo "Identifies missing or stale security entities managed by Neutron." + echo "" + echo "Options:" + echo " --scan Execute the comparison and diagnostic scan (read-only)." + echo " --fix Execute the scan AND automatically deletes stale OVN ACLs and Port_Groups from the OVN NBDB." + echo " --help Display this help message and exit." + echo "" + echo "Exit Codes for Automation (CronJobs):" + echo " 0: Script completed successfully (Fix mode) OR Scan mode found no stale resources." + echo " 1: Scan mode found stale resources (Signals a cleanup action is required)." + echo " 2: Fatal error during dependency check or OVN DB query." + echo "" +} + +if [ "$#" -eq 0 ] || [ "$HELP_MODE" = true ]; then + show_help + exit 0 +fi + +if [ "$SCAN_MODE" = true ]; then + + if [ "$FIX_MODE" = true ]; then + echo "==========================================================================" + echo " WARNING: FIX MODE IS ACTIVE! Stale ACLs and Port_Groups will be DELETED." + echo "==========================================================================" + echo "" + else + echo "========================================================" + echo " SCAN MODE ACTIVE (Read-Only). Use --fix to apply changes." + echo "========================================================" + echo "" + fi + + echo "## 1. Extracting Neutron Security Group and Rule IDs..." + + # Extract Neutron Rules + NEUTRON_RULES_DATA=$(openstack security group rule list -f value) + NEUTRON_RULES_IDS=$(echo "$NEUTRON_RULES_DATA" | awk '{print $1}' | sort) + NEUTRON_RULE_COUNT=$(echo "$NEUTRON_RULES_IDS" | wc -l) + echo " -> Found $NEUTRON_RULE_COUNT Neutron Security Group Rules." + + # Extract Neutron Security Groups + NEUTRON_SG_DATA=$(openstack security group list -f value) + NEUTRON_SG_IDS=$(echo "$NEUTRON_SG_DATA" | awk '{print $1}' | sort) + NEUTRON_SG_COUNT=$(echo "$NEUTRON_SG_IDS" | wc -l) + echo " -> Found $NEUTRON_SG_COUNT Neutron Security Groups." + + echo "" + + # Build Sets for fast comparison + NEUTRON_RULE_SET=" " + for id in $NEUTRON_RULES_IDS; do + NEUTRON_RULE_SET="${NEUTRON_RULE_SET}${id} " + done + + NEUTRON_SG_SET=" " + for id in $NEUTRON_SG_IDS; do + NEUTRON_SG_SET="${NEUTRON_SG_SET}${id} " + done + + echo "## 2. OVN ACL Comparison (Policy Rules)" + + declare -A ACL_UUIDS_MAP + STALE_ACL_UUIDS=() + + OVN_ACL_DATA=$($KO_NBCTL_CMD --columns=_uuid,external_ids --bare --format=csv find ACL) + + if [ $? -ne 0 ]; then + echo " [FATAL ERROR] Failed to execute 'ovn-nbctl find ACL' command." + exit 2 + fi + + # ACL_UUIDS_MAP uses Neutron Rule ID (Key) to OVN ACL UUID (Value) + eval "$( + echo "$OVN_ACL_DATA" | + awk ' + BEGIN { FS="," } + NF==2 { + ovn_uuid = $1 + external_ids = $2 + + if (external_ids ~ /neutron:security_group_rule_id=/) { + if (match(external_ids, /neutron:security_group_rule_id=([a-f0-9-]+)/, arr)) { + neutron_id = arr[1] + if (neutron_id != "") { + # Output a Bash assignment statement for direct eval + print "ACL_UUIDS_MAP[\"" neutron_id "\"]=\"" ovn_uuid "\"" + } + } + } + } + ' + )" + + OVN_RULE_COUNT=${#ACL_UUIDS_MAP[@]} + echo " -> Successfully mapped $OVN_RULE_COUNT unique Neutron Rule IDs to OVN ACLs." + echo "" + + echo "## 3. OVN Port_Group Comparison (Security Groups)" + + declare -A PG_UUIDS_MAP + STALE_PG_UUIDS=() + + OVN_PG_DATA=$($KO_NBCTL_CMD --columns=_uuid,external_ids --bare --format=csv find Port_Group) + + if [ $? -ne 0 ]; then + echo " [FATAL ERROR] Failed to execute 'ovn-nbctl find Port_Group' command." + exit 2 + fi + + # PG_UUIDS_MAP uses Neutron SG ID (Key) to OVN Port_Group UUID (Value) + eval "$( + echo "$OVN_PG_DATA" | + awk ' + BEGIN { FS="," } + NF==2 { + ovn_uuid = $1 + external_ids = $2 + + if (external_ids ~ /neutron:security_group_id=/) { + if (match(external_ids, /neutron:security_group_id=([a-f0-9-]+)/, arr)) { + neutron_id = arr[1] + if (neutron_id != "") { + # Output a Bash assignment statement for direct eval + print "PG_UUIDS_MAP[\"" neutron_id "\"]=\"" ovn_uuid "\"" + } + } + } + } + ' + )" + + OVN_PG_COUNT=${#PG_UUIDS_MAP[@]} + echo " -> Successfully mapped $OVN_PG_COUNT unique Neutron SG IDs to OVN Port_Groups." + echo "" + + echo "## 4. Comparison Report (Neutron Resources)" + echo "------------------------------------------" + + echo "### A. Policy Rules (ACLs) - Neutron Rules vs OVN ACLs" + MISSING_RULES=0 + for id in $NEUTRON_RULES_IDS; do + if [[ ! ${ACL_UUIDS_MAP["$id"]} ]]; then + echo " [MISSING] Neutron SG Rule ID: $id" + MISSING_RULES=$((MISSING_RULES + 1)) + fi + done + if [ $MISSING_RULES -eq 0 ]; then + echo " [OK] All $NEUTRON_RULE_COUNT Neutron SG Rules found in OVN NBDB." + else + echo " [ERROR] Total Missing Rules: $MISSING_RULES" + fi + echo "" + + echo "### B. Stale Policy Rules (ACLs) in OVN NBDB" + STALE_RULES=0 + for neutron_id in "${!ACL_UUIDS_MAP[@]}"; do + if ! echo "$NEUTRON_RULE_SET" | grep -q " ${neutron_id} "; then + ovn_uuid="${ACL_UUIDS_MAP["$neutron_id"]}" + echo " [STALE] Rule ID: $neutron_id (OVN ACL UUID: $ovn_uuid)" + STALE_ACL_UUIDS+=("$ovn_uuid") + STALE_RULES=$((STALE_RULES + 1)) + fi + done + + if [ $STALE_RULES -eq 0 ]; then + echo " [OK] No stale Neutron-managed ACLs found in OVN NBDB." + else + echo " [CLEANUP NEEDED] Total Stale Rules: $STALE_RULES" + STALE_FOUND=1 + fi + echo "" + + echo "### C. Security Groups (Port_Groups) - Neutron SGs vs OVN Port_Groups" + MISSING_SGS=0 + for id in $NEUTRON_SG_IDS; do + if [[ ! ${PG_UUIDS_MAP["$id"]} ]]; then + echo " [MISSING] Neutron SG ID: $id" + MISSING_SGS=$((MISSING_SGS + 1)) + fi + done + if [ $MISSING_SGS -eq 0 ]; then + echo " [OK] All $NEUTRON_SG_COUNT Neutron SGs found as OVN Port_Groups." + else + echo " [ERROR] Total Missing SGs: $MISSING_SGS" + fi + echo "" + + echo "### D. Stale Port_Groups in OVN NBDB" + STALE_SGS=0 + for neutron_id in "${!PG_UUIDS_MAP[@]}"; do + if ! echo "$NEUTRON_SG_SET" | grep -q " ${neutron_id} "; then + ovn_uuid="${PG_UUIDS_MAP["$neutron_id"]}" + echo " [STALE] SG ID: $neutron_id (OVN Port_Group UUID: $ovn_uuid)" + STALE_PG_UUIDS+=("$ovn_uuid") + STALE_SGS=$((STALE_SGS + 1)) + fi + done + + if [ $STALE_SGS -eq 0 ]; then + echo " [OK] No stale Neutron-managed Port_Groups found in OVN NBDB." + else + echo " [CLEANUP NEEDED] Total Stale Port_Groups: $STALE_SGS" + STALE_FOUND=1 + fi + echo "" + + if [ "$FIX_MODE" = true ] && [ "$STALE_FOUND" -eq 1 ]; then + echo "## 5. Remediation: Deleting Stale Resources from OVN NBDB" + + ACL_CLEANUP_COUNT=0 + ACL_TOTAL_TO_CLEANUP=${#STALE_ACL_UUIDS[@]} + for acl_uuid in "${STALE_ACL_UUIDS[@]}"; do + ACL_CLEANUP_COUNT=$((ACL_CLEANUP_COUNT + 1)) + echo " -> [ACL $ACL_CLEANUP_COUNT/$ACL_TOTAL_TO_CLEANUP] Attempting to destroy STALE ACL UUID: $acl_uuid" + $KO_NBCTL_CMD destroy ACL "$acl_uuid" || echo " -> WARNING: Failed to destroy ACL $acl_uuid. May require manual cleanup." + done + + PG_CLEANUP_COUNT=0 + PG_TOTAL_TO_CLEANUP=${#STALE_PG_UUIDS[@]} + for pg_uuid in "${STALE_PG_UUIDS[@]}"; do + PG_CLEANUP_COUNT=$((PG_CLEANUP_COUNT + 1)) + echo " -> [PG $PG_CLEANUP_COUNT/$PG_TOTAL_TO_CLEANUP] Attempting to destroy STALE Port_Group UUID: $pg_uuid" + $KO_NBCTL_CMD destroy Port_Group "$pg_uuid" || echo " -> WARNING: Failed to destroy Port_Group $pg_uuid. May require manual cleanup." + done + + echo " [COMPLETE] Remediation attempt finished." + exit 0 + elif [ "$FIX_MODE" = true ] && [ "$STALE_FOUND" -eq 0 ]; then + echo "## 5. Remediation" + echo " [SKIP] Fix mode enabled, but no stale resources found to delete." + exit 0 + fi + + exit "$STALE_FOUND" + +fi