End-to-end scenarios — python-ironicclient — branch stable/2026.2
Branch
stable/2026.2@af2ceeb9c4f2— repository https://opendev.org/openstack/python-ironicclient — analysed on 2026-11-01
Each scenario was run against a local stub, with its id in _rewrite/scenarios_stable-2026.2.json. The stub's answers were scripted, and do not show that Ironic answers the same way. What Ironic does behind the API is in reverse-spec-ironic/.
1. A list against an older server: negotiation
Id neg-406-downgrade. The stub announces a maximum of 1.90.
sequenceDiagram
participant U as openstack baremetal node list
participant K as Keystone
participant I as Stub
U->>K: POST /v3/auth/tokens
K-->>U: 201, token and catalog
U->>I: GET /v1/nodes, API version 1.115
I-->>U: 406
U->>I: GET /v1, no version header
alt headers present
I-->>U: 200, Minimum 1.1, Maximum 1.90
U->>I: GET /v1/nodes, API version 1.90
I-->>U: 200 {"nodes": []}
Note over U: exit 0, cache file written
else no version headers
I-->>U: 200
U->>I: GET /v1 again
Note over U: RuntimeError, exit 1
else GET /v1 fails
I-->>U: 500
Note over U: Internal Server Error (HTTP 500), exit 1
endWhere to look: --debug shows the version used. If the user pinned a version, the failure says Requested API version … is not supported, and removing the option fixes it. Each new process goes through this again.
2. Moving a node with --wait
Ids wait-manage-ok, wait-manage-failed, wait-manage-other-stable, wait-manage-timeout.
sequenceDiagram
participant U as baremetal node manage x --wait 30
participant I as Stub
U->>I: PUT /v1/nodes/x/states/provision {"target": "manage"}
I-->>U: 200
Note over U: prints Waiting for provision state manageable
loop every 2 s
U->>I: GET /v1/nodes/x
alt provision_state = manageable
I-->>U: 200
Note over U: exit 0
else "error" or ends in " failed"
I-->>U: 200, last_error
Note over U: StateTransitionFailed, exit 1
else no target_provision_state
I-->>U: 200
Note over U: unexpected stable state, exit 1
else still moving
I-->>U: 200, target_provision_state set
end
end
Note over U: timeout: StateTransitionTimeout, exit 1Where to look: the error shows the state and last_error. A timeout on the client changes nothing on the server: the action keeps running. The first check runs at once, with no delay, so a state that already matches ends the wait [observed wait-service-already-active].
3. A conflict on a locked node
Id err-409-exhausts-retries.
sequenceDiagram
participant U as baremetal node create --driver x
participant I as Stub
loop 6 attempts, 2 s apart
U->>I: POST /v1/nodes
I-->>U: 409 {"error_message": "...locked..."}
end
Note over U: logs Attempt 6 of 6, prints locked (HTTP 409), exit 1Where to look: a command that takes 10 seconds then fails is this loop. A 503 behaves the same, unless it has a Retry-After header, in which case the command fails at once with a TypeError [observed err-503-retry-after].
4. Bulk creation from a file
Ids create-file-ok, create-file-port-mismatch.
sequenceDiagram
participant U as baremetal create resources.yaml
participant F as File
participant I as Stub
U->>F: read, then JSON schema check
alt invalid
Note over U: While validating the resources file(s)..., nothing sent
else valid
U->>I: POST /v1/chassis
I-->>U: uuid c1
U->>I: POST /v1/nodes, chassis_uuid c1
I-->>U: uuid n1
U->>I: POST /v1/ports, node_uuid n1
I-->>U: uuid p1
Note over U: exit 0
end
Note over U,I: a failed parent skips its children, others go on
Note over U,I: nothing is rolled back, errors are listed at the end, exit 1Where to look: after an error, the resources before it exist. Running the file again will conflict with them, unless UUIDs or names differ [inferred]. A wrong node_uuid on a port shows a raw Python tuple (02 § 5, defect 8).
5. The baremetal shell without Keystone
Ids legacy-noauth-endpoint, legacy-latest, legacy-no-endpoint.
sequenceDiagram
participant U as baremetal
participant I as Stub
alt --os-endpoint given
U->>I: GET /v1/nodes, 1.115, dummy token
I-->>U: 200
else --os-baremetal-api-version latest
U->>I: GET /v1
I-->>U: Maximum 1.90
U->>I: GET /v1/nodes, 1.90
else no endpoint
Note over U: The Bare Metal API endpoint cannot be detected..., exit 1
endWhere to look: this path is for a standalone Ironic, so nothing contacts Keystone. Whether a given Ironic accepts it depends on its auth settings; this was not tested.
Source: reverse-spec-python-ironicclient/04-scenarios_stable-2026.2.md. The _rewrite/ and _inventory/ files are not published on the site.