A Bash + embedded-Python script that connects to a NetApp ONTAP source cluster via SSH, collects all configuration data relevant to a customer migration, and produces a multi-sheet Excel workbook containing both raw collected data and ready-to-paste ONTAP migration and teardown commands.
- Single SSH session per command — combines multiple customer IDs into a single wildcard filter (
*cs03*,*cs12*,...) so the cluster is queried once regardless of how many customers are migrated - Auto-detects VLANs from network interface
curr-portfields (range 1–4094) - Destination aggregate collection via a second SSH pass to the new cluster (
-n) - Subnet config INI file — proposes destination IP ranges per VLAN, persists them, and uses them to generate LIF create commands and NFS mount IPs
- Optional ping verification (
-P) — pings every proposed IP via the source cluster and iterates until the range is clean - Overlap detection — flags when the proposed destination IP range overlaps with the source subnet's ip-ranges and emits a corrective
network subnet modifycommand - ONTAP version resilience — multi-step fallback chain for commands that differ between ONTAP versions (field availability, empty-result rc=255 behaviour)
| Tab | Content |
|---|---|
| Info | Table of contents — cluster, customer IDs, detected VLANs, script version, Jira, comment, ping-check status |
| 1 vServer Show | vserver show |
| 2 Network Interfaces | net int show |
| 3 Broadcast Domain | broadcast-domain show |
| 4 Volume Show | volume show |
| 5 Export Policy Rules | export-policy rule show |
| 6 Snapshot Policies | snapshot policy show |
| 6b Job Schedules | job schedule cron show |
| 7 CIFS Server | cifs server show |
| 8 vServer Peer | vserver peer show |
| 9 SnapMirror Policy | snapmirror policy show |
| 10 Routes | network route show |
| 11 Subnet Show | network subnet show |
| 11b QoS Policy Groups | qos policy-group show |
| 12 Destination Aggregates | aggr show on destination cluster (requires -n) |
| 13 Migration Setup | Ready-to-paste ONTAP commands: VLAN port / broadcast-domain / subnet / LIF / volume / snapshot-policy / export-policy / QoS / NFS mounts / CIFS paths |
| 14 Teardown Commands | Ordered offline + delete sequence with pre-flight NFS connected-client check |
| 15 Ping Results | Per-IP ping outcome with colour coding (only when -P is used) |
| Requirement | Notes |
|---|---|
| Bash ≥ 4 | macOS ships with Bash 3 — install via Homebrew: brew install bash |
| SSH key-based auth | Must be configured for the ONTAP user on source (and optionally destination) cluster |
| Python 3 | Required for Excel generation |
| openpyxl | Installed automatically by the script via pip3 if missing |
git clone https://github.com/<your-org>/netapp_auto_collect_migration_details.git
cd netapp_auto_collect_migration_details
chmod +x netapp_auto_collect_migration_details.sh./netapp_auto_collect_migration_details.sh -c <cluster> -v <id(s)> [OPTIONS]
| Flag | Description | Default |
|---|---|---|
-c <cluster> |
Source cluster hostname or IP (required) | — |
-v <id(s)> |
Customer ID(s), comma-separated (required) — e.g. cs03,cs12 |
— |
-u <user> |
SSH username | $NETAPP_USER or admin |
-j <jira> |
Jira task number, e.g. OPS-1234 |
— |
-m <comment> |
Free-text comment | — |
-o <dir> |
Output directory (created if needed) | output/migration |
-t <type> |
Disk-type filter: SSD, SATA, or NVME. Adds a _{type} suffix to vserver / LIF / volume names and restricts aggregate selection |
— |
-n <cluster> |
Destination cluster hostname or IP. Enables tab 12 (destination aggregates) and populates aggregate names in volume create commands | — |
-P |
Ping-check proposed destination IPs from the source cluster before continuing | — |
-h |
Show help | — |
Collect data for a single customer:
./netapp_auto_collect_migration_details.sh \
-c src-cluster1 \
-v cs03Multiple customers, SSD-only migration, with destination cluster:
./netapp_auto_collect_migration_details.sh \
-c src-cluster1 \
-v cs03,cs12,csrp03,csrp09 \
-n dst-cluster4 \
-t SSDFull run with ping verification, Jira reference and custom output path:
./netapp_auto_collect_migration_details.sh \
-c src-cluster1 \
-v cs03,cs12 \
-n dst-cluster4 \
-t SSD \
-P \
-j OPS-1234 \
-m "Q2 storage cleanup" \
-o /tmp/migration/q2On first run the script proposes destination IP ranges for every detected VLAN and writes them to:
<outdir>/subnet_config_<cluster>_<customers>.ini
Example:
[cs03_313]
subnet = 10.10.13.0/24
gateway = 10.10.13.254
ip-ranges = 10.10.13.11-10.10.13.20
[cs03_316]
subnet = 10.10.16.0/24
gateway = 10.10.16.254
ip-ranges = 10.10.16.21-10.10.16.30If the file already exists the script shows a diff of existing vs new values and asks whether to overwrite (o) or keep (k) before continuing.
- Block size =
⌈ lif_count / 10 ⌉ × 10— smallest multiple of 10 that covers the required LIF count - Ranges are band-aligned:
.1–.10,.11–.20,.21–.30… - Start = first band-start after the highest source LIF IP in the subnet
- Source LIF IPs, the gateway, and broadcast address are never included in the proposed range
- If the proposed destination range overlaps with the source subnet's ip-ranges, a red
network subnet modifycommand is added to tab 13 to narrow the source range before migration
When the destination ip-range overlaps the source, tab 13 automatically includes a red-highlighted command for the source cluster:
network subnet modify -subnet-name <source_subnet> -ip-ranges <adjusted_range>
This must be run on the source cluster before creating LIFs on the destination.
All intermediate ONTAP output and the final Excel file are written to the output directory (-o, default output/migration):
output/migration/
├── subnet_config_<cluster>_<customers>.ini # IP range config (edit before re-running)
├── <cluster>_<customers>_migration.xlsx # Excel workbook
└── <tmp_work_dir>/ # Raw ONTAP CLI output (auto-cleaned)
├── 01_vserver_show.txt
├── 02_net_int_show.txt
├── 03_broadcast_domain.txt
└── ...
The script includes automatic fallback chains for commands that behave differently across ONTAP versions:
- Snapshot policies — tries
countsfields → numbered fields → schedules-only → cluster-wide - CIFS / vServer peer / SnapMirror / QoS / subnet — tries filtered query → bare query → cluster-wide
- Broadcast domain — tries customer-name filter → cluster-wide (Python filters by VLAN)
- Empty results — ONTAP returns
rc=255on some versions when a query matches no entries. The script detects this and silently tries the next fallback rather than reporting a warning.
The SSH user needs read access to the following command families:
vserver show network interface show broadcast-domain show
volume show export-policy rule show snapshot policy show
job schedule cron show cifs server show vserver peer show
snapmirror policy show network route show network subnet show
qos policy-group show aggr show network ping
A read-only custom role covering these commands is sufficient. The migration and teardown commands in the Excel workbook are generated locally and never executed by the script itself.
MIT