Skip to content

Week 4 Day 3: vManage API Automation

Python: Query and Report Cloud OnRamp Status

#!/usr/bin/env python3

"""
vManage API: Cloud OnRamp monitoring and reporting
Generates daily status report for all sites
"""

import requests
import json
import urllib3
from datetime import datetime, timedelta
from collections import defaultdict

urllib3.disable_warnings()

VMANAGE_HOST = "vmanage.abhavtech.com"
USERNAME = "admin"
PASSWORD = "<VMANAGE_PASSWORD>"


class CloudOnRampMonitor:
    def __init__(self, host, username, password):
        self.base = f"https://{host}"
        self.s = requests.Session()
        self.s.verify = False
        self._authenticate(username, password)

    def _authenticate(self, username, password):
        self.s.post(
            f"{self.base}/j_security_check",
            data={"j_username": username, "j_password": password},
            headers={"Content-Type": "application/x-www-form-urlencoded"}
        )
        token = self.s.get(f"{self.base}/dataservice/client/token").text
        self.s.headers["X-XSRF-TOKEN"] = token

    def get(self, endpoint):
        return self.s.get(f"{self.base}/dataservice/{endpoint}").json()

    def get_saas_app_status(self):
        """Get current SaaS app performance per site"""
        data = self.get("cloudonramp/saas/gateway/apps")
        return data.get("data", [])

    def get_device_tunnel_stats(self, system_ip, hours=24):
        """Get tunnel statistics for a device"""
        end_time = int(datetime.now().timestamp() * 1000)
        start_time = int((datetime.now() - timedelta(hours=hours)).timestamp() * 1000)
        data = self.get(
            f"statistics/interface/fec/aggregation?deviceId={system_ip}"
            f"&startTime={start_time}&endTime={end_time}"
        )
        return data.get("data", [])

    def get_app_route_stats(self, hours=24):
        """Get application route statistics across all devices"""
        end_time = int(datetime.now().timestamp() * 1000)
        start_time = int((datetime.now() - timedelta(hours=hours)).timestamp() * 1000)
        data = self.get(
            f"statistics/approute/fec/aggregation"
            f"?startTime={start_time}&endTime={end_time}&count=100"
        )
        return data.get("data", [])

    def get_umbrella_status(self):
        """Get Umbrella integration health"""
        return self.get("cloudonramp/colo")

    def get_all_devices(self):
        """Get all WAN edge device inventory"""
        data = self.get("device?type=vedge")
        return {d["host-name"]: d for d in data.get("data", [])}

    def generate_report(self):
        """Generate comprehensive Cloud OnRamp status report"""
        print("=" * 70)
        print("  ABHAVTECH SD-WAN CLOUD ONRAMP — DAILY STATUS REPORT")
        print(f"  Generated: {datetime.now().strftime('%Y-%m-%d %H:%M UTC')}")
        print("=" * 70)

# --- SaaS App Status ---

        print("\n📊 CLOUD ONRAMP FOR SaaS — APP PERFORMANCE")
        print("-" * 70)
        saas_data = self.get_saas_app_status()
        if saas_data:
            app_stats = defaultdict(list)
            for entry in saas_data:
                app_stats[entry.get("appName", "unknown")].append(entry)

            for app, entries in app_stats.items():
                latencies = [e.get("latency", 0) for e in entries if e.get("latency")]
                avg_lat = sum(latencies) / len(latencies) if latencies else 0
                gateways = set(e.get("bestPath", "unknown") for e in entries)
                status = "✅" if avg_lat < 100 else "⚠️ "
                print(f"  {status} {app:25} Avg Latency: {avg_lat:6.1f}ms  Gateway: {', '.join(gateways)}")
        else:
            print("  No SaaS data available")

## --- Device Inventory ---

        print("\n📡 WAN EDGE DEVICE STATUS")
        print("-" * 70)
        devices = self.get_all_devices()
        reachable = sum(1 for d in devices.values() if d.get("reachability") == "reachable")
        total = len(devices)
        print(f"  Devices: {reachable}/{total} reachable")
        for name, dev in sorted(devices.items()):
            status = "✅" if dev.get("reachability") == "reachable" else "❌"
            print(f"  {status} {name:20} {dev.get('reachability', 'unknown'):12} {dev.get('version', 'N/A')}")

## --- App Route Statistics ---

        print("\n📈 APPLICATION ROUTE SLA COMPLIANCE (LAST 24H)")
        print("-" * 70)
        route_stats = self.get_app_route_stats(hours=24)
        if route_stats:
            for stat in route_stats[:10]:
                app = stat.get("name", "unknown")
                latency = stat.get("average_latency", 0)
                loss = stat.get("average_loss", 0)
                jitter = stat.get("average_jitter", 0)
                sla_ok = latency < 100 and loss < 1.0
                status = "✅" if sla_ok else "❌"
                print(f"  {status} {app:25} Lat:{latency:5.0f}ms Loss:{loss:4.1f}% Jitter:{jitter:4.0f}ms")

        print("\n" + "=" * 70)
        print("  Report complete. Next report in 24 hours.")
        print("=" * 70)


if __name__ == "__main__":
    monitor = CloudOnRampMonitor(VMANAGE_HOST, USERNAME, PASSWORD)
    monitor.generate_report()

Cron Job for Automated Daily Reporting

## Add to crontab on monitoring server

crontab -e

## Run daily report at 06:00 UTC

0 6 * * * /usr/bin/python3 /opt/scripts/cloudonramp_report.py >> /var/log/sdwan/cloudonramp_$(date +\%Y\%m\%d).log 2>&1

## Send report to Splunk via HTTP Event Collector

0 6 * * * /opt/scripts/cloudonramp_report.py | \
  curl -s -k -H "Authorization: Splunk <HEC_TOKEN>" \
  -H "Content-Type: application/json" \
  https://splunk.abhavtech.com:8088/services/collector/event \
  --data-binary @- \
  -o /dev/null

Week 4 Day 4: End-to-End Validation Suite

#!/bin/bash

## e2e_cloud_onramp_validation.sh

## Complete Cloud OnRamp validation across all three modes


VMANAGE="vmanage.abhavtech.com"
COOKIE_FILE="/tmp/vmanage_cookies.txt"

## Authenticate

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_FILE > /dev/null

echo "========================================================"
echo "  ABHAVTECH CLOUD ONRAMP — END-TO-END VALIDATION"
echo "  $(date)"
echo "========================================================"

## ============================================================

## SECTION 1: CLOUD ONRAMP FOR SaaS

## ============================================================

echo ""
echo "━━━━ SECTION 1: CLOUD ONRAMP FOR SaaS ━━━━"

## Check SaaS app registration

echo ""
echo "[1.1] SaaS App Probe Status"
APP_COUNT=$(curl -k -s -X GET https://$VMANAGE/dataservice/cloudonramp/saas/apps \
  -b $COOKIE_FILE | python3 -c "import json,sys; d=json.load(sys.stdin); print(len(d.get('data', [])))")
echo "  Apps configured: $APP_COUNT (expected: 6)"
[[ "$APP_COUNT" -ge 6 ]] && echo "  ✅ All SaaS apps probed" || echo "  ❌ Missing app probes"

## Check Teams traffic path

echo ""
echo "[1.2] Teams Voice — ExpressRoute Verification"
for HUB in mum-hub-01 lon-hub-01 nj-hub-01; do
  TEAMS_PATH=$(ssh admin@$HUB "show sdwan app-fwd cflowd flows | grep -i teams | head -1" 2>/dev/null)
  if echo "$TEAMS_PATH" | grep -qi "expressroute"; then
    echo "  ✅ [$HUB]: Teams via ExpressRoute"
  else
    echo "  ⚠️  [$HUB]: Teams path: $TEAMS_PATH"
  fi
done

## Check O365 latency (should be <20ms via ExpressRoute)

echo ""
echo "[1.3] Office 365 Latency"
for HOST in "outlook.office365.com" "teams.microsoft.com"; do
  LAT=$(ping -c 5 -q $HOST 2>/dev/null | tail -1 | awk -F/ '{printf "%.0f", $5}')
  [[ -n "$LAT" && "$LAT" -lt 20 ]] && STATUS="✅" || STATUS="⚠️ "
  echo "  $STATUS $HOST: ${LAT}ms (threshold: <20ms)"
done

## Check branch DIA breakout

echo ""
echo "[1.4] Branch Direct Internet Access (No Backhaul)"
for BRANCH in blr-isr-01 del-isr-01; do
  ROUTE=$(ssh admin@$BRANCH "show ip route 0.0.0.0 | head -3" 2>/dev/null)
  if echo "$ROUTE" | grep -q "GigabitEthernet.*[Ww][Aa][Nn]"; then
    echo "  ✅ [$BRANCH]: Default route → DIA (local breakout)"
  else
    echo "  ❌ [$BRANCH]: Default route → Hub (backhauled — check policy)"
  fi
done

## ============================================================

## SECTION 2: CLOUD ONRAMP FOR IaaS (AZURE)

## ============================================================

echo ""
echo "━━━━ SECTION 2: CLOUD ONRAMP FOR IaaS (AZURE) ━━━━"

## Check Azure Virtual WAN tunnels

echo ""
echo "[2.1] Azure Virtual WAN IPsec Tunnels"
for SITE in mum-hub-01 lon-hub-01 nj-hub-01 blr-isr-01; do
  T_STATE=$(ssh admin@$SITE "show crypto ikev2 sa | grep -c READY" 2>/dev/null)
  [[ "$T_STATE" -ge 1 ]] && echo "  ✅ [$SITE]: IKEv2 SA established (READY)" \
                          || echo "  ❌ [$SITE]: IKEv2 SA not ready"
done

## Check Azure VNet route propagation

echo ""
echo "[2.2] Azure VNet Route Propagation"
for SITE in mum-hub-01 blr-isr-01 del-isr-01; do
  R1=$(ssh admin@$SITE "show ip route 10.100.2.0" 2>/dev/null | grep -c "10.100")
  R2=$(ssh admin@$SITE "show ip route 10.101.1.0" 2>/dev/null | grep -c "10.101")
  [[ $R1 -ge 1 && $R2 -ge 1 ]] && echo "  ✅ [$SITE]: Azure routes present" \
                                 || echo "  ❌ [$SITE]: Missing Azure routes"
done

## Check Azure SQL connectivity

echo ""
echo "[2.3] Azure SQL Private Endpoint Connectivity (1433)"
for BRANCH in "blr-user-host" "del-user-host"; do
  RESULT=$(timeout 5 bash -c "echo '' > /dev/tcp/10.100.10.10/1433" 2>/dev/null)
  [[ $? -eq 0 ]] && echo "  ✅ Azure SQL: Port 1433 reachable" \
                  || echo "  ❌ Azure SQL: Port 1433 not reachable"
done

## Check Private DNS

echo ""
echo "[2.4] Private Endpoint DNS Resolution"
for FQDN in "abhavtech-sql.database.windows.net" "abhavtechstorage.blob.core.windows.net"; do
  IP=$(nslookup $FQDN 10.101.1.10 2>/dev/null | grep "Address" | tail -1 | awk '{print $2}')
  [[ "$IP" == "10.100.10."* ]] && echo "  ✅ $FQDN$IP (private)" \
                                 || echo "  ❌ $FQDN$IP (expected 10.100.10.x)"
done

## ============================================================

## SECTION 3: CLOUD ONRAMP FOR SASE (UMBRELLA)

## ============================================================

echo ""
echo "━━━━ SECTION 3: CLOUD ONRAMP FOR SASE (UMBRELLA) ━━━━"

## Check Umbrella SIG tunnel

echo ""
echo "[3.1] Umbrella SIG Tunnel Status"
for HUB in mum-hub-01 lon-hub-01 nj-hub-01; do
  T300=$(ssh admin@$HUB "show interfaces Tunnel300 | grep 'line protocol'" 2>/dev/null | grep -c "up")
  [[ $T300 -ge 1 ]] && echo "  ✅ [$HUB]: Umbrella SIG Tunnel300 UP" \
                     || echo "  ❌ [$HUB]: Umbrella SIG Tunnel300 DOWN"
done

## Check Umbrella DNS registration

echo ""
echo "[3.2] Branch Umbrella DNS Registration"
for BRANCH in blr-isr-01 del-isr-01; do
  REG=$(ssh admin@$BRANCH "show umbrella config | include Status" 2>/dev/null)
  echo "  [$BRANCH]: $REG"
done

## Check DNS security (malicious domain blocked)

echo ""
echo "[3.3] Umbrella DNS Security (Malicious Domain Block Test)"
BLOCKED=$(nslookup malicious-test.abhavtech-test.com 208.67.222.222 2>/dev/null | grep -c "NXDOMAIN\|blocked")
[[ $BLOCKED -ge 1 ]] && echo "  ✅ Malicious domain blocked by Umbrella" \
                       || echo "  ⚠️  DNS blocking not verified (manual check required)"

## ============================================================

## SECTION 4: QoS VERIFICATION

## ============================================================

echo ""
echo "━━━━ SECTION 4: QoS POLICY VERIFICATION ━━━━"

echo ""
echo "[4.1] QoS Policy Attachment"
for HUB in mum-hub-01 lon-hub-01 nj-hub-01; do
  QOS=$(ssh admin@$HUB "show policy-map interface TenGigabitEthernet0/0/0.100 | include policy" 2>/dev/null | head -1)
  [[ -n "$QOS" ]] && echo "  ✅ [$HUB]: QoS policy active on MPLS" \
                   || echo "  ❌ [$HUB]: No QoS policy on MPLS"
done

echo ""
echo "[4.2] DSCP Marking Verification (EF for Teams)"
for HUB in mum-hub-01; do
  EF_COUNT=$(ssh admin@$HUB "show policy-map interface TenGigabitEthernet0/0/2.4001 class QOS-EF | include packets" 2>/dev/null | awk '{sum+=$2} END {print sum}')
  [[ "$EF_COUNT" -gt "0" ]] && echo "  ✅ [$HUB]: EF (Teams) traffic counted: $EF_COUNT packets" \
                              || echo "  ⚠️  [$HUB]: No EF traffic counted (Teams may not be active)"
done

## ============================================================

## SUMMARY

## ============================================================

echo ""
echo "========================================================"
echo "  VALIDATION COMPLETE — $(date)"
echo "========================================================"
echo "  Check any ❌ items before proceeding to production."
echo "========================================================"

Week 4 Day 5: Production Cutover and Monitoring

Pre-Cutover Final Checklist

CLOUD ONRAMP SaaS:
□ 6 SaaS apps have active probes: O365, Webex, Salesforce, ServiceNow, Workday, Zoom
□ 3 hub gateways active: Mumbai (APAC), London (EMEA), New Jersey (Americas)
□ All 19 sites reporting probe results
□ Teams traffic: ExpressRoute (EF DSCP) at all hub sites
□ Branch SaaS: Local DIA breakout confirmed (not backhauled)
□ SaaS probe automatic path switching: Tested and functional

CLOUD ONRAMP IaaS (AZURE):
□ Virtual WAN hub: Active in Central India
□ All 19 sites IPsec tunnels: Established
□ Azure VNet routes (10.100.0.0/16): Visible in all site routing tables
□ Azure SQL (10.100.10.10) port 1433: Reachable from Bangalore, Delhi
□ Private DNS: Returning 10.100.10.x from all branches
□ IaaS failover tested: DIA primary → MPLS backup <30s

CLOUD ONRAMP SASE (UMBRELLA):
□ Hub Umbrella SIG tunnels: Active (Tunnel300/301 UP)
□ Branch DNS redirection: All branches pointing to 208.67.222.222
□ Umbrella device registration: All 19 devices registered in Umbrella dashboard
□ DNS security: Malicious domain test blocked
□ SSL inspection: Active for non-whitelisted domains
□ CASB: M365 activity monitoring active

QoS AND POLICIES:
□ QoS policy: Active on all MPLS, DIA, ExpressRoute interfaces
□ DSCP EF: Set for Teams voice on all hub interfaces
□ AAR policy: Deployed to all 19 WAN edges via device template
□ Control policy: Azure routes distributed to all branches

MONITORING:
□ vManage dashboards: Cloud OnRamp view configured
□ Splunk: SD-WAN integration active (vManage → Splunk)
□ ThousandEyes: Tests active for O365 from hub sites
□ Automated daily report script: Running via cron
□ Alerts configured: Tunnel down, SLA breach, probe threshold

Activate Production Policies

## Step 1: Attach device templates to all sites (vManage UI)

## Configuration → Templates → Device Templates

## Select template → Attach Devices → Select all sites → Dry Run first


## Step 2: Verify dry run shows no conflicts

## If dry run passes → Push to devices


## Step 3: Monitor during rollout

watch -n 30 'curl -k -s -b /tmp/vmanage_cookies.txt \
  https://vmanage.abhavtech.com/dataservice/device/action/status \
  | python3 -c "import json,sys; d=json.load(sys.stdin); \
  [print(f\"{i[\"vmanage-id\"]:20} {i[\"status\"]}\") for i in d.get(\"data\",[])]"'

## Step 4: Monitor SaaS probe results (should show path optimization immediately)

## vManage → Monitor → Cloud OnRamp for SaaS → View app paths


## Step 5: Monitor for 4 hours, then declare success

echo "Production cutover complete: $(date)"

Rollback Procedure

## If issues detected — immediate rollback:


## Step 1: Detach problematic device template in vManage UI

## Configuration → Templates → Device Templates → Detach Device


## Step 2: Revert to previous template version

## Configuration → Templates → Template Versions → Activate Previous


## Step 3: Clear stale policy on device if needed

ssh admin@mum-hub-01
sdwan
no policy
## SD-WAN falls back to basic routing — SaaS traffic returns to MPLS


## Step 4: Notify stakeholders

echo "Rollback initiated at $(date)" | mail -s "SD-WAN Policy Rollback" noc@abhavtech.com

Appendix A: Complete Policy JSON Reference

AAR Policy JSON Export (Hub Sites)

{
  "policyDefinition": {
    "name": "Abhavtech-Hub-CloudOnRamp-AAR",
    "type": "appRoute",
    "sequences": [
      {
        "sequenceId": 10,
        "sequenceName": "Teams-Voice-EF",
        "sequenceType": "applicationFirewall",
        "match": {
          "entries": [
            {"field": "app-list", "value": "ms-teams-media"},
            {"field": "protocol", "value": "17"}
          ]
        },
        "actions": [
          {
            "type": "set",
            "parameter": {
              "slaClass": "SLA-TEAMS-VOICE",
              "preferredColor": "azure-expressroute",
              "backupSlaPreferredColor": "mpls",
              "dscp": "46"
            }
          }
        ]
      },
      {
        "sequenceId": 30,
        "sequenceName": "Exchange-Online",
        "sequenceType": "applicationFirewall",
        "match": {
          "entries": [
            {"field": "app-list", "value": "office365-exchange"}
          ]
        },
        "actions": [
          {
            "type": "set",
            "parameter": {
              "slaClass": "SLA-O365-INTERACTIVE",
              "preferredColor": "azure-expressroute",
              "backupSlaPreferredColor": "mpls",
              "dscp": "18"
            }
          }
        ]
      },
      {
        "sequenceId": 60,
        "sequenceName": "Corporate-Apps-MPLS",
        "sequenceType": "applicationFirewall",
        "match": {
          "entries": [
            {"field": "destination_ip", "value": "10.252.0.0/16"}
          ]
        },
        "actions": [
          {
            "type": "set",
            "parameter": {
              "slaClass": "SLA-BUSINESS-APPS",
              "preferredColor": "mpls",
              "backupSlaPreferredColor": "dia",
              "dscp": "18"
            }
          }
        ]
      },
      {
        "sequenceId": 70,
        "sequenceName": "Azure-VNet-Traffic",
        "sequenceType": "applicationFirewall",
        "match": {
          "entries": [
            {"field": "destination_ip", "value": "AZURE-VNETS"}
          ]
        },
        "actions": [
          {
            "type": "set",
            "parameter": {
              "slaClass": "SLA-BUSINESS-APPS",
              "preferredColor": "dia",
              "backupSlaPreferredColor": "mpls",
              "dscp": "18"
            }
          }
        ]
      },
      {
        "sequenceId": 999,
        "sequenceName": "Default-Internet",
        "sequenceType": "applicationFirewall",
        "match": {
          "entries": [
            {"field": "destination_ip", "value": "0.0.0.0/0"}
          ]
        },
        "actions": [
          {
            "type": "set",
            "parameter": {
              "slaClass": "SLA-BEST-EFFORT",
              "preferredColor": "dia"
            }
          }
        ]
      }
    ]
  }
}

Appendix B: IOS-XE Quick Reference

Verification Commands

! --- Cloud OnRamp / App-Aware Routing ---
show sdwan app-fwd cflowd flows         ! Active application flows
show sdwan policy app-route-policy      ! Policy attached to device
show sdwan policy app-route-stats       ! SLA compliance statistics
show sdwan cloud-onramp saas path       ! SaaS probe path results
show sdwan omp routes                   ! OMP route table (includes Azure VNets)

! --- SD-WAN Control / Data Plane ---
show sdwan control connections          ! vSmart sessions
show sdwan bfd sessions                 ! BFD health sessions per tunnel
show sdwan ipsec outbound-connections   ! IPsec tunnel table
show sdwan tunnel statistics            ! Tunnel loss/latency/jitter per path

! --- Umbrella ---
show umbrella config                    ! Umbrella registration status
show umbrella deviceid                  ! Device ID registered with Umbrella
show umbrella statistics                ! DNS redirect counters
show umbrella dnscrypt                  ! DNSCrypt encryption status

! --- QoS ---
show policy-map interface <IF> output   ! QoS statistics per class
show policy-map interface <IF> class <CLASS>  ! Drops, queueing for a class

Appendix C: Troubleshooting Guide

Issue 1: SaaS Probe Not Selecting Best Path

## Symptom: Teams traffic still using MPLS even though ExpressRoute is better


## Check 1: Verify probe is active in vManage

## Monitor → Cloud OnRamp for SaaS → App → Probe Results

## Look for gateway selection per site


## Check 2: Verify AAR policy applied to device

ssh admin@mum-hub-01
show sdwan policy app-route-policy
## Expected: Policy "Abhavtech-Hub-CloudOnRamp-AAR" attached


## Check 3: Verify NBAR2 classifying Teams correctly

show ip nbar protocol-discovery top 10
## Should show ms-teams in top applications


## Check 4: Verify color labels on transports

show sdwan interface
## Expected: azure-expressroute color on ER interfaces


## Resolution if probe not switching:

## 1. Verify threshold (5% loss difference) — may need lowering to 2%

## 2. Check if ExpressRoute BGP is receiving Teams prefixes:

show bgp ipv4 unicast 52.112.0.0
## Expected: Via ExpressRoute peer (169.254.200.1)

Issue 2: Azure VNet Not Reachable from Branch

## Check 1: Branch has Azure route in table

ssh admin@blr-isr-01
show ip route 10.100.2.0
## If missing: Azure route not distributed from hub


## Check 2: IPsec tunnel UP

show crypto ikev2 sa
## Expected: 1 SA pair per tunnel (Tunnel200, Tunnel201)


## Check 3: BGP session to Azure VPN Gateway

show bgp ipv4 unicast summary | include 65515
## Expected: Neighbor in established state


## Check 4: Azure route in OMP

show sdwan omp routes | grep 10.100
## Expected: Azure VNet routes learned via OMP from hub


## Resolution:

## 1. If OMP missing: Check control policy redistributing Azure routes

## 2. If IPsec down: Check PSK, IKEv2 proposal (AES256/SHA384/DH14)

## 3. If BGP down: Verify ASN (65515 Azure side)

Issue 3: Umbrella DNS Not Intercepting

! Check umbrella registration
show umbrella config
! Expected: Status = REGISTERED

! Check DNS interception on LAN interface
show umbrella statistics
! Expected: DNS redirect count incrementing

! Check DNSCrypt status
show umbrella dnscrypt
! Expected: Enabled, certificates valid

! Verify DNS query redirection working
! From a LAN PC:
nslookup suspicious-domain.com 192.168.50.1  ! LAN gateway IP
! Should return NXDOMAIN or Umbrella block page IP (146.112.62.40)
! NOT 192.168.x.x (internal) — means Umbrella is intercepting

! If not working:
! 1. Verify umbrella token is valid (get new from Umbrella dashboard)
! 2. Verify parameter-map applied to correct interface (LAN-facing)
! 3. Verify no ip dns server conflict on LAN

Appendix D: Validation Checklists

Week 1 — Cloud OnRamp SaaS

□ 6 SaaS apps configured with probes
□ Hub gateways: Mumbai, London, NJ active
□ All 19 sites reporting probe latency
□ Teams voice → azure-expressroute (EF DSCP)
□ O365 Exchange → azure-expressroute (AF21 DSCP)
□ Salesforce → best-path per probe (not hardcoded)
□ Branch O365 → DIA local breakout (no backhaul)
□ SaaS automatic failover tested (kill MPLS → DIA takes over <30s)

Week 2 — Cloud OnRamp IaaS (Azure)

□ Azure SP created with Contributor + Network Contributor roles
□ vManage connected to Azure subscription
□ Virtual WAN configured in vManage (auto-provisioned tunnels)
□ 19/19 sites have IPsec tunnels to Azure VPN Gateway
□ Azure VNet routes in all site routing tables
□ Control policy distributing Azure routes to all branches
□ Data policy steering Azure traffic via DIA transport
□ Azure SQL (10.100.10.10) reachable from Bangalore and Delhi
□ Private DNS returning 10.100.10.x from all sites
□ IaaS failover tested: DIA → MPLS <30s

Week 3 — Cloud OnRamp SASE (Umbrella)

□ vManage → Umbrella integration via API active
□ Hub Umbrella SIG tunnels: Tunnel300/301 UP at Mumbai, London, NJ
□ All 19 branch devices registered in Umbrella dashboard
□ DNS redirection: All LAN DNS queries → 208.67.222.222
□ DNSCrypt enabled on all branches
□ Malicious domain test: Blocked by Umbrella
□ SSL inspection active for non-whitelisted traffic
□ CASB: M365 activity monitoring active
□ SWG: Social media monitoring active
□ Shadow IT detection: Unauthorized cloud apps flagged

Week 4 — QoS and Production

□ QoS policy active on all MPLS interfaces (hub and branch)
□ QoS policy active on all DIA interfaces
□ QoS policy active on all ExpressRoute sub-interfaces
□ EF class: Teams voice shows priority queuing active
□ AF21 class: Business apps showing bandwidth guarantee
□ vManage API daily report: Running via cron
□ Splunk integration: SD-WAN events flowing
□ All device templates attached and pushed to all 19 sites
□ Full validation script: All sections PASS
□ 4-hour production monitoring: No issues
□ NOC team: Briefed on new dashboards and escalation paths

Implementation Complete

Total Duration: 4 Weeks (80 Hours)

Cloud OnRamp Capabilities Deployed: - SaaS: 6 applications (O365, Webex, Salesforce, ServiceNow, Workday, Zoom) with automated best-path probing from all 19 sites - IaaS: Azure Virtual WAN automated gateway with 19-site IPsec mesh, BGP route distribution, and Private Link connectivity - SASE: Cisco Umbrella integrated for DIA security (DNS, SWG, Cloud Firewall, CASB) across all 19 sites - QoS: 5-class policy active on all transport types with EF priority for Teams voice

Policy Hierarchy Enforced:

Teams Voice → ExpressRoute (EF DSCP 46)
O365 Exchange/SharePoint → ExpressRoute (AF21 DSCP 18)
Corporate Apps → MPLS (AF21 DSCP 18)
Azure VNets → Virtual WAN via DIA (AF21 DSCP 18)
SaaS (Salesforce/ServiceNow/Workday) → Best probe path
Internet/Shadow IT → Umbrella SIG (inspected and filtered)