diff mbox

[5/7] osstest: introduce a FreeBSD build script

Message ID 20170523135148.77673-6-roger.pau@citrix.com (mailing list archive)
State New, archived
Headers show

Commit Message

Roger Pau Monne May 23, 2017, 1:51 p.m. UTC
In order to generate the FreeBSD installer image and the install media.

The install sets are the vanilla ones generated by the 'ftp' release target.
The installer image is handcrafted based on the filesystem created by the
'bootonly' target, which is then populated with the ssh host keys, and setup
in order to use the serial console. The other difference from upstream FreeBSD
installer images is that the one built by osstest uses a ramdisk instead of
relying on the installer media to be somehow attached, either on a CD or USB
drive. This is required in order to boot the image from pxelinux (where no CD
or USB is actually attached to the host, and everything is fetched from tftp).

Due to the nature of the FreeBSD build, the outputs are different from what
osstest expects from a buildjob, more specifically there's no path_freebsdist
produced, and thus ts-build-check needs to be modified in order to accommodate
this. The FreeBSD build output is going to produce the following binaries
path_freebsd-{base,kernel,manifest,image}.

Signed-off-by: Roger Pau Monné <roger.pau@citrix.com>
---
 ts-build-check   |  14 +++-
 ts-freebsd-build | 230 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 241 insertions(+), 3 deletions(-)
 create mode 100755 ts-freebsd-build

Comments

Ian Jackson May 23, 2017, 5:58 p.m. UTC | #1
Roger Pau Monne writes ("[PATCH 5/7] osstest: introduce a FreeBSD build script"):
> -    my $path= "path_${part}dist";
> -    logm("checking $k $path");
> -    get_stashed($path, $r{$k});
> +    if ("$part" eq "freebsd") {
> +        foreach (qw(base kernel manifest image)) {
> +            my $path= "path_${part}-$_";
> +            logm("checking $k $path");
> +            get_stashed($path, $r{$k});
> +        }
> +    } else {
> +        my $path= "path_${part}dist";
> +        logm("checking $k $path");
> +        get_stashed($path, $r{$k});

This is quite ugly.  I don't think this knowledge should be in
ts-build-check.

...

I think in fact that the right answer is probably to have
ts-build-check be more general somehow.

I have looked through the history of ts-{,xen-}build-check and I think
the current approach is a historical accident.  In the beginning it
was a wrapper around ts-xen-install which used a special check flag;
then that gradually generalised to what we have now - but it still
retains the same origins.

I was going to suggest checking the job status, but might be an
inconvenience during by-hand testing.

I considered having sg-run-job specify the parts it's going to use, as
command line arguments, with plumbing in sg-run-job from the recipe,
but that's still going to have to be buildjob-runvar-specific.

I considered controlling this via runvars from make-flight:
   freebsdbuildjob=391031.build-amd64-freebsd
   freebsdbuildjobpaths=-base,-kernel,-manifest,-image
But it's also quite ugly.

I have a radical suggestion:

Suppose we have ts-freebsd-build set
    path_freebsddist=$stash/build/freebsd/
and have it put the files in there with fixed, known, names
    path_freebsddist=$stash/build/freebsd/image
    path_freebsddist=$stash/build/freebsd/manifest
    path_freebsddist=$stash/build/freebsd/kernel.sets
    path_freebsddist=$stash/build/freebsd/base.sets
or something ?

Is there a reason why that wouldn't work ?

The stashing process would have to take care to set the runvar only
after it had created all the files.

> +    target_cmd_build($ho, 7200, $builddir, <<END);
> +cd freebsd
> +export MAKEOBJDIRPREFIX=$builddir/obj
> +(make $makeflags TARGET=$r{arch} buildworld 2>&1 && touch ../build-ok-stamp) \\
> +    |tee ../log

How about using Osstest::BuildSupport::buildcmd_stamped_logged ?

> +    logm("Creating the install sets");
> +    # NB: the steps below need to be done as root or the permissions
> +    # of the files won't be properly set (and the target will fail).
> +    target_cmd_root($ho, <<END, 900);

target_cmd_root does not imply set -e; only target_cmd_build does.

You may want to invent buildcmd_stamped_logged_root or something.

> +# Enable DHCP on all network interfaces
> +echo 'ifconfig_DEFAULT="DHCP"' >> \$target/etc/rc.conf

Is this wise ?  We may at some point have hosts which have two network
interfaces connected (perhaps to the test network, or to each other,
or something) in which case this is probably wrong.

There are a lot of \.  I wonder if you might find
<<'ENDQ'.<<END.<<'ENDQ' a useful construct.

Ian.
Roger Pau Monne May 24, 2017, 2:15 p.m. UTC | #2
On Tue, May 23, 2017 at 06:58:59PM +0100, Ian Jackson wrote:
> Roger Pau Monne writes ("[PATCH 5/7] osstest: introduce a FreeBSD build script"):
> > -    my $path= "path_${part}dist";
> > -    logm("checking $k $path");
> > -    get_stashed($path, $r{$k});
> > +    if ("$part" eq "freebsd") {
> > +        foreach (qw(base kernel manifest image)) {
> > +            my $path= "path_${part}-$_";
> > +            logm("checking $k $path");
> > +            get_stashed($path, $r{$k});
> > +        }
> > +    } else {
> > +        my $path= "path_${part}dist";
> > +        logm("checking $k $path");
> > +        get_stashed($path, $r{$k});
> 
> This is quite ugly.  I don't think this knowledge should be in
> ts-build-check.
> 
> ...
> 
> I think in fact that the right answer is probably to have
> ts-build-check be more general somehow.
> 
> I have looked through the history of ts-{,xen-}build-check and I think
> the current approach is a historical accident.  In the beginning it
> was a wrapper around ts-xen-install which used a special check flag;
> then that gradually generalised to what we have now - but it still
> retains the same origins.
> 
> I was going to suggest checking the job status, but might be an
> inconvenience during by-hand testing.
> 
> I considered having sg-run-job specify the parts it's going to use, as
> command line arguments, with plumbing in sg-run-job from the recipe,
> but that's still going to have to be buildjob-runvar-specific.
> 
> I considered controlling this via runvars from make-flight:
>    freebsdbuildjob=391031.build-amd64-freebsd
>    freebsdbuildjobpaths=-base,-kernel,-manifest,-image
> But it's also quite ugly.
> 
> I have a radical suggestion:
> 
> Suppose we have ts-freebsd-build set
>     path_freebsddist=$stash/build/freebsd/
> and have it put the files in there with fixed, known, names
>     path_freebsddist=$stash/build/freebsd/image
>     path_freebsddist=$stash/build/freebsd/manifest
>     path_freebsddist=$stash/build/freebsd/kernel.sets
>     path_freebsddist=$stash/build/freebsd/base.sets
> or something ?
> 
> Is there a reason why that wouldn't work ?
> 
> The stashing process would have to take care to set the runvar only
> after it had created all the files.

That seems fine, and then osstest would rely on the fact that
path_freebsddist must only be set when all the files have been
uploaded, because ts-build-check itself won't check that the files are
there anymore.

> > +    target_cmd_build($ho, 7200, $builddir, <<END);
> > +cd freebsd
> > +export MAKEOBJDIRPREFIX=$builddir/obj
> > +(make $makeflags TARGET=$r{arch} buildworld 2>&1 && touch ../build-ok-stamp) \\
> > +    |tee ../log
> 
> How about using Osstest::BuildSupport::buildcmd_stamped_logged ?

That seems suitable, I've used this rune because it's what
ts-kernel-build was using, now I realize ts-xen-build is indeed using
buildcmd_stamped_logged.

> > +    logm("Creating the install sets");
> > +    # NB: the steps below need to be done as root or the permissions
> > +    # of the files won't be properly set (and the target will fail).
> > +    target_cmd_root($ho, <<END, 900);
> 
> target_cmd_root does not imply set -e; only target_cmd_build does.
> 
> You may want to invent buildcmd_stamped_logged_root or something.

Yes, that sounds right.

> 
> > +# Enable DHCP on all network interfaces
> > +echo 'ifconfig_DEFAULT="DHCP"' >> \$target/etc/rc.conf
> 
> Is this wise ?  We may at some point have hosts which have two network
> interfaces connected (perhaps to the test network, or to each other,
> or something) in which case this is probably wrong.

This just means that on the installer all the network interfaces will
try to get a DHCP address. This is for the installer image itself, the
installed system will only setup DHCP on the primary interface (ie:
the one that matches the IP address at $ho->{Ip}.

> There are a lot of \.  I wonder if you might find
> <<'ENDQ'.<<END.<<'ENDQ' a useful construct.

In fact I can define two perl variables and use them instead. There's
really no reason they have to be shell variables ($target and $output).

Roger.
Ian Jackson May 24, 2017, 2:19 p.m. UTC | #3
Roger Pau Monne writes ("Re: [PATCH 5/7] osstest: introduce a FreeBSD build script"):
> On Tue, May 23, 2017 at 06:58:59PM +0100, Ian Jackson wrote:
> > Suppose we have ts-freebsd-build set
> >     path_freebsddist=$stash/build/freebsd/
> > and have it put the files in there with fixed, known, names
> >     path_freebsddist=$stash/build/freebsd/image
> >     path_freebsddist=$stash/build/freebsd/manifest
> >     path_freebsddist=$stash/build/freebsd/kernel.sets
> >     path_freebsddist=$stash/build/freebsd/base.sets
> > or something ?
> > 
> > Is there a reason why that wouldn't work ?
> > 
> > The stashing process would have to take care to set the runvar only
> > after it had created all the files.
> 
> That seems fine, and then osstest would rely on the fact that
> path_freebsddist must only be set when all the files have been
> uploaded, because ts-build-check itself won't check that the files are
> there anymore.

Exactly.

> > > +# Enable DHCP on all network interfaces
> > > +echo 'ifconfig_DEFAULT="DHCP"' >> \$target/etc/rc.conf
> > 
> > Is this wise ?  We may at some point have hosts which have two network
> > interfaces connected (perhaps to the test network, or to each other,
> > or something) in which case this is probably wrong.
> 
> This just means that on the installer all the network interfaces will
> try to get a DHCP address. This is for the installer image itself, the
> installed system will only setup DHCP on the primary interface (ie:
> the one that matches the IP address at $ho->{Ip}.

OK, good.

> > There are a lot of \.  I wonder if you might find
> > <<'ENDQ'.<<END.<<'ENDQ' a useful construct.
> 
> In fact I can define two perl variables and use them instead. There's
> really no reason they have to be shell variables ($target and
> $output).

OK, I guess.  I typically prefer to avoid feeding large quantities of
sh through the perl interpolator.  What you suggest means the reader
sees a shell script full of $variable references which actually refer
to perl variables, not shell ones.  I think that's a bit confusing.

But, ultimately, up to you.

Ian.
diff mbox

Patch

diff --git a/ts-build-check b/ts-build-check
index b9ade876..68d6cc2d 100755
--- a/ts-build-check
+++ b/ts-build-check
@@ -28,9 +28,17 @@  logm("checking builds ...");
 foreach my $k (sort keys %r) {
     next unless $k =~ m/^(.*?)(_?)buildjob$/;
     my $part= $1;
-    my $path= "path_${part}dist";
-    logm("checking $k $path");
-    get_stashed($path, $r{$k});
+    if ("$part" eq "freebsd") {
+        foreach (qw(base kernel manifest image)) {
+            my $path= "path_${part}-$_";
+            logm("checking $k $path");
+            get_stashed($path, $r{$k});
+        }
+    } else {
+        my $path= "path_${part}dist";
+        logm("checking $k $path");
+        get_stashed($path, $r{$k});
+    }
 }
 
 logm("all ok.");
diff --git a/ts-freebsd-build b/ts-freebsd-build
new file mode 100755
index 00000000..c0366c97
--- /dev/null
+++ b/ts-freebsd-build
@@ -0,0 +1,230 @@ 
+#!/usr/bin/perl -w
+# This is part of "osstest", an automated testing framework for Xen.
+# Copyright (C) 2017 Citrix Inc.
+# 
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+# 
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU Affero General Public License for more details.
+# 
+# You should have received a copy of the GNU Affero General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+use strict qw(vars);
+use DBI;
+use POSIX;
+
+unshift @INC, qw(.);
+use Osstest;
+use Osstest::TestSupport;
+use Osstest::BuildSupport;
+
+tsreadconfig();
+
+selectbuildhost(\@ARGV);
+builddirsprops();
+
+sub install_deps () {
+    target_cmd_root($ho, 'pkg install git', 300);
+}
+
+sub checkout () {
+    prepbuilddirs();
+
+    # Remove the directory as root, there might be files owned by root
+    target_cmd_root($ho, <<END, 300);
+chflags -fR noschg $builddir/freebsd
+rm -rf $builddir/freebsd
+END
+
+    logm("Checkout the FreeBSD source tree");
+    build_clone($ho, 'freebsd', $builddir, 'freebsd');
+}
+
+sub build () {
+    my $authkeys = authorized_keys();
+    my $target = "bootonly";
+
+    # Build process as documented in the handbook:
+    # https://www.freebsd.org/doc/handbook/updating-src.html
+
+    logm("Cleaning up previous builds");
+    target_cmd_build($ho, 300, $builddir, <<END);
+cd freebsd
+export MAKEOBJDIRPREFIX=$builddir/obj
+make cleanworld
+END
+
+    logm("Building world");
+    target_cmd_build($ho, 7200, $builddir, <<END);
+cd freebsd
+export MAKEOBJDIRPREFIX=$builddir/obj
+(make $makeflags TARGET=$r{arch} buildworld 2>&1 && touch ../build-ok-stamp) \\
+    |tee ../log
+test -f ../build-ok-stamp
+echo ok.
+END
+
+    logm("Building kernel");
+    target_cmd_build($ho, 3600, $builddir, <<END);
+cd freebsd
+export MAKEOBJDIRPREFIX=$builddir/obj
+(make $makeflags TARGET=$r{arch} buildkernel 2>&1 && touch ../build-ok-stamp) \\
+    |tee ../log
+test -f ../build-ok-stamp
+echo ok.
+END
+
+    logm("Creating the install sets");
+    # NB: the steps below need to be done as root or the permissions
+    # of the files won't be properly set (and the target will fail).
+    target_cmd_root($ho, <<END, 900);
+cd $builddir/freebsd
+export MAKEOBJDIRPREFIX=$builddir/obj
+(make -C release TARGET=$r{arch} ftp 2>&1 && touch ../build-ok-stamp) \\
+    |tee ../log
+test -f ../build-ok-stamp
+echo ok.
+END
+
+    logm("Populating the installer image");
+    target_cmd_root($ho, <<END, 900);
+cd $builddir/freebsd
+export MAKEOBJDIRPREFIX=$builddir/obj
+(make -C release TARGET=$r{arch} $target 2>&1 && touch ../build-ok-stamp) \\
+    |tee ../log
+test -f ../build-ok-stamp
+echo ok.
+END
+
+    logm("Placing ssh host keys");
+    foreach my $file (<$c{OverlayLocal}/etc/ssh/ssh_host_*_key*>) {
+        target_putfile_root($ho, 30, $file,
+                            "$builddir/freebsd/release/$target/etc/ssh/");
+    }
+
+    logm("Configuring the installer image");
+    target_cmd_root($ho, <<END, 30);
+set -ex
+target=$builddir/freebsd/release/$target
+# Enable sshd by default
+echo 'sshd_enable="YES"' >> \$target/etc/rc.conf
+
+# Allow root login and copy the keys
+echo 'PermitRootLogin yes' >> \$target/etc/ssh/sshd_config
+mkdir -p \$target/root/.ssh
+cat << ENDKEYS > \$target/root/.ssh/authorized_keys
+$authkeys
+ENDKEYS
+
+# Set host keys permissions
+chown root:wheel \$target/etc/ssh/ssh_host_*_key*
+chmod 0600 \$target/etc/ssh/ssh_host_*_key
+chmod 0644 \$target/etc/ssh/ssh_host_*_key.pub
+
+# Setup serial console output for stage1
+printf "%s" "-h -S$c{Baud}" >> \$target/boot.config
+cat << ENDBOOT >> \$target/boot/loader.conf
+# Serial console configuration
+boot_serial="YES"
+comconsole_speed="$c{Baud}"
+console="comconsole"
+boot_verbose="YES"
+beastie_disable="YES"
+
+# mfs boot parameters
+geom_uzip_load="YES"
+tmpfs_load="YES"
+mfs_load="YES"
+mfs_type="mfs_root"
+mfs_name="/mfsroot"
+vfs.root.mountfrom="ufs:/dev/ufs/FreeBSD_Install"
+ENDBOOT
+
+# Enable DHCP on all network interfaces
+echo 'ifconfig_DEFAULT="DHCP"' >> \$target/etc/rc.conf
+
+# Remove the local script that launches the installer by default
+rm -rf \$target/etc/rc.local
+
+# Create a temporary fstab with the root dir
+echo '/dev/ufs/FreeBSD_Install / ufs rw 1 1' > \$target/etc/fstab
+
+# Remove the linked resolv.conf
+rm -rf \$target/etc/resolv.conf
+END
+
+    logm("Create the installer");
+    target_cmd_root($ho, <<END, 600);
+set -ex
+target=$builddir/freebsd/release/$target
+output=$builddir/install.img
+mkdir -p \$output.tmp
+
+# Do some pruning
+rm -rf \$target/usr/share/man
+rm -rf \$target/usr/share/examples
+rm -rf \$target/usr/share/doc
+rm -rf \$target/usr/share/dtrace
+
+# Create a mfs root image
+makefs -b 10% -B little -o label=FreeBSD_Install \$output.tmp/mfsroot \$target
+# Compress image
+gzip \$output.tmp/mfsroot
+
+# Copy boot to the staging dir
+cp -r \$target/boot \$output.tmp/
+cp \$target/boot.config \$output.tmp/
+
+# The loader only needs the tmpfs and geom_uzip modules in order
+# to boot into the mfs root, the rest of the modules can be loaded from
+# the mfs root itself.
+for module in `ls \$output.tmp/boot/kernel/*.ko`; do
+    if [ `basename "\$module"` != "geom_uzip.ko" ] && \\
+       [ `basename "\$module"` != "tmpfs.ko" ]; then
+        rm -f \$module
+    fi
+done
+
+makefs -B little \$output.part \$output.tmp
+
+# Make the image bootable
+mkimg -s gpt -b \$target/boot/pmbr -p efi:=\$target/boot/boot1.efifat \\
+    -p freebsd-boot:=\$target/boot/gptboot -p freebsd-ufs:=\$output.part \\
+    -p freebsd-swap::1M -o \$output
+
+rm \$output.part
+rm -rf \$output.tmp
+END
+}
+
+sub stash () {
+    logm("Stashing FreeBSD build output");
+    built_stash_file($ho, $builddir, "freebsd-image", "install.img", 0);
+    built_stash_file($ho, $builddir, "freebsd-manifest",
+                     "freebsd/release/ftp/MANIFEST", 0);
+    built_stash_file($ho, $builddir, "freebsd-base",
+                     "freebsd/release/ftp/base.txz", 0);
+    built_stash_file($ho, $builddir, "freebsd-kernel",
+                     "freebsd/release/ftp/kernel.txz", 0);
+    built_stash_debugfile($ho, $builddir, "freebsd-kernel-dbg",
+                          "freebsd/release/ftp/kernel-dbg.txz", 0);
+    my $srcversion = target_cmd_output_root($ho, <<END, 30);
+awk '/^\\\#define[[:space:]]*__FreeBSD_version/ { print \$3 }' \\
+    $builddir/freebsd/sys/sys/param.h | cut -c1-2
+END
+    store_runvar("freebsd_version", "$srcversion");
+}
+
+install_deps();
+checkout();
+build();
+stash();
+
+logm("FreeBSD build successful");
+