diff --git a/napalm_device_types/models.py b/napalm_device_types/models.py index 8188854..8f547ab 100644 --- a/napalm_device_types/models.py +++ b/napalm_device_types/models.py @@ -150,6 +150,53 @@ class Dot1XConfigDict(TypedDict): # --------------------------------------------------------------------------- +class InterfaceConfigDict(TypedDict, total=False): + """Settable configuration for a single switch interface. + + All fields are optional – only the fields present in the dict are applied; + omitted fields are left unchanged on the device. + + * description (str) – human-readable port label + * enabled (bool) – administrative state (``True`` = no shutdown) + * speed (int) – link speed in Mbps; ``0`` = auto-negotiate + * duplex (str) – ``"full"``, ``"half"``, or ``"auto"`` + * mtu (int) – maximum transmission unit in bytes + * mode (str) – port mode: ``"access"``, ``"trunk"``, or ``"routed"`` + * access_vlan (int) – untagged VLAN ID; effective when *mode* is ``"access"`` + * voice_vlan (int) – voice VLAN ID (``0`` = disabled) + * trunk_vlans (list of int) – tagged VLAN IDs allowed on trunk; + empty list means *all* VLANs; effective when *mode* is ``"trunk"`` + * native_vlan (int) – native (untagged) VLAN on a trunk port + """ + + description: str + enabled: bool + speed: int + duplex: str + mtu: int + mode: str + access_vlan: int + voice_vlan: int + trunk_vlans: List[int] + native_vlan: int + + +class VlanConfigDict(TypedDict, total=False): + """Settable configuration for a single VLAN. + + All fields are optional – only those present are applied. + + * name (str) – human-readable VLAN name + * active (bool) – whether the VLAN is active (``True``) or suspended (``False``) + * interfaces (list of str) – access-port interface names that should be + assigned to this VLAN (replaces the current membership) + """ + + name: str + active: bool + interfaces: List[str] + + class STPInterfaceDict(TypedDict): role: str state: str diff --git a/napalm_device_types/switch.py b/napalm_device_types/switch.py index f2cd49e..bac11ef 100644 --- a/napalm_device_types/switch.py +++ b/napalm_device_types/switch.py @@ -14,10 +14,12 @@ from typing import Dict from napalm.base import NetworkDriver from napalm_device_types.models import ( Dot1XPortDict, + InterfaceConfigDict, MACACLDict, PoESummaryDict, PortChannelDict, SpanningTreeDict, + VlanConfigDict, ) @@ -259,6 +261,110 @@ class SwitchDriver(NetworkDriver): """ raise NotImplementedError + def set_vlan(self, vlan_id: int, config: VlanConfigDict) -> None: + """ + Creates or updates a VLAN on the switch. + + If the VLAN does not yet exist it is created first. Only the keys + present in *config* are applied; omitted keys leave the existing VLAN + configuration untouched. + + :param vlan_id: VLAN ID (1–4094). + :param config: A (partial) :class:`~napalm_device_types.models.VlanConfigDict` + containing the fields to set. Supported keys: + + * ``name`` (str) – human-readable VLAN name + * ``active`` (bool) – ``True`` = active, ``False`` = suspended + * ``interfaces`` (list of str) – access-port names to assign to + this VLAN (replaces the current membership list) + + :raises NotImplementedError: If the driver does not implement this method. + :raises ValueError: If *vlan_id* is out of range or a field value is invalid. + + Example – create VLAN 10 with a name:: + + driver.set_vlan(10, {"name": "Workstations", "active": True}) + + Example – assign ports to an existing VLAN:: + + driver.set_vlan( + 10, + {"interfaces": ["GigabitEthernet0/1", "GigabitEthernet0/2"]}, + ) + """ + raise NotImplementedError + + def delete_vlan(self, vlan_id: int) -> None: + """ + Removes a VLAN from the switch. + + All ports that were assigned to this VLAN as their access VLAN are + moved to the default VLAN (1) by the driver before deletion. Trunk + ports that carry this VLAN will have it removed from their allowed + VLAN list. + + :param vlan_id: VLAN ID (1–4094) to delete. + :raises NotImplementedError: If the driver does not implement this method. + :raises ValueError: If *vlan_id* is out of range or the VLAN does not + exist on the device. + + Example:: + + driver.delete_vlan(10) + """ + raise NotImplementedError + + def set_interface(self, interface: str, config: InterfaceConfigDict) -> None: + """ + Applies configuration to a single switch interface. + + Only the keys present in *config* are changed; omitted keys leave the + current device configuration untouched. + + :param interface: Interface name (e.g. ``"GigabitEthernet0/1"``). + :param config: A (partial) :class:`~napalm_device_types.models.InterfaceConfigDict` + containing the fields to update. Supported keys: + + * ``description`` (str) – human-readable port label + * ``enabled`` (bool) – administrative state + * ``speed`` (int) – link speed in Mbps; ``0`` = auto-negotiate + * ``duplex`` (str) – ``"full"``, ``"half"``, or ``"auto"`` + * ``mtu`` (int) – maximum transmission unit in bytes + * ``mode`` (str) – ``"access"``, ``"trunk"``, or ``"routed"`` + * ``access_vlan`` (int) – untagged VLAN; relevant when mode is ``"access"`` + * ``voice_vlan`` (int) – voice VLAN ID (``0`` = disabled) + * ``trunk_vlans`` (list of int) – tagged VLANs; empty = allow all + * ``native_vlan`` (int) – native VLAN on trunk ports + + :raises NotImplementedError: If the driver does not implement this method. + :raises ValueError: If *interface* does not exist or an invalid value is + supplied for a configuration field. + + Example – convert port to access VLAN 10 and add a description:: + + driver.set_interface( + "GigabitEthernet0/1", + { + "description": "Workstation port", + "enabled": True, + "mode": "access", + "access_vlan": 10, + }, + ) + + Example – configure a trunk port:: + + driver.set_interface( + "GigabitEthernet0/2", + { + "mode": "trunk", + "trunk_vlans": [10, 20, 30], + "native_vlan": 1, + }, + ) + """ + raise NotImplementedError + def set_poe_enabled(self, interface: str, enabled: bool) -> None: """ Administratively enables or disables PoE on a single port. diff --git a/pyproject.toml b/pyproject.toml index 029750f..8aaa988 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [build-system] requires = ["setuptools>=68", "wheel"] -build-backend = "setuptools.backends.legacy:build" +build-backend = "setuptools.build_meta" [project] name = "napalm-device-types"