This section will cover creation of a custom Component subclass,
creation of a relationship to our NetBotDevice class, and modeling of
the components to fill the relationship.
In Device modeling, we added
a temp_sensor_count attribute to our NetBotz devices. This isn’t very
useful. It would be more useful to monitor the temperature being
reported by each of these sensors. So that’s what we’ll do. Modeling
each sensor as a component allows Zenoss to automatically discover and
monitor sensors regardless of how many a particular device has.
Find temperature sensor attributes
In Device modeling, we used smidump to extract
temperature sensor information from NETBOTZV2-MIB. This will be even
more applicable as we decide what attributes and metrics are available
on each sensor. Let’s use smidump and snmpwalk for a refresher on
what’s available.
Find temperature information in NETBOTZV2-MIB using the following command.
Note the 21604919 in the first response. This is the SNMP index of the
first temperature sensor, or the first row in the table. I like to then
restrict my snmpwalk results to only show this row with a command like
the following.
Now we have everything we should need to make decisions about what
attributes we should model for our sensors and which would better be
collected as datasources to have thresholds applied and plotted over
time on graphs.
My initial thoughts would be to model the following as attributes.
tempSensorId
tempSensorEncId (enclosure ID)
tempSensorPortId
I would then want to collect tempSensorValueStr as a datasource
because it offers the best precision. Zenoss is capable of handling
numeric strings so we don’t have to collect tempSensorValue and divide
it by 10 like other systems might.
Create a component subclass
Use the following steps to create a NetBotzTemperatureSensor class
with the attributes discovered above.
Update zenpack.yaml to include the
following NetBotzTemperatureSensor entry in the classes section,
and the new class_relationships section.
It’s important to pick unique class names. The best
practice is to use a short prefix based on the ZenPack’s name
followed by the type of thing the class represents as is being
done here.
Both of the new properties should be strings. Since string is
the default type, we don’t need to specify it. This just leaves
the label.
Despite noting above that we always wanted to model
the tempSensorId attribute, we aren’t adding an attribute for
it here. This is because Component already has both an id
and title attribute that wherein we can store the value
of tempSensorId.
The class_relationships section is very important. We could
never have any temperature sensors in the system if we didn’t
relate them to something else. The 1:MC between the two class
names describes the type of relationship. Specifically it says
that one NetBotzDevice can contain many NetBotzTemperatureSensor
objects. For more information, see
Relationships.
Test TemperatureSensor class
With our component class defined and relationships setup we can
use zendmd to make sure we didn’t make any mistakes. Execute the
following snippet in zendmd.
This error is indicating that we have
no netBotzTemperatureSensors relationship on the device object. This
would seemingly make no sense because we just added it. The key here is
that existing objects like the Netbotz01 device don’t automatically
get new relationships. We have to either delete the device and add it
again, or execute the following in zendmd to create the newly-defined
relationship.
device.buildRelations()commit()
Now you can go back and run the original snippet again. You should see
the name of the sensor and device objects printed if everything worked
as planned.
Update the modeler plugin
As with the NetBotzDevice class, the next step after creating our
model class is to populate it with a modeler plugin. We could create a
new modeler plugin to only capture the temperature sensor components,
but we’ll update the NetBotz modeler plugin we previously created to
model the sensors instead.
Edit $ZP_DIR/modeler/plugins/training/snmp/NetBotz.py and replace
its contents with the following.
fromProducts.DataCollector.plugins.CollectorPluginimport(SnmpPlugin,GetTableMap,)classNetBotz(SnmpPlugin):relname='netBotzTemperatureSensors'modname='ZenPacks.training.NetBotz.NetBotzTemperatureSensor'snmpGetTableMaps=(GetTableMap('tempSensorTable','1.3.6.1.4.1.5528.100.4.1.1.1',{'.1':'tempSensorId','.5':'tempSensorEncId','.6':'tempSensorPortId',}),)defprocess(self,device,results,log):temp_sensors=results[1].get('tempSensorTable',{})rm=self.relMap()forsnmpindex,rowintemp_sensors.items():name=row.get('tempSensorId')ifnotname:log.warn('Skipping temperature sensor with no name')continuerm.append(self.objectMap({'id':self.prepId(name),'title':name,'snmpindex':snmpindex.strip('.'),'enclosure':row.get('tempSensorEncId'),'port':row.get('tempSensorPortId'),}))returnrm
Let’s take a closer look at how we changed the modeler plugin.
We added relname and modname as class attributes.
These two settings control the meta-data that will automatically
be set when the self.relMap and self.objectMap methods are
called in the process method.
The target relname we should use depends on a couple of
things. First, all leading uppercase letters of the class name
will be converted to lowercase;
that is, NetBotzTemperatureSensor becomes netBotzTemperatureSensor.
Second, the letter s is added to the end if it is a to-many
relationship; that is, netBotzTemperatureSensor becomes
netBotzTemperatureSensors.
Setting relname to netBotzTemperatureSensors will cause
the self.relMap call to create a RelationshipMap that will
be applied to the netBotzTemperatureSensors relationship
defined on the NetBotzDevice object.
Setting modname to ZenPacks.training.NetBotz.TemperatureSensor will
cause the self.objectMap calls in the process method to
create ObjectMap instances that will be turned into instances
of our TemperatureSensor class.
We’re now requesting
the tempSensorEncId and tempSensorPortId columns be returned
in the SNMP table request results. We’ll use these to populate
their corresponding fields on the TemperatureSensor class.
Most of the procses method has been changed.
We’re now creating a RelationshipMap and appending
an ObjectMap to it for each temperature sensor in the results.
We use the self.relMap and self.objectMap utility methods to
make this easier.
Restart Zope and zenhub to load the changed module.
We already added the training.snmp.NetBotz modeler plugin the
the /NetBotz device class in an earlier exercise. So we only need to
run zenmodeler to test the temperature sensor modeling updates.
Run zenmodeler run --device=Netbotz01
We should see Changes in configuration applied near the end of
zenmodeler’s output. The changes referred to should be 14
temperature sensor objects being created and added to the device’s
netBotzTemperatureSensors relationship.
Check the Netbotz01 device in the web interface. The temperature
sensors should now be visible.