Developer's Guide

  • Docs Home
  • Community Home

4. Create a Modeler

When you navigate to a particular host and from the page menu select ManageModel Device, which runs all of the associated modelers (which, confusingly enough, are set for a device through the MoreCollector Plugins menu item). What we need to do is copy and customize an existing modeler plugin from $ZENHOME/Products/DataCollector/plugins/zenoss/snmp and then add that plugin to our list of plugins that our platform's device class will use.

We'll start with creating a Filesystem modeler plugin. We'll copy the HRFileSystemMap plugin and call our plugin AIXFileSystemMap.py. Using the information in the MIB, we can find the place where it stores the list of file systems.

Table 12.1. Modeler Functions

NameRequired?Description
condition()NReturns True or False to indicate whether or not to run the other functions
preprocess()NThis will get called before the process() function
process()YThis is the actual function that processes any information retrieved from a query and converts it into a format suitable for updating the device model.

4.1. Verify the SNMP connectivity and OIDs

First, verify that your server's SNMP daemon is functional and that you have the correct SNMP version and credentials. We'll assume that we're using SNMP version 1 and are using the public community, and that your new host will allow connections from our Zenoss server.

Run the snmpwalk command from the Zenoss monitoring server:

snmpwalk -v1 -c public myaixbox.example.com 1.3.6.1.4.1.2.6.191.1 | head

This produces a lot of output that we've truncated to save patience and space.

SNMPv2-SMI::enterprises.2.6.191.1.1.1.0 = INTEGER: 5
SNMPv2-SMI::enterprises.2.6.191.1.1.2.0 = ""
SNMPv2-SMI::enterprises.2.6.191.1.1.3.0 = INTEGER: 2
SNMPv2-SMI::enterprises.2.6.191.1.1.4.0 = Gauge32: 0
SNMPv2-SMI::enterprises.2.6.191.1.1.5.0 = INTEGER: 0
SNMPv2-SMI::enterprises.2.6.191.1.1.6.0 = INTEGER: 2
SNMPv2-SMI::enterprises.2.6.191.1.1.7.0 = STRING:
"The current used percentage 93 of the file system /mnt  has gon"
SNMPv2-SMI::enterprises.2.6.191.1.1.9.0 = INTEGER: 0
SNMPv2-SMI::enterprises.2.6.191.1.1.10.0 = INTEGER: 0
SNMPv2-SMI::enterprises.2.6.191.1.1.11.0 = INTEGER: 0

If you don't see output like the above, nothing else will work. Find the issue and fix it.

The Zenoss community Web site has a ZenPack with a graphical MIB browser that might help for these steps.

4.2. Common SNMP Issues

Following is a list of some common reasons why snmpwalk may not return any data:

  • SNMP daemon on the remote system is not running.

  • SNMP daemon on the remote system has different security credentials than what you are using (for example, version 1 instead of version 2c, wrong community name).

  • SNMP daemon on the remote system allows connections only from certain IP addresses or IP address ranges, and the Zenoss server does not meet that criteria.

  • SNMP daemon on the remote allows queries only to certain portions of certain MIBs, and you have specified something not allowed by that policy.

  • Firewall or firewalls between the Zenoss server and the remote system to not allow UDP or SNMP traffic.

  • Firewall on the Zenoss server does not allow UDP or SNMP traffic outbound or inbound.

  • Firewall on the remote system does not allow UDP or SNMP traffic outbound or inbound.

As a first sanity check, try the snmpwalk command on the remote host. For example:

snmpwalk -v1 -c public localhost 1.3.6.1.4.1.2.6.191.1 | head

4.3. Modeler Code

Multiple modelers for different components of a system can be created, or one huge modeler for everything can be created. Smaller modelers are preferred for maintenance reasons. The following modeler is for the file systems, and would live in the modeler/plugins/ directory of your ZenPack.

Python requires that __init__.py files be in both the modeler/ and the modeler/plugins/ directories. If they are missing your modeler will not load.

__doc__ = """AIXFileSystemMap

This modeler determines the filesystems on the device and updates
appropriately.  It is up to the performance template that must be
named 'Filesystems' to collect the actual performance data
(eg free/available blocks).
"""

import re

from Products.ZenUtils.Utils import unsigned
from Products.DataCollector.plugins.CollectorPlugin import SnmpPlugin, \
      GetTableMap
from Products.DataCollector.plugins.DataMaps import ObjectMap

class AIXFileSystemMap(SnmpPlugin):

    maptype = "FileSystemMap"
    compname = "os"
    relname = "filesystems"
    modname = "Products.ZenModel.FileSystem"
    deviceProperties =  \
      SnmpPlugin.deviceProperties + ('zFileSystemMapIgnoreNames',)

    #
    # These column names are for the aixFsTable from the
    #  /usr/samples/snmpd/aixmib.my MIB file located on your AIX hosts.
    # (It's in the bos.net.tcp.adt fileset.)
    #
    columns = {
         '.1': 'snmpindex', # aixFsIndex
         '.2': 'storageDevice', # aixFsName
         '.3': 'mount', # aixFsMountPoint
         '.4': 'type', # aixFsType
         '.5': 'totalBlocks', # aixFsSize - a value in MB

#
# Comment out the following entries to reduce the amount
# of stuff that we need to send.  They are listed here
# for reference and completeness.
#
#         '.6': 'aixFsFree',
#         '.7': 'aixFsNumINodes',
#         '.8': 'aixFsUsedInodes',
#         '.9': 'aixFsStatus',
#         '.10': 'aixFsExecution',
#         '.11': 'aixFsResultMsg',
         }

    snmpGetTableMaps = (
        GetTableMap('aixFsTable', '.1.3.6.1.4.1.2.6.191.6.2.1', columns),
    )

    #
    # This table is included for reference
    #
    aixFsType = {
         1: 'jfs',
         2: 'jfs2',
         3: 'cdrfs',
         4: 'procfs',
         5: 'cachefs',
         6: 'autofs',
         7: 'afs',
         8: 'dfs',
         9: 'nfs',
         10: 'nfs3',
         11: 'other',
    }

    def process(self, device, results, log):
        """Gather data from the standard AIX snmpd + friends"""

        log.info('processing %s for device %s', self.name(), device.id)
        getdata, tabledata = results

        #
        # Gather the data using SNMP and just exit if there's an SNMP
        # issue.  If we don't, the filesystem table in Zenoss will get
        # wiped out.  Ouch!
        #
        fstable = tabledata.get( "aixFsTable" )
        if not fstable:
            log.warn('No SNMP response from %s for the %s plugin',
                      device.id, self.name() )
            log.warn( "Data= %s", getdata )
            log.warn( "Columns= %s", self.columns )
            return

        skipfsnames = getattr(device, 'zFileSystemMapIgnoreNames', None)
        maps = []
        rm = self.relMap()
        for fs in fstable.values():
            if not fs.has_key("totalBlocks"):
               continue # Ignore blank entries

            if not self.checkColumns(fs, self.columns, log):
               log.warn( "Data= %s", getdata )
               log.warn( "Columns= %s", self.columns )
               continue

            log.debug( "Found %s", fs['mount'] )
            #
            # Ensure that we only check on local disk
            # NB: it may make sense to report on AFS/DFS volumes....
            #
            fstype = self.aixFsType.get( fs['type'], None)
            if fstype not in ( 'jfs', 'jfs2' ):
               continue

            if fs['totalBlocks'] > 0 and (not skipfsnames or \
               not re.search(skipfsnames,fs['mount'])):
                om = self.objectMap(fs)

                #
                # The internal id that Zenoss uses can be used in URLs,
                # while Unix filesystem names cannot.
                # Map to an URL-safe name.
                #
                om.id = self.prepId(om.mount)

                #
                # Map our MIB data to what Zenoss expects
                #
                om.blockSize = 1024**2; # ie MB

                rm.append(om)
        maps.append(rm)

        #
        # As a final sanity check, see if we found anything.  If we
        # didn't find anything, that's probably an error so just return.
        #
        if len(maps) == 0:
           log.warn( "No filesystems found by %s for %s",
                     self.name(), device.id)
           return

        return maps

Note

Because this question occurs so often in the mailing lists, the following information bears repeating. The function name required of any modeler is the process() function.

4.4. Testing the Modeler

To test your new modeler plugin, add it to the list of modeler plugins. From within the newly-created AIX device class, select More > Collector Plugins to select the appropriate plugin, which should be in the list of items to add.

You can test your new plugin by using zenmodeler from the command line:

zenmodeler run -d myaixbox.example.com -v 10

For testing purposes, you may want to add this and only this modeler plugin to one particular host and make it the only plugin. Any syntax errors or exceptions will be visible so that you can hopefully debug them.

Once you're satisfied that everything is working correctly, verify everything by running the Manage > Model Device command and then examining the OS tab. If everything is correct, you'll see your list of file systems in the Filesystem area, but with unknown for everything except the total size of the file systems. The actual usage numbers of the file system is collected by a different mechanism -- a performance data collector.

Keep in mind that a modeler is run infrequently (eg once a day or once a week, depending on your settings), while a performance data collector is run every five or ten minutes.