view README @ 6:a1e629ed86fc default tip

Added 'env' and 'logFile' options to Process constructor.
author Atul Varma <varmaa@toolness.com>
date Sun, 02 Sep 2012 04:40:21 +0000
parents 3f775e3235fb
children
line wrap: on
line source

.. -*- coding: utf-8 -*-

===========================================
 ProcessManager: Simple Process Management
===========================================

.. contents::
.. sectnum::

Introduction
============

What is ProcessManager?
-----------------------

ProcessManager is a simple Python-based solution for
managing--starting, stopping, and restarting--any process or
collection of processes that provide services for an indefinite period
of time (e.g., a server or daemon) on a Unix-based OS.

Why use ProcessManager?
-----------------------

Unix-based operating systems provide a variety of tools for managing
server and daemon processes. In general, these tools involve a
daunting variety of shell scripts, command-line utilities,
configuration files, and directory heirarchies.  Furthermore, the
specifics of the tools vary from platform to platform. While managing
a service that has already been pre-configured "out of the box" may be
relatively simple, configuring a new service to be stopped, started,
and restarted inevitably requires a thorough understanding of all the
specific tools involved.

ProcessManager attempts to mitigate these problems by using *one* tool
to get the job done.  Python's eminent readability, ease of use,
and robust support for systems programming tasks make it an ideal
candidate for this role.

That said, ProcessManager is not intended to be used as a replacement
for an operating system's existing init system. This will be
clarified in the example below.

A ProcessManager Example
------------------------

The best way to illustrate ProcessManager is through an
example. Suppose we have two simple service applications called
``foo`` and ``bar``, each of which have their own specific
configuration parameters: they need to be executed under service
accounts for security reasons, they have their own configuration
files, and so forth.

A simple Python script serves the dual role of configuration file
and command-line process management utility::

  #! /usr/bin/env python

  import ProcessManager
  from ProcessManager import Process

  # dataDir is where all intermediate data files are stored.
  ProcessManager.init( dataDir = "/var/ProcessManager" )

  ProcessManager.add( Process(
    name = "foo",
    desc = "my foo server",
    program = "/usr/local/bin/foo",
    args = ["--config-file=/etc/foo.conf"],
    workingDir = "/var/foo",
    uid = "nobody",
    gid = "nobody"
    ))

  ProcessManager.add( Process(
    name = "bar",
    desc = "my bar server",
    program = "/usr/local/bin/bar",
    args = ["--port=8082", "--no-daemon"],
    workingDir = "/var/bar",
    uid = "www",
    gid = "www"
    ))

  ProcessManager.main()

Assume this Python script is called ``my-servers.py``.  Running this
script with no parameters will result in the following help text::

  usage:
    my-servers.py <target> <command> [options]

  targets:
    foo                  my foo server
    bar                  my bar server
    all                  (this target applies the command to all
                         of the above targets)

  commands:
    status               show status of the target
    start                start the target
    stop                 stop the target
    restart              restart (stop, then start) the target

  options:
    -h, --help           show this help message and exit
    -e, --enable-stderr  enable output of starting target's stderr to console
    -o, --enable-stdout  enable output of starting target's stdout to console
    -v, --version        print version information and exit

Invoking ``my-servers.py all status`` results in the following::

  foo                            stopped
  bar                            stopped

Invoking ``my-servers.py foo start`` results in the following::

  Launching foo...               OK

Note that there would be a noticeable delay before the text ``OK``
appeared, as ProcessManager would be launching the process.  If the
process failed to launch for some reason, the word ``FAILED`` would
have appeared instead.

Now, invoking ``my-servers.py all status`` again results in the
following::

  foo                            running
  bar                            stopped

If at any point ``foo`` stops running via a mechanism other than
``my-servers.py foo stop``, the following will be displayed::

  foo                            crashed
  bar                            stopped

Support for rc-scripts
----------------------

The above example is useful for ad-hoc and development purposes, but
production services ultimately need to become part of the underlying
OS's init system, which ProcessManager is not intended to
replace. Rather, ProcessManager can be used to augment it.

At present, such support is limited to operating systems that use
rc-scripts, such as System V, NetBSD, and Linux. The rest of this
section assumes that this is the case.

The above example, ``my-servers.py``, can be seamlessly converted into
a multi-purpose rc-script by changing its last line to the following::

  ProcessManager.rcScriptMain()

Assuming we want to integrate the services ``foo`` and ``bar`` with
the underlying init system, we simply create symbolic links
``/etc/init.d/foo`` and ``/etc/init.d/bar``, both of which point to
``my-servers.py``.  Executing ``/etc/init.d/foo`` now results in the
following::

  usage:
    foo <command> [options]

  This script controls my foo server.

  commands:
    status               show status of the target
    start                start the target
    stop                 stop the target
    restart              restart (stop, then start) the target

  options:
    -h, --help           show this help message and exit
    -e, --enable-stderr  enable output of starting target's stderr to console
    -o, --enable-stdout  enable output of starting target's stdout to console
    -v, --version        print version information and exit

Executing ``/etc/init.d/bar`` results in a similar display tailored to
the ``bar`` target. Both scripts can now be integrated with the
underlying operating system's init system.

Obtaining the latest version
============================

ProcessManager can be downloaded from the following location:

  http://www.humanized.com/ProcessManager/ProcessManager-0.0.4.tar.gz

Prerequisites
=============

ProcessManager has been tested on Python 2.4, though it may work with
earlier versions.  There are no other requirements for running
ProcessManager, save that the operating system it is running on be
Unix-based.

Installation
============

Installing ProcessManager is done as follows::

  tar -zxvf ProcessManager-0.0.4.tar.gz
  cd ProcessManager-0.0.4
  python setup.py install

Usage
=====

Please see "A ProcessManager Example", above, for basic instructions
on using this tool.

For the time being, the best source of further documentation can be
found via pydoc.  Just execute the following at the command line::

  pydoc ProcessManager

Limitations
===========

ProcessManager has fairly limited functionality. Among its
limitations:

  * It can't run processes that attempt to fork or daemonize on their
    own.

  * ProcessManager has no way of *really* knowing if a spawned process
    successfully launched; it simply checks to see if the process
    still exists 5 seconds after it was launched, and if so, it deems
    the process launch to be successful. However, it should also be
    noted that a number of existing rc-scripts operate under similar
    conditions.

  * It has no conception of dependency order (e.g., specifying that
    process A depends on process B).

  * It is incapable of launching services in parallel.

In the future, ProcessManager may be extended to address these
limitations.

Contact Information
===================

Please feel free to send questions, comments, bug reports, and other
correspondence regarding ProcessManager to ``atul@humanized.com``.

License
=======

This software is distributed under the following license::

  Copyright (c) 2006, Humanized, Inc.
  All rights reserved.

  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 Humanized, Inc. 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.