We are currently building about a dozen [FreeBSD][] servers at work. The build process is pretty well documented, but it’s a bit labor intensive. So I had one of my student assistants look into automating the process somewhat. This post discusses our assumptions and initial conditions, along with our results and recommendations. Hopefully this can help others trying to implement similar plans.
[FreeBSD]: http://www.freebsd.org/
We implemented this on FreeBSD versions 6.2, 6.3, 6.4. We will also be testing this on version 7.1 later this month. We are focusing on the *i386* architecture, and we would like to try large (≥3 [GiB][]) memory configurations with the *amd* architecture as well.
All of our systems have a common set of basic tools:
– [portmaster][]
– [portupgrade][]
– [portaudit][]
– [spinner][]
– [screen][]
– [postfix][]
– [nagios][]
– [sudo][]
– [bash][]
– [emacs][]
– [lynx][]
Ideally we would like to install all of these common tools with one command that doesn’t require further user intervention. We could have created a [package][] for this, but I’m pretty sure we would need to build a separate package for every possible FreeBSD version and architecture — that’s 4 O/S versions x 2 architectures = 8 packages, which doesn’t seem worthwhile for ~12 systems.
Another possible approach would have been creation of a “metaport”, a single pseudo-application listing all of the tools as dependencies. I didn’t pursue this because it doesn’t (by itself) address the user intervention issue.
One more goal of this project was the automation/scripting of some common system configuration tasks such as enabling/starting NTP, setting up network printers, etc. This doesn’t have anything to do with the ports/packages system, so we needed to write a script for this part. Most of this code is pretty obvious and mundane, but I’ve included it in the article for the sake of completeness.
The trickiest part of this whole project was figuring out how to do unattended installation of ports with options, e.g. [screen][]. Normally when you install such a port, you will be presented with an ncurses menu of options for that port. Each of these options should correspond to a WITH\_* / WITHOUT\_* variable that controls how the port is built, possibly affecting the port’s dependencies, etc. The options menu is displayed when the ‘config’ target is built:
# cd /usr/ports/sysutils/screen
# make config
(ncurses option menu appears, user chooses which options to enable/disable)
# grep ^WITH /var/db/ports/screen/options
WITHOUT_CJK=true
WITH_INFO=true
WITH_MAN=true
WITH_NETHACK=true
WITH_XTERM_256=true
WITHOUT_HOSTINLOCKED=true
WITHOUT_SHOWENC=true
The options are saved in **/var/db/ports/*portname*/options**, as shown above. Once you have figured out which options to enable/disable on one system (interactively), you can copy them into a port-specific section of /etc/make.conf as follows:
# echo ‘# Options for sysutils/screen’ >>/etc/make.conf
# echo ‘if ${.CURDIR:M*ports/sysutils/screen}’ >>/etc/make.conf
# grep ^WITH /var/db/ports/screen/options >>/etc/make.conf
# echo ‘.endif’ >>/etc/make.conf
We’ll now test this by removing the config file and building the port with the **BATCH=yes** flag set. This should prevent the ncurses config screen from popping up.
# cd /usr/ports/sysutils/screen
# make rmconfig clean
(We’re using /bin/sh for our installation script, as well as for testing.)
(If you’re using csh, you’ll need to use *setenv* instead of *export*.)
# export BATCH=yes
# make install clean
(Lots and lots of output, but no configuration prompting!)
The components of the solution are all in place! Now all we need is to put them together and write the script, but that’ll have to wait until next week.
[GiB]: http://en.wikipedia.org/wiki/Gibibyte “What’s a GiB (gibibyte)?”
[portmaster]: http://www.FreeBSD.org/cgi/url.cgi?ports/ports-mgmt/portmaster/pkg-descr
[bash]: http://www.FreeBSD.org/cgi/url.cgi?ports/shells/bash/pkg-descr
[screen]: http://www.FreeBSD.org/cgi/url.cgi?ports/sysutils/screen/pkg-descr
[postfix]: http://www.FreeBSD.org/cgi/url.cgi?ports/mail/postfix/pkg-descr
[emacs]: http://www.FreeBSD.org/cgi/url.cgi?ports/editors/emacs/pkg-descr
[portupgrade]: http://www.FreeBSD.org/cgi/url.cgi?ports/ports-mgmt/portupgrade/pkg-descr
[spinner]: http://www.FreeBSD.org/cgi/url.cgi?ports/sysutils/spinner/pkg-descr
[portaudit]: http://www.FreeBSD.org/cgi/url.cgi?ports/ports-mgmt/portaudit/pkg-descr
[lynx]: http://www.FreeBSD.org/cgi/url.cgi?ports/www/lynx/pkg-descr
[sudo]: http://www.FreeBSD.org/cgi/url.cgi?ports/security/sudo/pkg-descr
[nagios]: http://www.nagios.org/
[package]: http://www.freebsd.org/doc/en/books/handbook/ports-overview.html “Description of ‘package’ in FreeBSD”
Thanks for this post it helped me.
Though, I *think* you have a typo as a copy/paste didn’t do it.
I resolved the issue by adding a . before this “if”
echo ‘if ${.CURDIR:M*ports/sysutils/screen}’ >>/etc/make.conf
echo ‘.if ${.CURDIR:M*ports/sysutils/screen}’ >>/etc/make.conf
And it now works… at least here 🙂
Thanks again for the recipe 🙂