Alternative Way to monitor Zimbra service status from an external "monitor" server

Revision as of 05:55, 3 April 2010 by Richardteachout (talk | contribs)

I needed a way to monitor a cluster of Zimbra servers (in our case, we are running the OSS edition, but this would work for NE as well) from a remote monitor server. We didn't need details, disk space, just "were the services fully up and running" for the entire cluster. So we found a "poor mans" way to do it, which has worked fantastic for us, so I thought I would share.

First, install Apache (and php is needed for this example), and configure it to run on an alternate port (it is also suggested you firewall this to only be allowed from authorized hosts, but that is beyond this concept page) We have a dedicated server running a mailbox store, with NO users on it, and running logger with centralized syslog from all the server in our cluster of 10 machines, so we did this on that server, as it makes the most sense. You could do this on every/any server running logger however..

Then add something like:

        DocumentRoot    /opt/zimbra/customstat/www
        ErrorLog        /opt/zimbra/customstat/logs/error_log
        CustomLog       /opt/zimbra/customstat/logs/access_log common
       DirectoryIndex index.php

Then make the directory /opt/zimbra/customstat/ (owned by zimbra is OK, just be sure you have a chmod 744 on the directory and a chmod 755 on the files you are about to run) Create 3 files.

The first is a small config file, so name it "config.php"

//Zimbra Logger Service mySQL Connection Information
$host      = "";
$mysqluser = "zimbra";
//Change this to call the zimbra function to get the password.. maybe
//to get the password, run    "/opt/zimbra/bin/zmlocalconfig -s -m nokey zimbra_logger_mysql_password" and put it below
$password = "";

The second is the actual status page. name it "status.php"


include 'config.php';

if(!$dbconnect = mysql_connect("$host", "$mysqluser", "$password")) {
   print "Connection failed to the host 'localhost'.";
} // if
if (!mysql_select_db('zimbra_logger')) {
   print "Cannot connect to database 'zimbra_logger'";
} // if

$table_id = 'service_status';
$query = "SELECT * FROM $table_id";

$dbresult = mysql_query($query, $dbconnect);

// create a new XML document
$doc = new DomDocument('1.0');

// create root node
$root = $doc->createElement('root');
$root = $doc->appendChild($root);

// process one row at a time
while($row = mysql_fetch_assoc($dbresult)) {
 // add node for each row
  $occ = $doc->createElement($table_id);
  $occ = $root->appendChild($occ);
 // add a child node for each field
  foreach ($row as $fieldname => $fieldvalue) {
  $child = $doc->createElement($fieldname);
    $child = $occ->appendChild($child);
   $value = $doc->createTextNode($fieldvalue);
    $value = $child->appendChild($value);
  } // foreach
} // while
// get completed xml document
$xml_string = $doc->saveXML();

// Uncomment below if you are going to use this interface as an XML report
//        print $xml_string;
//        exit;

//print $xml_string;
$xml_doc = new DomDocument;

$xp = new XsltProcessor();
// create a DOM document and load the XSL stylesheet
  $xsl = new DomDocument;
  // import the XSL styelsheet into the XSLT process

 // transform the XML into HTML using the XSL file
  if ($html = $xp->transformToXML($xml_doc)) {
      echo $html;
  } else {
      trigger_error('XSL transformation failed.', E_USER_ERROR);
  } // if


The third is the layout page, name it status.xsl

<?xml version='1.0'?>
<xsl:stylesheet xmlns:xsl="" version="1.0">

<xsl:output method='html'/>

<!-- param values may be changed during the XSL Transformation -->
<xsl:param name="title">Server Status for IPmonitor</xsl:param>
<xsl:param name="script">test2.php</xsl:param>
<xsl:param name="numrows">0</xsl:param>
<xsl:param name="curpage">1</xsl:param>
<xsl:param name="lastpage">2</xsl:param>
<xsl:param name="script_time">0.2744</xsl:param>

<xsl:template match="root">

<html xmlns="">
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"/>
<title><xsl:value-of select="$title"/></title>
    <style type="text/css">
        caption { font-weight: bold; }
        TH {      font-family: MS Sans Serif; font-size: 10pt;background-color: #CCCCCC;border-left: solid 1 #000000;
            border-top: solid 1 #000000;border-bottom: solid 1 #000000;border-right: none;padding-left: 5px;padding-right: 5px;padding-top: 2px;padding-bottom: 2px;}
        .footer { font-family: MS Sans Serif; font-size: 10pt;background-color: #CCCCCC;border-left: solid 1 #000000;
            border-top: solid 1 #000000;border-bottom: solid 1 #000000;border-right: none;padding-left: 5px;padding-right: 5px;padding-top: 2px;padding-bottom: 2px;}
        tr.odd {  background: #eeeeee; }
        tr.even { background: #dddddd; }
        .center { text-align: center; }



<table border="1">
<caption><xsl:value-of select="$title"/></caption>
          <xsl:apply-templates select="service_status">
            <xsl:sort select="server" />
            <xsl:sort select="service" />
        <td colspan="2" class="footer">
        Status of 1 eq Running<br/>
        Status of 0 eq Not Running</td>

<xsl:template match="service_status">
        <xsl:attribute name="class">
        <xsl:when test="position()mod 2">odd</xsl:when>
    <td><xsl:value-of select="server"/>.<xsl:value-of select="service"/>.<xsl:value-of select="status"/></td>
    <td><xsl:value-of select="time"/></td>

Now, just startup apache, and visit the new page you have: You should get a table Server Status for IPmonitor Server.Service.Status Time 2010-04-03 00:44:01 2010-04-03 00:44:01 2010-04-03 00:44:01 2010-04-03 00:44:01 2010-04-03 00:44:01

For every server logging to this logger, you should see a row with the servername.service.0/1 (0=not running, 1=running) and the date of last update

Now, you can use just about any monitoring system to do a GET on the /status.php page, and check for existence of (for example) "" if it doesn't exist or is .0, your monitor wouldn't match, and hence the service is down, so set-off the appropriate alerts to notify your Support team.

Yes, all of this could be done using SNMP, but the OSS version doesn't include SNMP natively, and we didn't want to configure it on these servers, so this was a quick way to get the data we needed, without much of any overhead on the server itself, as it was just a sql query, that looked up data that was already being populated.


Jump to: navigation, search