Cover V11, I07

Article
Figure 1

jul2002.tar

Using Depot to Create a Centralized, Flexible, and Manageable Software Repository

Bob Jobsky

Do you wish you had a centralized software repository on one server for all flavors of UNIX? And that you could associate each file with the utility it belongs with? And have multiple versions of the same software on the same system? And thatyour users could install their own software versions without using disk space? For free? These features and more are possible using a utility called depot (http://ftp.andrew.cmu.edu/pub/depot/), which has not changed since version 5.13 in 1995.

Depot alone is not enough, however. In this article, I will outline how to combine depot with the use of NFS, wrappers, and a chrooted environment to easily implement a very flexible and manageable UNIX software repository. Within a day, it's possible to complete the setup and start populating the repository with your favorite packages.

Overview

Depot is central to the success of the software repository. It is used to create a virtual directory tree of symbolic links that point to the actual locations of the software packages that make up your repository. The real repository can be centralized on one file server or distributed across several servers. I describe the one server approach here. Each version of each package for each OS gets its own directory on the server. Each client then has a depot.pref configuration file that instructs depot how to create the symbolic links in its virtual directory tree. Depot superimposes the links for all the software packages into one directory tree. The result is a single entry in the PATH variable, yet each package is in its own "space" on one server making package management much easier.

Figure 1 shows the scalable directory structure of a depot server and the relationship of the virtual repository on a depot client to the depot server. All directories and symbolic links within the virtual repository are managed by the depot utility through entries made in the depot.pref file on the client. In the sample depot.pref file of Figure 1, the third column specifies the top-level directory trees that are mapped into the top level of the virtual repository. To have version 5.8 of vim available for use on Solaris 8 hosts, you first populate the repository on the depot server using one of the methods described in the section "Four Methods to Add a Utility to the Repository" below. If you used method 4, the resulting vim install tree would then get moved to /export/disk1/software/vim/5.8/sol8. Then, on each Solaris 8 depot client, add the entry path vim /depot/depot_server/depot/vim/5.8/sol8 to the /abc/depot/depot/depot.pref file and run the depot utility. All the symlinks will be automatically created and vim will then be available in the /abc/depot/bin directory.

I am currently working for a startup that is almost exclusively Solaris except for a few Linux hosts. Therefore, the details described below are mostly for the Solaris operating system. There will be minor differences with other flavors of UNIX. Since my company does have a few Linux hosts, and plans to add more, I have verified this technique on Linux, though I have not yet rolled it out to the development environment. As long as depot can be compiled, and a chroot environment created, this technique should port to any flavor of UNIX.

Disk Space

The required file server disk space depends on many factors. You should plan on reserving at least 2 GB per OS version. Keep in mind that you want your file server to hold the original downloaded packages and tarballs, the installed directory trees, as well as a chroot directory tree for each version of the OS. My chroot directory trees alone are about 500 MB each for Solaris 2.5, 2.6, 7, and 8. My Linux chroot directory tree is 830 MB, but could be significantly reduced if disk space was more of a concern than the time required to optimize the chroot environment.

Directory Structure

On the repository file server, create a software directory with the top-level directory structure shown in Figure 1. For this article, I assume the software directory is a subdirectory of /export/disk1.

Export this directory to your network. Here is a sample dfstab entry for a Solaris host:

share -F nfs -o \
rw=@10.1.1.0,root=bld_hst_os1.domain.com:bld_hst_os2.domain.com /export/disk1/software
Note that you will need to allow root access to one host for each OS version you plan on supporting in the repository. These "build hosts" need to chroot into directories that are created later.

On each client, create the directories /abc/depot/depot and /depot/depot_server where abc is a short abbreviation for your company or organization. Here, /abc/depot will be the top of the virtual directory tree of symlinks created by depot, and /depot/depot_server will be the automount point to the real repository on the file server.

After reading this article, you may be tempted to use /usr/local for the top of the virtual directory tree. I urge you not to use /usr/local or any other path that is a default for precompiled packages. If you do, then you will not be able to install any precompiled Solaris packages independently of the depot.

Now, make the automount entries. Add the following line to /etc/auto_master:

/depot        auto_depot
Then create /etc/auto_depot and add the line:

depot_server        depot_server:/export/disk1/software/depot
Since these mounts might be in constant use, you could make them permanent instead by adding equivalent entries to the vfstab file.

Also, on each build host, create a directory /software. Note that it is possible for the file server to also be a client and a build host.

Creating a chroot Environment

Unfortunately, there are some packages that need to be compiled for and installed into their final resting places. They will not work if they are later relocated. Other packages have environment variables that are supposed to allow relocation but occasionally fail to work properly if moved. I had such problems with emacs. For these types of packages, you need to supply the prefix=/abc/depot option to the configure utility. However, since your build host is most likely a client as well, its /abc/depot directory is where all of the depot's symlinks are. Executing make install will superimpose the package's real files into depot's virtual tree.

Unless you can afford the luxury of a dedicated build host for each OS version so the build host does not need the /abc/depot virtual directory tree, you will have to create a chroot environment so you can have an empty /abc/depot directory. I recommend placing these chroot environments on the file server since it probably has plenty of available disk space and any host can become a build host simply by modifying the root access list of the exported share on the depot server.

Unlike a minimal chroot environment for Internet services described in "Jailed Internet Services" by Liam Widdowson (Sys Admin magazine, August 2001), this chroot environment needs to be very robust to compile the variety of apps that are available. Simple scripts are provided below, which create Solaris and Linux chroot environments that are practically a copy of the real OS. You will first need to mount the /export/disk1/software directory on the filer to /software on the build host. The build host will need root privileges on the mount point. The script runs on the build host:

#!/bin/sh
# Make a Solaris 8 chroot environment.
OSVERSION=sol8 ; export OSVERSION
CHROOTHOME=/software/chroot/$OSVERSION ; export CHROOTHOME
DOWNLOADHOME=/software/downloads ; export DOWNLOADHOME
mkdir -p $CHROOTHOME
cd $CHROOTHOME
mkdir -p usr/dt usr/local var/tmp tmp builds abc/depot
ln -s ./usr/bin bin
ln -s ./usr/lib lib
cd /
tar cf - sbin etc platform kernel devices | ( cd $CHROOTHOME ; tar xf - )
ufsdump 0ubf 126 - /dev | ( cd $CHROOTHOME ; ufsrestore rbf 126 - )
rm $CHROOTHOME/restoresymtable
cd /usr
tar cf - bin lib ccs openwin ucb sbin share include | ( cd $CHROOTHOME/usr ; tar xf - )
cd /usr/dt
tar cf - lib include share | ( cd $CHROOTHOME/usr/dt ; tar xf - )

pkgadd -n -R $CHROOTHOME -d $DOWNLOADHOME/make-3.79.1-$OSVERSION-sparc-local
pkgadd -n -R $CHROOTHOME -d $DOWNLOADHOME/gcc-2.95.3-$OSVERSION-sparc-local
pkgadd -n -R $CHROOTHOME -d $DOWNLOADHOME/perl-5.6.1-$OSVERSION-sparc-local
pkgadd -n -R $CHROOTHOME -d $DOWNLOADHOME/bash-2.05-$OSVERSION-sparc-local
pkgadd -n -R $CHROOTHOME -d $DOWNLOADHOME/gzip-1.3-$OSVERSION-sparc-local
pkgadd -n -R $CHROOTHOME -d $DOWNLOADHOME/zlib-1.1.3-$OSVERSION-sparc-local

#!/bin/bash
# Make a Linux 2.4 kernel chroot environment
OSVERSION=lnx24 ; export OSVERSION
CHROOTHOME=/software/chroot/$OSVERSION ; export CHROOTHOME
mkdir -p $CHROOTHOME
cd $CHROOTHOME
mkdir -p usr/X11R6 usr/bin usr/share usr/lib usr/libexec usr/sbin usr/include \
  sbin bin lib var/tmp tmp builds abc/depot
cd /
tar cf - sbin bin lib etc var | ( cd $CHROOTHOME ; tar xf - )
dump 0bf 64 - /dev | ( cd $CHROOTHOME ; restore rbf 64 - )
rm $CHROOTHOME/restoresymtable
cd /usr
tar cf - X11R6 bin lib libexec sbin share include | ( cd $CHROOTHOME/usr ; tar xf - )
You may need to add additional packages and utilities to the chroot environment to be able to compile every package you want. For example, I found I later needed to install tk and tcl. I also found that some packages required the existence of X header files. For Linux, I needed to install byacc in order to compile depot. Just be sure NOT to install these permanent packages into the /abc/depot directory. The sole purpose of this chroot environment is to have a clean /abc/depot directory, so you can make install a package into it and then relocate it into the real software repository outside the chroot environment.

If your OS does not have prebuilt packages available for GNU tools, you will need to find some other way to get them into your chroot environment. Copying /usr/local or whatever directory tree your tools are currently in is probably the easiest method. Unfortunately, this directory tree may be huge and contain gigabytes of unneeded packages. This is the exact problem depot will solve for you, once it is set up. For now, you may have to build them from scratch into the chroot environment.

Adding the Depot Utility to the Software Depot

The first utility that is added to the software depot is depot itself. Depot is not available as a package for Solaris, so it needs to be compiled. It can be compiled in the chroot environment using method 3 as described below. The GNU make utility and a compiler are required to install depot. Also, gzip is required when running the depot command to update the virtual repository. Because these three utilities are able to be relocated, it is possible to install each into the real repository using one of the four methods below. Each utility's bin directory then needs to temporarily be added to the PATH variable. After depot is installed and the virtual directory updated, entries for the three utilities can be added to the depot.pref file and another update performed. After this update, links for gzip, depot, make, and gcc should exist in /abc/depot/bin so the temporary PATH entries can be replaced with /abc/depot/bin.

Four Methods to Add a Utility to the Repository

There are four basic methods to add a utility to the repository. Before discussing the details, you must make a decision in each of the four methods: Should the utility be added once for an older OS version and then, if possible, used by later OS versions? Or should the utility be added for each version of the OS? Since disk space is not a concern for me, but repository consistency and organization are, I always choose to add a separate instance of the utility even if, for example, the Solaris 2.5 binaries will work on Solaris 8. The only exception is if there is a precompiled version for Solaris 2.5 and not any later version.

Method 1

The easiest and quickest method to install a utility is by using the package-management utilities of the OS on precompiled binary packages. The requirements of this method are:

  • The package management utility needs to have relocation options so that the directory where the package will be installed can be specified. Solaris's pkgadd utility achieves this with the -R option. Note that Red Hat Linux's rpm utility has a similar option but I found that every rpm I tried to install in an alternate directory reported that the package could not be relocated.
  • Package management utilities have a directory or database in which package information is stored. This must be able to be relocated to allow for installation of multiple versions of the same package for multiple OS versions. Solaris's packadd utility meets this requirement by placing the package information in the var directory under the root directory specified by the -R option.
  • The utility itself must be able to be relocated. Many prepackaged utilities are available at http://www.sunfreeware.com. By default, they are compiled and packaged to run under /usr/local. Even though pkgadd can relocate the utility, it may not run from /abc/depot. If this is the case, the utility must be compiled in the chroot environment as described in method 4 below.

To add the precompiled Solaris 2.5 tk package to the repository, execute the following on a Solaris build host. Note that the build host for this method can be any version of Solaris since the downloads directory is located on the file server and is common to all build hosts:

mkdir -p /software/depot/tk/8.3.3/sol25
pkgadd -R /software/depot/tk/8.3.3/sol25 -d /software/downloads/tk-8.3.3-sol25-sparc-local
Now add the following line to the /abc/depot/depot/depot.pref file on any Solaris 2.5 client that needs tk:

path    tk              /depot/depot_server/tk/8.3.3/sol25/usr/local
Update the virtual repository on each Solaris 2.5 client by executing:

/abc/depot/bin/depot -u -T /abc/depot   # unlock the repository
/abc/depot/bin/depot -T /abc/depot      # Do the update
Document the install in a /software/notes/tk.8.3.3.install file.

Method 2

The next easiest method to install a utility is simply an extension to method 1. Basically, some precompiled packages can be relocated only if environment variables are set that override the default location for which the package was previously compiled. In this case, a wrapper script must be created for the executable.

As in method 1, install the package into the repository. Here I use the less utility as an example for Solaris 7. The precompiled less package expects the terminfo directory to be located in /usr/local/share/terminfo. However, if the ncurses package is installed using method 1, its virtual location will be in /abc/depot/share/terminfo. Here are the steps:

mkdir -p /software/depot/less/358/sol7
pkgadd -R /software/depot/less/358/sol7 -d /software/downloads/less-358-sol7-sparc-local
Rename the less executable and add a symlink to the wrapper:

cd /software/depot/less/358/sol7/usr/local/bin
mv less less.pkg
ln -s /abc/depot/wrappers/less.wrapper less
Create the wrapper:

cd /software/depot/wrappers/wrappers
vi less.wrapper
chmod 755 wrapper
cat less.wrapper

#!/bin/sh
TERMINFO=/abc/depot/share/terminfo
export TERMINFO
LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/abc/depot/lib
export LD_LIBRARY_PATH
exec /abc/depot/bin/less.pkg "$@"
Add the following line to the /abc/depot/depot/depot.pref file on any Solaris 7 client that needs less:

path    less            /depot/depot_server/less/358/sol7/usr/local
Note that for the first wrapper script, you also must add the following line to the depot.pref file. This same entry will automatically update any additional scripts added to the wrappers directory during future installs:

path    wrappers     /depot/depot_server/wrappers
Update the virtual repository on each Solaris 7 client as described in method 1 and document the install in /software/notes/less-358.install.

Method 3

The third method to install a utility is used when the utility can be relocated but is not available in a precompiled package format. I seldom use this method because installation is nearly as much work as for method 4; and method 4 will always work whereas there is a chance this method will not. If it turns out the utility cannot be relocated, you will need to repeat the installation using method 4.

The one utility for which I do use this method is depot itself. Because the depot binary can be relocated, it can be installed directly into the real repository, even though it will be run from the virtual directory /abc/depot/bin.

This method must be performed on a build host with the same OS version as the destination repository. In this example, the build host must be Solaris 2.6:

mkdir /software/depot/depot/5.13/sol26
mkdir /builds ; cd /builds
tar xf /software/downloads/depot-5.13.tar
cd depot-5.13
export CC=gcc
./configure --prefix=/software/depot/depot/5.13/sol26 --exec-prefix=/software/depot/depot/5.13/sol26
make
make install
Note that yacc and ar are needed to compile depot. For Red Hat Linux 7.2, I needed to install the byacc rpm to have yacc available.

Add the following line to the /abc/depot/depot/depot.pref file on any Solaris 2.6 client that will be using the depot repository:

path    depot           /depot/depot_server/depot/5.13/sol26
Update the virtual repository on each Solaris 2.6 client as described in method 1. However, in this example, depot is the first utility to be added to the virtual repository. /abc/depot/bin does not yet exist. Therefore, depot's absolute path must be used just this once. Also, there is no depot database to unlock so running depot with the -u option can be skipped:

/software/depot/depot/5.13/sol26/bin/depot -T /abc/depot
Document the install.

Method 4

The fourth possible method to install a utility is the most universal and also the most time consuming. However, if there is no precompiled binary package, or the utility can't be relocated, or you simply want to be in control of the parameters you compile with, this is the method to use. For some flavors of UNIX, this may be the only method that can be used for all utilities. Keep in mind, though, that after you compile and install once, all clients will have access to the utility just by making the appropriate entry to the depot.pref file. A little work up front will have a big payoff later.

The basic concept for this method is to compile and install the utility in a chroot environment where /abc/depot is an empty directory. Then the install tree is relocated to the real repository outside the chroot environment. When the depot is updated, symlinks will be created under /abc/depot to the real repository. This allows the utility to believe it is running from the location for which it was compiled.

Because the packaged version of cvs on http://www.sunfreeware.com is two-years old, I decided to install the latest version using this method:

cp /software/downloads/cvs-1.11.1p1.tar.gz  /software/chroot/sol8/builds
Now change to the chroot environment on the build host, compile, and install:

chroot /software/chroot/sol8 /bin/bash
cd /builds
gunzip cvs-1.11.1p1.tar.gz
tar xf cvs-1.11.1p1.tar
cd cvs-1.11.1p1
./configure --prefix=/abc/depot --without-gssapi
make
make install
At this point, the make install should have created a directory tree under the chrooted /abc/depot. Exit the chroot environment and relocate the entire cvs install tree to the cvs V1.11.1p1 repository:

exit
mkdir -p /software/depot/cvs/1.11.1p1/sol8
mv /software/chroot/sol8/abc/depot/* /software/depot/cvs/1.11.1p1/sol8
Now add the following line to the /abc/depot/depot/depot.pref file on any Solaris 8 client that will be using cvs:

path    cvs             /depot/depot_server/cvs/1.11.1p1/sol8
Update the virtual repository on each Solaris 8 client as described in method 1, and don't forget to clean up the chroot environment and document.

Documentation

Although brief, this section is as important as all the other sections combined. For every hour you save in administration time by using the software repository, you will save another hour by taking a few minutes to document each and every utility you install. Almost every utility has its installation quirks, whether or not depot is used as described in this article. Even if an install goes cleanly, it is worthwhile to document that fact.

Even though many people like to document by installing within a script session, I like to work in three to four open windows simultaneously. I find it easiest to cut and paste my commands into an editor as I proceed. When I finish installing a utility for one version of Solaris, I simply cut and paste out of my install notes to install the other Solaris versions of the utility, making slight modifications where necessary. Whatever your documentation style is, please create a file "pkgname.version.install" in the /software/notes directory and place your commands in it.

Comments

A common problem when updating your repository's symlinks with the depot command involves errors about unresolved conflicts. These are due to identically named files in two repositories trying to exist in the same virtual directory space. For example, many make installs will place a "dir" file in the info directory. Rename all but the emacs "dir" file to dir.utility, then copy the pertinent lines from "dir.utility" to the emacs "dir". Similarly, some installs put their documentation directly into the doc directory. Create a subdirectory of doc named "utility", then move all the documentation files to it.

Some utilities are replacements for standard OS utilities, but usually more efficient and powerful. If they are placed in the /abc/depot repository and /abc/depot/bin is first in your PATH, some problems may occur by using the replacement version instead of the standard OS version. In this case, create two virtual repositories -- one contains symlinks to utilities needed at the front of the PATH, while the other virtual repository contains symlinks needed at the end of the PATH variable.

Taking the last comment a step further, note that many virtual repositories can be created on the same client using almost no disk space while having only a single real repository on the file server. Each virtual repository might contain different combinations or versions of utilities for use by different user groups on the same client. Also, users can use the depot command to create virtual repositories within their home directories, again using very little space. As the administrator, you can populate the real repository with as many different versions of a utility as you want, then let the users modify their depot.pref file(s) to suit their needs. This only works, however, for utilities that are location-independent or able to be relocated through the use of environment variables.

Documenting the contents of a depot.pref file for a particular build can help with configuration management. It is very easy to return a client to a previously known state simply by restoring the depot.pref file to its previous state, which assumes you leave old versions of utilities in the real repository.

Because of security and availability concerns, it may not be desirable or possible to have NFS mounts within a production environment. However, because of the modular nature of the development repository and the depot utility, a very specific subset of the real depot repository can simply be copied to each production server, then the depot.pref file can be configured to point to the local repository instead of the remote one. To ensure the utilities work properly, keep the virtual repository in the same location as in the development environment, namely /abc/depot.

On a similar note, the entire repository can be replicated to various sites. Each site can pick which versions of which utilities to use simply by maintaining the depot.pref files on the clients.

To centralize the management of the depot.pref file, you can write a script that concatenates or merges network, group, and host-specific pieces of depot.pref together and then pushes them out to the depot clients.

For utilities that have config files within the repository, replace the config file in the real repository with a symlink to a local location, then add the real config file to that location on each client.

In the rare event that a utility needs a regular file and not a symlink to exist in the virtual directory, make an entry in the depot.pref file such as:

specialfile            etc/sudoers
Note that I do not recommend placing system-critical utilities into a repository unless the repository is local to the host.

To switch between versions of a utility on a host, simply change the entry in the depot.pref and rebuild the virtual repository with the depot command.

I have set up an email account at depotaid@hotmail.com. Depending on the mail volume and time commitment, I will try to respond to questions concerning this architecture. There are many details I simply cannot cover here.

Conclusion

Combining the depot utility with a chroot build environment for each OS allows an administrator to create a single software repository that is extremely flexible, scalable, portable, and manageable. This power is achieved because each utility is self-contained within its own directory tree. Basically, any version of a utility only needs to be built once on the file server to have it available for every host of that OS type within an organization.

Bob Jobsky has been working as a UNIX systems administrator since 1993. He holds Chemical and Electrical Engineering degrees and currently works at SupplyEdge Inc. in Pasadena, CA.