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

LLDP-MIB - Cannot create a consistent method resolution #90

Closed
steven-douilliet opened this issue Jul 30, 2024 · 6 comments
Closed

LLDP-MIB - Cannot create a consistent method resolution #90

steven-douilliet opened this issue Jul 30, 2024 · 6 comments
Labels
area:pysmi PySMI package bug Something isn't working workaround available While this is a bug, feasible workarounds exist so users can continue their work.

Comments

@steven-douilliet
Copy link

Environment

  • Python version: 3.12
  • Package versions:
Package Version
pyasn1 0.6.0
pysnmp-lextudio 6.2.1
pysmi 1.4.4
ply 3.20.0
pycryptodomex 1.4.4

Steps to Reproduce

  1. Install all dependencies listed above.
  2. (a) Run an SNMP command (walk, get, etc) using LLDP-MIB:
snmpwalk -v2c -c public 172.16.10.100 LLDP-MIB::lldpRemTable
  1. (b) Or use this python script:
import asyncio
import json

from pysnmp.hlapi.asyncio import *


async def main():
    g = walkCmd(
        SnmpEngine(),
        CommunityData('public'),
        UdpTransportTarget(('172.16.10.100', 161)),
        ContextData(),
        ObjectType(ObjectIdentity("LLDP-MIB", "lldpRemTable")),
        lexicographicMode=False
    )
    entries = {}
    async for errorIndication, errorStatus, errorIndex, varBinds in g:
        if errorIndication:
            print(errorIndication)
        elif errorStatus:
            print(
                "{} at {}".format(
                    errorStatus.prettyPrint(),
                    errorIndex and varBinds[int(errorIndex) - 1][0] or "?",
                )
            )
        else:
            for oid, value in varBinds:
                index = (oid.asTuple()[-1])
                entry = entries.setdefault(index, {})
                entry[oid.getLabel()[-1]] = value.prettyPrint()
    print(json.dumps(entries))


asyncio.run(main())

Expected Behavior

LLDP-MIB::lldpRemTable is resolved and the table entries are returned.
For example (using linux command snmptable):

$ snmptable -v2c -c public 172.16.10.100 LLDP-MIB::lldpRemTable
SNMP table: LLDP-MIB::lldpRemTable

 lldpRemChassisIdSubtype     lldpRemChassisId lldpRemPortIdSubtype lldpRemPortId lldpRemPortDesc lldpRemSysName                                                    lldpRemSysDesc lldpRemSysCapSupported lldpRemSysCapEnabled
              macAddress "0C 5F 95 0C F7 A1 "        interfaceName   "Ethernet1" Je suis le Goat        arista2 Arista Networks EOS version 4.29.8M running on an Arista vEOS-lab               "28 00 "             "20 00 "
              macAddress "0C C0 23 EC 73 30 "        interfaceName   "Ethernet1" Je suis le Boss      localhost Arista Networks EOS version 4.29.8M running on an Arista vEOS-lab               "28 00 "             "20 00 "
              macAddress "0C 5F 95 0C F7 A1 "        interfaceName "Management1"                        arista2 Arista Networks EOS version 4.29.8M running on an Arista vEOS-lab               "28 00 "             "20 00 "
              macAddress "0C C0 23 EC 73 30 "        interfaceName "Management1"                      localhost Arista Networks EOS version 4.29.8M running on an Arista vEOS-lab               "28 00 "             "20 00 "

Observed Behavior

A load error is occured with root cause the following python error:

Traceback (most recent call last):
  File "/home/anonymous/nano-core/venv/lib/python3.12/site-packages/pysnmp/smi/builder.py", line 376, in loadModule
    exec(codeObj, g)
  File "/home/anonymous/.pysnmp/mibs/RMON2-MIB.py", line 153, in <module>
    class LastCreateTime(TextualConvention, TimeStamp):
TypeError: Cannot create a consistent method resolution
order (MRO) for bases TextualConvention, TimeStamp

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/home/anonymous/nano-core/venv/lib/python3.12/site-packages/pysnmp/smi/builder.py", line 376, in loadModule
    exec(codeObj, g)
  File "/home/anonymous/.pysnmp/mibs/LLDP-MIB.py", line 53, in <module>
    ZeroBasedCounter32) = mibBuilder.importSymbols(
                          ^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/anonymous/nano-core/venv/lib/python3.12/site-packages/pysnmp/smi/builder.py", line 464, in importSymbols
    self.loadModules(modName, **userCtx)
  File "/home/anonymous/nano-core/venv/lib/python3.12/site-packages/pysnmp/smi/builder.py", line 417, in loadModules
    self.loadModule(modName, **userCtx)
  File "/home/anonymous/nano-core/venv/lib/python3.12/site-packages/pysnmp/smi/builder.py", line 380, in loadModule
    raise error.MibLoadError(
pysnmp.smi.error.MibLoadError: MIB module '/home/anonymous/.pysnmp/mibs/RMON2-MIB/home/anonymous/.pysnmp/mibs/RMON2-MIB.py' load error: ['Traceback (most recent call last):\n', '  File "/home/anonymous/nano-core/venv/lib/python3.12/site-packages/pysnmp/smi/builder.py", line 376, in loadModule\n    exec(codeObj, g)\n', '  File "/home/anonymous/.pysnmp/mibs/RMON2-MIB.py", line 153, in <module>\n    class LastCreateTime(TextualConvention, TimeStamp):\n', 'TypeError: Cannot create a consistent method resolution\norder (MRO) for bases TextualConvention, TimeStamp\n'] caused by <class 'TypeError'>: Cannot create a consistent method resolution
order (MRO) for bases TextualConvention, TimeStamp

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/home/anonymous/nano-core/dev/apps/ssiapp/test.py", line 35, in <module>
    asyncio.run(main())
  File "/usr/lib/python3.12/asyncio/runners.py", line 194, in run
    return runner.run(main)
           ^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/asyncio/runners.py", line 118, in run
    return self._loop.run_until_complete(task)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/asyncio/base_events.py", line 687, in run_until_complete
    return future.result()
           ^^^^^^^^^^^^^^^
  File "/home/anonymous/nano-core/dev/apps/ssiapp/test.py", line 17, in main
    async for errorIndication, errorStatus, errorIndex, varBinds in g:
  File "/home/anonymous/nano-core/venv/lib/python3.12/site-packages/pysnmp/hlapi/asyncio/cmdgen.py", line 728, in walkCmd
    initialVars = [x[0] for x in vbProcessor.makeVarBinds(snmpEngine, varBinds)]
                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/anonymous/nano-core/venv/lib/python3.12/site-packages/pysnmp/hlapi/asyncio/varbinds.py", line 41, in makeVarBinds
    varBind.resolveWithMib(mibViewController, ignoreErrors=False)
  File "/home/anonymous/nano-core/venv/lib/python3.12/site-packages/pysnmp/smi/rfc1902.py", line 937, in resolveWithMib
    self.__args[0].resolveWithMib(mibViewController)
  File "/home/anonymous/nano-core/venv/lib/python3.12/site-packages/pysnmp/smi/rfc1902.py", line 506, in resolveWithMib
    (mibNode,) = mibViewController.mibBuilder.importSymbols(
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/anonymous/nano-core/venv/lib/python3.12/site-packages/pysnmp/smi/builder.py", line 464, in importSymbols
    self.loadModules(modName, **userCtx)
  File "/home/anonymous/nano-core/venv/lib/python3.12/site-packages/pysnmp/smi/builder.py", line 417, in loadModules
    self.loadModule(modName, **userCtx)
  File "/home/anonymous/nano-core/venv/lib/python3.12/site-packages/pysnmp/smi/builder.py", line 380, in loadModule
    raise error.MibLoadError(
pysnmp.smi.error.MibLoadError: MIB module '/home/anonymous/.pysnmp/mibs/LLDP-MIB/home/anonymous/.pysnmp/mibs/LLDP-MIB.py' load error: ['Traceback (most recent call last):\n', '  File "/home/anonymous/nano-core/venv/lib/python3.12/site-packages/pysnmp/smi/builder.py", line 376, in loadModule\n    exec(codeObj, g)\n', '  File "/home/anonymous/.pysnmp/mibs/RMON2-MIB.py", line 153, in <module>\n    class LastCreateTime(TextualConvention, TimeStamp):\n', 'TypeError: Cannot create a consistent method resolution\norder (MRO) for bases TextualConvention, TimeStamp\n', '\nDuring handling of the above exception, another exception occurred:\n\n', 'Traceback (most recent call last):\n', '  File "/home/anonymous/nano-core/venv/lib/python3.12/site-packages/pysnmp/smi/builder.py", line 376, in loadModule\n    exec(codeObj, g)\n', '  File "/home/anonymous/.pysnmp/mibs/LLDP-MIB.py", line 53, in <module>\n    ZeroBasedCounter32) = mibBuilder.importSymbols(\n                          ^^^^^^^^^^^^^^^^^^^^^^^^^\n', '  File "/home/anonymous/nano-core/venv/lib/python3.12/site-packages/pysnmp/smi/builder.py", line 464, in importSymbols\n    self.loadModules(modName, **userCtx)\n', '  File "/home/anonymous/nano-core/venv/lib/python3.12/site-packages/pysnmp/smi/builder.py", line 417, in loadModules\n    self.loadModule(modName, **userCtx)\n', '  File "/home/anonymous/nano-core/venv/lib/python3.12/site-packages/pysnmp/smi/builder.py", line 380, in loadModule\n    raise error.MibLoadError(\n', 'pysnmp.smi.error.MibLoadError: MIB module \'/home/anonymous/.pysnmp/mibs/RMON2-MIB/home/anonymous/.pysnmp/mibs/RMON2-MIB.py\' load error: [\'Traceback (most recent call last):\\n\', \'  File "/home/anonymous/nano-core/venv/lib/python3.12/site-packages/pysnmp/smi/builder.py", line 376, in loadModule\\n    exec(codeObj, g)\\n\', \'  File "/home/anonymous/.pysnmp/mibs/RMON2-MIB.py", line 153, in <module>\\n    class LastCreateTime(TextualConvention, TimeStamp):\\n\', \'TypeError: Cannot create a consistent method resolution\\norder (MRO) for bases TextualConvention, TimeStamp\\n\'] caused by <class \'TypeError\'>: Cannot create a consistent method resolution\norder (MRO) for bases TextualConvention, TimeStamp\n'] caused by <class 'pysnmp.smi.error.MibLoadError'>: MIB module '/home/anonymous/.pysnmp/mibs/RMON2-MIB/home/anonymous/.pysnmp/mibs/RMON2-MIB.py' load error: ['Traceback (most recent call last):\n', '  File "/home/anonymous/nano-core/venv/lib/python3.12/site-packages/pysnmp/smi/builder.py", line 376, in loadModule\n    exec(codeObj, g)\n', '  File "/home/anonymous/.pysnmp/mibs/RMON2-MIB.py", line 153, in <module>\n    class LastCreateTime(TextualConvention, TimeStamp):\n', 'TypeError: Cannot create a consistent method resolution\norder (MRO) for bases TextualConvention, TimeStamp\n'] caused by <class 'TypeError'>: Cannot create a consistent method resolution
order (MRO) for bases TextualConvention, TimeStamp

The root cause is the TypeError: Cannot create a consistent method resolution, which indicates an inheritance issue.

Please note that when using another MIB, such as IF-MIB::ifTable, the resolution works correctly and no errors occur.

@steven-douilliet steven-douilliet changed the title SNMP translation - Cannot create a consistent method resolution LLDP-MIB - Cannot create a consistent method resolution Jul 30, 2024
@lextm lextm added area:pysmi PySMI package bug Something isn't working up for grabs Pull requests are welcome priority:low Low priority items. labels Jul 30, 2024
@lextm
Copy link

lextm commented Jul 30, 2024

Similar to #91, this is a bug in PySMI where it should further analyze the generated types and avoid duplicate inheritance.

While the bugfix won't come soon, the manual workaround is also simple,

  1. Open up RMON2-MIB.py in a text editor.
  2. Change class LastCreateTime(TextualConvention, TimeStamp) to class LastCreateTime(TimeStamp).

BTW, please switch from pysnmp-lextudio to pysnmp, as we won't update the former any more.

@lextm lextm added the workaround available While this is a bug, feasible workarounds exist so users can continue their work. label Aug 2, 2024
@lextm
Copy link

lextm commented Aug 16, 2024

Close it now as won't work on it in near future.

@lextm lextm closed this as completed Aug 16, 2024
@mmakaay
Copy link

mmakaay commented Aug 19, 2024

We ran into this issue too, with the MIB compilation step in our application after switching to Python 3.12.

Manually fixing the .py file was no full work-around, because we generate the .py files on application startup in our Docker container, based on a plugin system (where each plugin can provide extra MIBs when required). Therefore, I automated the process of fixing the code, by leveraging the Python ast package.

As possible inspiration for others that run into the same issue, here the gist of the method in our compiler that takes care of fixing the generate pysnmp MIB files that are stored in the output_path directory. When there are more patterns to fix, these can be added quickly to this skeleton.

import ast
from pathlib import Path


class VisitorThatFixesMroIssue(ast.NodeTransformer):
    def __init__(self) -> None:
        super().__init__()
        self.did_fix_code = False

        def visit_ClassDef(self, node: ast.ClassDef) -> ast.AST:
            base_names = [base.id for base in node.bases if isinstance(base, ast.Name)]
            if base_names == ['TextualConvention', 'DisplayString']:
                node.bases = [node.bases[1]]
                self.did_fix_code = True
            return self.generic_visit(node)
    
    
def fix_mib_py_file(file_path: Path) -> None:
      tree = ast.parse(source=file_path.read_text())
      visitor = VisitorThatFixesMroIssue()
      visitor.visit(tree)
      if visitor.did_fix_code:
          file_path.write_text(ast.unparse(tree))

Just an idea

A quick fix for the pysmi code, might be to apply the above change right from the code generating template at https://github.com/lextudio/pysmi/blob/main/pysmi/codegen/templates/pysnmp/mib-definitions.j2#L219
The generating template code could could be something like this:

{%if definition['type']['type'] == 'DisplayString' %}
class {{ symbol }}({{ definition['type']['type'] }}):
{% else %}
class {{ symbol }}(TextualConvention, {{ definition['type']['type'] }}):
{% endif %}

@lextm
Copy link

lextm commented Sep 2, 2024

Should have been fixed in PySMI release 1.5.

@mmakaay
Copy link

mmakaay commented Sep 5, 2024

Yes, I can confirm that it works for the issues that I ran into.
Upgrading to 1.5.0 fully vanished them. Thanks!

@steven-douilliet
Copy link
Author

Hello,
That it works!
Thanks

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area:pysmi PySMI package bug Something isn't working workaround available While this is a bug, feasible workarounds exist so users can continue their work.
Projects
None yet
Development

No branches or pull requests

3 participants