Archived community.zenoss.org | full text search
Skip navigation
Currently Being Moderated

12.4 Create a Modeler

VERSION 1 
Created on: Oct 28, 2010 1:58 PM by Zenoss API - Last Modified:  Oct 28, 2010 1:58 PM by Zenoss API

 4. Create a Modeler

When you navigate to a particular host, select Modeler Plugins from the left panel, and then select Model Device from the Action menu, the system runs all of the associated modelers. 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 do not see output like that 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 monitoring 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 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. With the newly created AIX device class selected, click Details, and then select Modeler Plugins. Add the appropriate plugin from the list, and then click Save.

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 are satisfied that everything is working correctly, verify everything by modeling the device and then navigating to the device overview page. If everything is correct, you'll see your list of file systems, 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 (such as once a day or once a week, depending on your settings), while a performance data collector is run every five or ten minutes.

Comments (0)