Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Select generic SNMPHandler for Cisco Small Business switches in PortAdmin #3250

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 1 addition & 0 deletions changelog.d/3249.added.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Added support for setting access port VLANs for Cisco Small Business switches in PortAdmin (by reverting to non-Cisco-specific handler routines for this subgroup of products)
7 changes: 7 additions & 0 deletions python/nav/portadmin/handlers.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,16 @@ class ManagementHandler:
a class.
"""

VENDOR = None

def __init__(self, netbox: manage.Netbox, **kwargs):
self.netbox = netbox

@classmethod
def can_handle(cls, netbox: manage.Netbox) -> bool:
"""Returns True if this handler can handle the given netbox"""
return netbox.type and netbox.type.get_enterprise_id() == cls.VENDOR

def set_interface_description(self, interface: manage.Interface, description: str):
"""Configures a single interface's description, AKA the ifalias value"""
raise NotImplementedError
Expand Down
9 changes: 5 additions & 4 deletions python/nav/portadmin/management.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@
from nav.portadmin.snmp.hp import HP
from nav.portadmin.napalm.juniper import Juniper

VENDOR_MAP = {cls.VENDOR: cls for cls in (Cisco, Dell, H3C, HP, Juniper)}
SUPPORTED_HANDLERS = (Cisco, Dell, H3C, HP, Juniper)
FALLBACK_HANDLER = SNMPHandler


class ManagementFactory(object):
Expand All @@ -37,9 +38,9 @@ def get_instance(cls, netbox: manage.Netbox, **kwargs) -> ManagementHandler:
if not netbox.type:
raise NoNetboxTypeError()

vendor_id = netbox.type.get_enterprise_id()
handler = VENDOR_MAP.get(vendor_id, SNMPHandler)
return handler(netbox, **kwargs)
matched_handlers = (h for h in SUPPORTED_HANDLERS if h.can_handle(netbox))
chosen_handler = next(matched_handlers, FALLBACK_HANDLER)
return chosen_handler(netbox, **kwargs)

def __init__(self):
pass
2 changes: 0 additions & 2 deletions python/nav/portadmin/snmp/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,8 +88,6 @@ class InvalidManagementProfileError(ManagementError):
class SNMPHandler(ManagementHandler):
"""Implements PortAdmin management functions for SNMP-enabled switches"""

VENDOR = None

QBRIDGENODES = get_mib('Q-BRIDGE-MIB')['nodes']

SYSOBJECTID = '.1.3.6.1.2.1.1.2.0'
Expand Down
13 changes: 13 additions & 0 deletions python/nav/portadmin/snmp/cisco.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@
class Cisco(SNMPHandler):
"""A specialized class for handling ports in CISCO switches."""

# Cisco sysObjectIDs under this tree are not normal Cisco products and should
# probably not be handled by this handler
OTHER_ENTERPRISES = OID('.1.3.6.1.4.1.9.6')

VENDOR = VENDOR_ID_CISCOSYSTEMS

VTPNODES = get_mib('CISCO-VTP-MIB')['nodes']
Expand Down Expand Up @@ -85,6 +89,15 @@ def __init__(self, netbox, **kwargs):
self.voice_vlan_oid = '1.3.6.1.4.1.9.9.68.1.5.1.1.1'
self.cdp_oid = '1.3.6.1.4.1.9.9.23.1.1.1.1.2'

@classmethod
def can_handle(cls, netbox: manage.Netbox) -> bool:
"""Returns True if this handler can handle this netbox"""
if netbox.type and cls.OTHER_ENTERPRISES.is_a_prefix_of(
netbox.type.sysobjectid
):
return False
return super().can_handle(netbox)

@translate_protocol_errors
def get_interface_native_vlan(self, interface):
return self._query_netbox(self.vlan_oid, interface.ifindex)
Expand Down
8 changes: 8 additions & 0 deletions tests/unittests/portadmin/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ def netbox_hp(profile):

netbox_type = Mock()
netbox_type.vendor = vendor
netbox_type.sysobjectid = '1.3.6.1.4.1.11.2.3.7.11.45'
netbox_type.get_enterprise_id.return_value = VENDOR_ID_HEWLETT_PACKARD

netbox = Mock()
Expand All @@ -40,6 +41,7 @@ def netbox_cisco(profile):

netbox_type = Mock()
netbox_type.vendor = vendor
netbox_type.sysobjectid = '1.3.6.1.4.1.9.1.278'
netbox_type.get_enterprise_id.return_value = VENDOR_ID_CISCOSYSTEMS

netbox = Mock()
Expand All @@ -50,6 +52,12 @@ def netbox_cisco(profile):
return netbox


@pytest.fixture
def netbox_cisco_smb(netbox_cisco):
netbox_cisco.type.sysobjectid = '1.3.6.1.4.1.9.6.1.1004.10.1'
return netbox_cisco


@pytest.fixture
def handler_hp(netbox_hp):
return ManagementFactory.get_instance(netbox_hp)
Expand Down
8 changes: 8 additions & 0 deletions tests/unittests/portadmin/portadmin_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

from nav.oids import OID
from nav.portadmin.management import ManagementFactory
from nav.portadmin.snmp.base import SNMPHandler
from nav.portadmin.snmp.hp import HP
from nav.portadmin.snmp.cisco import Cisco

Expand All @@ -17,6 +18,13 @@ def test_get_cisco(self, netbox_cisco):
assert handler is not None, "Could not get handler-object"
assert isinstance(handler, Cisco), "Wrong handler-type"

def test_when_device_is_cisco_smb_switch_it_should_return_generic_snmp_handler(
self, netbox_cisco_smb
):
handler = ManagementFactory.get_instance(netbox_cisco_smb)
assert handler is not None, "Could not get handler-object"
assert type(handler) is SNMPHandler, "Wrong handler-type"


class TestPortadminResponseHP:
def test_get_vlan_hp(self, handler_hp):
Expand Down
Loading