NAME

Cluster::Init - Clusterwide "init", spawn cluster applications

SYNOPSIS

use Cluster::Init;

my $init = new Cluster::Init;

# spawn all apps for resource group "foo", runlevel "run"
$init->tell("foo","run");

# spawn all apps for resource group "foo", runlevel "runmore"
# (this stops everything started by runlevel "run")
$init->tell("foo","runmore");

# spawn all apps for resource group "bar", runlevel "3"
# (this does *not* stop or otherwise affect anything in "foo")
$init->tell("bar",3);

DESCRIPTION

This module provides basic init functionality, giving you a single inittab-like file to manage initialization and daemon startup across a cluster or collection of machines.

This module is used by OpenMosix::HA, for instance, to provide high availability with failure detection, automatic migration, and restart of applications running in a cluster. OpenMosix::HA provides you with the ability to build 24x7 mission-critical, high-performance server farms using only commodity hardware. See OpenMosix::HA.

I wrote the original version of this module to provide a more flexible interface between IBM's AIX HACMP cluster manager and managed applications. This provided a cleaner configuration, much faster configuration changes, and respawn ability for individual daemons.

Other uses abound, including non-cluster environments -- use your imagination. Generically, what you get in this package is an application-level "init" written in Perl, with added bits in the form of resource groups, status file output, and a 'test' runmode (see below).

INSTALLATION

Use Perl's normal sequence:

perl Makefile.PL
make
make test
make install

This module includes a script, clinit, which will be installed when you run 'make install'. See the output of perl -V:installscript to find out which directory the script is installed in.

CONFIGURATION

You will need to create a configuration file, /etc/cltab by default, which is identical in format to /etc/inittab, with a new "resource group" column added. See t/cltab in the Cluster::Init distribution for an example. This file must be replicated across all hosts in the cluster by some means of your own. On OpenMosix clusters, OpenMosix::HA will replicate this file for you. See http://www.Infrastructures.Org for ways to do this in other environments.

A resource group is a collection of applications and physical resources (like filesystem mounts) which need to execute together on the same cluster node. Resource groups allow easy migration of applications between nodes. For example, sendmail, /etc/sendmail.cf, and the /var/spool/mqueue directory might make up a resource group. From /etc/cltab you could spawn the scripts which update sendmail.cf, mount mqueue, and then start sendmail itself. For another example, Apache, a virtual IP address, and the filesystem containing the HTML document tree might together constitute a resource group. To start this resource group, you might need to mount the filesystem, ifconfig the virtual IP, and start httpd. This sequence can easily be specified in /etc/cltab.

Any time Cluster::Init changes the runlevel of a resource group, it will update a status file, /var/run/clinit/clstat by default. This file can be read directly or via the status() method, below.

You can specify tests to be performed during startup of a resource group: In addition to the init-style modes of 'once', 'wait', 'respawn', and 'off', Cluster::Init supports a 'test' runmode. If the return code of a 'test' command is anything other than zero, then the resource group as a whole is marked as 'FAILED' in clstat. For example, this 'test' mode is used by OpenMosix::HA to test a node for eligibility before attempting to start a resource group there.

CLINIT SCRIPT

Cluster::Init includes clinit, a script which is intended to be a bolt-in cluster init tool. The script is called like init, with the addition of a new "resource group" argument. See the output of clinit -h.

The first time you execute clinit you will need to use the -d flag only, to start the Cluster::Init daemon.

Once you have the daemon running, use clinit without the -d flag. This will cause it to run as a client only, talking to the daemon via a UNIX domain socket. At this point you will use clinit in roughly the same way you would use the UNIX telinit, in this case commanding resource groups to switch to different runlevels. That's it!

Use the -k flag to tell the daemon and all child processes to shut down gracefully.

CLINIT SCRIPT EXAMPLES

(here we will show an example cltab, some clinit command lines, and the resulting clstat contents -- in the meantime take a look at the contents of t/*)

PUBLIC METHODS

daemon(%parms)

The server-side constructor. Accepts an optional hash containing the paths to the configuration file, socket, and status output file, like this:

  my $init = new Cluster::Init (
      'cltab' => '/etc/cltab',
      'socket' => '/var/run/clinit/init.s'
      'clstat' => '/var/run/clinit/clstat'
			  );

You can also specify 'socket' and 'clstat' locations in the cltab file itself, like this:

# location of socket
:::socket:/tmp/init.s
# location of status file
:::clstat:/tmp/clstat

Settings found in the cltab file override those found in the constructor.

This method opens a UNIX domain socket, /var/run/clinit/init.s by default. Subsequent executions communicate with the first via this socket.

status(group=>'foo',level=>'bar',clstat=>'/tmp/clstat')

This method will read the status file for you, dumping it to stdout. All arguments are optional. If you provide 'group' or 'level', then output will be filtered accordingly. If you specify 'clstat', then the status file at the given pathname wil be read (this is handy if you need to query multiple Cluster::Init status files in a shared cluster filesystem).

In addition to the usual $obj->status() syntax, the status() method can also be called as a class function, as in Cluster::Init::status(clstat=>'/tmp/clstat'). The 'clstat' argument is required in this case. Again, this is handy if you want to query a running Cluster::Init on another machine via a shared filesystem, without creating an Cluster::Init object or daemon here.

shutdown()

Causes daemon to stop all child processes and exit.

tell($resource_group,$runlevel)

This method talks to a running Cluster::Init daemon, telling it to switch the given resource group to the given runlevel.

All processes listed in the configuration file (normally /etc/cltab) which belong to the new runlevel will be started if they aren't already running.

All processes in the resource group which do not belong to the new runlevel will be killed.

Other resource groups will not be affected.

shutdown()

Causes daemon to stop all child processes and exit.

status(group=>'foo',level=>'bar',clstat=>'/tmp/clstat')

This method will read the status file for you, dumping it to stdout. All arguments are optional. If you provide 'group' or 'level', then output will be filtered accordingly. If you specify 'clstat', then the status file at the given pathname wil be read (this is handy if you need to query multiple Cluster::Init status files in a shared cluster filesystem).

In addition to the usual $obj->status() syntax, the status() method can also be called as a class function, as in Cluster::Init::status(clstat=>'/tmp/clstat'). The 'clstat' argument is required in this case. Again, this is handy if you want to query a running Cluster::Init on another machine via a shared filesystem, without creating an Cluster::Init object or daemon here.

PRIVATE METHODS

The following methods are documented here for internal use only. No user serviceable parts inside.

_open_socket()

Opens a client-side socket.

_start_daemon()

Opens server-side socket, starts main event loop, with long-running event watchers for accepting and processing commands from client, child exits, status file maintenance, etc.

_daemon()

Watcher triggered by I/O activity on server socket; calls accept() and sets a watcher for client I/O.

_client()

Watcher triggered by I/O activity on accept()ed client socket; parses text from client and does the right thing.

_tellgroup($group,$level)

Finds the watcher for a particular resource group, and tells it what the new runlevel is. If the watcher isn't running yet, then we start it.

_group()

Watcher triggered by control activity for a resource group; start and/or stop watchers for the individual entries in the group. Maintain master summary of group info.

Setting a runlevel of undef() causes the group to stop all of its processes and cancel its watcher.

_entry()

Watcher triggered by control activity for an individual cltab entry; start or stop process accordingly. Will also be triggered indirectly by signals, via _sigchld.

Each entry gets an active watcher, all the time, regardless of whether the entry is for a currently active runlevel or not.

If the cltab entry for a given watcher disappears, then the watcher kills its own process and cancels itself.

BUGS

AUTHOR

Steve Traugott
CPAN ID: STEVEGT
stevegt@TerraLuna.Org
http://www.stevegt.com

COPYRIGHT

Copyright (c) 2003 Steve Traugott. All rights reserved. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.

The full text of the license can be found in the LICENSE file included with this module.

SEE ALSO

perl(1).