Home > FreeBSD > Using sysinstall for automated FreeBSD 8.x installs

Using sysinstall for automated FreeBSD 8.x installs

First, allow me to point out that as of FreeBSD 9 sysinstall is no longer the default install mechanism.  Therefore, this post addresses versions previous to FreeBSD 9.

Summary

It’s important to understand that our provisioning platform is Cobbler. Therefore, you may find references to Cobbler in this post. There may need to be code modifications to permit these concepts to work within other platforms.

This set of config files and scripts allows us to more dynamically control host builds by scripting much of the process and hosting an answer file remotely. Doing so helps us avoid the need of creating multiple mfsroot files for varying profiles, etc.

Out of the box, sysinstall does not support pure HTTP installs. To enable full HTTP support, one of my former colleagues wrote a patch which was applied to the sysinstall source and compiled. This new binary was put into the mfsroot file.

mfsroot.gz

The mfsroot.gz is a BSD UFS filesystem environment that contains config files, scripts, and binaries necessary to complete a FreeBSD 8.x install. This file is retrieved by the PXE boot file and loads it into memory. The procedure described below takes the contents of an mfsroot.gz from the FreeBSD DVD install media and adds the files described later in this post to that file.

The mfsroot contained within the vendor install media is setup to run sysinstall. It can be
modified in various ways to manipulate the FreeBSD install.

Prerequisites

  • mfsroot file: This file can be found on the vendor media. Just copy it
    locally.
  • A FreeBSD host: This host is where you will perform these procedures.
  • The FreeBSD host should have bash installed and when executing this
    procedure, it is the current shell

Procedure

Modifying the mfsroot involves changes to the existing file to change the behavior of the environment. Some common files modified are the loader.rc and loader.conf files. When adding new files to the mfsroot, such as a newly compiled boot_crunch file, it will require creating a new mfsroot file. This section will describe both methods of modifying the mfsroot.

Modifying Existing mfsroot

To modify an existing mfsroot all that needs to be done is to create a memdisk device and mount it. Once mounted, you can modify the mfsroot simply by cd’ing into the new mount point and making your desired changes. We assume the memdisk device is md0 and the mount point is /mnt.

To create this memdisk and mount it, one only need to run the following:

# mdconfig -f $path_to_mfsroot
# mount /dev/md0 /mnt

Once changes have been made to the mfsroot, you can dismount and remove the memdisk device by executing the following:

# umount /mnt mdconfig -d -u 0
# mdconfig -d -u 0

Creating New mfsroot from Existing mfsroot

When adding files to an mfsroot, such as the boot_crunch, will require a new, larger mfsroot. This procedure discussed how to accomplish this.

This procedure assumes the following:

  • we are adding a boot_crunch file
  • Resulting mfsroot will need to be 12MB.
  • Existing mfsroot mount point will be /tmp/mfsroot_old
  • New mfsroot mount point will be /tmp/mfsroot_new
  • Existing mfsroot is /tmp/mfsroot_old
  • Memdisk device for the existing mfsroot is md0
  • Memdisk device for the new mfsroot is md1
  • New boot_crunch file is /tmp/bootcrunch/boot_crunch
# mkdir /tmp/mfsroot_old /tmp/mfsroot_new
# dd if=/dev/zero of=/tmp/mfsroot bs=1024 count=12288
# mdconfig -f /tmp/mfsroot_old; mdconfig -f /tmp/mfsroot
# newfs /dev/md1
# mount /dev/md0 /tmp/mfsroot_old; mount /dev/md1 /tmp/mfsroot_new
# cd /tmp/mfsroot_old; tar -cf - . | (cd/tmp/mfsroot_new; tar -xf -)
# cp /tmp/bootcrunch/boot_crunch /tmp/mfsroot_new/stand/
# cd /tmp/mfsroot_new/stand
# for i in $(./boot_crunch 2>&1|grep -v usage); do
    if [ "$i" != "boot_crunch" ]; then
      rm -f ./"$i"; ln ./boot_crunch "$i";
    fi
  done
# cd /; umount /tmp/mfsroot_old; umount /tmp/mfsroot_new
# mdconfig -d -u 0; mdconfig -d -u 1

At the completion of this procedure, /tmp/mfsroot will be the new mfsroot. Replace the old mfsroot with this one.

install.cfg

The install.cfg file is sysinstall’s config file. When sysinstall is executed it checks for the existence of this file. If the file does not exist, it runs interactively else it executes the file and performs the operations contained within it. This file exists in stand/ inside of the mfsroot file.

The syntax of the file is archaic and strict, but can be quite powerful if you spend the time to learn it. That is a moot point now though since sysinstall is deprecated in more recent versions of FreeBSD.

The file below simply sets up the environment where sysinstall will run, then executes a script called doconfig.sh which is described below.

# Turn on extra debugging.
debug=YES

# Turn off all prompting.
nonInteractive=YES
noWarn=YES

command=/bin/sh /stand/doconfig.sh
system
# Chain to the config we just downloaded
configFile=/stand/cobbler.cfg
loadConfig

doconfig.sh

This script, also in stand/ inside the mfsroot file, is the workhorse. It completes the setup of the environment by setting variables and communicating with the remote server to grab the remainder of the install.cfg file which we see is referred to as stand/cobbler.cfg. We describe this later in the post.

#!/bin/sh

server=`kenv -q boot.nfsroot.server`
mac=`kenv -q boot.netif.hwaddr`
ip=`kenv -q boot.netif.ip`
nm=`kenv -q boot.netif.netmask`
gw=`kenv -q boot.netif.gateway`
name=`kenv -q dhcp.host-name`
route=`kenv -q dhcp.routers`

# Returns true if a given network interface has the specified MAC address.
macmatch()
{
  local addr

  addr=`ifconfig $1 | grep ether | awk -F" " '{ print $2 }'`
  [ "$addr" = "$2" ]
  return $?
}

for ifn in `ifconfig -l`; do
  case $ifn in
    *)
      if macmatch $ifn $mac; then
        iface=$ifn
      fi
    ;;
  esac
done

# Bring up the interface so we can fetch the remote install.cfg file.  Confuses sysinstall, so
# bring it back down after fetching install.cfg.  Kinda assuming we're on the same subnet
# as the server, otherwise won't work.
ifconfig "$iface" "$ip" netmask "$nm"
sleep 5
route add default $gw

# Use Fetch to get my answer file from my cobbler/remote server.  Use awk to pull out different
# sections using "% /path/to/file" syntax.
fetch -qo - "http://$server/cblr/svc/op/ks/system/$name" |
	awk '/^% /{f=$2} /^[^%]/ && f{print > f}'

# Bringing down the interface
ifconfig $iface down
route delete default $gw

# Setup our media.  This file is loaded by sysinstall after it retrieves the install.cfg from the
# cobbler/remote server.
cat > /stand/media.cfg <<EOF
netDev=${iface}
defaultrouter=${route}
ipaddr=${ip}
netmask=${nm}
_httpPath=http://${server}/cobbler/ks_mirror/freebsd82-x86_64
mediaSetHTTP
EOF

cobbler.cfg

The cobbler.cfg is hosted on a remote server and is fetched via HTTP. It can be separated into sections that are executed as shell scripts to enable more dynamic control over the configuration. The doconfig.sh script above separates the sections of the files based on “% $filename” syntax.

The $disk variables below are substituted with the actual disk identifier. You can find that using the install.disk kernel variable.

% /stand/cobbler.cfg
# The installation media is setup in the doconfig.sh script
hostname=$system_name
configFile=/stand/media.cfg
loadConfig

# Select which distributions we want.
dists=base kernels GENERIC SMP doc catpages
distSetCustom

# Figure out the disk configuration
disk=${disk}
partition=all
bootManager=standard
diskPartitionEditor
${disk}s1-1=ufs 12582912 / # 6 GB root
${disk}s1-2=swap ${swap} none # swap
${disk}s1-3=ufs 2097152 /tmp 1 # tmp
${disk}s1-4=ufs 4194304 /var 1 # 2 GB var
${disk}s1-5=ufs 4194304 /home 1 # 2 GB home

# OK, everything is set.  Do it!
installCommit

package=perl
packageAdd

shutdown
Categories: FreeBSD
  1. No comments yet.
  1. No trackbacks yet.

Leave a comment