Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
b9a2b2b
Add nd_interface_ethernet_access module with bulk normalize delete
allenrobel Apr 8, 2026
63ce57f
Fix EpManageInterfacesDelete docstring and add missing module-level e…
allenrobel Apr 8, 2026
889be9d
EpManageInterfacesNormalize : clarify docstring
allenrobel Apr 9, 2026
1f40cf9
EpManageInterfacesDelete: update docstring
allenrobel Apr 9, 2026
7351d53
Add shared interface enums and constrain EthernetAccessPolicyModel fi…
allenrobel Apr 9, 2026
d8a1f23
Rename validator parameter v to value for consistency with serializers
allenrobel Apr 9, 2026
bcd58fb
Add bulk create and delete support to EthernetBaseOrchestrator
allenrobel Apr 10, 2026
4f661e8
Refactor EthernetBaseOrchestrator to inherit from NDBaseInterfaceOrch…
allenrobel Apr 15, 2026
ca925e4
Fix Pylance reportIncompatibleVariableOverride on bulk endpoint fields
allenrobel Apr 15, 2026
1026a5c
Suppress Pylance reportAttributeAccessIssue in EthernetBaseOrchestrator
allenrobel Apr 15, 2026
3c752ec
Migrate EthernetBaseOrchestrator to RestSend
allenrobel Apr 22, 2026
0d2220e
Modernize type annotations (PEP 585 / PEP 604)
allenrobel Apr 23, 2026
c069d4f
Add unit tests for nd_interface_ethernet_access
allenrobel Apr 23, 2026
50eb5c9
Add file-based logging to nd_interface_ethernet_access
allenrobel Apr 24, 2026
24233c1
Add logging usage to integration tests main.yaml
allenrobel Apr 24, 2026
43529c4
Adopt AsciiDescription type in EthernetAccessPolicyModel
allenrobel Apr 28, 2026
b8a61d0
Add deploymentFreeze response to query_all happy-path test
allenrobel Apr 28, 2026
c3c1df3
Type storm_control level fields as float matching OpenAPI
allenrobel Apr 30, 2026
2c602f7
Hardcode policy_type in ethernet access model
allenrobel May 4, 2026
9c1e0c9
Use YAML anchors to dedupe ethernet_access integration tests
allenrobel May 6, 2026
a63bc2a
Extract file-level pre-test cleanup into setup.yaml
allenrobel May 6, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
96 changes: 96 additions & 0 deletions plugins/module_utils/endpoints/v1/manage/manage_interfaces.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,12 @@
(POST /api/v1/manage/fabrics/{fabric_name}/switches/{switch_sn}/interfaces)
- `EpManageInterfacesPut` - Update a specific interface
(PUT /api/v1/manage/fabrics/{fabric_name}/switches/{switch_sn}/interfaces/{interface_name})
- `EpManageInterfacesDelete` - Delete a virtual interface (loopback, SVI); not supported for physical ethernet
(DELETE /api/v1/manage/fabrics/{fabric_name}/switches/{switch_sn}/interfaces/{interface_name})
- `EpManageInterfacesDeploy` - Deploy interface configurations
(POST /api/v1/manage/fabrics/{fabric_name}/interfaceActions/deploy)
- `EpManageInterfacesNormalize` - Reset physical interface configurations to default
(POST /api/v1/manage/fabrics/{fabric_name}/interfaceActions/normalize)
- `EpManageInterfacesRemove` - Bulk delete interfaces
(POST /api/v1/manage/fabrics/{fabric_name}/interfaceActions/remove)
"""
Expand Down Expand Up @@ -238,6 +242,46 @@ def verb(self) -> HttpVerbEnum:
return HttpVerbEnum.PUT


class EpManageInterfacesDelete(_EpManageInterfacesBase):
"""
# Summary

Delete a specific interface configuration.

- Path: `/api/v1/manage/fabrics/{fabric_name}/switches/{switch_sn}/interfaces/{interface_name}`
- Verb: DELETE

This endpoint works for virtual interfaces (loopback, SVI) only. For physical ethernet interfaces, the API returns
HTTP 500 ("Interface cannot be deleted!!!").

To reset physical interfaces to their default state, see `EpManageInterfacesNormalize` and set the payload to an
appropriate default config (for example `module_utils/models/interfaces/interface_default_config.py`).

## Raises

### ValueError

- Via inherited `path` property if `fabric_name`, `switch_sn`, or `interface_name` is not set.
"""

class_name: Literal["EpManageInterfacesDelete"] = Field(
default="EpManageInterfacesDelete", frozen=True, description="Class name for backward compatibility"
)

@property
def verb(self) -> HttpVerbEnum:
"""
# Summary

Return `HttpVerbEnum.DELETE`.

## Raises

None
"""
return HttpVerbEnum.DELETE


class EpManageInterfacesDeploy(FabricNameMixin, NDEndpointBaseModel):
"""
# Summary
Expand Down Expand Up @@ -290,6 +334,58 @@ def verb(self) -> HttpVerbEnum:
return HttpVerbEnum.POST


class EpManageInterfacesNormalize(FabricNameMixin, NDEndpointBaseModel):
"""
# Summary

Normalize interface configurations on switches.

- Path: `/api/v1/manage/fabrics/{fabric_name}/interfaceActions/normalize`
- Verb: POST
- Body: `{"interfaceType": "ethernet", "configData": {...}, "switchInterfaces": [{"interfaceName": "...", "switchId": "..."}]}`

## Raises

### ValueError

- Via `path` property if `fabric_name` is not set.
"""

class_name: Literal["EpManageInterfacesNormalize"] = Field(
default="EpManageInterfacesNormalize", frozen=True, description="Class name for backward compatibility"
)

@property
def path(self) -> str:
"""
# Summary

Build the normalize endpoint path.

## Raises

### ValueError

- If `fabric_name` is not set before accessing `path`.
"""
if self.fabric_name is None:
raise ValueError(f"{type(self).__name__}.path: fabric_name must be set before accessing path.")
return BasePath.path("fabrics", self.fabric_name, "interfaceActions", "normalize")

@property
def verb(self) -> HttpVerbEnum:
"""
# Summary

Return `HttpVerbEnum.POST`.

## Raises

None
"""
return HttpVerbEnum.POST


class EpManageInterfacesRemove(FabricNameMixin, NDEndpointBaseModel):
"""
# Summary
Expand Down
135 changes: 135 additions & 0 deletions plugins/module_utils/models/interfaces/enums.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
# Copyright: (c) 2026, Allen Robel (@allenrobel)

# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt)

"""
# Summary

Shared enum definitions for ethernet interface models.

These enums are derived from ND config templates (e.g. `int_access_host`, `int_trunk_host`) and constrain policy
fields across multiple interface types. Each enum's member values match the API's expected strings exactly.
"""

from __future__ import annotations

from enum import Enum


class AccessHostPolicyTypeEnum(str, Enum):
"""
# Summary

Policy type for access host interfaces.
"""

ACCESS_HOST = "accessHost"


class BpduFilterEnum(str, Enum):
"""
# Summary

Spanning-tree BPDU filter settings.
"""

ENABLE = "enable"
DISABLE = "disable"
DEFAULT = "default"


class BpduGuardEnum(str, Enum):
"""
# Summary

Spanning-tree BPDU guard settings.
"""

ENABLE = "enable"
DISABLE = "disable"
DEFAULT = "default"


class DuplexModeEnum(str, Enum):
"""
# Summary

Port duplex mode settings.
"""

AUTO = "auto"
FULL = "full"
HALF = "half"


class FecEnum(str, Enum):
"""
# Summary

Forward error correction (FEC) mode.
"""

AUTO = "auto"
FC_FEC = "fcFec"
OFF = "off"
RS_CONS16 = "rsCons16"
RS_FEC = "rsFec"
RS_IEEE = "rsIEEE"


class LinkTypeEnum(str, Enum):
"""
# Summary

Spanning-tree link type.
"""

AUTO = "auto"
POINT_TO_POINT = "pointToPoint"
SHARED = "shared"


class MtuEnum(str, Enum):
"""
# Summary

Interface MTU setting.
"""

DEFAULT = "default"
JUMBO = "jumbo"


class SpeedEnum(str, Enum):
"""
# Summary

Interface speed setting.
"""

AUTO = "auto"
TEN_MB = "10Mb"
HUNDRED_MB = "100Mb"
ONE_GB = "1Gb"
TWO_POINT_FIVE_GB = "2.5Gb"
FIVE_GB = "5Gb"
TEN_GB = "10Gb"
TWENTY_FIVE_GB = "25Gb"
FORTY_GB = "40Gb"
FIFTY_GB = "50Gb"
HUNDRED_GB = "100Gb"
TWO_HUNDRED_GB = "200Gb"
FOUR_HUNDRED_GB = "400Gb"
EIGHT_HUNDRED_GB = "800Gb"


class StormControlActionEnum(str, Enum):
"""
# Summary

Storm control action on threshold violation.
"""

SHUTDOWN = "shutdown"
TRAP = "trap"
DEFAULT = "default"
Loading