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.
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.
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
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:
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.
ProcessManager can be downloaded from the following location:
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.
Installing ProcessManager is done as follows:
tar -zxvf ProcessManager-0.0.4.tar.gz cd ProcessManager-0.0.4 python setup.py install
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:
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.
Please feel free to send questions, comments, bug reports, and other correspondence regarding ProcessManager to firstname.lastname@example.org.
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.