Ad Widget

Collapse

Enhanced SNMP Low Level Discovery

Collapse
X
 
  • Time
  • Show
Clear All
new posts
  • koopmant
    Junior Member
    • Jun 2014
    • 4

    #1

    Enhanced SNMP Low Level Discovery

    Hey,

    Wanted to share this script I wrote to enhance the LLD for SNMP. Read comments in script for how to use it and examples. Script will need to be placed in your Zabbix ExternalScripts directory and made executable. Only addition PHP module I had to install on my Zabbix server was php-snmp.

    PHP Code:
    #!/usr/bin/php
    <?PHP
    /* Version 2.1
     * Author: Tim Koopman
     *
     * For doing SNMP Low Level Discoveries in ZABBIX
     * Inbuilt only allows filter macros on SNMPINDEX and SNMPVALUE
     * While you can change what SNMPVALUE would represent by changing the OID
     * you sometimes what more values, one for filtering and one for item prototype names.
     *
     * This script allows you to add as many other values as you like
     * I use with the following to allow me to filter for interfaces that Admin Status is Up
     * while still having the interface name on each of the items names.
     *
     * Edit discovery rule "Network Interfaces" on template "Template SNMP Interfaces"
     * Type: External check
     * Key: SNMPDiscovery.php["-h", {HOST.CONN}, "-c", {$SNMP_COMMUNITY}, "--index", "IF-MIB::ifDescr", "--value", "IF-MIB::ifAdminStatus,ifAdminStatus"]
     * Filter:
     *    Macro: {#ifAdminStatus}
     *    Regexp: 1
     *
     * When used without the --value option the result would be identical to the inbuilt SNMP LLD.
     * This means all existing item prototypes will continue to work as is.
     * Can add as many --value options as you need.
     *
     * v2.0 added --filter as I wanted to seperate SNMP storage devices between memory and disks but Zabbix
     * won't allow you to have the same key with just different filters. So doing it this way
     * means the keys will be different and you can leave the Zabbix filter options blank
     *
     * Usage
     * SNMPDiscovery.php -h <host> -c <community> --index <OID> [--value <OID>,<MACRONAME>]... [--filter <OID>,<REGEX>]...
     *   -h        : SNMP Host to query. When used in Zabbix this would normally be {HOST.CONN}
     *   -c        : SNMP Community. When used in Zabbix this would normally be {$SNMP_COMMUNITY}
     *   --index   : OID to walk. Is used to populate {#SNMPINDEX} and {#SNMPVALUE} macros.
     *   --value   : Comma seperated OID and macro name to also return. Can reference in zabbix using macro {#<MACRONAME>}
     *               You can use --value multiple times if you need more macros returned.
     *   --filter  : Comma seperated OID and regular expression. Any index that does not matches the regex will be excluded from the results.
     *               You can use --filter multiple times if you need.
     *
     * Returns JSON text which Zabbix LLD uses.
     *
     * Examples
     *   SNMPDiscovery.php -h 127.0.0.1 -c public --index IF-MIB::ifDescr --value IF-MIB::ifAdminStatus,ifAdminStatus
     *   SNMPDiscovery.php -h 127.0.0.1 -c public --index HOST-RESOURCES-MIB::hrStorageDescr --filter HOST-RESOURCES-MIB::hrStorageType,hrStorageFixedDisk$
     *   SNMPDiscovery.php -h 127.0.0.1 -c public --index HOST-RESOURCES-MIB::hrStorageDescr --filter 'HOST-RESOURCES-MIB::hrStorageType,(hrStorageRam|hrStorageVirtualMemory)$'
    */
    error_reporting(E_ALLE_WARNING);

    function 
    SNMPData($data)
    {
        if (
    strPos($data"STRING: ")===0)
        {
            
    preg_match_all('!^STRING: \"?(.*?)\"?$!'$data$matches);
            return 
    $matches[1][0];
        } elseif (
    strPos($data"INTEGER: ")===0) {
            
    preg_match_all('!\d+!'$data$matches);
            return (int) 
    $matches[0][0];
        } else {
            return 
    $data;
        }
    }

    $options getopt("c:h:",array("index:","value:","filter:"));
    if (
    count($options) == 0)
    {
        print 
    "Usage: SNMPDiscovery.php -h <host> -c <community> --index <OID> [--value <OID>,<MACRONAME>]... [--filter <OID>,<REGEX>]...\n";
        exit(
    1);
    }

    $values = Array();
    if (
    array_key_exists("value"$options))
    {
        if (
    is_array($options["value"]))
        {
            foreach(
    $options["value"] as $value)
            {
                
    $explode explode(","$value);
                
    $values[$explode[0]] = $explode[1];
            }
        } else {
            
    $explode explode(","$options["value"]);
            
    $values[$explode[0]] = $explode[1];
        }
    }

    $filters = Array();
    $defaultFilter false;
    if (
    array_key_exists("filter"$options))
    {
        if (
    is_array($options["filter"]))
        {
            foreach(
    $options["filter"] as $value)
            {
                
    $explode explode(","$value);
                
    $filters[$explode[0]] = $explode[1];
            }
        } else {
            
    $explode explode(","$options["filter"]);
            
    $filters[$explode[0]] = $explode[1];
        }
    } else {
        
    $defaultFilter true;
    }

    $data = Array();

    $keys snmprealwalk($options["h"], $options["c"] , $options["index"], 10000 5);
    foreach(
    $keys as $key => $value)
    {
        
    $key substr($keystrlen($options["index"])+1);
        
    $value SNMPData($value);
        
    $dataItem = Array();
        
    $dataItem["{#SNMPINDEX}"] = $key;
        
    $dataItem["{#SNMPVALUE}"] = $value;
        
        
    $filtered $defaultFilter;
        foreach(
    $filters as $oid => $regex)
        {
            
    $oidvalue snmpget($options["h"], $options["c"], "{$oid}.{$key}"100005);
            
    $oidvalue SNMPData($oidvalue);
            if (
    preg_match("/".$regex."/"$oidvalue)) $filtered true;
        }
        
        if (
    $filtered)
        {
            foreach(
    $values as $oid => $name)
            {
                
    $oidvalue snmpget($options["h"], $options["c"], "{$oid}.{$key}"100005);
                
    $oidvalue SNMPData($oidvalue);
                
    $dataItem["{#{$name}}"] = $oidvalue;
            }

            
    array_push($data$dataItem);
        }
    }

    $jsonData = Array();
    $jsonData["data"] = $data;

    echo 
    json_encode($jsonData);
    echo 
    "\n";
    ?>
    Note: I don't do any real checking of what you pass but it should just die with an error if you pass it something wrong so run it from command line first to make sure you get JSON output.

    Hope this helps someone else.

    Tim
    Last edited by koopmant; 20-06-2014, 13:10. Reason: Updated script
  • aib
    Senior Member
    • Jan 2014
    • 1615

    #2
    Well done!
    Thank you!
    Sincerely yours,
    Aleksey

    Comment

    • chojin
      Member
      Zabbix Certified Specialist
      • Jul 2011
      • 64

      #3
      Added your script to the https://www.zabbix.org/wiki/Advanced_SNMP_Discovery wiki. Feel free to detail/maintain it there.

      Comment

      • gjaekel
        Junior Member
        • Nov 2014
        • 14

        #4
        Is there a problem with sparse enumerations?

        Dear Tim,

        First let me say thank you for your script. For Network switch graphs, it help us to have a textual port description (Interface Alias) and also the type and operational link status within the title.

        Currently i try to add a Cisco UCS Controller to Zabbix, but here -- in contrast to other switches -- your script fail to scan the interface set with empty data.

        Code:
        # ./SNMPDiscovery.php -hucs0 -csecret --index=IF-MIB::ifDescr --value=IF-MIB::ifAlias,SNMPALIAS --value=IF-MIB::ifType,SNMPTYPE --value=IF-MIB::ifOperStatus,SNMPOPERSTATUS
        {"data":[]}

        From a snmp walk i see as a difference, that the index numbers of the ifDescr don't start at 1 and are sparse, too.

        Code:
        # snmpwalk ucs0-f IF-MIB::ifDescr
        IF-MIB::ifDescr.17301504 = STRING: fc2/1
        IF-MIB::ifDescr.17305600 = STRING: fc2/2
        IF-MIB::ifDescr.17309696 = STRING: fc2/3
        IF-MIB::ifDescr.17313792 = STRING: fc2/4
        IF-MIB::ifDescr.17317888 = STRING: fc2/5
        IF-MIB::ifDescr.17321984 = STRING: fc2/6
        IF-MIB::ifDescr.83886080 = STRING: mgmt0
        IF-MIB::ifDescr.101191680 = STRING: sup-fc0
        IF-MIB::ifDescr.369098823 = STRING: port-channel72
        IF-MIB::ifDescr.436207616 = STRING: Ethernet1/1
        IF-MIB::ifDescr.436211712 = STRING: Ethernet1/2
        IF-MIB::ifDescr.436215808 = STRING: Ethernet1/3
        IF-MIB::ifDescr.436219904 = STRING: Ethernet1/4
        IF-MIB::ifDescr.436224000 = STRING: Ethernet1/5
        IF-MIB::ifDescr.436228096 = STRING: Ethernet1/6
        IF-MIB::ifDescr.436232192 = STRING: Ethernet1/7
        IF-MIB::ifDescr.436236288 = STRING: Ethernet1/8
        IF-MIB::ifDescr.436240384 = STRING: Ethernet1/9
        IF-MIB::ifDescr.436244480 = STRING: Ethernet1/10
        IF-MIB::ifDescr.436248576 = STRING: Ethernet1/11
        IF-MIB::ifDescr.436252672 = STRING: Ethernet1/12
        [...]
        IF-MIB::ifDescr.520159680 = STRING: Ethernet2/1/8
        IF-MIB::ifDescr.520159744 = STRING: Ethernet2/1/9
        Is the current code not able to comprehend this? And if, may you fix this?

        Guido

        Comment

        • gjaekel
          Junior Member
          • Nov 2014
          • 14

          #5
          Problem Solved

          Dear Tim,

          I was able to trace down the Problem: In line 111 you use the line
          Code:
          $keys = snmprealwalk($options["h"], $options["c"] , $options["index"], 10000 , 5);
          Referred to http://php.net/manual/de/function.snmprealwalk.php, the last parameters describe a timeout in us and a retry count. This means, that your timeout is 10ms which seems simply to short for the queried device. The functions parameter default is 1000000us = 1s and 5 retries.

          After changed this line to
          Code:
          $keys = snmprealwalk($options["h"], $options["c"] , $options["index"]);
          the call delivers data and the script runs as intended.

          I suggest either to adjust the timeouts for the used snmprealwalk (and maybe for the snmpget's, too) or to introduce a timeout option.

          greetings

          Guido

          Comment

          • Ammer
            Junior Member
            • Dec 2013
            • 14

            #6
            SNMP version needed

            Hi,
            [EDIT] Problem was the same as mentioned above. Removed 1000,5 from strings and then it gave me results.

            [/EDIT]

            I tried to get the script working but it seems SNMP wants to know what snmp version it needs to use.

            Code:
            ./SNMPDiscovery.php -h 10.251.82.254 -c public --index IF-MIB::ifDescr --value IF-MIB::ifAdminStatus,ifAdminStatus
            {"data":[]}
            
            snmpwalk -c public 10.251.82.254 IF-MIB::ifDescr
            snmpwalk: No securityName specified
            
            snmpwalk -v2c -c public 10.251.82.254 IF-MIB::ifDescr
            IF-MIB::ifDescr.1 = STRING: ether1
            IF-MIB::ifDescr.2 = STRING: ether2
            Is there a way to add this to the script?
            Last edited by Ammer; 08-12-2014, 21:03.

            Comment

            • gjaekel
              Junior Member
              • Nov 2014
              • 14

              #7
              snmpcmd and used snmp-version

              Dear Ammer,

              you always have to specify the used snmp version snmpwalk and others. You may use -v at the commandline or place it and other option in /etc/snmp/snmp.conf (or some other locations, refer to the manpages). I'm currently using
              Code:
              defVersion 2c
              defCommunity secret
              mibs +ALL
              mibdirs +/usr/local/share/snmp/mibs
              This will be also used by the snmp-bindings of PHP, therefore you may even left out the '-c'-Option of SNMPDiscover.php. But because it's declared to be a required option, you first have to pimp the script once more.

              In the script I also have replaced the snmp function calls by variables and add commandline logic to switch between v1 (-1) and v2 (default). Because Sun/Orcacle-JVMs don't implement v1, but some of our USV don't implement v2.

              Comment

              • ptera
                Senior Member
                • Oct 2014
                • 109

                #8
                You can use --filter multiple times if you need.

                Zabbix 2.4.5 - CentOS Linux 6.6
                Want to filter interfaces that are up and are Gig interfaces only.

                If I run with single filter it works.
                When I put in more than one filter then nothing is filtered.

                Code:
                ./SNMPDiscovery.php -h  -c  --index IF-MIB::ifDescr 
                --value IF-MIB::ifDescr,ifDescr --value IF-MIB::ifOperStatus,ifOperStatus
                 --filter IF-MIB::ifOperStatus,1
                I get all interfaces with "{#ifOperStatus}":1

                Code:
                ./SNMPDiscovery.php -h  -c  --index IF-MIB::ifDescr 
                --value IF-MIB::ifDescr,ifDescr --value IF-MIB::ifOperStatus,ifOperStatus 
                --filter IF-MIB::ifDescr,Gig
                I get just the Gig interfaces "{#ifDescr}":"GigabitEthernet1\/9"

                But every attempt to put both filters on yields both filters ignored and returns all interfaces with all OperStatus.

                Code:
                ./SNMPDiscovery.php -h -c  --index IF-MIB::ifDescr 
                --value IF-MIB::ifDescr,ifDescr --value IF-MIB::ifOperStatus,ifOperStatus 
                --filter IF-MIB::ifDescr,Gig --filter IF-MIB::ifOperStatus,1
                How do I get multiple filters to work?

                I also get the red x next to this saying "Value should be a JSON object"
                Thanks

                PS

                Code:
                ./SNMPDiscovery.php -h -c   --index IF-MIB::ifDescr 
                --value IF-MIB::ifDescr,ifDescr --value IF-MIB::ifOperStatus,ifOperStatus  
                --filter IF-MIB::ifOperStatus,1
                This code works from CLI but not from the discovery rules of the template.

                So I decided to try your example above
                HTML Code:
                Edit discovery rule "Network Interfaces" on template "Template SNMP Interfaces"
                 * Type: External check
                 * Key: SNMPDiscovery.php["-h", {HOST.CONN}, "-c", {$SNMP_COMMUNITY}, "--index", "IF-MIB::ifDescr", "--value", "IF-MIB::ifAdminStatus,ifAdminStatus"]
                 * Filter:
                 *    Macro: {#ifAdminStatus}
                 *    Regexp: 1
                I no longer got the red x but
                Got nothing back until I removed the filter. Confused.

                This one works from CLI but returns everything from zabbix

                Code:
                ./SNMPDiscovery.php -h  -c   --index IF-MIB::ifDescr --value IF-MIB::ifOperStatus,ifOperStatus  --filter IF-MIB::ifOperStatus,1
                Code:
                SNMPDiscovery.php[ "-h","{HOST.CONN}","-c","{$SNMP_COMMUNITY}","--index","IF-MIB::ifDescr","--value","IF-MIB::ifOperStatus,ifOperStatus","--filter","IF-MIB::ifOperStatus,1"]
                Last edited by ptera; 06-05-2015, 21:39.

                Comment

                • ik_zelf
                  Member
                  • Feb 2015
                  • 60

                  #9
                  Originally posted by koopmant
                  Hey,

                  Wanted to share this script I wrote to enhance the LLD for SNMP. Read comments in script for how to use it and examples. Script will need to be placed in your Zabbix ExternalScripts directory and made executable. Only addition PHP module I had to install on my Zabbix server was php-snmp.

                  Note: I don't do any real checking of what you pass but it should just die with an error if you pass it something wrong so run it from command line first to make sure you get JSON output.

                  Hope this helps someone else.

                  Tim
                  Hi Tim,

                  thanks for the script. Could it be that there exists a limitation on the numbers that can be returned?

                  # SUN-AK-MIB::sunAkShareAvailableGB.1 = Counter32: 6209
                  # SUN-AK-MIB::sunAkShareAvailableGB.2 = Counter32: 1791
                  # SUN-AK-MIB::sunAkShareAvailableGB.3 = Counter32: 1159
                  # SUN-AK-MIB::sunAkShareSizeB.1 = Counter64: 8796093022208
                  # SUN-AK-MIB::sunAkShareSizeB.2 = Counter64: 2199023255552
                  # SUN-AK-MIB::sunAkShareSizeB.3 = Counter64: 2199023255552

                  When I try to select the SizeB values I get FALSE and when I select the GB values I do get the correct values:

                  Code:
                  > snmp_discovery.php -h dm01-zfs -cpublic --index SUN-AK-MIB::sunAkShareName \
                  >                                         --value SUN-AK-MIB::sunAkShareAvailableGB,sunAkShareAvailableGB \
                  >                                         --value SUN-AK-MIB::sunAkShareSizeGB,sunAkShareSizeGB
                  {"data":[{"{#SNMPINDEX}":"1","{#SNMPVALUE}":"Pool01\/ExaBackup\/dm01_backup","{#sunAkShareAvailableGB}":"Counter32: 6208","{#sunAkShareSizeGB}":"Counter32: 8192"},{"{#SNMPINDEX}":"2","{#SNMPVALUE}":"Pool01\/ExaBackup\/fs_backup","{#sunAkShareAvailableGB}":"Counter32: 1791","{#sunAkShareSizeGB}":"Counter32: 2048"},{"{#SNMPINDEX}":"3","{#SNMPVALUE}":"Pool01\/ExaBackup\/dm02_backup","{#sunAkShareAvailableGB}":"Counter32: 1158","{#sunAkShareSizeGB}":"Counter32: 2048"}]}
                  Code:
                  > snmp_discovery.php -h dm01-zfs -cpublic --index SUN-AK-MIB::sunAkShareName --value SUN-AK-MIB::sunAkShareAvailableB,sunAkShareAvailableB
                  {"data":[{"{#SNMPINDEX}":"1","{#SNMPVALUE}":"Pool01\/ExaBackup\/dm01_backup","{#sunAkShareAvailableB}":false},{"{#SNMPINDEX}":"2","{#SNMPVALUE}":"Pool01\/ExaBackup\/fs_backup","{#sunAkShareAvailableB}":false},{"{#SNMPINDEX}":"3","{#SNMPVALUE}":"Pool01\/ExaBackup\/dm02_backup","{#sunAkShareAvailableB}":false}]}
                  I am not even sure if the data can be read by zabbix at this moment. Do you happen to have any idea how I could return the Counter64 values ?

                  Thanks,
                  Ronald.

                  Comment

                  • Skrator
                    Junior Member
                    Zabbix Certified SpecialistZabbix Certified Professional
                    • Apr 2015
                    • 8

                    #10
                    Update: Support to SNMPv3

                    Hello, I needed this script to work with SNMPv3 as well. So I included the option to choose which SNMP version you want with the '-v' option, just like the net-snmp tools. The script is retrocompatible, so you can update it and have the discovery with the old parameters still working.

                    In general, it basically uses the same parameters you would use with the net-snmp tools (snmpget, snmpwalk, etc.).

                    Here is the result:

                    PHP Code:
                    #!/usr/bin/php
                    <?PHP
                    /* Version 2.2
                     * Author: Tim Koopman
                     * Added SNMPv3 support by Tauame Pacce:
                     *
                     * Request timeouts raised to 1s, from 10ms.
                     * There is a new -v option to inform the protocol version to be used.
                     * Also several SNMPv3 only options were added.
                     *    
                     * Version 2.1:
                     *
                     * For doing SNMP Low Level Discoveries in ZABBIX
                     * Inbuilt only allows filter macros on SNMPINDEX and SNMPVALUE
                     * While you can change what SNMPVALUE would represent by changing the OID
                     * you sometimes what more values, one for filtering and one for item prototype names.
                     *
                     * This script allows you to add as many other values as you like
                     * I use with the following to allow me to filter for interfaces that Admin Status is Up
                     * while still having the interface name on each of the items names.
                     *
                     * Edit discovery rule "Network Interfaces" on template "Template SNMP Interfaces"
                     * Type: External check
                     * Key: SNMPDiscovery.php["-h", {HOST.CONN}, "-c", {$SNMP_COMMUNITY}, "--index", "IF-MIB::ifDescr", "--value", "IF-MIB::ifAdminStatus,ifAdminStatus"]
                     * Filter:
                     *    Macro: {#ifAdminStatus}
                     *    Regexp: 1
                     *
                     * When used without the --value option the result would be identical to the inbuilt SNMP LLD.
                     * This means all existing item prototypes will continue to work as is.
                     * Can add as many --value options as you need.
                     *
                     * v2.0 added --filter as I wanted to seperate SNMP storage devices between memory and disks but Zabbix
                     * won't allow you to have the same key with just different filters. So doing it this way
                     * means the keys will be different and you can leave the Zabbix filter options blank
                     *
                     * Usage
                     * SNMPDiscovery.php -h <host> -c <community> [-v 1|2c|3] --index <OID>
                        [-n <CONTEXTNAME> -u <SECURITYNAME> -l noAuthNoPriv|authNoPriv|authPriv [-a MD5|SHA -A <AUTHPASS>] [-x AES|DES -X <PRIVPASS>] ]
                        [--value <OID>,<MACRONAME>]... [--filter <OID>,<REGEX>]...
                        
                     *   -h        : SNMP Host to query. When used in Zabbix this would normally be {HOST.CONN}
                     *   -c        : SNMP Community. When used in Zabbix this would normally be {$SNMP_COMMUNITY}
                     *   -v        : SNMP version to be used, possible options are "1", "2c" or "3". Defaults to "1".
                     *   --index   : OID to walk. Is used to populate {#SNMPINDEX} and {#SNMPVALUE} macros.
                     *   --value   : Comma seperated OID and macro name to also return. Can reference in zabbix using macro {#<MACRONAME>}
                     *               You can use --value multiple times if you need more macros returned.
                     *   --filter  : Comma seperated OID and regular expression. Any index that does not matches the regex will be excluded from the results.
                     *               You can use --filter multiple times if you need.
                     *
                     *   SNMPv3 exclusive options (enabled with "-v 3"):
                     *   -u        : Security Name.
                     *   -a        : Authentication Protocol, usually "MD5" or "SHA". Defaults to "SHA".
                     *   -x        : Privacy Protocol, usually "AES" or "DES". Defaults to "DES".
                     *   -A        : Authentication passphrase (Only enabled with "-a" option).
                     *   -X        : Privacy passphrase (Only enabled with "-x" option).
                     *   -l        : Security level, possible options are "noAuthNoPriv", "authNoPriv" or "authPriv". Defaults to "authPriv".
                     *
                     * Returns JSON text which Zabbix LLD uses.
                     *
                     * Examples
                     *   SNMPDiscovery.php -h 127.0.0.1 -c public --index IF-MIB::ifDescr --value IF-MIB::ifAdminStatus,ifAdminStatus
                     *   SNMPDiscovery.php -h 127.0.0.1 -c public --index HOST-RESOURCES-MIB::hrStorageDescr --filter HOST-RESOURCES-MIB::hrStorageType,hrStorageFixedDisk$
                     *   SNMPDiscovery.php -h 127.0.0.1 -c public --index HOST-RESOURCES-MIB::hrStorageDescr --filter 'HOST-RESOURCES-MIB::hrStorageType,(hrStorageRam|hrStorageVirtualMemory)$'
                     *   SNMPDiscovery.php -h 127.0.0.1 -v 3 -u bob -a AES -A mypasswd -l authNoPriv --index IF-MIB::ifDescr --value IF-MIB::ifAdminStatus,ifAdminStatus
                    */
                    error_reporting(E_ALLE_WARNING);
                     
                    function 
                    SNMPData($data)
                    {
                        if (
                    strPos($data"STRING: ")===0)
                        {
                            
                    preg_match_all('!^STRING: \"?(.*?)\"?$!'$data$matches);
                            return 
                    $matches[1][0];
                        } elseif (
                    strPos($data"INTEGER: ")===0) {
                            
                    preg_match_all('!\d+!'$data$matches);
                            return (int) 
                    $matches[0][0];
                        } else {
                            return 
                    $data;
                        }
                    }

                    function 
                    usage()
                    {
                        print 
                    "Usage: SNMPDiscovery.php -h <host> -c <community> --index <OID>
                        [-v 3 -u <SECURITYNAME> -l <SECURITYLEVEL> [-a <AUTHPROTOCOL> -A <AUTHPASS>] [-x <PRIVPROTOCOL> -X <PRIVPASS>] ]
                        [--value <OID>,<MACRONAME>]... [--filter <OID>,<REGEX>]...\n"
                    ;
                        exit(
                    1);
                    }
                     

                    $options getopt("c:h:v:u:a:x:A:X:l:",array("index:","value:","filter:"));

                    if (
                    count($options) == 0)
                    {
                        
                    usage();
                    }

                    if (!
                    array_key_exists("a"$options))
                    {
                        
                    $options["a"]="SHA";
                    }

                    if (!
                    array_key_exists("A"$options))
                    {
                        
                    $options["A"]="";
                    }


                    if (!
                    array_key_exists("x"$options))
                    {
                        
                    $options["x"]="DES";
                    }

                    if (!
                    array_key_exists("X"$options))
                    {
                        
                    $options["X"]="";
                    }


                    if (!
                    array_key_exists("l"$options))
                    {
                        
                    $options["l"]="authPriv";
                    }

                    $values = Array();
                    if (
                    array_key_exists("value"$options))
                    {
                        if (
                    is_array($options["value"]))
                        {
                            foreach(
                    $options["value"] as $value)
                            {
                                
                    $explode explode(","$value);
                                
                    $values[$explode[0]] = $explode[1];
                            }
                        } else {
                            
                    $explode explode(","$options["value"]);
                            
                    $values[$explode[0]] = $explode[1];
                        }
                    }
                     
                    $filters = Array();
                    $defaultFilter false;
                    if (
                    array_key_exists("filter"$options))
                    {
                        if (
                    is_array($options["filter"]))
                        {
                            foreach(
                    $options["filter"] as $value)
                            {
                                
                    $explode explode(","$value);
                                
                    $filters[$explode[0]] = $explode[1];
                            }
                        } else {
                            
                    $explode explode(","$options["filter"]);
                            
                    $filters[$explode[0]] = $explode[1];
                        }
                    } else {
                        
                    $defaultFilter true;
                    }
                     
                    $data = Array();
                     
                    if (
                    array_key_exists("v"$options))
                    {
                        switch(
                    $options["v"])
                        {
                            case 
                    "1":
                                
                    $keys snmprealwalk($options["h"], $options["c"] , $options["index"], 1000000 5);
                                break;
                            case 
                    "2c":
                                
                    $keys snmp2_real_walk($options["h"], $options["c"] , $options["index"], 1000000 5);
                                break;
                            case 
                    "3":
                                
                    $keys snmp3_real_walk($options["h"], $options["u"] , $options["l"], $options["a"], $options["A"], $options["x"], $options["X"], $options["index"], 1000000 5);
                                break;
                            default:
                                
                    $keys snmprealwalk($options["h"], $options["c"] , $options["index"], 1000000 5);
                        }
                    }else{
                        
                    $keys snmprealwalk($options["h"], $options["c"] , $options["index"], 1000000 5);
                    }

                    foreach(
                    $keys as $key => $value)
                    {
                        
                    $key substr($keystrlen($options["index"])+1);
                        
                    $value SNMPData($value);
                        
                    $dataItem = Array();
                        
                    $dataItem["{#SNMPINDEX}"] = $key;
                        
                    $dataItem["{#SNMPVALUE}"] = $value;
                     
                        
                    $filtered $defaultFilter;
                        foreach(
                    $filters as $oid => $regex)
                        {
                            if (
                    array_key_exists("v"$options))
                            {
                                switch(
                    $options["v"])
                                {
                                    case 
                    "1":
                                        
                    $oidvalue snmpget($options["h"], $options["c"], "{$oid}.{$key}"10000005);
                                        break;
                                    case 
                    "2c":
                                        
                    $oidvalue snmp2_get($options["h"], $options["c"], "{$oid}.{$key}"10000005);
                                        break;
                                    case 
                    "3":
                                        
                    $oidvalue snmp3_get($options["h"], $options["u"] , $options["l"], $options["a"], $options["A"], $options["x"], $options["X"], "{$oid}.{$key}"1000000 5);
                                        break;
                                    default:
                                        
                    $oidvalue snmpget($options["h"], $options["c"], "{$oid}.{$key}"10000005);
                                }
                            }else{
                                
                    $oidvalue snmpget($options["h"], $options["c"], "{$oid}.{$key}"10000005);
                            }
                            
                    $oidvalue SNMPData($oidvalue);
                            if (
                    preg_match("/".$regex."/"$oidvalue)) $filtered true;
                        }
                     
                        if (
                    $filtered)
                        {
                            foreach(
                    $values as $oid => $name)
                            {
                                if (
                    array_key_exists("v"$options))
                                {
                                    switch(
                    $options["v"])
                                    {
                                        case 
                    "1":
                                            
                    $oidvalue snmpget($options["h"], $options["c"], "{$oid}.{$key}"10000005);
                                            break;
                                        case 
                    "2c":
                                            
                    $oidvalue snmp2_get($options["h"], $options["c"], "{$oid}.{$key}"10000005);
                                            break;
                                        case 
                    "3":
                                            
                    $oidvalue snmp3_get($options["h"], $options["u"] , $options["l"], $options["a"], $options["A"], $options["x"], $options["X"], "{$oid}.{$key}"1000000 5);
                                            break;
                                        default:
                                            
                    $oidvalue snmpget($options["h"], $options["c"], "{$oid}.{$key}"10000005);
                                    }
                                }else{
                                    
                    $oidvalue snmpget($options["h"], $options["c"], "{$oid}.{$key}"10000005);
                                }
                                
                    $oidvalue SNMPData($oidvalue);
                                
                    $dataItem["{#{$name}}"] = $oidvalue;
                            }
                     
                            
                    array_push($data$dataItem);
                        }
                    }
                     
                    $jsonData = Array();
                    $jsonData["data"] = $data;
                     
                    echo 
                    json_encode($jsonData);
                    echo 
                    "\n";
                    ?>
                    Hope it helps.

                    Comment

                    • Cenzoooo
                      Member
                      • Jul 2015
                      • 37

                      #11
                      &quot;Timeout while executing a shell script.&quot;

                      Hello!

                      Thanks for your script, but it don't work for me.

                      I did discovery rule with key:
                      SNMPDiscovery.php["-h", {HOST.CONN}, "-c", {$SNMP_COMMUNITY}, "--index", "IF-MIB::ifDescr", "--value", "IF-MIB::ifAlias,ifAlias"]

                      And with 2 filters (regex), 1. which match only certain port descriptions (Eth,Ge,xe...) and 2. for "ifAlias", as I don't want to find interfaces with no Alias, so i did regex who does not accept empty strings. Regex is : ^(?!\s*$).+

                      Problem is my discovery rule returns status "Not supported" and error : "Timeout while executing a shell script."

                      Please help!

                      Comment

                      • gjaekel
                        Junior Member
                        • Nov 2014
                        • 14

                        #12
                        Originally posted by Cenzoooo
                        Hello!
                        Problem is my discovery rule returns status "Not supported" and error : "Timeout while executing a shell script."
                        What kind of device you're going to monitor? What's the value for script timeout in the Zabbix server configuration? Did you try to call the script "by hand" on commandline? (You may get a comfortable output by piping it to a json pretty printer like 'json_pp')

                        In the current version, the script first do a bulk walk on the index, but then a single fetch for every item of the additional "rows" you add. This (and the communication overhead) will take a lot of time on devices like a well-endowed core switch with hundreds of interfaces and/or with snmpd running at low-priority. I have to monitor such things and i have to rise the timeout to the current upper limit of 30s (btw: It's no good approach to limit configuration values to some developers think best).

                        It would be much better for performance to get the additional rows with a bulk command and mix this information to build the final output.

                        Comment

                        • Cenzoooo
                          Member
                          • Jul 2015
                          • 37

                          #13
                          Originally posted by gjaekel
                          What kind of device you're going to monitor? What's the value for script timeout in the Zabbix server configuration? Did you try to call the script "by hand" on commandline? (You may get a comfortable output by piping it to a json pretty printer like 'json_pp')

                          In the current version, the script first do a bulk walk on the index, but then a single fetch for every item of the additional "rows" you add. This (and the communication overhead) will take a lot of time on devices like a well-endowed core switch with hundreds of interfaces and/or with snmpd running at low-priority. I have to monitor such things and i have to rise the timeout to the current upper limit of 30s (btw: It's no good approach to limit configuration values to some developers think best).

                          It would be much better for performance to get the additional rows with a bulk command and mix this information to build the final output.

                          I did put also 30 sec timeout, but still i get this error on most of my core equipment (which have many interfaces). When i put script on equipment with lower number of interfaces it works correctly...

                          In CLI when i start script, it takes 9-10 seconds to get results... In zabbix timeout is configured do 30secs...


                          Any1 have any more solutions for this problem?

                          Comment

                          • Skrator
                            Junior Member
                            Zabbix Certified SpecialistZabbix Certified Professional
                            • Apr 2015
                            • 8

                            #14
                            Use Zabbix Sender

                            As a general rule, for scripts that might take more than 30s to respond, I usually go for the zabbix_sender utility. In this case, create a 2 line script:

                            Code:
                            #!/bin/bash
                            OUTPUT_VAR=$(php /usr/lib/zabbix/externalscripts/SNMPDiscovery.php ...params... )
                            zabbix_sender --host <hostname> --zabbix-server <server> --key <itemkey> --value "$OUTPUT_VAR"
                            and add it to the crontab with the desired frequency.

                            If this doesn't work, let me know.

                            Comment

                            • gjaekel
                              Junior Member
                              • Nov 2014
                              • 14

                              #15
                              Re: Use Zabbix Sender

                              Originally posted by Skrator
                              As a general rule, for scripts that might take more than 30s to respond, I usually go for the zabbix_sender utility.
                              [...]
                              If this doesn't work, let me know.
                              If wonder how this will work for a discovery script.

                              @Devels: As the interval used for discovery typically is much longer than for item queries, zabbix_server should use another configurable timeout for this exec call.

                              Comment

                              Working...