OpenKeel: the sovereign French Cloud solution of the inherent group, with a European reach Discover inherent

Reverse-spec · Clients

python-neutronclient — Scenarios

Scenarios — 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

Sequences were seen on the local stub [observed], under the run IDs of [_rewrite/defect-repros_stable-2026.2.json](_rewrite/defect-repros_stable-2026.2.json). The stub is not Neutron, so what happens after the response, in a real service, is not covered.

1. Loading the plugin

The process builds its command table before any network call. This is what decides that a command exists.

sequenceDiagram
  autonumber
  actor U as User
  participant S as openstack shell
  participant E as Python entry points
  participant P as neutronclient.osc.plugin
  U->>S: openstack network log list
  S->>E: load group openstack.cli.extension
  E->>P: import module
  S->>P: read API_NAME, API_VERSION_OPTION, DEFAULT_API_VERSION
  S->>S: read network_api_version from the cloud config (default 2)
  alt version major is 2
    S->>E: load group openstack.neutronclient.v2 (34 commands)
    E-->>S: entries, IGNORED_MODULES matches none
    S-->>U: runs the command
  else --os-network-api-version 3
    S->>E: load group openstack.neutronclient.v3 (empty)
    S-->>U: warning, then not an openstack command, exit 2
  end

Diagnostics: openstack command list --group neutronclient lists the group. Sources: openstackclient:openstackclient/shell.py:101, openstackclient:openstackclient/shell.py:150, cliff:cliff/commandmanager.py:135, neutronclient/osc/plugin.py:26.

2. Creating a network log (Python binding)

sequenceDiagram
  autonumber
  actor U as User
  participant C as CreateNetworkLog
  participant N as Client
  participant KA as keystoneauth session
  participant KS as Keystone
  participant Q as Neutron
  U->>C: network log create n --resource-type SECURITY_GROUP --resource y --event drop
  C->>C: lower-case the type, upper-case the event, check the choices
  C->>N: Client(session, region_name, endpoint_type)
  Note over N: warning on stderr: python binding is deprecated
  C->>N: find_resource(security_group, y)
  N->>KA: GET /v2.0/security-groups?name=y
  KA->>KS: POST /v3/auth/tokens, first request only
  KS-->>KA: token, catalog
  KA->>Q: GET /network/v2.0/security-groups?name=y
  alt no match
    Q-->>N: 200 security_groups empty
    N-->>U: Unable to find security_group with name or id, exit 1
  else two matches
    Q-->>N: 200 with 2 entries
    N-->>U: Multiple security_group matches found, exit 1
  else one match
    Q-->>N: 200 with 1 entry
    C->>N: create_network_log with envelope log
    N->>Q: POST /network/v2.0/log/logs
    Q-->>N: 201 log
    N-->>U: table, exit 0
  end

Diagnostics: an error shown as a Python dict means a NeutronError without detail. 'Client' object has no attribute 'list_foos' means that the resource type has no method in the class, and that no request went out. Run: log-create-sg. Sources: neutronclient/osc/v2/logging/network_log.py:69-105, neutronclient/v2_0/client.py:476.

3. Appending to a port chain (SDK, read-modify-write)

sequenceDiagram
  autonumber
  actor U as User
  participant C as SetSfcPortChain
  participant S as openstacksdk
  participant Q as Neutron
  U->>C: sfc port chain set x --port-pair-group y --flow-classifier z
  C->>S: find_sfc_port_chain(x)
  S->>Q: GET /sfc/port_chains/x
  C->>S: find y, then z, in _get_common_attrs
  S->>Q: GET /sfc/port_pair_groups/y
  S->>Q: GET /sfc/flow_classifiers/z
  C->>S: find x, read flow_classifiers
  S->>Q: GET /sfc/port_chains/x
  C->>S: find z again
  S->>Q: GET /sfc/flow_classifiers/z
  C->>S: find x, read port_pair_groups
  S->>Q: GET /sfc/port_chains/x
  C->>S: find y again
  S->>Q: GET /sfc/port_pair_groups/y
  C->>S: update_sfc_port_chain(id, full lists)
  S->>Q: PUT /sfc/port_chains/{id}
  alt conflict
    Q-->>C: 409
    C-->>U: Failed to update port chain, exit 1
  else success
    Q-->>C: 200
    C-->>U: nothing, exit 0
  end

Diagnostics: seven GET for one change is the normal cost. Without If-Match, a change made between the read and the write is overwritten. With a name unknown to the server, the first GET is followed by ?name=. Run: pc-set-append. Sources: neutronclient/osc/v2/sfc/sfc_port_chain.py:204-256.

4. Creating a service graph (client-side checks)

sequenceDiagram
  autonumber
  actor U as User
  participant C as CreateSfcServiceGraph
  participant S as openstacksdk
  participant Q as Neutron
  U->>C: sfc service graph create g --branching-point a:b --branching-point b:c --branching-point c:a
  loop each branching point
    C->>C: colon present, no duplicate destination
    C->>S: find source chain
    S->>Q: GET /sfc/port_chains/a
    C->>S: find destination chain
    S->>Q: GET /sfc/port_chains/b
    C->>C: _check_cycle, adding the edge
  end
  alt two-node cycle or self-loop
    C-->>U: Error Service graph contains a cycle, exit 1
  else longer cycle, not detected
    C->>S: create_sfc_service_graph
    S->>Q: POST /sfc/service_graphs
    Q-->>U: the server decides
  end

Diagnostics: the client check is partial, see defect 2 of 02 § 4. Whether a real server refuses the graph was not tested. Runs: graph-cycle-2-detected, graph-cycle-3-missed. Sources: neutronclient/osc/v2/sfc/sfc_service_graph.py:210-272.

5. A service using the library: Nova and Neutron errors

This scenario was read, not run: no consumer was started. Only find_resourceid_by_name_or_id was exercised, on the stub.

sequenceDiagram
  autonumber
  participant N as nova-api
  participant W as ClientWrapper
  participant C as Client
  participant Q as Neutron
  N->>W: get_client(context)
  W->>C: Client(session, auth, global_request_id, connect_retries, ...)
  N->>W: show_port(id)
  W->>C: show_port(id)
  C->>Q: GET /v2.0/ports/{id}, X-OpenStack-Request-ID
  alt 200
    Q-->>N: port dict with request_ids
  else 404 with type PortNotFound
    Q-->>C: NeutronError
    C-->>N: PortNotFoundClient, handled per call site
  else 401
    Q-->>C: Unauthorized
    C-->>W: Unauthorized
    W-->>N: exception.Unauthorized for a user, NeutronAdminCredentialConfigurationInvalid for an admin client
  end

Diagnostics: Nova's mapping depends on the type string in the body. A service sending another type gives the generic NotFound, and Nova's except PortNotFoundClient no longer matches. Sources: nova:nova/network/neutron.py:164-205, nova:nova/network/neutron.py:701, neutronclient/v2_0/client.py:70, neutronclient/common/exceptions.py:143.

Source: reverse-spec-python-neutronclient/04-scenarios_stable-2026.2.md. The _rewrite/ and _inventory/ files are not published on the site.