Section 20.5. Things That Make It Go


20.5. Things That Make It Go

In order to explain how to integrate an Open Source application server into your system, we have to do a little Linux Sysadmin training. We need to show you how server processes are generally managed on Linux systems.

20.5.1. System V Init System

Virtually all Linux distributions use some variant of the System V init system to create and customize programs and services that run at the startup of the box. Now, we don't want to write a Linux system administration manual, but we do need to tell you enough to decide how to make JBoss available when needed on your server.

The core of the System V init system is the /etc/inittab file. Everything else devolves from this configuration file. In the days before network services, the primary startup tasks were to get getty programs running and then run a single startup shell script. The /etc/inittab file handles these tasks beautifully. Since then, the world of UNIX and Linux has become a complex mixture of client-server programs and protocols, so a complex set of conventions has been developed to turn the primitive /etc/inittab into a much richer set of controls. Let's take a very brief look at /etc/inittab and how it works; then we'll move on to the extended scripts that manage server processes. That is where we will integrate JBoss.

A key concept in the System V init system is the runlevel. The idea is that a system can have a number of "standard" configurations, numbered from 0 to 6, where 0 is shutdown, 1 is single-user, 2 to 5 are up to the system administrator, and 6 is reboot. The init[9] command can be used (by the root user) to change the system from its current runlevel to another:

[9] telinit is a common alias from other UNIX implementations. Linux symlinks this to init.

 # init 1 

What happens when you issue such a command is determined by the /etc/inittab file. Let's take a look at the out-of-the-box /etc/inittab file from a Fedora Core 1[10] system (Example 20.1).

[10] During the writing of this book, RedHat decided to put their completely Free Software OS out to a public-controlled project and to stop calling it "RedHat." The name RedHat is reserved for Fedora-based Linux systems that must be purchased with support contracts. It is still the same system with a different name maintained by basically the same people. The key difference is that you cannot purchase support for Fedora (at least from RedHat, we expect some enterprising folks to offer Fedora support for a fee at some point).

This is a pretty complex file, and we don't want to bog down in it too much, since most of what interests us occurs outside this file.

The basic format of a line in /etc/inittab is:

 id:runlevels:action:process 

The id is a unique 14 character identifier. The runlevels is a list of the runlevel numbers to which the record applies. The action specifies what action is to be taken. The process is the program to run. The respawn action, for example, tells init that when the process exits, it should be run again. The once action says it should be run once on transition to the runlevel. We won't go into too much more here. See the man inittab page for details.

The part that concerns us are the l0 through l6 entries. Note that these cause the /etc/rc.d/rc script to be run once, with the runlevel passed as an argument. This is the key to System V init system.

Example 20.1. Fedora Core 1 default /etc/inittab file
 # # inittab       This file describes how the INIT process should set up #               the system in a certain runlevel. # # Author:       Miquel van Smoorenburg, miquels@drinkel.nl.mugnet.org> #               Modified for RHS Linux by Marc Ewing and Donnie Barnes # # Default runlevel. The runlevels used by RHS are: #   0 - halt (Do NOT set initdefault to this) #   1 - Single user mode #   2 - Multiuser, without NFS #       (The same as 3, if you do not have networking) #   3 - Full multiuser mode #   4 - unused #   5 - X11 #   6 - reboot (Do NOT set initdefault to this) # id:5:initdefault: # System initialization. si::sysinit:/etc/rc.d/rc.sysinit l0:0:wait:/etc/rc.d/rc 0 l1:1:wait:/etc/rc.d/rc 1 l2:2:wait:/etc/rc.d/rc 2 l3:3:wait:/etc/rc.d/rc 3 l4:4:wait:/etc/rc.d/rc 4 l5:5:wait:/etc/rc.d/rc 5 l6:6:wait:/etc/rc.d/rc 6 # Trap CTRL-ALT-DELETE ca::ctrlaltdel:/sbin/shutdown -t3 -r now # When our UPS tells us power has failed, assume we have a few minutes # of power left. Schedule a shutdown for 2 minutes from now. # This does, of course, assume you have powered installed and your # UPS connected and working correctly. pf::powerfail:/sbin/shutdown -f -h +2 "Power Failure; System Shutting Down" # If power was restored before the shutdown kicked in, cancel it. pr:12345:powerokwait:/sbin/shutdown -c "Power Restored; Shutdown Cancelled" # Run gettys in standard runlevels 1:2345:respawn:/sbin/mingetty tty1 2:2345:respawn:/sbin/mingetty tty2 3:2345:respawn:/sbin/mingetty tty3 4:2345:respawn:/sbin/mingetty tty4 5:2345:respawn:/sbin/mingetty tty5 6:2345:respawn:/sbin/mingetty tty6 # Run xdm in runlevel 5 x:5:respawn:/etc/X11/prefdm -nodaemon 

Note

Some Linux distributions run different scripts for each runlevel instead of passing the runlevel as an argument to a single script. The details are not important. The net effect is that a script is run for each runlevel.


Sure, you could put the code to run JBoss directly in that script if you want. But these scripts have been designed to handle arbitrary sets of services without you having to modify those scripts directly. How? By doing what Linux (and its UNIX antecedents) does so well: making complex systems out of simple parts.

Each service you might wish to start and stop gets a shell script that controls it. This shell script must take a command argument. The minimum set of commands that must be supported are start and stop. Other options such as restart and status are often supported, but start and stop are the important ones.

The script for atd, the one-shot job scheduler, is a fine example. Let's take a look at it (Example 20.2).

Example 20.2. The atd init shell script
 #!/bin/bash # # /etc/rc.d/init.d/atd # # Starts the at daemon # # chkconfig: 345 95 5 # description: Runs commands scheduled by the at command at the \ #    time specified when at was run, and runs batch commands when \ #    the load average is low enough. # processname: atd # Source function library. . /etc/init.d/functions test -x /usr/sbin/atd || exit 0 RETVAL=0 # # See how we were called. # prog="atd" start() {   # Check if atd is already running   if [ ! -f /var/lock/subsys/atd ]; then     echo -n $"Starting $prog: "     daemon /usr/sbin/atd     RETVAL=$?     [ $RETVAL -eq 0 ] touch /var/lock/subsys/atd     echo   fi   return $RETVAL } stop() {   echo -n $"Stopping $prog: "   killproc /usr/sbin/atd   RETVAL=$?   [ $RETVAL -eq 0 ] && rm -f /var/lock/subsys/atd   echo     return $RETVAL } restart() {   stop   start } reload() {   restart } status_at() {   status /usr/sbin/atd } case "$1" in start)   start   ;; stop)   stop   ;; reload|restart)   restart   ;; condrestart)   if [ -f /var/lock/subsys/atd ]; then     restart   fi   ;; status)   status_at   ;; *)   echo $"Usage: $0 {start|stop|restart|condrestart|status}"   exit 1 esac exit $? exit $RETVAL 

This script is from a RedHat Linux system. Those comments at the top are a magic incantation for the chkconfig program that ships with that distribution[11] (and with Fedora Core). We'll talk more about chkconfig in the next section.

[11] The RedHat chkconfig program is conceptually similar to the one in the IRIX operating system.

As you can see, the basic premise is that when a daemon is started, the process ID is saved into a file. If the "stop" option is passed, the PID is looked up and the process is killed. That's the basic idea. But wait! There's more!

Each runlevel has a directory of scripts. Let's look at the contents of such a directory (Example 20.3).

Example 20.3. A directory of scripts
 [mschwarz@host238 mschwarz]$ cd /etc/rc5.d [mschwarz@host238 rc5.d]$ ls K01yum         K73ypbind           S18rpcgssd     S58ntpd K05saslauthd   K74nscd             S19rpcidmapd   S80sendmail K11jboss       K89netplugd         S19rpcsvcgssd  S80spamassassin K12mysqld      S00microcode_ctl    S20random      S85gpm K15httpd       S04readahead_early  S24pcmcia      S90crond K15postgresql  S05kudzu            S25netfs       S90vmware K20nfs         S06cpuspeed         S26apmd        S90xfs K24irda        S08iptables         S28autofs      S95anacron K35smb         S09isdn             S40smartd      S95atd K35vncserver   S10network          S44acpid       S96readahead K35winbind     S12syslog           S55cups        S97messagebus K36lisa        S13irqbalance       S55sshd        S97rhnsd K50snmpd       S13portmap          S56rawdevices  S99local K50snmptrapd   S14nfslock          S56xinetd 

Notice the file S95atd? Let's look at the long form ls output for that file:

 [mschwarz@host238 rc5.d]$ ls -la S95atd lrwxrwxrwx  1 root   root   13 Feb  2 02:08 S95atd -> ../init.d/atd 

The file is a symbolic link to the file in the init.d directory! If you take a look at the actual script run by the /etc/inittab file on a runlevel change, you will notice that what it does is to pick up all the files in the rcX.d directory (where X is the runlevel being changed to[12]) that begin with the letter K, run through them in numerical order, and execute the linked scripts with stop as the argument. It then picks up all the files that begin with S, runs through them in numerical order, and executes the linked scripts with start as the argument.

[12] That phrase actually caused my high school grammar teacher to materialize in my office and scold me. I invite anyone who can come up with an elegant and grammatical way to phrase that to contact me at mschwarz@multitool.net. I'm perfectly serious.

This sounds like a mess, but it is actually a very nice way to automate the starting and stopping of services by runlevel. Adding or removing a new service is simply a matter of creating the /etc/init.d script, and then adding the appropriate symlinks to the rcX.d directories.[13] So, first we have to take an init script and modify it to run JBoss.

[13] Just a quick reminder that not all Linux distributions name their directories or scripts in precisely the same way, but they all use something similar. By examining the /etc/inittab file and the contents of the /etc directory, you should be able to figure out the details of any given distribution. Over time, more and more distributions have come to exactly match the naming scheme described here. RedHat, Fedora, and Debian, for example, all follow this naming scheme.

20.5.2. RedHat/Fedora chkconfig

RedHat and its stepchild, Fedora, use a program called chkconfig to automate the setup and integration of init scripts.

The chkconfig program has four basic functions. Two involve adding and removing services from management. That's our main interest here, but we'll get to that in a moment. The other two involve querying and setting the runlevels in which services run. That is the more common use, so we'll look at those first.

 [root@host238 root]# chkconfig --list ntpd ntpd           0:off   1:off   2:off   3:on    4:off    5:on    6:off 

Tip

chkconfig --list without specifying a service name will list all the services managed by chkconfig, including those that are provided by xinetd, which we will not cover here.


As you can see, ntpd runs at runlevels 3 and 5, and does not run at any others. The --list argument lets you query the runlevels.

 [root@host238 root]# chkconfig --levels 2345 ntpd on [root@host238 root]# chkconfig --list ntpd ntpd           0:off   1:off   2:on    3:on    4:on   5:on   6:off 

The --levels argument lets you specify a list of runlevels that will apply to the named service. The last argument may be on or off to specify which setting to apply to those runlevels. The current value (on or off) for a specified runlevel is overwritten by whatever you specify. There is more to this; see the manpage for chkconfig for details.

Now, before we put JBoss under management, we need to make a script for it. Or rather, we need to modify the one provided by JBoss. In the bin subdirectory of JBoss, you will find a script called jboss_init_redhat.sh. You will notice that it has the "chkconfig mojo" in itthat is, the "chkconfig:" comment line. We mentioned this in passing when we looked at the atd init script, but we didn't tell you what those three numbers after the colon actually mean. The first is the list of runlevels in which you want the program to run. The second is the start priority, which is the number that will follow the S in the rcX.d runlevel symlink directory. The third number is the stop priority, which is the number that will follow the K in the rcX.d runlevel symlink directory.

These start and stop priority numbers can be very important indeed. Some services (like NFS) depend upon others (like portmap). Your JBoss server might depend on a service like mysqld or postgresql. Don't toy with these orders lightly. You can seriously mess up your services if you don't know what you are doing. Still, you will probably have to tweak things to get them completely right. Just be cautious and think about every change.

Example 20.4 is the script as it comes with JBoss 3.2.3.

There are three things we have to change here. The first are the runlevels in the "chkconfig:" line (we'll show you the changed lines with a couple of lines of context):

 # # chkconfig: 345 80 20 # description: JBoss EJB Container # 

Next, we may need to change the paths to JBoss and to the Java runtime. In our case, if you installed into /usr/local and created the symbolic link as we suggested, you don't need to change the JBOSS_HOME, but you have to change the JAVAPTH variable:[14]

[14] We are assuming you have set up your Java SDK as described in Chapter 6. If your java* commands are located somewhere else, change this path to point at them.

Example 20.4. Out-of-the-box JBoss init script for RedHat
 #!/bin/sh # # JBoss Control Script # # chkconfig: 3 80 20 # description: JBoss EJB Container # # To use this script, # run it as root - it will switch to the specified user. # It loses all console output - use the log. # # Here is a little (and extremely primitive) # startup/shutdown script for RedHat systems. It assumes # that JBoss lives in /usr/local/jboss, it's run by user # 'jboss' and JDK binaries are in /usr/local/jdk/bin. All # this can be changed in the script itself. # Bojan # # Either amend this script for your requirements # or just ensure that the following variables are set correctly # before calling the script. # [ #420297 ] JBoss startup/shutdown for RedHat # define where jboss is - this is the directory # containing directories log, bin, conf, etc. JBOSS_HOME=${JBOSS_HOME:-"/usr/local/jboss"} # make sure Java is on your path JAVAPTH=${JAVAPTH:-"/usr/local/jdk/bin"} # define the classpath for the shutdown class JBOSSCP=${JBOSSCP:-"$JBOSS_HOME/bin/shutdown.jar:$JBOSS_HOME/client/jnet.jar"} # define the script to use to start jboss JBOSSSH=${JBOSSSH:-"$JBOSS_HOME/bin/run.sh -c all"} if [ -n "$JBOSS_CONSOLE" -a ! -d "$JBOSS_CONSOLE" ]; then   # ensure the file exists   touch $JBOSS_CONSOLE fi if [ -n "$JBOSS_CONSOLE" -a ! -f "$JBOSS_CONSOLE" ]; then   echo "WARNING: location for saving console log invalid: $JBOSS_CONSOLE"   echo "WARNING: ignoring it and using /dev/null"   JBOSS_CONSOLE="/dev/null" fi # define what will be done with the console log JBOSS_CONSOLE=${JBOSS_CONSOLE:-"/dev/null"} # define the user under which JBoss will run, # or use RUNASIS to run as the current user JBOSSUS=${JBOSSUS:-"jboss"} CMD_START="cd $JBOSS_HOME/bin; $JBOSSSH" CMD_STOP="java -classpath $JBOSSCP org.jboss.Shutdown --shutdown" if [ "$JBOSSUS" = "RUNASIS" ]; then   SUBIT="" else   SUBIT="su - $JBOSSUS -c " fi if [ -z "`echo $PATH | grep $JAVAPTH`" ]; then   export PATH=$PATH:$JAVAPTH fi if [ ! -d "$JBOSS_HOME" ]; then   echo JBOSS_HOME does not exist as a valid directory : $JBOSS_HOME   exit 1 fi echo CMD_START = $CMD_START case "$1" in start)     cd $JBOSS_HOME/bin     if [ -z "$SUBIT" ]; then         eval $CMD_START ${JBOSS_CONSOLE} 2>1     else         $SUBIT "$CMD_START ${JBOSS_CONSOLE} 2>1 "     fi     ;; stop)     if [ -z "$SUBIT" ]; then         $CMD_STOP     else         $SUBIT "$CMD_STOP"     fi     ;; restart)     $0 stop     $0 start     ;; *)     echo "usage: $0 (start|stop|restart|help)" esac 

 # define where JBoss is - this is the directory # containing directories log, bin, conf, etc. JBOSS_HOME=${JBOSS_HOME:-"/usr/local/jboss"} # make sure Java is on your path JAVAPTH=${JAVAPTH:-"/usr/java/jdk/bin"} 

Finally, we don't need to run the "all" configuration, we only need the default configuration at the moment, so we change the argument to the run.sh invocation:

 # define the script to use to start JBoss JBOSSSH=${JBOSSSH:-"$JBOSS_HOME/bin/run.sh -c default"} 

JBoss Configurations

When you unpacked JBoss, it contained three predefined server configurations located in jboss/server. The three configurations are named all (which runs every single service JBoss supports, including RMI/IIOP and clustering features), default (which runs only the set needed to run servlets, JSP, and EJBs), and minimal (which runs just JNDI, the logger, and a URL deployment service; no Web container, no JMS, no EJBs).

In effect, the selected configuration is the server. You can, of course, customize any configuration, and you may create additional configurations.


Now, this script allows you to run JBoss as any user. It defaults to user jboss if none is specified. You have to decide what to do here. Without specifying a user, it will run as root. That is a major security risk. On an out-of-the-box RedHat or Fedora system, there is no user called jboss. We will have to create one. There are a lot of security concerns to creating a special "nonlogin" user. The most important involve changing the user entries in /etc/passwd and /etc/shadow after you create the user. Unfortunately, the JBoss program needs to run a shell script, so you cannot set the shell to /sbin/nologin as is usual. Set the password for the user in /etc/shadow to x, which is completely invalid and will forbid login to the account by password.

Example 20.5. Using chkconfig to include JBoss start script
 [root@cvs root]# cd /usr/local/jboss/bin [root@cvs bin]# cp jboss_init_redhat.sh /etc/init.d/jboss [root@cvs bin]# chkconfig --add jboss [root@cvs bin]# chkconfig --list jboss jboss           0:off 1:off 2:off 3:on          4:on    5:on    6:off [root@cvs bin]# /etc/init.d/jboss start CMD_START = cd /usr/local/jboss/bin; /usr/local/jboss/bin/run.sh -c default 

Finally, you will need to add the user jboss to any groups you created for JBoss management (such as local in our case). Truth be told, it would be a good idea to use the jboss user to install JBoss. It will avoid having to deal with some file ownership and permission issues. If you do not do this, the simplest way to get this init script working (you will get permission errors) is to run

 chmod -R g+w /usr/local/jboss 

That will make the script work with the jboss user, provided jboss belongs to the group owner of the JBoss installation.

The final step is to copy your modified script to its final destination and run chkconfig to install it in all the runlevels (Example 20.5).

You now have JBoss running. You can start and stop it with the script, and it will come up and shut down automatically depending on the runlevel you switch to. Beauty, eh?

20.5.3. Other Distributions

You don't need chkconfig to set up equivalent scripts. In fact, the same script provided by JBoss for RedHat will work with most distributions that use System V init system. You will have to copy the init script and then create the appropriate symlinks manually, or locate the automated setup tools for your particular distribution (Debian, for example, has many such tools which you select with their package management system).

20.5.4. IDE Integration

Another piece of software you might want to look at is JBoss-IDE,[15] an Eclipse plug-in for JBoss. The software is not downloadable from the footnoted Web site, it is available only from the Eclipse Install/Update manager, so run your copy of Eclipse and install it. We will not cover JBoss-IDE here, but if you use Eclipse as your development platform, JBoss-IDE is very useful for managing and deploying EJB's, servlets, and JSP.

[15] http://www.jboss.org/developers/projects/jboss/jbosside



    Java Application Development with Linux
    Java Application Development on Linux
    ISBN: 013143697X
    EAN: 2147483647
    Year: 2004
    Pages: 292

    flylib.com © 2008-2017.
    If you may any questions please contact us: flylib@qtcs.net