Skip to main content

nsxctl

A command-line tool for VMware NSX groups, tags and distributed firewall rules, across a Global Manager and any number of Local Managers.

pipx install nsxctl
nsxctl init          # guided setup: managers, credentials, a reachability check
nsxctl compliance    # tagging posture across every Local Manager

Or download one file and run it — no install, no dependencies, nothing to configure by hand:

curl -O https://raw.githubusercontent.com/sampath9966/nsx-vDefend/main/nsx-toolkit.py
python3 nsx-toolkit.py

Both paths are fully supported and tested. The single file exists for the locked-down jumpbox where you cannot install anything; requests is used when present and the Python standard library when it is not.


Commands

nsxctl                                  interactive menu
nsxctl init                             guided first-run setup
nsxctl status                           reachability, auth and API base per manager
nsxctl doctor                           what does THIS NSX actually serve?
nsxctl managers                         list configured managers
nsxctl profiles                         estates this inventory defines
nsxctl projects                         NSX Projects on each manager
nsxctl login [NAME]                     set or replace stored credentials
nsxctl config show | path | validate    what config is in effect, and from where

nsxctl group list [--contains X] [--members]
nsxctl group show NAME
nsxctl group create NAME --criteria 'tag:env=prod AND tag:tier=web'
nsxctl group edit NAME | group delete NAME

nsxctl tag list VM                      every tag on a VM, checked against your taxonomy
nsxctl tag find --scope S --tag T       every VM carrying a tag
nsxctl tag edit VM                      interactive add/remove
nsxctl tag apply FILE.csv               bulk change (dry run by default)
nsxctl tag ticket FILE.csv              change-plan document, validated against live NSX

nsxctl snapshot save [NAME]             capture the current configuration
nsxctl snapshot list | show NAME
nsxctl snapshot diff BEFORE AFTER       compare two snapshots
nsxctl snapshot restore NAME            put a snapshot's config back
nsxctl drift [NAME]                     what changed since the snapshot, and who

nsxctl rule list [--policy P] [--action DROP] [--disabled]
nsxctl rule show NAME
nsxctl policy list | service list | service show NAME

nsxctl rule create NAME --policy P --from G1 --to G2 --service S --action ALLOW
nsxctl rule edit NAME | rule move NAME --before OTHER | rule delete NAME
nsxctl apply FILE.yaml                  declarative batch (dry run by default)
nsxctl recommend FLOWS.csv              propose rules from observed traffic

nsxctl trace VM_A VM_B [--port N]       can A reach B, and what decided it
nsxctl impact VM                        what breaks if I change this VM
nsxctl parity STATIC DYNAMIC            static vs dynamic group migration progress
nsxctl compliance                       tagging posture across every Local Manager
nsxctl audit list | undo                audited writes, and undo one

nsxctl completion bash | zsh | fish     shell completion
nsxctl version

nsxctl <command> --help shows a command's options and examples.

Global flags work on either side of the subcommand — nsxctl --json compliance and nsxctl compliance --json are the same thing.

Reading what is there

nsxctl rule list --policy app-tier      # in NSX evaluation order
nsxctl rule show allow-web-db
nsxctl policy list
nsxctl service list                     # and which ones trace can decide

rule list sorts by category first (Ethernet -> Emergency -> Infrastructure -> Environment -> Application), then policy and rule sequence. That is not the order the API returns them in, and it is the order that decides traffic.

service list's last column says whether each service is a plain L4 port set. That is what makes an undecided nsxctl trace verdict explicable rather than mystifying.

Rule hygiene

nsxctl rule hygiene                          # the "is my policy sane" report
nsxctl rule hygiene --out-html hygiene.html  # a file you can email
nsxctl rule hygiene --fail-on critical       # for a pipeline or cron

Twelve checks across three categories:

Finding Severity Basis
any_any_allow critical source and destination both ANY with ALLOW
missing_group critical references a group that does not exist
any_any_other high source and destination both ANY, non-ALLOW
broad_applied_to high applied-to is ANY — enforced everywhere
shadowed_by_any_any high unreachable: an any-any rule sits above it
unused_since_baseline high zero hits between two baseline reads
no_criteria_group medium referenced group has no criteria — rule is inert
drop_not_logged medium DROP/REJECT with logging off
duplicate_rule medium identical match criteria to an earlier rule
unused_rule medium (soft) counter reads zero
disabled_rule low dead configuration
empty_group low (soft) group resolves to 0 VM members

Findings marked soft are indications, not proof, and the detail column says why. Two things this report deliberately will not claim:

  • A zero hit count does not mean a rule is unused. NSX counters are cumulative since the last reset — a reboot or a rule edit zeroes them. Use a baseline (below) for a claim you can defend.
  • Groups matched on VIF, IP-set, segment or segment-port criteria are never reported as empty. The VM member API returns nothing for them, so a naive count would flag live groups as dead. They report as not measurable.

Shadow detection does no port or CIDR arithmetic, so it cannot produce a false "unreachable". It only flags what is provable: an exact-duplicate match key, or a rule sitting below one that matches everything.

Config snapshots and drift

nsxctl snapshot save approved     # capture groups, policies and rules
# ... a week, and someone edits a rule in the UI ...
nsxctl drift                      # what changed, and who changed it
MODIFIED rule https [security]   by dave
    + destination_groups: ['ANY']
    - destination_groups: ['/infra/domains/default/groups/g-web']
MODIFIED policy Perimeter (edited) [cosmetic]   by dave
    display_name: Perimeter -> Perimeter (edited)

Changes are classified security (can alter what traffic is permitted) or cosmetic (only a name, description or note), so a scheduled check stays quiet about a rename and is loud about a new any-any rule:

nsxctl drift --fail-on-drift security     # exit 1 only on real changes
nsxctl snapshot diff approved current --out-html drift.html

nsxctl snapshot diff needs no live NSX — it compares two stored snapshots.

The tree is config-as-code. One JSON file per object, sorted keys, volatile fields stripped, so ordinary tools work on it:

approved/
  manifest.json
  groups/lm-london/g-web.json
  policies/lm-london/p1/_policy.json
  policies/lm-london/p1/rules/https.json
git diff --no-index snapshots/approved snapshots/current

Two details that make this work rather than merely look like it works:

  • Volatile fields never reach the object files. _revision, _last_modified_time, realization_id and friends change when nothing real changed; left in, every diff would be noise. They ride in the manifest instead, which is where --out-html and the console get who changed it.
  • source_groups compares as a set; expression compares in order. Membership is what matters for the first, but group criteria are Condition AND Condition — reordering them changes which workloads match. Anything unrecognised is compared in order and treated as security-relevant, because a false "changed" costs a second look and a missed one costs an incident.

VM tags are excluded unless you pass --with-tags: retagging is routine churn that would bury a real rule change.

Proving a rule is unused

nsxctl rule baseline save --baseline-file monday.json
# ... a week of production traffic later ...
nsxctl rule baseline compare --baseline-file monday.json

A counter that did not move between the two reads genuinely saw no matching traffic in that window — evidence you can attach to a deletion request.

If the second read is lower than the first, the counter was reset and the window proves nothing. That reports as counter_reset, never as unused; claiming no traffic when the evidence was wiped is how a live firewall rule gets deleted.

Can A reach B, and what stopped it

nsxctl trace web-prod-01 db-prod-01 --port 3306
nsxctl trace web-prod-01 --to 10.20.30.40 --port 443
nsxctl trace web-prod-01 db-prod-01 --port 3306 --static   # no packet

Two engines answer that, and they answer different questions, so the report never blends them:

  WHAT THE POLICY SAYS   (evaluated here -- no packet sent)
  ----------------------------------------------------------------
    DROP  by rule 'block-legacy-db' in policy 'app-tier'  [seq 40, Application]

  WHAT THE DATA PLANE DID   (traceflow -- a synthetic packet was sent)
  ----------------------------------------------------------------
    DROPPED  at FIREWALL on esx-01
    by rule 'block-legacy-db' in policy 'app-tier'   acl_rule_id 4130

  Agreed: the policy and the data plane tell the same story.

When they disagree, that disagreement is the finding -- NAT, a partial realization, or a rule not yet pushed to a host will each produce it -- and the report lists the likely causes rather than picking a winner.

Four things the command handles rather than papers over:

  • Traceflow is a Manager API and the Global Manager does not serve it. The command finds the Local Manager that actually hosts the source VM and targets that one. With no LM connected it says so and runs the static half.
  • It needs a logical port, not a VM. VM → VIF → logical switch port is the real chain. A multi-NIC VM is ambiguous, so the NICs are listed and you pick with --nic; it will not choose for you. A powered-off VM or an unrealized port each get their own message.
  • It injects a real packet. Synthetic and harmless, but real, so it sits behind the same confirmation as a write: --yes for scripts, --static to send nothing. The traceflow object is always deleted afterwards, including on timeout.
  • The verdict comes back as a number. An observation says acl_rule_id 4130. The policy rule's rule_id carries the same integer, so the deduplicated sweep turns it into a rule and policy name. An id no rule in the domain carries is reported as the raw number, never hidden.

Static evaluation walks rules in NSX's real order -- category first (Ethernet → Emergency → Infrastructure → Environment → Application), then policy and rule sequence -- because a per-policy ordering answers the wrong question. Where it cannot decide a rule it says so instead of guessing:

    UNCERTAIN: 1 rule(s) ahead of this one could not be decided:
      app-tier / icmp-rule
        service Ping is not a plain L4 port set

Only L4PortSetServiceEntry reduces to a port comparison. ICMP, ALG and IP-protocol services are left undecided, and without --port a rule limited to any service is undecided too -- calling one a non-match is how a trace names the wrong rule.

Creating and changing rules

nsxctl group create g-web --criteria 'tag:env=prod AND tag:tier=web'
nsxctl rule create allow-web-db --policy app-tier \
    --from g-web --to g-db --service MySQL --action ALLOW
nsxctl rule move allow-web-db --before deny-all
nsxctl apply changes.yaml

Dry run by default. Nothing is written without --enable-writes, and the plan is rendered by the same diff engine nsxctl drift uses, so a preview of a change looks exactly like the drift report of that change:

  MODIFY rule allow-web-db   [lm-london]
      [security] action: ALLOW -> DROP
      [cosmetic] display_name: allow-web-db -> Allow web to db

The proposed rule is run through rule hygiene before it is written:

  PREFLIGHT: the proposed change would be reported by `nsxctl rule hygiene`:
    critical any_any_allow
      source and destination are both ANY with ALLOW -- permits all traffic

Concurrent edits are refused by NSX itself. Every write carries back the _revision it read; NSX answers 412 if anything changed in between, so two operators editing the same rule cannot silently clobber each other:

$ nsxctl rule edit allow-web-db --action DROP --enable-writes
  FAILED modify rule 'allow-web-db'
      modify rule 'allow-web-db' changed on NSX since the plan was built, so
      the write was refused rather than overwriting somebody else's change.

--force overrides it. A GM-authored object is never written through a Local Manager -- NSX realizes those read-only, and the refusal names the reason.

Criteria syntax

tag:SCOPE=VALUE     tag equals          tag:env=prod
tag:SCOPE~VALUE     tag contains        tag:owner~platform
name=VALUE          VM name equals      name=web-prod-01
name~VALUE          VM name contains    name~web-
ip:A[,B...]         IP addresses/CIDRs  ip:10.0.0.0/8

Joined with AND or OR. Mixing the two is refused rather than sent: NSX applies one conjunction operator per expression, so a mixed expression would not select what it reads as -- which for a firewall group is the whole ballgame.

Declarative batches

groups:
  - id: g-web
    display_name: Web tier
    criteria: 'tag:env=prod AND tag:tier=web'
  - id: g-retired
    state: absent

rules:
  - id: allow-web-db
    policy: app-tier
    source: [g-web]
    destination: [g-db]
    services: [MySQL]
    action: ALLOW

nsxctl apply changes.yaml plans every entry, prints one combined diff, and writes nothing that already matches NSX. JSON is always accepted; YAML needs PyYAML.

Undo is asymmetric, and says so

nsxctl audit undo reverses one entry. Every write -- tags, groups and rules alike -- is logged with both sides of it.

Undoing a Becomes Reliable?
create a delete yes
modify a write of the before-body yes
delete recreating the object no

Recreating a deleted object cannot be guaranteed: anything that referenced it may have been cleaned up in the meantime. Snapshots are the real backstop there, which is also why snapshot restore is deliberately not part of this -- restoring a whole DFW is a different class of risk from undoing one rule.

Audit entries written before authoring existed still list and still undo. The tag fields were kept and the general ones added alongside, with one reader mapping both shapes.

What does this NSX actually serve?

nsxctl doctor

The toolkit degrades rather than fails in a dozen places -- statistics may 404, traceflow is Local-Manager-only, Projects may not exist, some group criteria are not VM-resolvable. Every one of those is handled where it happens, which means a missing feature and a bug in the tool look identical until you ask:

  lm-london  Local Manager  https://lm-lon.example.com:443
    Capability          Status   Detail                    Affects
    ------------------  -------  ------------------------  -----------------------
    groups              ok       412 item(s)
    rule statistics     missing  404 -- not served ...      rule hygiene unused
                                                            checks, rule baseline
    traceflow           ok       0 item(s)

Every probe is a bounded read. Nothing is written, and traceflow is checked by listing, never by injecting a packet -- a capability check that put real traffic on the data plane every time somebody asked what their NSX supports would be its own kind of bug.

nsxctl doctor --json is the one output worth pasting into a bug report. --fail-on-missing makes it a pipeline gate.

Running it on a schedule

nsxctl rule hygiene --only-on-change --notify "$SLACK_WEBHOOK"
nsxctl drift --fail-on-drift security --out-junit drift.xml
nsxctl doctor --out-metrics /var/lib/node_exporter/nsxctl.prom
Flag What consumes it
--out-junit PATH A pipeline, showing each check as a test
--out-sarif PATH A code-scanning UI, annotating findings by severity
--out-metrics PATH A node_exporter textfile collector
--notify URL One POST with the summary, for chat or an incident tool
--only-on-change Print nothing and notify nobody unless the findings differ

--only-on-change is what makes a nightly cron bearable. Each run fingerprints its own findings and compares that with the last. Unchanged, the whole report is discarded before it reaches stdout, so cron sends no mail; changed, it prints in full and the webhook fires. Without it a scheduled hygiene report mails you the same 40 findings every morning until you pipe it to /dev/null -- and then you never see number 41.

The fingerprint is built only from what a finding is, never from when it ran, and the state is written only when --only-on-change is given: a plain interactive run that quietly primed it would make your first scheduled run silent with forty findings sitting there unreported.

Metrics emit a zero series when clean, because an alert rule needs a series that exists and reads zero, not one that vanishes.

Proposing rules from traffic you actually saw

nsxctl recommend flows.csv
nsxctl recommend flows.csv --policy app-tier --out-file proposed.json
nsxctl apply proposed.json          # review first; dry run by default

Reads a flow export you already have -- NSX Intelligence export, vRNI, a firewall-log query -- rather than calling the Intelligence recommendation API, which is licensed separately and absent on most estates. Column names are matched loosely (src, src_ip, source_ip all work) because every exporter names them differently and none of them are wrong.

    Source   Destination  Proto  Ports  Flows
    Web      DB           tcp    3306   913

  UNCLASSIFIED: 1 address(es) belong to no group:
    10.9.9.9           destination  5 flow(s)
    These are the most useful rows here: traffic exists and nobody has
    classified the workload. No rule is proposed for them.

Three things it will not do:

  • It never proposes a default-deny. No traffic seen in one window is not evidence none exists -- the same reasoning that stops a zero hit count retiring a rule.
  • It never invents a group for an address nobody claims. An unresolved endpoint is reported, because that is the finding.
  • A pair talking on more than --max-ports ports is flagged, not ruled. That shape is usually a scanner or a monitoring host, and one rule with fifty ports would bury it.

Denied flows are ignored unless --include-denied: a blocked flow is usually evidence the segmentation is working, not evidence a rule is missing.

Putting a snapshot back

nsxctl snapshot restore approved                      # dry run
nsxctl snapshot restore approved --enable-writes
nsxctl snapshot restore approved --prune --enable-writes

Per-object, through the same plan-then-apply path as nsxctl rule edit: each object gets a field-level diff you can read, a _revision check that refuses to overwrite a concurrent edit, and its own audit entry. A restore is reviewable and individually undoable, not a blind push of a whole tree.

Deleting is opt-in. An object that exists now but not in the snapshot is left alone unless you pass --prune: a snapshot records what was there, it does not assert that nothing else may exist, and a group created legitimately since is not drift to be erased.

More than one estate

nsxctl profiles
nsxctl --profile dr status
NSX_PROFILE=dr nsxctl compliance
{"default_profile": "prod",
 "profiles": {
   "prod": {"managers": [...]},
   "dr":   {"managers": [...]}}}

The flat single-estate inventory nsxctl init writes still works exactly as it always did. With several profiles and no default_profile, the tool refuses rather than picking one -- guessing which estate to talk to is the one wrong answer that matters.

NSX Projects

nsxctl projects
nsxctl --project tenant-a rule list

A Project has its own infra tree, so --project swaps the policy base rather than filtering results. Objects in the default infra are genuinely not visible from inside a project, and vice versa.

The three you'll actually use daily

# Is my tagging where I think it is?
nsxctl compliance

# What breaks if I retag this VM?
nsxctl impact web-prod-01

# Which VMs are tagged env=prod?
nsxctl tag find --scope env --tag prod --out-csv prod.csv

# What is wrong with my firewall policy?
nsxctl rule hygiene

# Why can't web01 reach db01?
nsxctl trace web-prod-01 db-prod-01 --port 3306

--debug logs every HTTP method, URL, status and timing to stderr. It is the first thing to reach for when an API behaves differently on your NSX version.


Installing

Method Command When
pipx pipx install nsxctl Recommended. Isolated, on PATH.
pip pip install --user nsxctl If you don't have pipx.
Single file download nsx-toolkit.py No install possible. No dependencies.
Binary download from Releases No Python at all.
Module python -m nsx_toolkit Console scripts awkward to reach.

Shell completion:

nsxctl completion bash > /etc/bash_completion.d/nsxctl
nsxctl completion zsh  > "${fpath[1]}/_nsxctl"
nsxctl completion fish > ~/.config/fish/completions/nsxctl.fish
nsxctl completion cache          # so TAB can complete object names too

The script is generated from the live command tree, so it always matches the commands your build actually has.

It also completes names, not just flags -- --policy <TAB>, --from <TAB>, nsxctl rule show <TAB>. Those come from a cache file that ordinary list commands refresh as a side effect. Pressing TAB never makes a network call: a completion that reached out to eight managers would turn a keystroke into a two-second stall, and into a hang on an unreachable one. A stale cache completes a stale name and NSX says so, which is the right failure. The cache is per profile and project, because completing production names into a DR command is worse than completing nothing.


Configuration

inventory.json

Looked for in the current directory, then ~/.nsx_toolkit/. Override with --inventory. nsxctl init writes it for you; nsxctl config path tells you which one is in effect. See examples/inventory.example.json.

{"managers": [
  {"name": "lm-london", "role": "lm", "host": "lm-lon.example.com",
   "port": 443, "verify_ssl": false, "auth": "session",
   "username_env": "NSX_LM_LONDON_USER",
   "password_env": "NSX_LM_LONDON_PASS"}
]}
Field Meaning
name Short label used in output and in --manager
role gm or lm. Tags and VM inventory are LM-only; groups and policies exist on both
host, port Manager address. Port defaults to 443
verify_ssl false for self-signed certificates. TLS warnings are suppressed only for the managers that set this
ca_bundle CA bundle to verify against, when verify_ssl is true
auth session (default), basic, token, or cert
timeout Per-request seconds. Default 30
username_env, password_env Environment variable names the credentials resolve from

taxonomy.json (optional)

Your tag scheme. Without one, a sensible default is used. Save it next to inventory.json or pass --taxonomy. See examples/taxonomy.example.json.

{
  "format": "^[a-z0-9][a-z0-9\\-]*$",
  "allow_unknown_scopes": false,
  "scopes": {
    "business-unit": {"required": true},
    "zone":          {"required": true, "values": ["red", "amber", "green"]},
    "owner":         {"required": false}
  }
}

required scopes drive nsxctl compliance. values, when present, restricts what a scope may be set to. YAML is accepted if PyYAML happens to be installed; JSON is used everywhere else so nothing needs installing.

nsxctl config show prints the taxonomy currently in effect.

Bulk tagging CSV

vm_name,scope,tag,action
web-prod-01,env,prod,add
web-prod-01,env,dev,remove

Rows with an unknown VM or a malformed action are reported individually rather than failing the whole file. See examples/bulk-tags.example.csv.

Credentials

Resolved in order: environment variable, OS keyring, local credentials file. Environment wins, so CI and scheduled jobs can inject credentials without touching disk.

When prompted, values are stored in the OS keyring where one exists. With no keyring, you are asked whether to write them to a file — never done silently. --store keyring|plaintext|none overrides; nsxctl login re-enters them.


Safety

  • Read-only by default. Changes need --enable-writes. That includes every authoring command: group create, rule edit and apply all print a plan and stop.
  • nsxctl trace injects a packet, and asks first. It is the one read in the toolkit that touches the data plane. --static sends nothing.
  • Dry run always runs first. nsxctl tag apply prints the full plan before anything is written.
  • Non-interactive writes need --yes. Without a terminal and without --yes, it refuses rather than assuming consent.
  • Concurrent edits are detected. Each VM is re-read immediately before it is written; if its tags changed since the plan was computed, that row fails instead of overwriting someone else's change. --force overrides. Group and rule writes get this from NSX itself: the _revision read at plan time rides back with the write, and NSX rejects a stale one with 412.
  • Every write is audited. ~/.nsx_toolkit/audit.log records who, when, which manager, and full before/after state. nsxctl audit list reviews it; nsxctl audit undo reverts an entry.
  • Console output truncates; exports never do. Long listings are capped on screen, but CSV and JSON always contain every row.

Exit codes

Code Meaning
0 Success
1 The command ran and found a problem (failed writes, validation errors, unreachable managers)
2 Could not start (bad arguments, no inventory, unknown manager)
3 Command not implemented in this release
130 Cancelled

Scope: what runs where

Action Global Manager Local Managers
Group search and criteria yes yes
VM inventory and tags no yes
Security policies and rules yes yes (including GM rules realized locally)

nsxctl impact deliberately sweeps every connected manager. GM-authored rules are realized read-only onto each LM, so a naive scan reports the same rule once per site; rules are deduped by their NSX path and attributed to the GM once.


Upgrading from the old flag interface

Every old flag still works and prints the replacement:

$ nsx-toolkit.py --dashboard
warning: --dashboard is deprecated and will be removed in 2.0.
         use: nsxctl compliance
Was Now
--verify nsxctl status
--dashboard nsxctl compliance
--groups [--contains X] [--members] nsxctl group list [--contains X] [--members]
--vm-tags VM nsxctl tag list VM
--vms-by-tag --scope S --tag T nsxctl tag find --scope S --tag T
--bulk-tag FILE nsxctl tag apply FILE
--change-ticket FILE nsxctl tag ticket FILE
--reverse-lookup VM nsxctl impact VM
--parity A B nsxctl parity A B
--audit-log nsxctl audit list
--list-managers nsxctl managers
--set-credentials nsxctl login
--init nsxctl init

Running several actions in one invocation (--groups --dashboard) still works and still writes one export file per result set.


Development

The single file is generated. Edit the package, then rebuild.

git clone https://github.com/sampath9966/nsx-vDefend
cd nsx-vDefend
pip install -e ".[dev]"

pytest -q                                  # full suite, no NSX required
ruff check src tests tools
python3 tools/build_single_file.py         # regenerate nsx-toolkit.py
python3 tools/build_single_file.py --check # CI runs this
python3 tools/verify_install.py            # build, install, drive the command

verify_install.py is the one that answers "does pip install nsxctl actually give someone a working command". It builds the wheel, installs it into a clean virtualenv with nothing else in it, and drives the console script that lands on PATH against a fake NSX as a subprocess — reads, tracing, an authoring dry run and a committed write, the audit trail, the JUnit/SARIF/metrics sinks, and shell completion. The virtualenv has no requests on purpose, so the stdlib transport is what gets exercised. The release workflow runs it before anything is published.

src/nsx_toolkit/
  version.py errors.py paths.py output.py   foundations
  api.py                                    every NSX path and field, declared once
  taxonomy.py config.py creds.py            configuration
  http.py                                   transport, retry, auth, VM index
  audit.py export.py render.py              cross-cutting services
  policy.py snapshot.py diff.py             traversal, capture, comparison
  trace.py                                  traceflow + static path evaluation
  authoring.py                              criteria parsing, planned writes
  sinks.py                                  JUnit, SARIF, metrics, webhook, state
  flows.py                                  observed flows -> proposed rules
  namecache.py                              names for completion, never live
  actions/                                  one module per operation
  commands/                                 the nsxctl command tree
  legacy.py                                 old flag translation
  wizard.py menu.py cli.py                  entry points
tools/build_single_file.py                  amalgamator
tests/fake_nsx.py                           in-process fake NSX manager

commands/ is the CLI surface; actions/ is the logic. A new command wires argument parsing to an existing act_* function.

Tests run against tests/fake_nsx.py, a real in-process HTTP server with Global and Local Manager personalities, so the suite exercises the actual transport, cursor pagination, retry loop and session authentication rather than a stub. No NSX is needed to develop or to run CI.

The amalgamator enforces three rules that a package hides but a single shared namespace does not tolerate. The build fails, with the fix in the error message, if you:

  • define the same top-level name in two modules,
  • write from . import some_module (binds a module object),
  • write from .x import y as z (the alias does not survive flattening).

Requirements

Python 3.9 or newer. requests is optional.

License

See LICENSE.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

nsxctl-1.0.0.tar.gz (231.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

nsxctl-1.0.0-py3-none-any.whl (186.2 kB view details)

Uploaded Python 3

File details

Details for the file nsxctl-1.0.0.tar.gz.

File metadata

  • Download URL: nsxctl-1.0.0.tar.gz
  • Upload date:
  • Size: 231.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for nsxctl-1.0.0.tar.gz
Algorithm Hash digest
SHA256 7650d24b50aac66ea64b7073c1530c0581f7f0365bd545b5724b9eefde73f4f6
MD5 44e105ef4c4854293fe898943e375279
BLAKE2b-256 b0e4dace9b5394d895e7415e49f8141749c0bc7db6b2270e09e8502842aa3c33

See more details on using hashes here.

Provenance

The following attestation bundles were made for nsxctl-1.0.0.tar.gz:

Publisher: release.yml on sampath9966/nsx-vDefend

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file nsxctl-1.0.0-py3-none-any.whl.

File metadata

  • Download URL: nsxctl-1.0.0-py3-none-any.whl
  • Upload date:
  • Size: 186.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for nsxctl-1.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 24840700cd661f3df805dbc72e52b380edd4d05fbb238979054edc7734851ae1
MD5 113cb15b16a523e67d0f859783271643
BLAKE2b-256 4c9e9350d8869a1e4c510c5e9cbb8aa97b757bdae50b4d4e49055b7bf36f3ddf

See more details on using hashes here.

Provenance

The following attestation bundles were made for nsxctl-1.0.0-py3-none-any.whl:

Publisher: release.yml on sampath9966/nsx-vDefend

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

1.1.0

2 files

This release

1.0.0 This release

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page