Skip to content

RestSend treats HTTP 207 Multi-Status as success even when results[].status is 'failed' or 'error' #295

Description

@allenrobel

Summary

plugins/module_utils/rest/response_handler_nd.py classifies HTTP 207 as success
(RETURN_CODE in (200, 201, 202, 204, 207)), so per-item failures inside the response
body are silently ignored. ND uses 207 as the wrapper status for batch interface
operations regardless of whether individual items succeeded or failed.

Reproduction (ND 4.2.1, lab SITE1, 2026-05-27)

POST /api/v1/manage/fabrics/SITE1/switches/<sn>/interfaces with interfaceType: "subInterface"
targeting a trunk-mode parent returns:

HTTP 207
{"results": [{"name": "Port-channel1.999",
              "status": "failed",
              "message": "Sub-interface can be created only on routed physical or
                          port-channel interfaces (discovered mode is not routed)
                          for interface Port-channel1.999[subInterface]"}]}

RestSend / ResponseHandler return this body up to the orchestrator without raising.
Any module hitting batch interface or interface-action endpoints (subinterface, breakout,
fabric_update_group, and likely vpc_pair too) will see "success" while ND actually
rejected every item in the batch — masking real failures and breaking idempotency.

Status string varies by endpoint

  • Subinterface POST → status: "failed" (verified above)
  • Breakout action → status: "error" (per existing memory project_breakout_design.md)

The fix needs to handle both literals.

Suggested fix

In response_handler_nd.py (or the per-verb response strategies under
plugins/module_utils/rest/response_strategies/), treat 207 as success only when no
item in results[] (or equivalent envelope) carries status in ("failed", "error")
.
When any item fails, propagate an error so RestSend.commit() raises and the
orchestrator's _request() surfaces a clean failure message to the user.

Test plan

  • Add a unit test: 207 with all results[].status == "ok" → success
  • Add a unit test: 207 with mixed results[] (some ok, some failed) → raises with the failure messages aggregated
  • Add a unit test: 207 with results[].status == "error" → raises (covers breakout style)
  • Integration test: attempt to POST nd_interface_subinterface_managed against a trunk-mode parent and assert the module fails with the ND parent-mode message rather than returning success

Context

Surfaced while scaffolding nd_interface_subinterface_managed against the ND 4.2.1 lab.
Same response shape as project_breakout_design.md flagged earlier, but with a different
status literal — so a fix must handle both.

Metadata

Metadata

Assignees

Labels

nac01NaC ND release 0.0.1

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions