Reverse-specification of python-neutronclient — branch stable/2026.2
Branch
stable/2026.2@596a9d99b188(14.0.0+ 2 maintenance commits) — repository https://opendev.org/openstack/python-neutronclient — analysed on 2026-11-01
- Scope: the whole repository (package
neutronclient): the OSC plugin, the Python client class, the leftovers of the removed CLI. The change history (step 7) was not requested, so there is no 06 file. - Dependencies read at fixed versions, from the venv: osc-lib 4.7.0, cliff 4.16.0, openstacksdk 4.20.0, keystoneauth1 5.17.0, python-keystoneclient 6.0.0, python-openstackclient 10.3.1. Cited with the prefixes
osc-lib:,cliff:,openstacksdk:,keystoneauth1:,openstackclient:. Other projects are cited with their clone name; their commits are in 07 § 4. - References are
file:linefrom the repository root. [observed] means seen by running the realopenstackcommand or the real class against the local stub. [inferred] marks a statement not followed to the end. - The stub is not Neutron. No real service, lab or cloud was contacted. Every [observed] result shows how the client reacts to canned answers, and says nothing about what a real service sends.
Files of this specification
| File | Content |
|---|---|
| 01-cli-commands_stable-2026.2.md | plugin loading, the 34 commands with arguments, routes and bodies, and the Python API the commands use |
| 02-errors_stable-2026.2.md | exit codes, the exception catalogue, the HTTP translation, the 23 messages of the commands, and the defects reproduced |
| 03-interactions_stable-2026.2.md | Keystone and Neutron through two client stacks, headers, URL building, retries |
| 04-scenarios_stable-2026.2.md | 5 scenarios with sequence diagrams and diagnostics |
| 05-async-processing_stable-2026.2.md | none; only client-side pagination and retry loops |
| 07-rewrite-pack_stable-2026.2.md | client contract: what the plugin and the library's users require from a Neutron service |
| _verification_stable-2026.2.md | output of the reference checker |
Overview
The package now provides three different things:
- An OSC plugin with 34 commands. All 34 load in the real shell [observed]. 27 (
sfc *) use openstacksdk and do not touch the class of this package. 7 (network log *,network loggable resources list,network onboard subnets) use it. - **A Python library,
neutronclient.v2_0.client.Client**, with 372 public methods and 168 path constants (neutronclient/v2_0/client.py:495), plus the exception moduleneutronclient/common/exceptions.py:42. It logs a deprecation warning on every instantiation (neutronclient/v2_0/client.py:253). Nova, Heat, Manila, Zun, ec2-api, Skyline and heat-tempest-plugin import it. - **The remains of the
neutronCLI**: 63 files and 8,693 lines underneutronclient/neutron/. No script starts them:setup.cfghas noconsole_scripts, so there is no legacy shell process. The package still imports them: the base moduleneutronclient/neutron/v2_0/__init__.py:53has the helperfind_resourceid_by_name_or_id, used by Nova, Heat and Zun.
**What IGNORED_MODULES does here: nothing, at this commit.** openstackclient:openstackclient/shell.py:34 lists neutronclient.osc.v2.fwaas, .taas, .networking_bgpvpn, .dynamic_routing and .vpnaas, but setup.cfg declares none of them: the only groups are openstack.cli.extension and openstack.neutronclient.v2, whose 34 entry points are in neutronclient/osc/v2/logging, sfc and subnet_onboard. The directory neutronclient/osc/v2/fwaas keeps only neutronclient/osc/v2/fwaas/constants.py:18, imported by the log command. The firewall, BGP VPN, dynamic routing, TaaS and VPN commands exist, and come from OSC itself (openstackclient:pyproject.toml:596). openstack command list --group neutronclient shows exactly the 34 [observed].
Architecture
flowchart LR user[User or script] -->|argv| osc[openstack process] osc -->|entry point openstack.cli.extension| plugin[neutronclient.osc.plugin] plugin -->|27 sfc commands| sdk[openstacksdk Proxy] plugin -->|7 log and onboard commands| nc[neutronclient.v2_0.client.Client] plugin -->|--project only| ksc[python-keystoneclient] sdk --> ksa[keystoneauth1 session] nc --> ksa ksc --> ksa ksa -->|HTTPS, X-Auth-Token| neutron[Neutron /v2.0] ksa -->|HTTPS| ks[Keystone] svc[Nova, Heat, Manila, Zun, ec2-api, Skyline] -->|import| nc
Processes
| Process | Entry point | Role | Listens to / consumes |
|---|---|---|---|
openstack (python-openstackclient) | setup.cfg:32, neutronclient/osc/plugin.py:38 | runs one plugin command | argv, environment; listens on nothing |
There is no neutron script, daemon, agent or server in this repository.
External dependencies
| System | Protocol | Library | Configuration | Usage |
|---|---|---|---|---|
| Neutron | HTTPS REST | Client → keystoneauth1; openstacksdk | Keystone catalog, type network | all commands |
| Keystone | HTTPS REST | keystoneauth1; python-keystoneclient for --project | --os-auth-url, clouds.yaml | token, catalog; project lookup in network log create |
Keystone v2 /tokens | HTTPS REST | requests directly, class HTTPClient | auth_url, only without a session | legacy password path, see 02 § 4 |
Key figures
| Item | Count |
|---|---|
| Commands | 34, all loaded; 94 arguments, 33 required |
| Client stack | 27 openstacksdk; 7 neutronclient, of which 2 can also call python-keystoneclient |
| Commands reaching a request on the stub | 34 of 34 in each of the 3 modes |
| Commands exiting 0 | 404 mode 0; {} mode 22; rich mode 34; rich with all options 34 |
| Routes observed for the commands | 48 (method, route, query keys) |
Public methods of Client | 372; 123 called by name in other projects [inferred]; 94 whose path has no match in neutron-lib or neutron definitions |
| Exception classes | 36 in the inventory; 0 specific to OSC commands |
| Unit tests | 154 of 154 pass, 90 vectors, same call sequences in two runs |
| Classes without a vector | 0 of 34 |
Commands deriving from command.Command that return a value | 0 of 15, by AST |
Points of attention
- **
sfc port pair group setcrashes on an unknown group [observed]**: it alone omitsignore_missing=False(neutronclient/osc/v2/sfc/sfc_port_pair_group.py:197), and prints'NoneType' object is not subscriptable. - The client-side cycle check misses cycles longer than 2 [observed]:
a:b b:c c:ais sent to the server and exits 0 (neutronclient/osc/v2/sfc/sfc_service_graph.py:233). - **
network log listreuses or loses the event [observed]**: with an emptyevent, the first row crashes and a later row shows the event of the previous row (neutronclient/osc/v2/logging/network_log.py:228). - **A
200 {}from the service gives a raw Python error [observed]**:tuple indices must be integers or slices, not stronnetwork log list(neutronclient/v2_0/client.py:403). A compatible service must always send the collection key. - **An error without
detailis displayed as a Python dict [observed]**:{'type': 'BadRequest', 'message': 'm'}, and the typed exception is lost (neutronclient/v2_0/client.py:67). A compatible service must sendtype,messageanddetail. - **The binding hard-codes
/v2.0[observed]**: a catalog URL ending in/v2.0gives/network/v2.0/v2.0/log/logson the 7 binding commands, while SDK commands cope (neutronclient/v2_0/client.py:260,openstacksdk:openstack/config/cloud_region.py:1134). - The docstring's usage fails against Keystone v3 [observed on the stub]: without a session, the class posts Keystone v2 credentials to
{auth_url}/tokens(neutronclient/client.py:221). Every project found here passes a session. - Two error formats: a 404 reads
stub: not foundon binding commands andNotFoundException: 404: Client Error for url: …, stub: not foundon SDK commands [observed]. - Every binding command prints a deprecation warning on stderr [observed] (
neutronclient/v2_0/client.py:253). Scripts that treat stderr output as failure will trip on it. - Unit tests cannot catch these: they mock both clients (
neutronclient/tests/unit/osc/v2/fakes.py:27), which is why items 1 to 5 pass them. - The release note overstates the removal: it says all CLI code was removed (
releasenotes/notes/remove-cli-code-53969e9aa927e530.yaml:10), and 63 files remain. - Probably dead routes in the library: 47 of the 63
/lband/lbaasmethods, and all 16 of/qos-queues,/network-gatewaysand/gateway-devices, have no match in neutron-lib or neutron definitions [inferred, by text search]. See the surface.
Blind spots / [inferred]
- No real Neutron was contacted, so nothing here proves that a service accepts these requests or sends these fields. Bodies such as
"symmetric": "true"were seen leaving the client; acceptance by a server was not tested. - networking-sfc is not cloned here, so the server side of the 27
sfccommands was not read. neutron-lib hassfc.pyandflowclassifier.pydefinitions, but/sfc/service_graphshas no text match in them. - The rich stub answers are hand-written from the commands' own field lists. A field that the real service sends and the stub omits was not exercised.
- **The
called_bycolumn is a name search**: another client with a method of the same name gives a false positive, Heat especially. No consumer was run. - **Legacy modules under
neutronclient/neutron/v2_0** were imported (94 modules of the package, 0 failures) and not exercised, apart fromfind_resourceid_by_name_or_id[observed]. - **
neutronclient.extensionentry points** (neutronclient/common/extension.py:22): no package in the venv declares one, so extension loading ran empty. - **TLS,
--insecure, client certificates andosprofilerheaders** were read, not run. The stub is plain HTTP. - Output formatting by cliff was not specified command by command.
- Language of the messages: translated with
oslo.i18n; only English was seen.
Source: reverse-spec-python-neutronclient/00-summary_stable-2026.2.md. The _rewrite/ and _inventory/ files are not published on the site.