Библиотека сайта rus-linux.net
|Maximum RPM: Taking the Red Hat Package Manager to the Limit|
|Prev||Chapter 20. Real-World Package Building||Next|
What do they mean,
(contains no files)?
The spec file has perfectly good %files lists…
Everything was going so smoothly, we forgot that the %files lists were going to need files. No problem, we just need to put the filenames in there, and we'll be all set. But is it really that easy?
Luckily, it's not too bad. Since we saved the output from our first make install, we can see the filenames as they're installed. Of course, it's important to make sure the install output is valid. Fortunately for us, amanda didn't require much fiddling by the time we got it built and tested. If it had, we would have had to get more recent output from the installation phase.
It's time for more decisions. We have one list of installed files, and two %files lists. It would be silly to put all the files in both %files lists, so we have to decide which file goes where.
The files in
/usr/lib/amanda are all the
client-side amanda programs, so that part was easy. The remaining
files are part of the original source archive. Amanda doesn't
install them, but they contain information that users should see.
The files in
/usr/sbin are programs that will
be run by the amanda administrator in order to perform backups and
restores. The files in
/usr/lib/amanda are the
server-side programs that do the actual work during backups.
Following that are a number of man pages: one for each program to be
run by the amanda administrator, and one with an overview of amanda.
Bringing up the rear are a number of files that are not installed,
but would be handy for the amanda administrator to have available.
There is some overlap with the files that will be part of the client
subpackage, but the additional files here discuss features that
would interest only amanda administrators. Included here is the
example subdirectory, which contains a few
example configuration files for the amanda server.
As in the client %files list, these last files can't be packaged by RPM as we've listed them. We need to use a few more of RPM's tricks to get them packaged.
Since we'd like the client subpackage to include those files that are not normally installed, and since the files are documentation, let's use the %doc directive on them. That will accomplish two things:
When the client subpackage is installed, it will direct RPM to place them in a package-specific directory in
It will tag the files as being documentation, making it possible for users to easily track down the documentation with a simple rpm -qd command
In the course of looking over the %files lists,
it becomes apparent that the directory
/usr/lib/amanda will contain only files from
the two amanda subpackages. If the subpackages are erased, the
directory will remain, which won't hurt anything, but it isn't as
neat as it could be. But if we add the directory to the list, RPM
will automatically package every file in the directory. Since the
files in that directory are part of both the client and the server
subpackages, we'll need to use the %dir directive
to instruct RPM to package only the directory.
/usr/manas documentation. Now our spec file has a complete set of tags, the two subpackages are defined, it has build-time scripts that work, and now, %files lists for each subpackage. Why don't we try that build again?
We're finally ready to test these packages!
Running some tests, it looks like everything is running well. But back in the section called Testing Newly Built Packages in Chapter 11, we mentioned that it was possible to install a newly-built package on the build system, and not realize that the package was missing files. Well, there's another reason why installing the package on the build-system for testing is a bad idea. Let's bring our packages to a different system, test them there, and see what happens.
The install went smoothly enough. However, testing did not. Why?
Nothing was set up! The server configuration files, the
inetd.conf entry for the client, everything was
missing. If we stop and think about it for a moment that makes
sense: we had gone through all those steps on the build system, but
none of those steps can be packaged as files.
After following the steps in the installation instructions, everything works. While we could expect users to do most of the grunt work associated with getting amanda configured, RPM does have the ability to run scripts when packages are installed and erased. Why don't we use that feature to make life easier for our users?
At this point in the build process, we're on the home stretch. The software builds correctly and is packaged. It's time to stop looking at things from a "build the software" perspective, and time to starting looking at things from a "package the software" point of view.
The difference lies in looking at the packages from the user's perspective. Does the package install easily, or does it require a lot of effort to make it operative? When the package is removed, does it clean up after itself, or does it leave bits and pieces strewn throughout the filesystem?
Let's put a bit more effort into this spec file, and make life easier on our users.
First, we start the script with a %post
statement, and indicate that this script is for the
client subpackage. As the comments indicate,
we only want to perform the following tasks if this is the first
time the client subpackage has been installed. To do this, we use
the first and only argument passed to the script. It is a number
indicating how many instances of this package will be installed
after the current installation is complete.
One of amanda's requirements is that the user ID running the dumps
on the client needs to be able to read from every disk's device
file. The folks at Red Hat have done half the work for us by creating
disk and giving that group read/write
access to every disk device. Since our dumpuser is
bin, we only need to add
bin to the
Two lines of sed, and we're done!
bincan access everything it needs while doing backups:
Since amanda uses dump to obtain the backups, and
since dump keeps track of the backups in
/etc/dumpdates, it's only natural that
bin will need read/write access to the file. In
a perfect world,
/etc/dumpdates would have
already been set to allow group
disk to read
and write, but we had to do it ourselves. It's not a big problem,
By using grep to look for lines that begin with
the letters amanda, we can easily see if
/etc/services is already configured properly.
It it isn't, we simply append a line to the end.
We also added a comment so that sysadmins will know where the entry came from, and either take our word for it or issue an rpm -q --scripts amanda-client command and see for themselves. We did it all on one line because it makes the script simpler.
Here, we've used the same approach to add an entry to
/etc/inetd.conf. We then hup
inetd so the change will take affect, and we're
That was short! And this huge difference brings up a good point about writing install scripts: It's important to understand what you as the package builder should do for the user, and what they should do for themselves.
In the case of the client package, every one of the steps performed by the post-install script was something that a fairly knowledgeable user could have done. But each of these steps have one thing in common. No matter how the user configures amanda, these steps will never change. And given the nature of client/server applications, there's a good chance that many more amanda client packages will be installed than amanda servers. Would you like to be tasked with installing this package on twenty systems, and performing each of the steps we've automated, twenty times? We thought not.
There is one step that we did not automate for
the client package. The step we left out is the creation of a
.rhosts file. Since this file must contain the
name of the amanda server, we have no way of knowing what the file
should look like. Therefore, that's one step we can't automate.
The server's post-install script is so short because there's little else that can be automated. The other steps required to set up an amanda server include:
Choosing a configuration name, which requires user input
Creating a directory to hold the server configuration files, named according to the configuration name, which depends on the first step
Modifying example configuration files to suit the site, which requires user input
Adding crontab entries to run amanda nightly, which requires user input
Since every step depends on the user making decisions, the best way to handle them is to not handle them at all. Let the user do it!
As before, we start out with a declaration of the type of script this is, and which subpackage it is for. Following that we have an if statement similar to the one we used in the install scripts, save one difference. Here, we're comparing the argument against zero. The reason is that we are trying to see if there will be zero instances of this package after the uninstall is complete. If this is the case, the remainder of the script needs to be run, since there are no other amanda client packages left.
That's odd. Why are we looking for a file from the server package?
If you look back at the install scripts for the client and server
packages, you'll find that the one thing they have in common is that
both the client and the server require the same entry in
If an amanda server is going to back itself up, it also needs the
amanda client software. Therefore, both subpackages need to add an
/etc/services. But what if one of the
packages is removed? Perhaps the server is being demoted to a
client, or maybe the server is no longer going to be backed up using
amanda. In these cases, the entry
/etc/services must stay. So, in the case of
the client, we look for a file from the server subpackage, and if
it's there, we leave the entry alone.
Granted, this is a somewhat unsightly way to see if a certain package is installed. Some of you are probably even saying, "Why can't RPM be used? Just do an rpm -q amanda-server, and decide what to do based on that." And that would be the best way to do it, except for one small point:
Only one invocation of RPM can run at any given time.
Since RPM is running to perform the uninstall, if the uninstall-script were to attempt to run RPM again, it would fail. The reason it would fail is because only one copy of RPM can access the database at a time. So we are stuck with our unsightly friend.
Here, we're using grep's ability to return lines
that don't match the search string, in order to
remove every trace of amanda from
/etc/inetd.conf. After issuing a hup on inetd,
By now the opening if statement is an old friend.
As you might have expected, we are verifying whether the client
package is installed, by looking for a file from that package. If
the client package isn't there, the entry is removed from
/etc/services. And that, is that.
Obviously, these scripts must be carefully tested. In the case of
amanda, since the two subpackages have some measure of
interdependency, it's necessary to try different sequences of
installing and erasing the two packages to make sure the
/etc/services logic works properly in all
After a bit of testing, our install and uninstall scripts pass with flying colors. From a technological standpoint, the client and server subpackages are ready to go.
However, just because a package has been properly built, and installs and can be erased without problems, doesn't mean that the package builder's job is done. It's necessary to look at each newly-built package from the user's perspective. Does the package contain everything the user needs in order to deploy it effectively? Or will the user need to fiddle with it, guessing as they go?
In the case of our amanda packages, it was obvious that some
additional documentation was required so that the user would know
what needed to be done in order to finalize the installation.
Simply directing the user to the standard amanda documentation
wasn't the right solution, either. Many of the steps outlined in
INSTALL document had already been done by
the post-install scripts. No, an interim documente was required.
Two, actually: one for the client, and one for the server.
So two files were created, one to be added to each subpackage. The question was, how to do it? Essentially, there were two options:
Put the files in the amanda directory tree that had been used to perform the initial builds and generate a new patch file
Create a tar file containing the two files, and modify the spec file to unpack the documentation into the amanda directory tree.
Drop the files directly into the amanda directory tree without using tar.
While the %setup macro might look intimidating, it wasn't that hard to construct. Here's what each options means:
-T — Do not perform the default archive unpacking.
-D — Do not delete the directory before unpacking.
-a1 — Unpack the archive specified by the source1 tag after changing directory.
At this point, the packages were complete. Certainly there is software out there that doesn't require this level of effort to package. Just as certainly there is software that is much more of a challenge. Hopefully this chapter has given you some idea about how to approach package building for more complex applications.