Re: Monitoring cyrusimapd

Nic Bernstein <[email protected]>
Newsgroups gmane.mail.imap.cyrus
Message-ID <[email protected]>
On 06/19/2018 10:23 AM, Albert Shih wrote:
> Hi everyone,
>
> I would like to know what kind of monitoring you perform on a cyrus-imapd.
> Beside classic (check_imap, check_disk, check_cpu etc...) do you have any
> special thing to monitor about cyrus-imapd.
>
> For example do you launch any check on each database ? How can I check if the replication work fine ?
>

We use the attached PHP plugin in Icinga to monitor the SNMP OIDs 
provided by Cyrus.  I haven't tried this with the newer Prometheus-based 
system, but it works just fine on 2.5.X systems built with SNMP enabled:

       Usage: $argv[0] -H <host> -C <community string> -s <service>
                 -p <property> -c <crit_range> -w <warn_range> -h -t
    <timeout> -d

       Required:
         -H [STRING|IP]
             Hostname or IP address
         -s Which service name to check: This may be any service defined in
             cyrus.conf on host being checked. For example: imap, imaps,
    pop3
             lmtp.  This is also used as a label for the results.

             * Note: To receive a list of services supported by host,
    use the
             special keyword 'list'.

             * Note: Services with special characters in their name, such as
             lmtp[v6], must be quoted; i.e. 'lmtp[v6]'.

       Options:
         -C  STRING
             SNMP community string (defaults to `public').
         -p <property>
             Which property to report (and alarm) on (defaults to 'active'):
                * forks
                * active
                * connections
    ...

Warning & critical thresholds are allowed (scalar or range) for all 
checks.  This is primarily a process oriented check  script. It's useful 
to keep an eye on how many of each service's processes are running 
versus the configured quantity.

You may want to take a look at issue 1827 on GitHub in regards to SNMP 
on Cyrus:
     https://github.com/cyrusimap/cyrus-imapd/issues/1827

Please note that this plugin relies upon utils.php by Marcel Kühn & Doug 
Warner:
http://doug.warner.fm/nagios-utilsphp-script-for-php-plugins.html

Cheers,
     -nic

-- 
Nic Bernstein                             [email protected]
Onlight Inc.                              www.onlight.com
6525 W Bluemound Rd., Ste 24	          v. 414.272.4477
Milwaukee, Wisconsin  53213-4073	  f. 414.290.0335

----
Cyrus Home Page: http://www.cyrusimap.org/
List Archives/Info: http://lists.andrew.cmu.edu/pipermail/info-cyrus/
To Unsubscribe:
https://lists.andrew.cmu.edu/mailman/listinfo/info-cyrus
check_cyrus.php (application/x-php, 9.6 KB)
#!/usr/local/bin/php
<?php
/**
 * check_cyrus.php
 *
 * Nagios plugin to check status of Cyrus IMAP server over SNMP
 *
 * See show_usage(), below, for usage information.
 *
 *
 * Please forward any such changes to us for inclusion in future releases.
 * mailto:<[email protected]>
 */

/**
 * Copyright (c) February 7, 2017
 * by Nic Bernstein <[email protected]>
 * for Onlight, Inc.
 * PO Box 511219
 * Milwaukee, WI  53203
 *
 * All rights reserved, except as provided by the following license
 * information...
 *
 * License Information:
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 * 
 * * Redistributions of source code must retain the above copyright
 *   notice, this list of conditions and the following disclaimer.
 * * Redistributions in binary form must reproduce the above
 *   copyright notice, this list of conditions and the following disclaimer
 *   in the documentation and/or other materials provided with the
 *   distribution.
 * * Neither the name of the Onlight, llc. nor the names of its
 *   contributors may be used to endorse or promote products derived from
 *   this software without specific prior written permission.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

require_once 'utils.php';

/**
 * show_usage()
 *
 * Print standard usage instructions and exit
 */
function show_usage() {
  global $argv;

  echo <<<_EOF_
  Usage: $argv[0] -H <host> -C <community string> -s <service>
            -p <property> -c <crit_range> -w <warn_range> -h -t <timeout> -d

  Required:
    -H [STRING|IP]
        Hostname or IP address
    -s Which service name to check: This may be any service defined in
        cyrus.conf on host being checked. For example: imap, imaps, pop3
        lmtp.  This is also used as a label for the results.

        * Note: To receive a list of services supported by host, use the
        special keyword 'list'.

        * Note: Services with special characters in their name, such as
        lmtp[v6], must be quoted; i.e. 'lmtp[v6]'.

  Actions:
    -h show this help
    -v show version

  Options:
    -C  STRING
        SNMP community string (defaults to `public').
    -p <property>
        Which property to report (and alarm) on (defaults to 'active'):
           * forks
           * active
           * connections
    -c <crit-range>
        Range which will not result in a CRITICAL status.
    -w <warn-range>
        Range which will not result in a WARNING status
        - Ranges are inclusive and are indicated with colons. When specified as
          'min:max' a STATE_OK will be returned if the result is within the indicated
          range or is equal to the upper or lower bound. A non-OK state will be
          returned if the result is outside the specified range.
        - If specified in the order 'max:min' a non-OK state will be returned if the
          result is within the (inclusive) range.
    -t  Timeout (in seconds, default 10)
    -d  Log debug output to error log

_EOF_;
  echo "\n";
}

/**
 * info
 *
 * Log information
 *
 * @param string  $message The error message to report
 * @param boolean $echo    (optional) Do we echo this message or simply log it?
 */
function info($message, $echo=TRUE) {
  if ($echo)
    echo "$message\n";
  syslog(LOG_INFO, $message);
}

/**
 * my_exit()
 *
 * Exit program with exit status and optional message and performance
 * data.
 *
 * @param integer $exit_status Exit status
 * @param string  $msg         (optional) message to write on exit (default empty)
 * @param unknown $perfdata    (optional)
 */
function my_exit($exit_status, $msg='', $perfdata='') {
  global $exit_code;
  $alert = $exit_code[$exit_status];
  $result = empty($msg) ? $alert : "$alert: $msg";
  $result = empty($perfdata) ? $result : "$result | $perfdata";
  info($result);
  exit($exit_status);
}

/**
 * my_unknown()
 *
 * Print message and exit with status 3 (UNKNOWN)
 *
 * @param string $msg message to write on exit (default empty)
 */
function my_unknown($msg='') {
  global $service;

  my_exit(STATE_UNKNOWN, "$service UNKNOWN - $msg");
}

/******** END OF FUNCTIONS ********/

/******** DECLARE CONSTANTS AND DEFAULTS ********/
define('THIS_VERSION','1.0');
//error_reporting(E_ALL);

/* Exit code display strings */
$exit_code = array(STATE_OK => 'OK',
                   STATE_WARNING => 'WARNING',
                   STATE_CRITICAL => 'CRITICAL',
                   STATE_UNKNOWN => 'UNKNOWN',
                   STATE_DEPENDENT => 'DEPENDENT',
                   );

/**
 * OIDs
 *
 * Note: We use numeric OID rather than
 *       `CYRUS-MASTER-MIB::' in case the MIB is not installed.
 */
define('cyrusMasterInfoUptime', '.1.3.6.1.4.1.3.6.1.1.3.0');
define('serviceName',           '.1.3.6.1.4.1.3.6.1.2.1.3');
define('serviceBase',           '.1.3.6.1.4.1.3.6.1.2.1.');
$serviceStats = array('forks'       => serviceBase . 1,
                      'active'      => serviceBase . 2,
                      'connections' => serviceBase . 5,
                      );

// Set some defaults
// Timeout for SNMP calls
$timeout = 10;

// Whether to log debugging info
$debug = FALSE;

// Which unit number of probe are we to read
$unit = 1;

// The SNMP community string
$comm = 'public';

// All properties we support
$props = array('forks', 'active', 'connections');

// The default property we care about
$prop = 'active';

// Report version?
$ver = FALSE;

// Process our command line options
$shortopts = 'H:s:p:C:c:w:hdt:v';
$opts = getopt($shortopts);

foreach ($opts as $opt => $value) {
  $val = strtolower($value);
  switch ($opt) {
  case 'H':
    // hostname or IP address
    $host = $value;
    break;

  case 'h':
    // Help
    show_usage();
    my_exit(0);
    break;

  case 's':
    // Service
    $service = $val;
    break;

  case 'p':
    // Property
    if (in_array($val, $props)) {
      $prop = $val;
    } else {
      show_usage();
      my_exit(STATE_UNKNOWN, "Unknown property '$val' specified");
    }
    break;

  case 'C':
    // SNMP community string
    $comm = $value;
    break;

  case 'c':
    $crit = new  Nagios_Plugin_Range($val);
    break;

  case 'w':
    $warn = new  Nagios_Plugin_Range($val);
    break;

  case 'd':
    $debug = TRUE;
    break;

  case 'v':
    $msg = "Version: " . THIS_VERSION;
    $ver = TRUE;
    break;

  case 't':
    $timeout = $value;
    break;

  }
}

// Simply report the version and exit
if ($ver) {
  my_exit(STATE_OK, $msg);
}

// Make sure we have the barest minimum of settings
if ($argc == 0) {
  show_usage();
  my_exit(STATE_UNKNOWN, "No arguments specified");
}

if (!isset($host) || empty($host)) {
  show_usage();
  my_exit(STATE_UNKNOWN, "Hostname must be specified");
}

if (!isset($service) || empty($service)) {
  show_usage();
  my_exit(STATE_UNKNOWN, "Service must be specified");
}


$timeout = $timeout * 1000000; // Timeout is in microseconds
snmp_set_valueretrieval(SNMP_VALUE_PLAIN);

// Get the process uptime
if (($result = snmp2_get($host, $comm, cyrusMasterInfoUptime, $timeout)) === FALSE) {
  my_unknown("SNMP failed to retrieve data from host $host");
}
$days = intval($result / 8640000);
$result = $result - ($days * 8640000);
$hours = intval($result / 360000);
$result = $result - ($hours * 360000);
$min = intval($result / 6000);
$result = $result - ($min * 6000);
$sec = intval($result / 100);
$uptime = sprintf("%d:%02d:%02d:%02d", $days, $hours, $min, $sec);

// Walk the hosts serviceName table to see what's available
if (($result = snmp2_real_walk($host, $comm, serviceName, $timeout)) === FALSE) {
  my_unknown("SNMP failed to retrieve data from host $host");
}

if ($service == 'list') {
  // Just furnish a list of reported services
  my_exit(STATE_OK, "Host $host up $uptime reports services " . implode(',', $result));
}
  
// Determine the index of our service
foreach ($result as $oid => $oval) {
  if ($oval == $service) {
    $index = substr($oid, -1);
    break;
  }
}
if (!isset($index)) {
	my_exit(STATE_UNKNOWN, "Service '$service' not reported by host $host");
}

$perfdata = "$service=";
// Get the rest of the values for this service
foreach ($serviceStats as $stat => $soid) {
  if (($result = snmp2_get($host, $comm, "$soid.$index", $timeout)) === FALSE) {
    my_unknown("SNMP failed to retrieve data from host $host");
  }
  $stats[$stat] = $result;
  // Prepend a semicolon to datum, if it's not the first
  if (substr($perfdata, -1) == '=') {
    $perfdata .= $result;
  } else {
    $perfdata .= ";$result";
  }
}

$states = array( 'warn' => STATE_WARNING, 'crit' => STATE_CRITICAL);

// Check crit first, so we raise the higher alert
foreach (array('crit', 'warn') as $cond) {
	if (isset($$cond) && $$cond->check_range($stats[$prop])) {
    $alert = sprintf('%s=%d(out of range)', $prop, $stats[$prop]);
    my_exit($states[$cond], "$service $uptime $alert", $perfdata);
  }
}

// We're okay
my_exit(STATE_OK, "$service $uptime $prop=$stats[$prop]", $perfdata);
?>
<?php //vim:set ts=2 sw=2 ai: ?>
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.