Managing Users' Environments with the Usepackage Environment Manager
Chandler Wilkerson
Sys admins who manage moderate to large mixed
installations of Unix/Linux systems with local users know the headaches
associated with keeping track of those users' environments across
different operating systems. In this article, I will detail an under-sung
utility called usepackage, which brings together environment management for
diverse systems, software packages, user classes, and shell styles into a
centralized configuration.
Creating centralized shell profiles by hand tends to
involve large, complicated switch statements with scripts that must be
ported to each shell style present on the systems. Other problems arise
when dealing with the number of different places software can install
itself. For instance, according to best practices standards, the use of
/usr/local in Unix/Linux is being deprecated in favor of /opt. We know how
long that lasts on a system as you install software packages. One of my
colleagues once quipped that even on distributions that don't include
a /usr/local directory by default, one will spontaneously generate if given
enough time.
If you use /opt as recommended, you run into another
problem with keeping track of packages. Rather than one /usr/local/bin
directory to include in everybody's path, you get many
/opt/package-name/bin directories, each with its own man path, libraries,
and sometimes even custom environment variables, such as JAVA_HOME for
Java.
One more common complication, just to make the job of
environment management even tougher, is that sometimes multiple versions of
packages will need to be installed side by side. This requires that
environment variables be changed from package to package, usually by a
complicated set of scripts that the systems administrators have to write by
hand.
This article is not, however, about /usr/local, /opt,
or best practice standards, but about the tough job of managing
users' environments in a system where conflicting packages may
install themselves in various, seemingly random locations.
Usepackage, written by Jonathan Hogg, is "...a
tool for managing the Unix environment for a multi-tool, multi-platform
site. It is designed to simplify login scripts and allow administrators to
control users' environments centrally." (See http://usepackage.sourceforge.net/.)
Usepackage consists of a central configuration file, a set of stubs to add
to the system profiles, and a binary that parses the configuration and
manipulates users' environment variables.
Using Use
The end-user interface to the usepackage system is
through the use command. The use command is implemented as a shell function that evaluates the output of the
usepackage binary. Scripts to create the use function are available in bash, csh, and ksh syntaxes. Usepackage can output commands to set relevant
environment variables in each language by passing the corresponding script's flag: -b, -c, or -k.
Users interact with the use command in two basic modes. Typing just use -l will print out a list of all
available packages, then use packagename will set environment variables for that particular
package.
Getting Started
Installing usepackage is straightforward. You can get
the latest tarball at http://sourceforge.net/projects/usepackage. From there, installation is a standard process of untar, configure, make, and sudo
make install. (You didn't untar it as root, did you?) One change I like to make is to add --prefix=/opt/usepackage to the configure process, as usepackage installs
itself by default to /usr/local.
Next, you should add the use function definition
scripts to the system's user profile. You can find the scripts
themselves under the "share/usepackage" directory. If your OS
or distribution has an /etc/profile.d directory, you can create symbolic
links to all the files in the share/usepackage directory to save time, for
example:
# ln -s /opt/usepackage/share/usepackage/* /etc/profile.d
# mv /etc/profile.d/use.bsh /etc/profile.d/use.sh
If your system does not have a profile.d directory,
you can just add source commands to the appropriate system login scripts.
Now you should be able to log in as a regular user and try the use command:
$ use -l
This should give you a list of available packages from
the default configuration file. The default configuration file is quite
functional for many setups. It includes path options such as none to empty paths and start
over, system to get
a typical set of system paths, and site to provide site-wide installed commands such as those
residing in /usr/local. More advanced path setups are available for power
users, such as bsd,
which applies to Solaris systems to include the /usr/ucb path for those who
prefer their ps command to work in the BSD way. The sysadm option includes the sbin directories for power users.
Finally, there is an X11 group that adds /usr/X11R6/bin to allow X11 users
to run X commands.
In addition to creating path lists for finding
applications, usepackage is good for managing
other environment variables. The packages mentioned above include settings for the MANPATH, INFOPATH, and LD_LIBRARY_PATH variables as well.
Once everything is configured, it is helpful to add a
note to the system's MOTD file directing users to try running use -l.
Configuring Usepackage
The configuration file is found under the
etc/usepackage.conf directory from wherever
usepackage was installed. Entries in the configuration file consist of an
optional label, for defining what appears in the use -l command, and a package
definition. Comments start with a #.
An excerpt of the default configuration defining the none and system packages is shown in
Listing 1.
The lines enclosed in angle brackets are labels that
will appear in the use -l command. The lines starting with system add definitions to the system package. The first one sets common
paths for most Unix/Linux operating systems, while the second two instances
add OS-specific lines for, in this example, Mac OS X (Darwin) and Solaris
versions 2.0 through 10.
The package definition format allows for matching of
architecture, operating system, OS release version, hostname, and specific
shell being used. Each subsequent option is optional, but requires that any
previous option(s) be defined in order to identify which option to match.
In the case of the Darwin match above, a wild card * is used as a placeholder for
architecture. In addition to matching packages to certain subsets of
systems and/or shells, a package definition may also require certain
prerequisite packages be included in order to use a certain package using
the <= construct.
A comma-separated list of variables may be defined or
added to on the right-hand side of the definitions. The += token indicates that the defined
value should be prepended to the existing value of the environment
variable. An =, on
the other hand, sets the value explicitly, and overwrites any preexisting
values. One more syntactic distinction separates path-style values from
regular values (as csh style shells handle paths differently). If the value is enclosed
in quotes, it is a literal value to be set as-is. If it is not enclosed in
quotes, it is interpreted as a colon-separated path list. For example, in
the system definition above, all of the variables are paths, and those paths are to be
prepended to existing values without overwriting. In the configuration for
the none package,
all the default variables are explicitly set to the empty string, "". This works as an
exception to the syntax for path versus regular variable as the empty
string means the same thing in either context.
In addition to packages consisting of variable
definitions, usepackage supports groups of packages using a similar syntax
to package definitions. Group definitions consist of a group name, a := and a comma-separated list
of packages. Usepackage also supports an include command to reference other configuration files. The
default example is (include ~/.packages), which allows users to define their own packages.
Managing Multiple Compilers
Although usepackage is originally designed to provide
a centralized environment configuration for user accounts that may span
multiple platforms, it is also of great utility in maintaining complex
configurations on individual machines. Our department maintains an
eight-processor machine for computational tasks. Multiple research groups
use this machine, and several of our high-performance computing classes use
it as an example of a symmetric multiprocessor (SMP) machine. Trying to
maintain the user environment for different groups needing different tools
would have been a mess through traditional /etc/profile hacks.
The system runs Gentoo Linux, and includes three
versions of GCC, a commercial compiler, and two different MPI library
versions. Dependencies between these packages can be complex, especially to
a researcher or student who is just concerned with compiling code. For
instance, one of the MPI libraries requires the commercial compiler, and
because the commercial compiler is linked against version 3.3.5 of GCC
found on Red Hat/Fedora systems, it requires access to the 32-bit GCC 3.3.5
library. The usepackage configuration for this system's compilers can
be found in Listing 2.
Cross-Site Configuration
Although the previous example provides for a complex
set of packages on just one system, the purpose of usepackage is more
global. To that end, it makes sense to maintain a single instance of the
configuration file, possibly on a shared filesystem like NFS. That
configuration should closely match the default configuration that comes
with the usepackage distribution, with a few tweaks for the local
environment. For instance, I like to remove the dot package altogether,
because usepackage prepends the most recently added package to the path,
and having . as your first path element is one of the biggest no-nos in Unix.
It would be possible to include local configurations,
such as the compilers and libraries above, in the central configuration
file using host or OS filters. Unfortunately, there is no way in usepackage
to prevent the labels for those packages from showing up in the use -l command on other systems.
Thus, to avoid confusing users by listing packages that do not exist, it is
best to save those definitions for a local configuration file. For local
packages, create another usepackage configuration file and place it on a
non-shared filesystem. Using a filename such as /etc/usepackage.local,
specific configurations for individual systems can be created and
referenced with an include command in the common usepackage.conf file.
Listing 3 provides a somewhat tweaked version of the
default usepackage.conf that would be suitable for the setup detailed
above.
Conclusion
Usepackage is a handy tool to manage users'
environments across a combination of different shells, operating systems,
and hardware. Due to the flexibility of its configuration format, it can be localized to
specific tasks and machines, further customized by users, and is capable of
supporting complex environments while offering users a simple interface.
For more information, visit the usepackage home page at: http://usepackage.sourceforge.net/.
Chandler Wilkerson has a M.S. in Computer Science and
is a LAN Administrator for the Department of Computer Science at the
University of Houston. He is responsible for managing Unix and Linux
servers, labs, and networking for the department. In his spare time,
Chandler tempts fate by juggling semi-dangerous objects.
|