Add options to build ONIE images

Open Network Install Environment is an open image format used by
networking vendor to ship a standardised image for networking white
box switches.

ONIE hardware takes this image at boot and a script to chain load
into the final environment via kexec. We can support Debian and
derivatives on such systems by packing an ISO which then gets
unpacked, kexec'ed and live-booted.

A base ONIE system can be tested in QEMU by building a VM following
these instrunctions:

https://github.com/opencomputeproject/onie/blob/master/machine/kvm_x86_64/INSTALL

Once built, boot onie-recovery-x86_64-kvm_x86_64-r0.iso in QEMU/libvirt
and on the console there will be the terminal prompt. Check the IP
assigned by libvirt and then scp the live image (ssh access is enabled
as root without password...). Then the .bin can be booted with:
 ONIE-RECOVERY:/ # onie-nos-install /tmp/live.hybrid.iso-ONIE.bin

The implementation is inspired by ONIE's own scripts that can be found
at:
https://github.com/opencomputeproject/onie/blob/master/contrib/debian-iso/cook-bits.sh

A new option, --onie (false by default) can be set to true to enable
building this new format in addition to an ISO.
An additional option, --onie-kernel-cmdline can be used to specify
additional options that the ONIE system should use when kexec'ing the
final image.
Note that only iso or hybrid-iso formats are supported.

For more information about the ONIE ecosystem see:
http://onie.org

Signed-off-by: Erik Ziegenbalg <eziegenb@Brocade.com>
Signed-off-by: Luca Boccassi <bluca@debian.org>
This commit is contained in:
Luca Boccassi 2018-03-16 19:30:50 +00:00
parent 8047c2425a
commit 46c9596926
5 changed files with 336 additions and 1 deletions

View File

@ -763,6 +763,12 @@ Set_defaults ()
# Setting net tarball
LB_NET_TARBALL="${LB_NET_TARBALL:-true}"
# Setting onie
LB_ONIE="${LB_ONIE:-false}"
# Setting onie additional kernel cmdline options
LB_ONIE_KERNEL_CMDLINE="${LB_ONIE_KERNEL_CMDLINE:-}"
# Setting firmware option
LB_FIRMWARE_CHROOT="${LB_FIRMWARE_CHROOT:-true}"
LB_FIRMWARE_BINARY="${LB_FIRMWARE_BINARY:-true}"

View File

@ -198,6 +198,10 @@
[\fB\-\-net\-cow\-server\fR \fIIP\fR|\fIHOSTNAME\fR]
.br
[\fB\-\-net\-tarball\fR true|false]
.br
[\fB\-\-onie\fR true|false]
.br
[\fB\-\-onie\-kernel\-cmdline\fR \fI"OPTION1 OPTION2"\fR]
.br
[\fB\-\-quiet\fR]
.br
@ -432,6 +436,10 @@ Example:
sets the IP or hostname that will be configured in the bootloader configuration for the copy\-on\-write filesystem of your netboot image and is by default empty.
.IP "\fB\-\-net\-tarball\fR true|false" 4
defines if a compressed tarball should be created. Disabling this options leads to no tarball at all, the plain binary directory is considered the output in this case. Default is true.
.IP "\fB\-\-onie\fR true|false" 4
defines if an ONIE.bin image is generated. ONIE binaries can be loaded by supported systems, and will in turn boot the live image. Note that iso or hybrid-iso are the only formats supported. For more information visit <\fIhttp://onie.org/\fR>. Default is false.
.IP "\fB\-\-onie\-kernel\-cmdline\fR \fI""OPTION1 OPTION2""\fR" 4
defines additional kernel command line options that the ONIE system will use when booting the image. Default is empty string.
.IP "\fB\-\-quiet\fR" 4
reduces the verbosity of messages output by \fBlb build\fR.
.IP "\fB\-\-archive\-areas\fR \fIARCHIVE_AREA\fR|""\fIARCHIVE_AREAS\fR""" 4

View File

@ -82,6 +82,7 @@ fi
# Building images
lb binary_iso ${@}
lb binary_onie ${@}
lb binary_netboot ${@}
lb binary_tar ${@}
lb binary_hdd ${@}

300
scripts/build/binary_onie Executable file
View File

@ -0,0 +1,300 @@
#!/bin/sh
## live-build(7) - System Build Scripts
## Copyright (C) 2017 Erik Ziegenbalg <eziegenb@brocade.com>
## Copyright (C) 2018 Luca Boccassi <bluca@debian.org>
##
## This program comes with ABSOLUTELY NO WARRANTY; for details see COPYING.
## This is free software, and you are welcome to redistribute it
## under certain conditions; see COPYING for details.
set -e
# Including common functions
[ -e "${LIVE_BUILD}/scripts/build.sh" ] && . "${LIVE_BUILD}/scripts/build.sh" || . /usr/lib/live/build.sh
# Setting static variables
DESCRIPTION="$(Echo 'build ONIE binary image')"
HELP=""
USAGE="${PROGRAM} [--force]"
Arguments "${@}"
# Reading configuration files
Read_conffiles config/all config/common config/bootstrap config/chroot config/binary config/source
Set_defaults
if [ "${LB_ONIE}" != "true" ]
then
exit 0
fi
case "${LIVE_IMAGE_TYPE}" in
iso)
IMAGE="${LIVE_IMAGE_NAME}-${LB_ARCHITECTURES}.iso"
;;
iso-hybrid)
IMAGE="${LIVE_IMAGE_NAME}-${LB_ARCHITECTURES}.hybrid.iso"
;;
*)
exit 0
;;
esac
Echo_message "Begin building onie binary..."
# Requiring stage file
Require_stagefile .build/config .build/binary_iso
# Checking stage file
Check_stagefile .build/binary_onie
# Checking lock file
Check_lockfile .lock
# Creating lock file
Create_lockfile .lock
### Adds needed helper script
## Based on https://github.com/opencomputeproject/onie/blob/master/contrib/debian-iso/sharch_body.sh
cat > sharch_body.sh << EOF
#!/bin/sh
#
# Copyright (C) 2015 Curt Brune <curt@cumulusnetworks.com>
#
# SPDX-License-Identifier: GPL-2.0
#
#
# Shell archive template
#
# Strings of the form %%VAR%% are replaced during construction.
#
echo -n "Verifying image checksum ..."
sha1=\$(sed -e '1,/^exit_marker$/d' "\$0" | sha1sum | awk '{ print \$1 }')
payload_sha1=%%IMAGE_SHA1%%
if [ "\$sha1" != "\$payload_sha1" ] ; then
echo
echo "ERROR: Unable to verify archive checksum"
echo "Expected: \$payload_sha1"
echo "Found : \$sha1"
exit 1
fi
echo " OK."
tmp_dir=
clean_up() {
if [ "\$(id -u)" = "0" ] ; then
umount \$tmp_dir > /dev/null 2>&1
fi
rm -rf \$tmp_dir
exit \$1
}
# Untar and launch install script in a tmpfs
cur_wd=\$(pwd)
archive_path=\$(realpath "\$0")
tmp_dir=\$(mktemp -d)
if [ "\$(id -u)" = "0" ] ; then
mount -t tmpfs tmpfs-installer \$tmp_dir || clean_up 1
fi
cd \$tmp_dir
echo -n "Preparing image archive ..."
sed -e '1,/^exit_marker\$/d' \$archive_path | tar xf - || clean_up 1
echo " OK."
cd \$cur_wd
extract=no
args=":x"
while getopts "\$args" a ; do
case \$a in
x)
extract=yes
;;
*)
;;
esac
done
if [ "\$extract" = "yes" ] ; then
# stop here
echo "Image extracted to: \$tmp_dir"
if [ "\$(id -u)" = "0" ] ; then
echo "To un-mount the tmpfs when finished type: umount \$tmp_dir"
fi
exit 0
fi
\$tmp_dir/installer/install.sh "\$@"
rc="\$?"
clean_up \$rc
exit_marker
EOF
### Based on onie cookbits script...
### https://github.com/opencomputeproject/onie/blob/master/contrib/debian-iso/cook-bits.sh
CURDIR=`pwd`
OUT=${CURDIR}/output
rm -rf $OUT
mkdir -p $OUT
WORKDIR=${CURDIR}/work
EXTRACTDIR="$WORKDIR/extract"
INSTALLDIR="$WORKDIR/installer"
IN_IMAGE="${IMAGE}"
output_file="${OUT}/${IN_IMAGE}-ONIE.bin"
echo "Creating $output_file:"
# prepare workspace
[ -d $EXTRACTDIR ] && chmod +w -R $EXTRACTDIR
rm -rf $WORKDIR
mkdir -p $EXTRACTDIR
mkdir -p $INSTALLDIR
# Link the iso binary root to the onie extract dir
ln -s ${CURDIR}/binary/* ${EXTRACTDIR}
echo -n "."
## pack ISO into initrd
# create initrd working dir
INITDIR=${WORKDIR}/initrd-extract
rm -rf ${INITDIR}
mkdir -p ${INITDIR}
cd ${INITDIR}
# extract current initrd
xzcat $EXTRACTDIR/live/initrd.img | cpio -d -i -m
echo -n "."
# copy inputed iso into initrd
cp "${CURDIR}/${IN_IMAGE}" ./conf/live.iso
echo -n "."
# repack
find . | cpio -o -H newc | xz --check=crc32 --x86 --lzma2=dict=512KiB > ${WORKDIR}/initrd.img
# cd back into rood dir
cd ${CURDIR}
echo -n "."
KERNEL='vmlinuz'
IN_KERNEL=$EXTRACTDIR/live/$KERNEL
[ -r $IN_KERNEL ] || {
echo "ERROR: Unable to find kernel in ISO: $IN_KERNEL"
exit 1
}
INITRD='initrd.img'
IN_INITRD=$WORKDIR/$INITRD
[ -r $IN_INITRD ] || {
echo "ERROR: Unable to find initrd in ISO: $IN_INITRD"
exit 1
}
# Note: specify kernel args you want the Debian installer to
# automatically append by putting them after the special marker "---".
# Here we want the Deb installer to auto include the serial console
# parameters.
# The minimal required parameters are included by default, and users
# can add more depending on what they need, eg: systemd parameters.
KERNEL_ARGS="--- boot=live nopersistent noeject dhcp fromiso=/conf/live.iso"
KERNEL_ARGS="${KERNEL_ARGS} ${LB_ONIE_KERNEL_CMDLINE}"
# To debug DI preseed file add these args
# DI_DEBUG_ARGS="DEBCONF_DEBUG=5 dbg/flags=all-x"
# Debian installer args
DI_ARGS="auto=true priority=critical $DI_DEBUG_ARGS"
cp -r $IN_KERNEL $IN_INITRD $INSTALLDIR
# Create custom install.sh script
touch $INSTALLDIR/install.sh
chmod +x $INSTALLDIR/install.sh
(cat <<EOF
#!/bin/sh
cd \$(dirname \$0)
# remove old partitions
for p in \$(seq 3 9) ; do
sgdisk -d \$p /dev/vda > /dev/null 2&>1
done
# bonk out on errors
set -e
echo "auto-detecting console..."
tty=\$(cat /sys/class/tty/console/active 2>/dev/null | awk 'END {print \$NF}')
speed=\$(stty -F /dev/\$tty speed 2>/dev/null)
bits=\$(stty -F /dev/\$tty -a 2>/dev/null | grep -o cs[5-8])
bits=\$(echo \$bits | grep -o [5-8])
con=''
if [ -n "\$speed" ]; then
con="console=\$tty,\${speed}n\${bits}"
else
con="console=\$tty"
fi
echo "using \$con"
kcmd_console=\$(cat /proc/cmdline | grep -o 'console=.* ')
kcmd_console=\$(echo \$kcmd_console | cut -d' ' -f2) # remove tty0
if [ \${kcmd_console}x != \${con}x ]; then
echo "WARNING: Detected console does not match boot console: \$kcmd_console != \$con"
fi
echo "Loading new kernel ..."
echo "kexec --load --initrd=$INITRD --append=\"$DI_ARGS $KERNEL_ARGS \$con\" $KERNEL"
kexec --load --initrd=$INITRD --append="$DI_ARGS $KERNEL_ARGS \$con" $KERNEL
kexec --exec
EOF
) >> $INSTALLDIR/install.sh
echo -n "."
# Repackage $INSTALLDIR into a self-extracting installer image
sharch="$WORKDIR/sharch.tar"
tar -C $WORKDIR -cf $sharch installer || {
echo "Error: Problems creating $sharch archive"
exit 1
}
[ -f "$sharch" ] || {
echo "Error: $sharch not found"
exit 1
}
echo -n "."
sha1=$(cat $sharch | sha1sum | awk '{print $1}')
echo -n "."
cp sharch_body.sh $output_file || {
echo "Error: Problems copying sharch_body.sh"
exit 1
}
# Replace variables in the sharch template
sed -i -e "s/%%IMAGE_SHA1%%/$sha1/" $output_file
echo -n "."
cat $sharch >> $output_file
mv $output_file ${CURDIR}
rm -rf $tmp_dir
rm -rf $OUT $WORKDIR
echo " Done."
ls -la $(basename $output_file)
Echo_message "onie-installer created..."
# Creating stage file
Create_stagefile .build/binary_onie

View File

@ -105,6 +105,8 @@ USAGE="${PROGRAM} [--apt apt|aptitude]\n\
\t [--net-cow-path PATH]\n\
\t [--net-cow-server IP|HOSTNAME]\n\
\t [--net-tarball true|false]\n\
\t [--onie true|false]\n\
\t [--onie-kernel-cmdline \"OPTION1 OPTION2\"]\n\
\t [--quiet]\n\
\t [--archive-areas ARCHIVE_AREA|\"ARCHIVE_AREAS\"]\n\
\t [--parent-archive-areas ARCHIVE_AREA|\"ARCHIVE_AREAS\"]\n\
@ -146,7 +148,7 @@ Local_arguments ()
grub-splash:,isohybrid-options:,hdd-label:,hdd-size:,hdd-partition-start:,iso-application:,iso-preparer:,iso-publisher:,
iso-volume:,jffs2-eraseblock:,memtest:,net-root-filesystem:,net-root-mountoptions:,
net-root-path:,net-root-server:,net-cow-filesystem:,net-cow-mountoptions:,net-cow-path:,
net-cow-server:,net-tarball:,firmware-binary:,firmware-chroot:,swap-file-path:,swap-file-size:,
net-cow-server:,net-tarball:,onie:,onie-kernel-cmdline:,firmware-binary:,firmware-chroot:,swap-file-path:,swap-file-size:,
loadlin:,win32-loader:,source:,source-images:,breakpoints,conffile:,debug,force,
help,ignore-system-defaults,quiet,usage,verbose,version,bootstrap-qemu-static:,bootstrap-qemu-arch:,
uefi-secure-boot:,
@ -656,6 +658,16 @@ Local_arguments ()
shift 2
;;
--onie)
LB_ONIE="${2}"
shift 2
;;
--onie-kernel-cmdline)
LB_ONIE_KERNEL_CMDLINE="${2}"
shift 2
;;
--firmware-binary)
LB_FIRMWARE_BINARY="${2}"
shift 2
@ -1291,6 +1303,14 @@ LB_NET_COW_SERVER="${LB_NET_COW_SERVER}"
# (Default: ${LB_NET_TARBALL})
LB_NET_TARBALL="${LB_NET_TARBALL}"
# \$LB_ONIE: set onie
# (Default: ${LB_ONIE})
LB_ONIE="${LB_ONIE}"
# \$LB_ONIE_KERNEL_CMDLINE: set onie additional kernel cmdline options
# (Default: ${LB_ONIE_KERNEL_CMDLINE})
LB_ONIE_KERNEL_CMDLINE="${LB_ONIE_KERNEL_CMDLINE}"
# \$LB_FIRMWARE_BINARY: include firmware packages in debian-installer
# (Default: ${LB_FIRMWARE_BINARY})
LB_FIRMWARE_BINARY="${LB_FIRMWARE_BINARY}"