From 068a4d6391b81875bc9e6ae9717e46b0d2ceedb1 Mon Sep 17 00:00:00 2001
From: thijs snijder <snijder@astron.nl>
Date: Thu, 31 Mar 2022 16:58:16 +0200
Subject: [PATCH] started on adding support for MIB compilation

---
 .../clients/snmp_client.py                    | 24 ++++++--
 .../devices/snmp_device.py                    | 56 ++++++-------------
 .../test/devices/SNMP_mib_loading/__init__.py |  0
 .../SNMP_mib_loading/test_mib_loading.py      |  0
 4 files changed, 35 insertions(+), 45 deletions(-)
 create mode 100644 tangostationcontrol/tangostationcontrol/test/devices/SNMP_mib_loading/__init__.py
 create mode 100644 tangostationcontrol/tangostationcontrol/test/devices/SNMP_mib_loading/test_mib_loading.py

diff --git a/tangostationcontrol/tangostationcontrol/clients/snmp_client.py b/tangostationcontrol/tangostationcontrol/clients/snmp_client.py
index 551f46626..d57e8eb25 100644
--- a/tangostationcontrol/tangostationcontrol/clients/snmp_client.py
+++ b/tangostationcontrol/tangostationcontrol/clients/snmp_client.py
@@ -108,12 +108,6 @@ class SNMP_client(CommClient):
 
         return read_function, write_function
 
-    @staticmethod
-    def load_mib(mib_name):
-        mibBuilder = builder.MibBuilder()
-        mibBuilder.loadModule(mib_name)
-
-
 class snmp_attribute:
 
     def __init__(self, client : SNMP_client, mib, name, idx, dtype, dim_x, dim_y):
@@ -237,3 +231,21 @@ class snmp_attribute:
             vals = vals[0]
 
         return vals
+
+class mib_loader:
+
+    def __init__(self):
+        self.mibBuilder = builder.MibBuilder()
+
+    def set_pymib_dir(self, mib_dir):
+        mib_source = builder.DirMibSource(mib_dir)
+        self.mibBuilder.addMibSources(mib_source)
+
+    def load_pymib(self, mib_name):
+        self.mibBuilder.loadModule(mib_name)
+
+    def compile_mibs(self, path):
+        from pysnmp.smi import compiler
+        compiler.addMibCompiler(self.mibBuilder, sources=[path, ])
+
+
diff --git a/tangostationcontrol/tangostationcontrol/devices/snmp_device.py b/tangostationcontrol/tangostationcontrol/devices/snmp_device.py
index 9905eec3c..323fab8c8 100644
--- a/tangostationcontrol/tangostationcontrol/devices/snmp_device.py
+++ b/tangostationcontrol/tangostationcontrol/devices/snmp_device.py
@@ -17,7 +17,7 @@ from tango.server import device_property
 from tango import AttrWriteType
 
 # Additional import
-from tangostationcontrol.clients.snmp_client import SNMP_client
+from tangostationcontrol.clients.snmp_client import SNMP_client, mib_loader
 from tangostationcontrol.clients.attribute_wrapper import attribute_wrapper
 from tangostationcontrol.devices.lofar_device import lofar_device
 
@@ -71,43 +71,15 @@ class SNMP(lofar_device):
     # Attributes
     # ----------
 
+    # example attributes. mib and name mandatory and index optional.
+    # will return a
 
-    # octetstring
-    sysDescr_R = attribute_wrapper(comms_annotation={"mib": "SNMPv2-MIB", "name": "sysDescr"}, datatype=numpy.str)
-    sysName_R = attribute_wrapper(comms_annotation={"mib": "SNMPv2-MIB", "name": "sysName"}, datatype=numpy.str)
-
-    # get a table element with the oid
-    ifDescr31_R = attribute_wrapper(comms_annotation={"oids": "1.3.6.1.2.1.2.2.1.2.31"}, datatype=numpy.str)
-
-    # get 10 table elements with the oid and dimension
-    ifDescr_R = attribute_wrapper(comms_annotation={"oids": "1.3.6.1.2.1.2.2.1.2"}, dims=(10,), datatype=numpy.str)
-
-    #timeticks
-    sysUpTime_R = attribute_wrapper(comms_annotation={"mib": "SNMPv2-MIB", "name": "sysUpTime"}, datatype=numpy.int64)
-
-    # OID
-    sysObjectID_R = attribute_wrapper(comms_annotation={"mib": "SNMPv2-MIB", "name": "sysObjectID"}, datatype=numpy.int64)
-
-    # integer
-    sysServices_R = attribute_wrapper(comms_annotation={"mib": "SNMPv2-MIB", "name": "sysServices"}, datatype=numpy.int64)
-    tcpRtoAlgorithm_R = attribute_wrapper(comms_annotation={"mib": "SNMPv2-MIB", "name": "tcpRtoAlgorithm"}, datatype=numpy.int64)
-    snmpEnableAuthenTraps_R = attribute_wrapper(comms_annotation={"mib": "SNMPv2-MIB", "name": "snmpEnableAuthenTraps"}, datatype=numpy.int64)
-
-    #gauge
-    tcpCurrEstab_R = attribute_wrapper(comms_annotation={"mib": "RFC1213-MIB", "name": "tcpCurrEstab"}, datatype=numpy.int64)
-
-    #counter32
-    tcpActiveOpens_R = attribute_wrapper(comms_annotation={"mib": "RFC1213-MIB", "name": "tcpActiveOpens"}, datatype=numpy.int64)
-    snmpInPkts_R = attribute_wrapper(comms_annotation={"mib": "SNMPv2-MIB", "name": "snmpInPkts"}, datatype=numpy.int64)
-
-    #IP address
-    ipAdEntAddr_R = attribute_wrapper(comms_annotation={"mib": "RFC1213-MIB", "name": "ipAdEntAddr", "index": (127,0,0,1)}, datatype=numpy.str)
-    ipAdEntIfIndex_R = attribute_wrapper(comms_annotation={"mib": "RFC1213-MIB", "name": "ipAdEntIfIndex", "index": (10, 87, 6, 14)}, datatype=numpy.str)
-
-    #str RW attribute
-    sysContact_obj_R = attribute_wrapper(comms_annotation={"mib": "SNMPv2-MIB", "name": "sysContact"}, datatype=numpy.str)
-    sysContact_obj_RW = attribute_wrapper(comms_annotation={"mib": "SNMPv2-MIB", "name": "sysContact"}, datatype=numpy.str, access=AttrWriteType.READ_WRITE)
-
+    # Reads from a table and returns an array of table entries 1 to 10 (note, tables require an index key and start at 1)
+    test_attr1_R = attribute_wrapper(comms_annotation={"mib": "test-MIB", "name": "test_attr1", "index": 1}, dims=(10,), datatype=numpy.str)
+    # indices can also be IP addresses sometimes. Gets a single scalar value
+    test_attr2_R = attribute_wrapper(comms_annotation={"mib": "test-MIB", "name": "test_attr2", "index": (127,0,0,1)}, datatype=numpy.int64)
+    # if the attribute doesn't get the value from a table, then no index is needed, or the default of 0 can be supplied.
+    test_attr3_R = attribute_wrapper(comms_annotation={"mib": "test-MIB", "name": "test_attr3"}, datatype=numpy.int64)
 
 
     # --------
@@ -133,10 +105,16 @@ class SNMP(lofar_device):
     def init_device(self):
         super().init_device()
 
-        # speeds up loading
+        # create the mib_loader
+        loader = mib_loader()
+
+        # set the directory with the compiled mib files.
+        loader.set_pymib_dir(self.SNMP_mib_dir)
+
         for i in self.attr_list():
             try:
-                SNMP_client.load_mib(i.comms_annotation["mib"])
+                # for all of the attributes attempt to load the pre-compiled MIB. Skips already loaded ones
+                loader.load_pymib(i.comms_annotation["mib"])
             except Exception as e:
                 raise Exception(f"Failed to load MIB file: {i.comms_annotation.get('mib')} for attribute {i.get_name()}") from e
 
diff --git a/tangostationcontrol/tangostationcontrol/test/devices/SNMP_mib_loading/__init__.py b/tangostationcontrol/tangostationcontrol/test/devices/SNMP_mib_loading/__init__.py
new file mode 100644
index 000000000..e69de29bb
diff --git a/tangostationcontrol/tangostationcontrol/test/devices/SNMP_mib_loading/test_mib_loading.py b/tangostationcontrol/tangostationcontrol/test/devices/SNMP_mib_loading/test_mib_loading.py
new file mode 100644
index 000000000..e69de29bb
-- 
GitLab