NSX Migration Tool

A Python script for exporting and importing NSX Distributed Firewall (DFW) rules, Security Groups, and VM Tags between NSX Manager instances running version 3.x or 4.x.

No third-party libraries required — uses Python standard library only.


Requirements

  • Python 3.6 or later
  • Network access to the NSX Manager API (port 443)
  • NSX credentials with at least Enterprise Admin or Security Admin role

Supported NSX Versions

  • NSX-T 3.x
  • NSX-T 4.x
  • NSX 9.x (including VCF-mode deployments)

What Gets Exported / Imported

Resource Export Source Import Target Notes
Tags /api/v1/fabric/virtual-machines ?action=update_tags Stored as VM tag assignments, not standalone objects
Security Groups /policy/api/v1/infra/domains/default/groups Same path via PATCH Full group definitions including membership criteria
DFW Rules /policy/api/v1/infra/domains/default/security-policies Same path via PATCH All policies and their rules, preserving order

Output Files (Export)

File Default Name Contents
Tags tags.json Unique tag list + per-VM assignment records
Security Groups sec_groups.json Full group definitions
DFW Rules dfw_rules.json Policies with embedded _rules arrays

Usage

python nsx_migrate.py <action> --host <NSX_IP> -u <username> -p <password> [options]

Actions

Action Description
export Export all resources to JSON files
import Import all resources in order: Tags → Security Groups → DFW Rules
import-tags Import only VM tag assignments
import-groups Import only security groups

Arguments

Connection

Argument Short Required Default Description
--host Yes NSX Manager hostname or IP address
--username -u Yes NSX Manager username
--password -p Yes NSX Manager password
--no-verify-ssl No False Disable SSL certificate verification (for self-signed certs)

Source context (export)

Argument Required Default Description
--src-org No default Source VCF org name
--src-project No (none) Source VCF project name — omit to use the default infra space
--src-vpc No (none) Source VPC name within the project — requires --src-project

Destination context (import)

Argument Required Default Description
--dst-org No default Destination VCF org name
--dst-project No (none) Destination VCF project name — omit to use the default infra space
--dst-vpc No (none) Destination VPC name within the project — requires --dst-project

Import behaviour

Argument Required Default Description
--conflict No overwrite Conflict handling mode — see below
--merge-tags No False Merge imported tags with existing VM tags instead of replacing

File paths

Argument Required Default Description
--dfw-rules-file No dfw_rules.json Path to DFW rules JSON file
--sec-groups-file No sec_groups.json Path to security groups JSON file
--tags-file No tags.json Path to tags JSON file

Project and VPC Context

NSX 9.x running in VCF mode supports multi-tenancy through Projects and VPCs. The script resolves API paths based on the context arguments provided.

Context API path used
No project/VPC (default) /policy/api/v1/infra/domains/default/...
Project only /policy/api/v1/orgs/{org}/projects/{project}/infra/domains/default/...
Project + VPC /policy/api/v1/orgs/{org}/projects/{project}/vpcs/{vpc}/...

Source and destination contexts are independent. You can export from a project and import to a different project, to a VPC, or to the default space — in any combination.

Note: VM tag lookups always use the global fabric API (/api/v1/fabric/virtual-machines) regardless of project or VPC context. Tags are a fabric-level concept and are not scoped to projects or VPCs.


Conflict Handling (--conflict)

Controls what happens when an object already exists on the destination NSX.

Mode Behavior
overwrite Always write the object, replacing any existing version (default)
skip Leave existing objects untouched; only import objects that do not exist
prompt Ask interactively for each conflict

Prompt Mode Keys

When --conflict prompt is used, the following keys are accepted per conflict:

Key Action
y Yes — overwrite this object
n No — skip this object
a Yes to all — overwrite this and all remaining conflicts without prompting

Note: In non-interactive environments (piped input, CI/CD), prompt mode defaults to skip when stdin is unavailable.


Tag Merge (--merge-tags)

Applies to import and import-tags actions only.

Mode Behavior
Without flag Replace all tags on the VM with the imported set (existing tags are removed)
--merge-tags Union of imported tags and existing tags — no tags are removed, only new ones added

Tag deduplication is based on the (scope, tag) pair.


VM Resolution (Cross-vCenter)

When importing tags, the script resolves VMs on the destination using a two-step lookup:

  1. Primary — external_id: Matches the vCenter MoRef ID. Works when both environments use the same vCenter or the IDs happen to align.
  2. Fallback — display_name: Matches by VM name. Used automatically when the external_id lookup returns no results.

If multiple VMs share the same display name, the first result is used and a warning is printed. If neither lookup finds the VM, a warning is logged and the assignment is skipped — the import continues.


Examples

Export from source NSX

python nsx_migrate.py export \
  --host 192.168.1.10 \
  --username admin \
  --password VMware1! \
  --no-verify-ssl

Produces tags.json, sec_groups.json, and dfw_rules.json in the current directory.


Full import to destination NSX (overwrite existing)

python nsx_migrate.py import \
  --host 192.168.2.10 \
  --username admin \
  --password VMware1! \
  --no-verify-ssl

Full import — skip objects that already exist

python nsx_migrate.py import \
  --host 192.168.2.10 \
  --username admin \
  --password VMware1! \
  --no-verify-ssl \
  --conflict skip

Full import — prompt on each conflict

python nsx_migrate.py import \
  --host 192.168.2.10 \
  --username admin \
  --password VMware1! \
  --no-verify-ssl \
  --conflict prompt

Import only tags, merging with existing

python nsx_migrate.py import-tags \
  --host 192.168.2.10 \
  --username admin \
  --password VMware1! \
  --no-verify-ssl \
  --merge-tags

Import only security groups, skip existing

python nsx_migrate.py import-groups \
  --host 192.168.2.10 \
  --username admin \
  --password VMware1! \
  --no-verify-ssl \
  --conflict skip

Export from a VCF project

python nsx_migrate.py export \
  --host 192.168.1.10 -u admin -p VMware1! --no-verify-ssl \
  --src-project my-project

Export from a VPC inside a project

python nsx_migrate.py export \
  --host 192.168.1.10 -u admin -p VMware1! --no-verify-ssl \
  --src-project my-project --src-vpc my-vpc

Import into a specific project

python nsx_migrate.py import \
  --host 192.168.2.10 -u admin -p VMware1! --no-verify-ssl \
  --dst-project my-project --conflict skip

Import into a VPC

python nsx_migrate.py import \
  --host 192.168.2.10 -u admin -p VMware1! --no-verify-ssl \
  --dst-project my-project --dst-vpc my-vpc

Cross-project migration on the same NSX host

# Step 1 — export from project-a
python nsx_migrate.py export \
  --host 192.168.1.10 -u admin -p VMware1! --no-verify-ssl \
  --src-project project-a

# Step 2 — import to project-b
python nsx_migrate.py import \
  --host 192.168.1.10 -u admin -p VMware1! --no-verify-ssl \
  --dst-project project-b --conflict skip

Use custom file names

# Export to custom paths
python nsx_migrate.py export \
  --host 192.168.1.10 -u admin -p VMware1! \
  --dfw-rules-file backup_dfw.json \
  --sec-groups-file backup_groups.json \
  --tags-file backup_tags.json

# Import from custom paths
python nsx_migrate.py import \
  --host 192.168.2.10 -u admin -p VMware1! \
  --dfw-rules-file backup_dfw.json \
  --sec-groups-file backup_groups.json \
  --tags-file backup_tags.json

Import Order

When running a full import, resources are always applied in the following order to ensure dependencies are satisfied:

1. Tags           — VMs must be present; no dependency on groups or rules
2. Security Groups — may reference tags in dynamic membership criteria
3. DFW Rules      — policies reference security groups as sources/destinations

Output / Status Codes

Each resource line during import prints one of the following prefixes:

Prefix Meaning
OK Successfully written to destination
SKIP Object already exists and was left untouched (skip or prompt=no)
WARNING Non-fatal issue (e.g. VM not found for tag assignment)
FAIL API call failed — error detail printed on the same line

A summary line is printed after each resource type showing total counts.


Notes and Limitations

  • Tags are not standalone objects in NSX. They exist only as attributes on VMs. The export captures tag assignments per VM; the import re-applies them. VMs must already exist and be visible to NSX on the destination.
  • Security group membership expressions are exported as-is. If expressions reference objects that do not exist on the destination (e.g. segments, tags not yet applied), the group will be created but membership may be empty until those dependencies exist.
  • DFW rule references (source/destination groups, services) are exported by path/ID. If referenced groups or services do not exist on the destination, rules will be created but may not match traffic as expected. Importing groups before rules (the default order) mitigates this for group references.
  • Read-only fields (_revision, _create_time, _last_modified_*, etc.) are stripped before import so PATCH requests do not fail due to server-managed metadata.
  • VCF deployments (NSX 9.x): VCF-mode NSX adds extra fields to objects (remote_path, unique_id, realization_id, owner_id) that reference the source environment's org/project context. These are automatically stripped before import so they are not carried across to the destination.
  • The script operates on the default domain only (/infra/domains/default).
S
Description
Script used to export rule sets from NSX Managers and Import them on a destination Manager
Readme
35 KiB
Languages
Python 100%