Week 1: Component-Level Testing¶
Test Matrix Week 1¶
┌────┬───────────────────────────────────────┬──────────────┬──────────────┐
│ ID │ Test │ Platform │ Pass Criteria│
├────┼───────────────────────────────────────┼──────────────┼──────────────┤
│1.1 │ GCP Cloud Interconnect BGP │ GCP + C8500 │ BGP ESTAB │
│1.2 │ GCP Vertex AI API reachability │ GCP │ HTTP 200 │
│1.3 │ Azure ExpressRoute BGP (3 circuits) │ Azure + C8500│ 6/6 sessions │
│1.4 │ Azure Virtual WAN IPsec (19 sites) │ Azure + vMgmt│ 19/19 UP │
│1.5 │ Azure Private Endpoints DNS │ Azure + DNS │ 10.100.10.x │
│1.6 │ SD-WAN fabric health (all 19 sites) │ vManage │ 19/19 reach │
│1.7 │ SD-WAN BFD sessions │ vManage │ >150 sessions│
│1.8 │ OMP route distribution │ vManage │ All VPNs OK │
│1.9 │ Umbrella DNS registration │ Umbrella │ 19/19 reg │
│1.10│ ThousandEyes agents │ TE │ 6/6 online │
└────┴───────────────────────────────────────┴──────────────┴──────────────┘
TEST 1.1: GCP Cloud Interconnect BGP¶
Objective: Verify BGP sessions between Mumbai C8500-12X (MUM-HUB-01) and GCP via Dedicated Interconnect
Procedure:
! On MUM-HUB-01
show bgp ipv4 unicast summary | include 169.254.0
! Expected output:
! 169.254.0.1 4 16550 1000 900 0 0 0 1d12h 45
! 169.254.0.5 4 16550 1000 900 0 0 0 1d12h 45
! (Google BGP ASN: 16550)
! Uptime column: Should show days, not recent restart
show bgp ipv4 unicast 34.0.0.0
! Expected: Route to GCP API ranges via 169.254.0.1 (Cloud Interconnect)
! Verify prefix count from GCP
show bgp ipv4 unicast neighbors 169.254.0.1 received-routes | count
! Expected: 15-30 routes (GCP public API ranges)
Pass Criteria: - Both BGP sessions (primary 169.254.0.1 and secondary 169.254.0.5) in ESTABLISHED state - Uptime > 1 hour (stable, not flapping) - 15+ prefixes received
Failure Action: Check VLAN config on Dedicated Interconnect attachment, verify MTU (1500 minimum, 1440 for GRE overhead), check Google-assigned BGP peer IPs in Cloud Console
TEST 1.2: GCP Vertex AI API Reachability¶
Objective: Confirm Vertex AI API (us-central1 / asia-south1) reachable from Mumbai hub via Cloud Interconnect (not public internet)
# Run from MUM-TEST-01 (10.100.1.50)
## Step 1: Check routing — Vertex AI traffic should use Cloud Interconnect
traceroute -n aiplatform.googleapis.com
## Expected: First hops via 169.254.0.1 (Cloud Interconnect peer), NOT via public internet gateways
## Step 2: Test Vertex AI API endpoint
curl -s -o /dev/null -w "%{http_code} %{time_total}s" \
-H "Authorization: Bearer $(gcloud auth print-access-token)" \
https://asia-south1-aiplatform.googleapis.com/v1/projects/abhavtech-ai/locations/asia-south1/endpoints
## Expected: 200 (or 403/404 if test project has no endpoints — that's OK, just need HTTP response)
## Latency: <10ms (Cloud Interconnect, not internet which would be 30-60ms)
## Step 3: Compare path (Cloud Interconnect vs internet)
## Via Cloud Interconnect (expected):
mtr --report -n -c 5 aiplatform.googleapis.com 2>/dev/null | tail -15
## Expected: Private hops (10.x.x.x, 169.254.x.x), final hop in Google space
## Step 4: Verify Private Service Access DNS
nslookup aiplatform.googleapis.com
## If PSA configured: Should return 10.x.x.x (private)
## If not PSA: Will return public Google IP — still OK if routing via interconnect
Pass Criteria: - Vertex AI API returns HTTP response (any 2xx/4xx — not timeout) - Traceroute shows Cloud Interconnect path (169.254.0.x hops) - Latency < 15ms from Mumbai hub
TEST 1.3: Azure ExpressRoute BGP Verification¶
Objective: Confirm all 6 BGP sessions (3 circuits × 2 paths) established and O365 prefixes received
#!/bin/bash
## expressroute_bgp_test.sh
echo "=== TEST 1.3: AZURE EXPRESSROUTE BGP ==="
## Expected: 6 sessions total (Mumbai, London, NJ × 2 peers each)
PASS=0; FAIL=0
check_bgp() {
local SITE=$1
local PRIMARY_IP=$2
local SECONDARY_IP=$3
echo ""
echo "--- $SITE ---"
## Check primary BGP
P_STATE=$(ssh admin@$SITE "show bgp ipv4 unicast summary | grep ${PRIMARY_IP}" 2>/dev/null | awk '{print $10}')
if echo "$P_STATE" | grep -qE "^[0-9]+$"; then
echo " ✅ Primary (${PRIMARY_IP}): ESTABLISHED (${P_STATE} prefixes)"
((PASS++))
else
echo " ❌ Primary (${PRIMARY_IP}): NOT established (state: $P_STATE)"
((FAIL++))
fi
## Check secondary BGP
S_STATE=$(ssh admin@$SITE "show bgp ipv4 unicast summary | grep ${SECONDARY_IP}" 2>/dev/null | awk '{print $10}')
if echo "$S_STATE" | grep -qE "^[0-9]+$"; then
echo " ✅ Secondary (${SECONDARY_IP}): ESTABLISHED (${S_STATE} prefixes)"
((PASS++))
else
echo " ❌ Secondary (${SECONDARY_IP}): NOT established (state: $S_STATE)"
((FAIL++))
fi
## Check O365 prefix count (should be 500-800 per circuit)
PREFIX_COUNT=$(ssh admin@$SITE "show bgp ipv4 unicast neighbors ${PRIMARY_IP} received-routes | count" 2>/dev/null | tail -1)
echo " O365 prefixes from primary: $PREFIX_COUNT"
[[ "$PREFIX_COUNT" -ge 500 ]] && echo " ✅ Prefix count OK (${PREFIX_COUNT} ≥ 500)" && ((PASS++)) \
|| { echo " ❌ Low prefix count (${PREFIX_COUNT} < 500)"; ((FAIL++)); }
}
check_bgp "mum-hub-01" "169.254.200.1" "169.254.200.5" # Mumbai (VLAN 4001)
check_bgp "lon-hub-01" "169.254.201.1" "169.254.201.5" # London (VLAN 4002)
check_bgp "nj-hub-01" "169.254.202.1" "169.254.202.5" # New Jersey (VLAN 4003)
echo ""
echo "=== TEST 1.3 RESULT: $PASS PASSED, $FAIL FAILED ==="
[[ $FAIL -eq 0 ]] && echo "✅ PASS" || echo "❌ FAIL"
Pass Criteria: - All 6 BGP sessions ESTABLISHED (Microsoft ASN 12076) - 500–800 prefixes per circuit (O365 + Azure AD + Common) - LOCAL_PREF: Primary circuits = 200, secondary = 100
TEST 1.4: Azure Virtual WAN IPsec Tunnels (All 19 Sites)¶
#!/bin/bash
## vwan_ipsec_test.sh
echo "=== TEST 1.4: AZURE VIRTUAL WAN IPsec TUNNELS ==="
## All 19 WAN edge system IPs
SITES=(
"mum-hub-01:10.252.1.1" "lon-hub-01:10.252.16.1" "nj-hub-01:10.252.32.1"
"chn-hub-01:10.252.2.1" "dal-hub-01:10.252.33.1"
"blr-isr-01:10.252.50.1" "del-isr-01:10.252.51.1"
"hyd-br-01:10.252.52.1" "pun-br-01:10.252.53.1" "ahm-br-01:10.252.54.1"
"noi-br-01:10.252.55.1" "kol-br-01:10.252.56.1" "jai-br-01:10.252.57.1"
"sur-br-01:10.252.58.1" "nag-br-01:10.252.59.1" "chd-br-01:10.252.60.1"
"coi-br-01:10.252.61.1" "luc-br-01:10.252.62.1" "fra-isr-01:10.252.17.1"
)
PASS=0; FAIL=0
for ENTRY in "${SITES[@]}"; do
HOSTNAME=$(echo $ENTRY | cut -d: -f1)
SYSTEM_IP=$(echo $ENTRY | cut -d: -f2)
## Check IPsec SA (IKEv2 READY state)
SA_COUNT=$(ssh admin@$HOSTNAME "show crypto ikev2 sa | grep -c READY" 2>/dev/null)
if [[ "$SA_COUNT" -ge 1 ]]; then
## Also check tunnel interface is up
T_UP=$(ssh admin@$HOSTNAME "show interfaces Tunnel200 | grep -c 'line protocol is up'" 2>/dev/null)
if [[ "$T_UP" -ge 1 ]]; then
echo " ✅ [$HOSTNAME]: IKEv2 READY, Tunnel200 UP"
((PASS++))
else
echo " ⚠️ [$HOSTNAME]: IKEv2 READY but Tunnel200 DOWN"
((FAIL++))
fi
else
echo " ❌ [$HOSTNAME]: No IKEv2 SA (not READY)"
((FAIL++))
fi
done
echo ""
echo "=== TEST 1.4: $PASS/19 sites PASS, $FAIL FAIL ==="
[[ $FAIL -eq 0 ]] && echo "✅ PASS: All 19 tunnels UP" \
|| echo "❌ FAIL: $FAIL sites need investigation"
TEST 1.5: Azure Private Endpoint DNS Resolution¶
#!/bin/bash
## private_endpoint_dns_test.sh
echo "=== TEST 1.5: AZURE PRIVATE ENDPOINT DNS ==="
## Internal DNS servers (on-premise AD, forward to 168.63.129.16 via conditional forwarder)
DNS_SERVER="10.252.1.100"
declare -A EXPECTED_IPS=(
["abhavtech-sql.database.windows.net"]="10.100.10.10"
["abhavtechstorage.blob.core.windows.net"]="10.100.10.20"
["abhavtechfiles.file.core.windows.net"]="10.100.10.21"
["abhavtech-kv.vault.azure.net"]="10.100.10.30"
)
PASS=0; FAIL=0
for FQDN in "${!EXPECTED_IPS[@]}"; do
EXPECTED="${EXPECTED_IPS[$FQDN]}"
## Test from Mumbai hub (should resolve to private IP)
RESOLVED=$(nslookup $FQDN $DNS_SERVER 2>/dev/null | grep "Address" | tail -1 | awk '{print $2}')
if [[ "$RESOLVED" == "$EXPECTED" ]]; then
echo " ✅ $FQDN → $RESOLVED (private ✓)"
((PASS++))
elif [[ "$RESOLVED" == 10.100.10.* ]]; then
echo " ⚠️ $FQDN → $RESOLVED (private, expected $EXPECTED)"
((PASS++))
else
echo " ❌ $FQDN → $RESOLVED (expected private $EXPECTED — got public or no response)"
((FAIL++))
fi
done
## Also test from branch site (Bangalore)
echo ""
echo "--- Testing from Bangalore branch (192.168.50.100) ---"
for FQDN in "abhavtech-sql.database.windows.net" "abhavtechstorage.blob.core.windows.net"; do
RESULT=$(ssh admin@blr-user-01 "nslookup $FQDN 10.252.1.100 2>/dev/null | grep Address | tail -1" 2>/dev/null | awk '{print $2}')
[[ "$RESULT" == "10.100.10."* ]] && { echo " ✅ [BLR] $FQDN → $RESULT (private)"; ((PASS++)); } \
|| { echo " ❌ [BLR] $FQDN → $RESULT (expected 10.100.10.x)"; ((FAIL++)); }
done
echo ""
echo "=== TEST 1.5: $PASS PASSED, $FAIL FAILED ==="
TEST 1.6–1.7: SD-WAN Fabric Health¶
#!/bin/bash
## sdwan_fabric_health_test.sh
echo "=== TEST 1.6-1.7: SD-WAN FABRIC HEALTH ==="
VMANAGE="vmanage.abhavtech.com"
COOKIE="/tmp/cookies.txt"
## Login
curl -k -s -X POST https://$VMANAGE/j_security_check \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "j_username=admin&j_password=<PASSWORD>" -c $COOKIE > /dev/null
echo ""
echo "--- TEST 1.6: Device Reachability ---"
DEVICES=$(curl -k -s -b $COOKIE "https://$VMANAGE/dataservice/device?type=vedge")
TOTAL=$(echo $DEVICES | python3 -c "import json,sys; d=json.load(sys.stdin); print(len(d.get('data', [])))")
REACHABLE=$(echo $DEVICES | python3 -c "import json,sys; d=json.load(sys.stdin); print(sum(1 for x in d['data'] if x.get('reachability')=='reachable'))")
echo " Devices: $REACHABLE/$TOTAL reachable"
[[ "$REACHABLE" -eq 19 ]] && echo " ✅ PASS: All 19 devices reachable" \
|| { echo " ❌ FAIL: $((19 - REACHABLE)) devices unreachable"; \
echo $DEVICES | python3 -c "import json,sys; d=json.load(sys.stdin); [print(f' - {x[\"host-name\"]} ({x[\"system-ip\"]})') for x in d['data'] if x.get('reachability')!='reachable']"; }
echo ""
echo "--- TEST 1.7: BFD Sessions ---"
for HUB in mum-hub-01 lon-hub-01 nj-hub-01; do
BFD_TOTAL=$(ssh admin@$HUB "show sdwan bfd sessions | wc -l" 2>/dev/null)
BFD_UP=$(ssh admin@$HUB "show sdwan bfd sessions | grep Up | wc -l" 2>/dev/null)
echo " [$HUB]: $BFD_UP/$BFD_TOTAL BFD sessions UP"
[[ "$BFD_UP" -ge 30 ]] && echo " ✅ PASS: BFD health OK" || echo " ❌ FAIL: Low BFD sessions"
done
echo ""
echo "--- TEST 1.8: OMP Route Distribution (VPN 1) ---"
for SITE in mum-hub-01 blr-isr-01 del-isr-01; do
OMP_COUNT=$(ssh admin@$SITE "show sdwan omp routes vpn 1 | count" 2>/dev/null | tail -1)
echo " [$SITE]: $OMP_COUNT OMP routes in VPN 1"
[[ "$OMP_COUNT" -ge 20 ]] && echo " ✅ PASS" || echo " ❌ FAIL: Low route count (expected 20+)"
done
TEST 1.9–1.10: Umbrella and ThousandEyes¶
## TEST 1.9: Umbrella Registration
echo "=== TEST 1.9: UMBRELLA DEVICE REGISTRATION ==="
for SITE in mum-hub-01 lon-hub-01 nj-hub-01 blr-isr-01 del-isr-01 hyd-br-01; do
STATUS=$(ssh admin@$SITE "show umbrella config | grep -i status" 2>/dev/null)
echo "$STATUS" | grep -qi "registered" && echo " ✅ [$SITE]: Umbrella registered" \
|| echo " ❌ [$SITE]: Umbrella NOT registered"
done
## TEST 1.10: ThousandEyes Agents
echo ""
echo "=== TEST 1.10: THOUSANDEYES AGENT STATUS ==="
## Use ThousandEyes API v7
TE_TOKEN="<TE_BEARER_TOKEN>"
curl -s -X GET "https://api.thousandeyes.com/v7/agents" \
-H "Authorization: Bearer $TE_TOKEN" | \
python3 -c "
import json, sys
data = json.load(sys.stdin)
agents = data.get('agents', [])
print(f'Total agents: {len(agents)}')
for a in agents:
status = '✅' if a.get('enabled') and a.get('agentState') == 'Online' else '❌'
print(f'{status} {a[\"agentName\"]:20} {a.get(\"agentState\",\"unknown\"):8} Last seen: {a.get(\"lastSeen\",\"N/A\")}')
"