Skip to content

Commit

Permalink
Merge branch 'feature/snmpv3-seeddb-connectivity' into snmpv3-synchro…
Browse files Browse the repository at this point in the history
…nous
  • Loading branch information
lunkwill42 committed Nov 9, 2023
2 parents 6a919a6 + dd1f5dc commit cf6bb72
Show file tree
Hide file tree
Showing 3 changed files with 138 additions and 10 deletions.
59 changes: 59 additions & 0 deletions python/nav/Snmp/profile.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
#
# Copyright (C) 2023 Sikt
#
# This file is part of Network Administration Visualized (NAV).
#
# NAV is free software: you can redistribute it and/or modify it under
# the terms of the GNU General Public License version 3 as published by
# the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
# more details. You should have received a copy of the GNU General Public
# License along with NAV. If not, see <http://www.gnu.org/licenses/>.
#
"""Helper functions to build SNMP sessions from NAV ManagementProfile instances"""
from functools import partial
from typing import Callable

from nav.models.manage import Netbox, ManagementProfile
from nav.Snmp import Snmp


def get_snmp_session_for_profile(profile: ManagementProfile) -> Callable:
"""Returns a nav.Snmp.Snmp constructor partially pre-configured with SNMP options
from an SNMP management profile.
Example usage:
>>> netbox = Netbox.objects.get(id=1)
>>> snmp = get_snmp_session_for_profile(
... netbox.get_preferred_snmp_management_profile())
>>> session = snmp(netbox.ip)
>>> session.get()
b'Linux 16e2ac5c6456 6.1.60 #1-NixOS SMP PREEMPT_DYNAMIC Wed Oct 25 10:03:17 UTC 2023 x86_64'
>>>
"""
if not profile.is_snmp:
raise ValueError("Cannot create SNMP session from non-SNMP management profile")

if profile.snmp_version < 3:
kwargs = {
"version": profile.configuration.get("version"),
"community": profile.configuration.get("community"),
}
else:
kwargs = {
opt: profile.configuration.get(opt) or None
for opt in (
"sec_level",
"auth_protocol",
"sec_name",
"auth_password",
"priv_protocol",
"priv_password",
)
}
kwargs["version"] = 3

return partial(Snmp, **kwargs)
15 changes: 5 additions & 10 deletions python/nav/web/seeddb/page/netbox/edit.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
from nav.models.manage import NetboxInfo, ManagementProfile
from nav.Snmp import Snmp, safestring
from nav.Snmp.errors import SnmpError
from nav.Snmp.profile import get_snmp_session_for_profile
from nav import napalm
from nav.util import is_valid_ip
from nav.web.seeddb import reverse_lazy
Expand Down Expand Up @@ -223,11 +224,7 @@ def check_snmp_version(ip, profile):
"""Check if version of snmp is supported by device"""
sysobjectid = '1.3.6.1.2.1.1.2.0'
try:
snmp = Snmp(
ip,
profile.configuration.get("community"),
profile.configuration.get("version"),
)
snmp = get_snmp_session_for_profile(profile)(ip)
snmp.get(sysobjectid)
except Exception: # pylint: disable=W0703
return False
Expand Down Expand Up @@ -256,16 +253,14 @@ def get_sysname(ip_address):

def get_type_id(ip_addr, profile):
"""Gets the id of the type of the ip_addr"""
netbox_type = snmp_type(
ip_addr, profile.configuration.get("community"), profile.snmp_version
)
netbox_type = snmp_type(ip_addr, profile)
if netbox_type:
return netbox_type.id


def snmp_type(ip_addr, snmp_ro, snmp_version):
def snmp_type(ip_addr, profile: ManagementProfile):
"""Query ip for sysobjectid using form data"""
snmp = Snmp(ip_addr, snmp_ro, snmp_version)
snmp = get_snmp_session_for_profile(profile)(ip_addr)
try:
sysobjectid = snmp.get('.1.3.6.1.2.1.1.2.0')
except SnmpError:
Expand Down
74 changes: 74 additions & 0 deletions tests/unittests/Snmp/profile_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
#
# Copyright (C) 2023 Sikt
#
# This file is part of Network Administration Visualized (NAV).
#
# NAV is free software: you can redistribute it and/or modify it under
# the terms of the GNU General Public License version 3 as published by
# the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
# more details. You should have received a copy of the GNU General Public
# License along with NAV. If not, see <http://www.gnu.org/licenses/>.
#
from unittest.mock import Mock

import pytest

from nav.Snmp import Snmp
from nav.Snmp.profile import get_snmp_session_for_profile


class TestGetSnmpSessionForProfile:
def test_when_valid_snmpv2_profile_is_given_it_should_return_a_valid_snmp_partial(
self, mock_snmpv2_profile
):
snmp = get_snmp_session_for_profile(mock_snmpv2_profile)
assert callable(snmp)
session = snmp("127.0.0.1")
assert isinstance(session, Snmp)

def test_when_valid_snmpv3_profile_is_given_it_should_return_a_valid_snmp_partial(
self, mock_snmpv3_profile
):
snmp = get_snmp_session_for_profile(mock_snmpv3_profile)
assert callable(snmp)
session = snmp("127.0.0.1")
assert isinstance(session, Snmp)

conf = mock_snmpv3_profile.configuration
assert session.sec_level.value == conf["sec_level"]
assert session.auth_protocol.value == conf["auth_protocol"]
assert session.sec_name == conf["sec_name"]
assert session.auth_password == conf["auth_password"]

def test_when_non_snmp_profile_is_given_it_should_raise_valueerror(self):
profile = Mock(is_snmp=False, is_snmpv3=False)
with pytest.raises(ValueError):
get_snmp_session_for_profile(profile)


@pytest.fixture
def mock_snmpv2_profile():
profile = Mock(is_snmp=True, is_snmpv3=False)
profile.configuration = {
"version": "2c",
"write": False,
"community": "public",
}
return profile


@pytest.fixture
def mock_snmpv3_profile():
profile = Mock(is_snmp=False, is_snmpv3=True)
profile.configuration = {
"version": "3",
"sec_level": "authNoPriv",
"auth_protocol": "SHA",
"sec_name": "foobar",
"auth_password": "zaphodbeeblebrox",
}
return profile

0 comments on commit cf6bb72

Please sign in to comment.