Each daemon should support:
$ mydaemon
start
This should daemon-ize the new daemon, running it forever in the background.
$ mydaemon
stop
This should find the collector and stop it with a graceful shutdown.
$ mydaemon
run
The new daemon should run for one cycle (if it has a cycle), and should not daemon-ize and log to stderr.
Thankfully most of this infrastructure is taken care of for you. Should you require more command-line options, here's how you should take advantage of the existing code:
from Products.ZenHub.PBDaemon import PBDaemon class myclass(PBDaemon) ... def buildOptions(self): """Build our list of command-line options """ PBDaemon.buildOptions(self) self.parser.add_option( '--newoption', dest='dest_var', action="store_true", default=False, help="Do something really interesting")
The option formats are as specified in the Python optparse
library.
Other features taken care of with the Zenoss daemon infrastructure is reading from configuration files, the --genconf
flag (which produces a configuration file populated with all options, comments and default values) as well as the --genxmltable
flag (which produces a DocBook XML table showing command-line switches). As other features can be added to the base class, if you follow this recommendation there are more things your daemon gets for free.
The code to allow commands to get command-line option values out of a config file in $ZENHOME/etc/
currently can only set values on lower-case options. Please be aware of this when you create new command-line options.
The daemons
directory should contain a file with the name of your daemon (the one that should appear under the Daemons tab under Settings). This file is an executable shell script which should contain the following:
#! /usr/bin/env bash . $ZENHOME/bin/zenfunctions MYPATH=`python -c "import os.path; print os.path.realpath('$0')"` THISDIR=`dirname $MYPATH` PRGHOME=`dirname $THISDIR` PRGNAME=mydaemon.py CFGFILE=$CFGDIR/mydaemon.conf generic "$@"
Of course, the PRGNAME
and CFGFILE
variables don't necessarily need to be contain the same name as the daemon. However, keeping the same name will certainly make things much less confusing.
The
file is assumed to live at the base of the ZenPack.mydaemon
.py
The basics of daemon communications are these.
Procedure 10.1. Daemon to ZenHub Communication Steps
A daemon connects to ZenHub. The raw mechanics of this are handled by the PBDaemon
classes so we don't need to explicitly code anything.
The daemon requests specific Services by name from ZenHub. The Services are classes either already known to ZenHub or classes provided in the services
directory in a ZenPack and are loaded by ZenHub at runtime.
The daemon calls remote_
methods on the Service objects from ZenHub to receive configuration information or perform other work.
The Services can also call remote_
methods on the daemon to provide updates, etc.
The services
directory needs to be created at the base directory of your ZenPack. Included in this directory is the __init__.py
file. The __init__.py
can be empty, but it must exist or any service class files cannot be loaded by zenhub.
zenhub imports Services (a daemon-to-Hub interface class) and the daemons can then use their own Service to perform actions. Look for the example closest to your needs from the $ZENHOME/Products/ZenHub/services/
directory as well as from other ZenPacks (such as HelloWorldZenPack or ZenJMX).
A basic Service class can be found in the Products.ZenHub.HubService.HubService
class. More complex daemons doing data collection may want to subclass Products.ZenHub.PerformanceConfig.PerformanceConfig
instead to take advantage of some additional infrastructure there.