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

Add initial SNMPv3 support to ipdevpoll #2743

Merged
merged 15 commits into from Nov 20, 2023

Conversation

lunkwill42
Copy link
Member

@lunkwill42 lunkwill42 commented Nov 15, 2023

This adds SNMPv3 support to ipdevpoll and the asynchronous SNMP libraries of NAV.

Summary:

  • Individual SNMP attributes were still stored directly on Netbox objects ("shadow" objects, not Django models). The pre-existing SNMPParameters namedtuple was changed into a dataclass with all necessary parameters for establishing SNMP v1/v2c/v3 communication, and each Netbox object now has an snmp_parameters attribute attached to it (unless it has no SNMP profile, that is).

  • SNMPv3-related bugs were found and fixed in the pynetsnmp-2 library during the development of this PR. This PR updates NAV's required version of this library as a result.

  • Additionally, SNMPv3 communication may lead to another type of timeout error being raised in unexpected places, so the SnmpTimeoutError from pynetsnmp needed to be handled in various places. Details are in the commit logs.

Closes #2736
Fixes #2522 as part of reworking how ipdevpoll accesses SNMP credentials.

Copy link

github-actions bot commented Nov 15, 2023

Test results

     12 files       12 suites   11m 42s ⏱️
3 267 tests 3 267 ✔️ 0 💤 0
9 276 runs  9 276 ✔️ 0 💤 0

Results for commit 1303115.

♻️ This comment has been updated with latest results.


# SNMPv3 only
sec_level: Optional[
Union[Literal["noAuthNoPriv"], Literal["authNoPriv"], Literal["authPriv"]]
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, the tests are failing on Python 3.7 because I introduced the use of Literal here.

We don't actually use the type annotations for anything automated (like actual type checking), and we're not quite ready to drop Python 3.7 support yet, so I'm thinking maybe just replace this with str. What do you think, @hmpf ?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Or maybe better yet: Switch to using the existing Enums in nav.Snmp,.defines

@lunkwill42 lunkwill42 closed this Nov 16, 2023
@lunkwill42 lunkwill42 reopened this Nov 16, 2023
Copy link

codecov bot commented Nov 16, 2023

Codecov Report

Attention: 4 lines in your changes are missing coverage. Please review.

Comparison is base (54449ed) 55.46% compared to head (1303115) 55.57%.
Report is 5 commits behind head on master.

Files Patch % Lines
python/nav/ipdevpoll/snmp/common.py 97.40% 2 Missing ⚠️
python/nav/mibs/mibretriever.py 60.00% 2 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master    #2743      +/-   ##
==========================================
+ Coverage   55.46%   55.57%   +0.10%     
==========================================
  Files         567      567              
  Lines       41172    41244      +72     
==========================================
+ Hits        22837    22922      +85     
+ Misses      18335    18322      -13     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

Dataclasses weren't a part of Python when this was originally written,
but as we need SNMPParameters to grow, it makes sense to refactor this
now.
A better design might subclass this into v1, v2c and v3 versions, but
inheritance would not be straightforward: community is part of v1 and
v2c, bulk parameters are valid for v2c and v3, and auth and privacy
parameters are only valid for v3.

This bunches everything together, but does not perform any error
detection or corrections.  Incoming profiles are assumed to be
correct and verified as they are inserted into NAV.
PyCharm wasn't able to properly deduce the return value of
Netbox.get_preferred_management_profile, so this adds a return value
annotation.
This extends SNMPParameters to include a factory class method which
does most of the work of `snmp_parameter_factory`, but which can also
fetch SNMP management profile information on a box-by-box basis.
This new method converts an SNMPParameter instance to a dict that can be
used as the kwargs of an AgentProxy init method.
Netbox shadow objects used to use the pseudo attributes `read_only` and
`snmp_version` to store the SNMP v1/v2c read-only community and SNMP
version.  On the Netbox Django model, these are computed properties,
based on the Netbox' preferred SNMP management profile, and have been
deprecated for a while.

Since ipdevpoll now needs to access more complicated SNMP management
configuration for a Netbox, this changes the Netbox shadow model to
store an SNMPParameters object directly, which will be populated from
the Netbox' preferred SNMP profile.

Usages of the removed attributes have been updated.  Usages mostly
concern themselves with verifying that a device actually has an SNMP
profile at all.

However, the ipdevpoll dataloader used the value of the pseudo
attributes to detect whether a Netbox' management credentials had
changed and needed to be reloaded from the database, and this patch does
not fully replace that.

This more or less fixes Uninett#2522
Insert a `v` to make output look more like one would usually refer
to the different SNMP versions.
Ensures the snmp_parameters attribute is None if a Netbox doesn't
actually have an SNMP profile.
This is the final step to make everything work.
Version 0.1.10 contains bugfixes that are crucial for SNMPv3 support.

This also removes the upper bounds of the version number, as we control
the pynetsnmp-2 dependency anyway.
`Literal` and `dict` cannot be used as type annotations under Python
3.7.  This changes SNMPParameters to use and enforce existing Enums
for several attributes, obviating the need for using Literal
annotations, as well as using `Dict` over `dict`
An SNMPv3 conversation may start with a discovery phase, to learn the
remote SNMP entity's authoritative EngineID.  This initial pair of
"discovery" and "report" packages are handled implicitly by NET-SNMP.

However, this can result in a timeout error from the async call to get
a value, rather than a timeout error that we generate "ourselves" when
we have waited too long.  This type of error is raised by pynetsnmp
as "yet another timeout exception class", rather than one of the
existing timeout exceptions.

This adds `SnmpTimeoutError` to the list of handled timeout exceptions
where timeouts are handled explicitly, while in the mibretriever
retrieval methods it is translated to a regular TimeoutError exception.
The ipdevpoll-internal Netbox data structure needs to be udpated when
the netbox' preferred SNMP profile has changed in the database, to
ensure we can still communicate with the netbox.

This is simply done by comparing the new computed `snmp_parameters`
attribute.  But, we must also remember to actually store the new value
in the Netbox.copy() method.
@lunkwill42 lunkwill42 marked this pull request as ready for review November 17, 2023 09:19
Copy link

sonarcloud bot commented Nov 17, 2023

Kudos, SonarCloud Quality Gate passed!    Quality Gate passed

Bug A 0 Bugs
Vulnerability A 0 Vulnerabilities
Security Hotspot A 0 Security Hotspots
Code Smell A 0 Code Smells

No Coverage information No Coverage information
0.0% 0.0% Duplication

Copy link
Contributor

@hmpf hmpf left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One comment, otherwise fine. SnmpParamaters sure makes the code prettier!

@hmpf hmpf self-requested a review November 20, 2023 09:46
@lunkwill42 lunkwill42 merged commit ac3aeed into Uninett:master Nov 20, 2023
21 checks passed
@lunkwill42 lunkwill42 deleted the feature/snmpv3-ipdevpoll branch November 20, 2023 10:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Add SNMPv3 session support to the asynchronous libraries Remove remaining uses of Netbox.snmp_version
2 participants