Update gen iso scripts for CentOS support in Debian

Update existing dynamic ISO generation scripts to target the last
CentOS release from within a Debian environment.

Changes are applied for gen-prestaged-iso-centos.sh for support
within a Debian instance.

The existing Debian-targeting files (gen-bootloader-iso.sh,
gen-prestaged-iso.sh) are updated for minor fixes in logging,
consistency, and overall code structure for ease of support and
maintenance.

This commit aligns recent changes of gen-bootloader-iso.sh into
gen-bootloader-iso-centos.sh, for easier support going forward.

And finally, unit tests are added for the gen-prestaged-iso* scripts.
The unit tests use shunit2 framework, which is dynamically pulled in as
required to run the tests. At this point, tests are only run manually;
they are not part of the loadbuild. Unit tests may be added for
gen-bootloader-iso.sh in a further commit; however, this is of lesser
priority since this script is employed frequently on subcloud remote
installations.

Test Plan

PASS:
- Test gen-prestaged-iso.sh for generating a prestaged ISO targeting a
  local Debian install. An ISO is generated and a full subcloud
  deployment is successful
- Test gen-prestaged-iso-centos.sh for generating a prestaged ISO
  targeting a local CentOS install. An ISO is generated and a full
  subcloud deployment is successful
- Run the two new unit tests, gen-prestaged-iso-test.sh, and
  gen-prestaged-iso-centos-test.sh, both in standalone and via
  run-tests.sh. Verify with both an empty and populated input directory.
- Verify full remote/redfish Debian subcloud install and deployment.
  Targeted at gen-bootloader-iso.sh changes.
- Verify full remote/redfish CentOS subcloud install and deployment.
  Targeted at gen-bootloader-iso-centos.sh changes.

Story: 2010611
Task: 48267
Depends-On: https://review.opendev.org/c/starlingx/metal/+/886662

Signed-off-by: Kyle MacLeod <kyle.macleod@windriver.com>
Change-Id: I31e76ed107f589b1196320b3c8d7243fb15d3491
This commit is contained in:
Kyle MacLeod 2023-06-20 17:47:11 -04:00
parent 8c865c4937
commit e5d9077c39
12 changed files with 1760 additions and 896 deletions

File diff suppressed because it is too large Load Diff

@ -29,18 +29,17 @@ BOOT_HOSTNAME=
BOOT_INTERFACE=
BOOT_IP=
BOOT_NETMASK=
MINIBOOT_INITRD_FILE=/var/miniboot/initrd-mini # populated by the loadbuild at this location
DEFAULT_GRUB_ENTRY=
DEFAULT_SYSLINUX_ENTRY=
DELETE="no"
GRUB_TIMEOUT=-1
INITRD_FILE=
INSTALL_TYPE=
REPACK=no # REPACK initrd is disabled until signing is fixed
INPUT_ISO=
INSTALL_TYPE=
LOCK_FILE=/var/run/.gen-bootloader-iso.lock
LOCK_TMOUT=600 # Wait up to 10 minutes, by default
LOG_TAG=$SCRIPTNAME
MINIBOOT_INITRD_FILE=/var/miniboot/initrd-mini # populated by the loadbuild at this location
NODE_ID=
OUTPUT_ISO=
REPACK=yes # Repack/trim the initrd and kernel images by default
@ -49,7 +48,6 @@ TIMEOUT=100
VERBOSE=${VERBOSE:-}
VERBOSE_LOG_DIR=/var/log/dcmanager/miniboot
VERBOSE_OVERRIDE_FILE=/tmp/gen-bootloader-verbose # turn on verbose if this file is present
WORKDIR=
WWW_ROOT_DIR=
XZ_ARGS="--threads=0 -9 --format=lzma"
@ -86,17 +84,6 @@ function log_warn {
logger -i -s -t "${LOG_TAG}" -- "WARN: $*"
}
function get_path_size {
local path=$1
du -hs "$path" | awk '{print $1}'
}
function log_path_size {
local path=$1
local msg=$2
log_info "$msg: $(get_path_size "$path")"
}
function fatal_error {
logger -i -s -t "${LOG_TAG}" -- "FATAL: $*"
exit 1
@ -127,6 +114,17 @@ function get_os {
esac
}
function get_path_size {
local path=$1
du -hs "$path" | awk '{print $1}'
}
function log_path_size {
local path=$1
local msg=$2
log_info "$msg: $(get_path_size "$path")"
}
function usage {
cat <<ENDUSAGE
Description: Sets up a mini bootimage.iso that includes the minimum required to
@ -224,7 +222,6 @@ function parse_arguments {
INPUT_ISO=$2
shift 2
;;
# TODO: do we need to support --addon for debian?
--addon)
ADDON=$2
shift 2
@ -307,12 +304,12 @@ function parse_arguments {
esac
;;
--timeout)
timeout_arg=$2
local -i timeout_arg=$2
shift 2
if [ $(( timeout_arg )) -gt 0 ]; then
if [ ${timeout_arg} -gt 0 ]; then
TIMEOUT=$(( timeout_arg * 10 ))
GRUB_TIMEOUT=${timeout_arg}
elif [ $(( timeout_arg )) -eq 0 ]; then
elif [ ${timeout_arg} -eq 0 ]; then
GRUB_TIMEOUT=0.001
fi
;;
@ -341,9 +338,9 @@ function parse_arguments {
shift 2
;;
--lock-timeout)
LOCK_TMOUT=$2
local -i LOCK_TMOUT=$2
shift 2
if [ "$LOCK_TMOUT" -le 0 ]; then
if [ "${LOCK_TMOUT}" -le 0 ]; then
echo "Lock timeout must be greater than 0" >&2
exit 1
fi
@ -387,22 +384,25 @@ function initialize_and_lock {
check_required_param "--id" "${NODE_ID}"
check_required_param "--www-root" "${WWW_ROOT_DIR}"
[ -d "${WWW_ROOT_DIR}" ] || fatal_error "Root directory ${WWW_ROOT_DIR} does not exist"
[ -d "${WWW_ROOT_DIR}/iso" ] || mkdir "${WWW_ROOT_DIR}/iso"
[ -f "$VERBOSE_OVERRIDE_FILE" ] && VERBOSE=1
if [ -n "$VERBOSE" ]; then
[ -f "${VERBOSE_OVERRIDE_FILE}" ] && VERBOSE=1
if [ -n "${VERBOSE}" ]; then
VERBOSE_RSYNC="--verbose"
XZ_ARGS="--verbose $XZ_ARGS"
# log all output to file
if [ ! -d "$(dirname "$VERBOSE_LOG_DIR")" ]; then
if [ ! -d "$(dirname "${VERBOSE_LOG_DIR}")" ]; then
# For testing: the base directory does not exist - use /tmp instead
VERBOSE_LOG_DIR=/tmp/miniboot
fi
[ -d "$VERBOSE_LOG_DIR" ] || mkdir -p "$VERBOSE_LOG_DIR"
[ -d "${VERBOSE_LOG_DIR}" ] || mkdir -p "${VERBOSE_LOG_DIR}"
local logfile="${VERBOSE_LOG_DIR}/gen-bootloader-iso-${NODE_ID}.log"
echo "Verbose: logging output to $logfile"
exec > >(tee "$logfile") 2>&1
[ -f "${logfile}" ] && rm -f "${logfile}"
touch "${logfile}"
echo "Verbose: logging output to ${logfile}"
echo "$(date) Starting $0"
printenv >> "${logfile}"
exec > >(tee --append "${logfile}") 2>&1
fi
# Initialize dynamic variables
@ -439,14 +439,14 @@ function initialize_and_lock {
# Run cleanup on any exit
trap cleanup_on_exit EXIT
BUILDDIR=$(mktemp -d -p "$SCRATCH_DIR" gen_bootloader_build_XXXXXX)
BUILDDIR=$(mktemp -d -p "${SCRATCH_DIR}" gen_bootloader_build_XXXXXX)
if [ -z "${BUILDDIR}" ] || [ ! -d "${BUILDDIR}" ]; then
fatal_error "Failed to create builddir: $BUILDDIR"
fatal_error "Failed to create builddir: ${BUILDDIR}"
fi
WORKDIR=$(mktemp -d -p "$SCRATCH_DIR" gen_bootloader_initrd_XXXXXX)
WORKDIR=$(mktemp -d -p "${SCRATCH_DIR}" gen_bootloader_initrd_XXXXXX)
if [ -z "${WORKDIR}" ] || [ ! -d "${WORKDIR}" ]; then
fatal_error "Failed to create initrd extract directory: $WORKDIR"
fatal_error "Failed to create WORKDIR directory: $WORKDIR"
fi
}
@ -468,12 +468,17 @@ function generate_boot_cfg {
for p in "${PARAMS[@]}"; do
param=${p%%=*}
value=${p#*=}
# Pull the boot device out of PARAMS and convert to instdev
if [ "$param" = "boot_device" ]; then
log_info "Setting instdev=$value from boot_device param"
instdev=$value
if [ "${param}" = "${p}" ]; then
# there is no '=' in the parameter; include it directly:
PARAM_LIST="${PARAM_LIST} ${param}"
else
# Pull the boot device out of PARAMS and convert to instdev
if [ "$param" = "boot_device" ]; then
log_info "Setting instdev=$value from boot_device param"
instdev=$value
fi
PARAM_LIST="${PARAM_LIST} ${param}=${value}"
fi
PARAM_LIST="${PARAM_LIST} ${param}=${value}"
done
fi
log_verbose "Parameters: ${PARAM_LIST}"
@ -557,8 +562,8 @@ LABEL 1
EOF
done
log_verbose "Generating grub.cfg, install_type: $INSTALL_TYPE, default: $DEFAULT_GRUB_ENTRY, timeout: $GRUB_TIMEOUT"
for f in ${isodir}/EFI/BOOT/grub.cfg ${EFI_MOUNT}/EFI/BOOT/grub.cfg; do
log_verbose "Generating grub.cfg, install_type: ${INSTALL_TYPE}, default: ${DEFAULT_GRUB_ENTRY}, timeout: ${GRUB_TIMEOUT}"
for f in "${isodir}/EFI/BOOT/grub.cfg" "${EFI_MOUNT}/EFI/BOOT/grub.cfg"; do
cat <<EOF > "${f}"
default=${DEFAULT_GRUB_ENTRY}
timeout=${GRUB_TIMEOUT}
@ -581,13 +586,13 @@ menuentry 'UEFI Graphical Console' --id=graphical {
}
EOF
done
if [ -n "$VERBOSE" ]; then
log_verbose "Contents of ${isodir}/EFI/BOOT/grub.cfg"
cat "${isodir}/EFI/BOOT/grub.cfg"
log_verbose ""
log_verbose "Contents of ${EFI_MOUNT}/EFI/BOOT/grub.cfg"
cat "${EFI_MOUNT}/EFI/BOOT/grub.cfg"
fi
if [ -n "$VERBOSE" ]; then
log_verbose "Contents of ${isodir}/EFI/BOOT/grub.cfg"
cat "${isodir}/EFI/BOOT/grub.cfg"
log_verbose ""
log_verbose "Contents of ${EFI_MOUNT}/EFI/BOOT/grub.cfg"
cat "${EFI_MOUNT}/EFI/BOOT/grub.cfg"
fi
}
function cleanup_on_exit {
@ -624,28 +629,28 @@ function handle_delete {
}
function create_miniboot_iso {
log_info "Creating minitboot ISO"
log_info "Creating miniboot ISO"
# Copy files for mini ISO build
rsync $VERBOSE_RSYNC -a \
rsync ${VERBOSE_RSYNC} -a \
--exclude ostree_repo \
--exclude pxeboot \
"${MNTDIR}/" "${BUILDDIR}"
check_rc_exit $? "Failed to rsync ISO from $MNTDIR to $BUILDDIR"
if [ "$REPACK" = yes ]; then
if [ "${REPACK}" = yes ]; then
# Use default initrd-mini location if none specified
# This picks up the initrd-mini file if it is available
# (included in ISO by the loadbuild). Otherwise we warn
# and continue without repacking initrd - instead using
# the original from the ISO.
if [ -z "$INITRD_FILE" ]; then
INITRD_FILE="$MINIBOOT_INITRD_FILE"
if [ -z "${INITRD_FILE}" ]; then
INITRD_FILE="${MINIBOOT_INITRD_FILE}"
fi
if [ -f "$INITRD_FILE" ]; then
if [ -f "${INITRD_FILE}" ]; then
if [ -f "${INITRD_FILE}.sig" ]; then
# Overwrite the original ISO initrd file:
log_info "Repacking miniboot ISO using initrd: ${INITRD_FILE} and ${INITRD_FILE}.sig"
cp "$INITRD_FILE" "${BUILDDIR}/initrd"
cp "${INITRD_FILE}" "${BUILDDIR}/initrd"
check_rc_exit $? "copy initrd failed"
cp "${INITRD_FILE}.sig" "${BUILDDIR}/initrd.sig"
check_rc_exit $? "copy initrd.sig failed"
@ -653,10 +658,10 @@ function create_miniboot_iso {
log_error "No initrd.sig found at: ${INITRD_FILE}.sig ...skipping initrd repack"
fi
else
log_warn "Could not find initrd file at $INITRD_FILE ...skipping initrd repack"
log_warn "Could not find initrd file at ${INITRD_FILE} ...skipping initrd repack"
fi
log_info "Trimming miniboot ISO content"
log_path_size "$BUILDDIR" "Size of extracted miniboot before trim"
log_path_size "${BUILDDIR}" "Size of extracted miniboot before trim"
# Remove unused kernel images:
rm "${BUILDDIR}"/{bzImage,bzImage-rt}
check_rc_exit $? "failed to trim miniboot iso files"
@ -668,18 +673,18 @@ function create_miniboot_iso {
# where any .cfg files are now copied into the /kickstart directory in the ISO
# Any files in this override directory can replace the files from the ISO copied
# from the rsync above.
if [ -n "$KICKSTART_OVERRIDE_DIR" ] \
&& [ -d "$KICKSTART_OVERRIDE_DIR" ] \
&& [ "$(echo "$KICKSTART_OVERRIDE_DIR/"*.cfg)" != "$KICKSTART_OVERRIDE_DIR/*.cfg" ]; then
log_info "Copying .cfg files from KICKSTART_OVERRIDE_DIR=$KICKSTART_OVERRIDE_DIR to $BUILDDIR/kickstart"
cp "$KICKSTART_OVERRIDE_DIR/"*.cfg "$BUILDDIR/kickstart"
if [ -n "${KICKSTART_OVERRIDE_DIR}" ] \
&& [ -d "${KICKSTART_OVERRIDE_DIR}" ] \
&& [ "$(echo "${KICKSTART_OVERRIDE_DIR}/"*.cfg)" != "${KICKSTART_OVERRIDE_DIR}/*.cfg" ]; then
log_info "Copying .cfg files from KICKSTART_OVERRIDE_DIR=${KICKSTART_OVERRIDE_DIR} to ${BUILDDIR}/kickstart"
cp "${KICKSTART_OVERRIDE_DIR}/"*.cfg "${BUILDDIR}/kickstart"
fi
# Setup syslinux and grub cfg files
if [ -z "${EFI_MOUNT}" ]; then
mount_efiboot_img "${BUILDDIR}"
check_rc_exit $? "failed to mount EFI"
log_info "Using EFI_MOUNT=$EFI_MOUNT"
log_info "Using EFI_MOUNT=${EFI_MOUNT}"
fi
generate_boot_cfg "${BUILDDIR}"
unmount_efiboot_img
@ -688,7 +693,7 @@ function create_miniboot_iso {
# Rebuild the ISO
OUTPUT_ISO=${NODE_DIR}/bootimage.iso
log_info "Creating $OUTPUT_ISO from BUILDDIR: ${BUILDDIR}"
log_info "Creating ${OUTPUT_ISO} from BUILDDIR: ${BUILDDIR}"
mkisofs -o "${OUTPUT_ISO}" \
-A 'instboot' -V 'instboot' \
-quiet -U -J -joliet-long -r -iso-level 2 \
@ -718,7 +723,7 @@ function main {
fi
parse_arguments "$@"
initialize_and_lock
mount_iso "$INPUT_ISO" "$SCRATCH_DIR"
mount_iso "${INPUT_ISO}" "${SCRATCH_DIR}"
create_miniboot_iso
unmount_iso
exit 0

@ -1,6 +1,6 @@
#!/bin/bash
#
# Copyright (c) 2021-2022 Wind River Systems, Inc.
# Copyright (c) 2021-2023 Wind River Systems, Inc.
#
# SPDX-License-Identifier: Apache-2.0
#
@ -14,26 +14,30 @@
# exceed 4 GB. Multiple archives can be provided. All archives
# must have the suffix 'tar.gz'.
function log_error {
echo "$@" >&2
# shellcheck disable=1091 # don't warn about following 'source <file>'
# shellcheck disable=2164 # don't warn about pushd/popd failures
# shellcheck disable=2181 # don't warn about using rc=$?
function log_fatal {
echo "$(date "+%F %H:%M:%S") FATAL: $*" >&2
exit 1
}
# Source shared utility functions
DIR_NAME=$(dirname $0)
if [ ! -f ${DIR_NAME}/stx-iso-utils-centos.sh ]; then
log_error "Unable to find required utility: stx-iso-utils-centos.sh"
exit 1
fi
function log_error {
echo "$(date "+%F %H:%M:%S"): ERROR: $*" >&2
}
source $(dirname $0)/stx-iso-utils-centos.sh
function log_info {
echo "$(date "+%F %H:%M:%S"): INFO: $*" >&2
}
# Usage manual.
function usage {
cat <<ENDUSAGE
Utility to convert a StarlingX installation iso into a prestaged subcloud
installation iso.
Utility to convert a StarlingX installation iso into a CentOS prestaged subcloud installation iso.
Usage:
$(basename $0) --input <input bootimage.iso>
$(basename "$0") --input <input bootimage.iso>
--output <output bootimage.iso>
[ --images <images.tar.gz> ]
[ --patch <patch-name.patch> ]
@ -83,6 +87,7 @@ ENDUSAGE
}
function cleanup {
# This is invoked from the trap handler.
common_cleanup
}
@ -94,31 +99,31 @@ function set_default_label {
local isodir=$1
if [ -z "${EFI_MOUNT}" ]; then
mount_efiboot_img ${isodir}
mount_efiboot_img "${isodir}"
fi
for f in ${isodir}/isolinux.cfg ${isodir}/syslinux.cfg; do
for f in "${isodir}/isolinux.cfg" "${isodir}/syslinux.cfg"; do
if [ "${DEFAULT_LABEL}" = "NULL" ]; then
# Remove default, if set
grep -q '^default' ${f}
grep -q '^default' "${f}"
if [ $? -eq 0 ]; then
sed -i '/^default/d' ${f}
sed -i '/^default/d' "${f}"
fi
else
grep -q '^default' ${f}
grep -q '^default' "${f}"
if [ $? -ne 0 ]; then
cat <<EOF >> ${f}
cat <<EOF >> "${f}"
default ${DEFAULT_SYSLINUX_ENTRY}
EOF
else
sed -i "s/^default.*/default ${DEFAULT_SYSLINUX_ENTRY}/" ${f}
sed -i "s/^default.*/default ${DEFAULT_SYSLINUX_ENTRY}/" "${f}"
fi
fi
done
for f in ${isodir}/EFI/BOOT/grub.cfg ${EFI_MOUNT}/EFI/BOOT/grub.cfg; do
sed -i "s/^default=.*/default=\"${DEFAULT_GRUB_ENTRY}\"/" ${f}
sed -i "s/^default=.*/default=\"${DEFAULT_GRUB_ENTRY}\"/" "${f}"
done
}
@ -126,27 +131,27 @@ function set_timeout {
local isodir=$1
if [ -z "${EFI_MOUNT}" ]; then
mount_efiboot_img ${isodir}
mount_efiboot_img "${isodir}"
fi
for f in ${isodir}/isolinux.cfg ${isodir}/syslinux.cfg; do
sed -i "s/^timeout.*/timeout ${TIMEOUT}/" ${f}
sed -i "s/^timeout.*/timeout ${TIMEOUT}/" "${f}"
done
for f in ${isodir}/EFI/BOOT/grub.cfg ${EFI_MOUNT}/EFI/BOOT/grub.cfg; do
sed -i "s/^timeout=.*/timeout=${GRUB_TIMEOUT}/" ${f}
sed -i "s/^timeout=.*/timeout=${GRUB_TIMEOUT}/" "${f}"
grep -q "^ set timeout=" ${f}
grep -q "^ set timeout=" "${f}"
if [ $? -eq 0 ]; then
# Submenu timeout is already added. Update the value
sed -i -e "s#^ set timeout=.*# set timeout=${GRUB_TIMEOUT}#" ${f}
sed -i -e "s#^ set timeout=.*# set timeout=${GRUB_TIMEOUT}#" "${f}"
if [ $? -ne 0 ]; then
log_error "Failed to update grub timeout"
exit 1
fi
else
# Parameter doesn't exist. Add it to the cmdline
sed -i -e "/^submenu/a \ \ set timeout=${GRUB_TIMEOUT}" ${f}
sed -i -e "/^submenu/a \ \ set timeout=${GRUB_TIMEOUT}" "${f}"
if [ $? -ne 0 ]; then
log_error "Failed to add grub timeout"
exit 1
@ -171,13 +176,14 @@ function normalized_path {
local path="${1}"
local default_fn="${2}"
local path_name="$(basename "${path}")"
local path_dir="$(dirname "${path}")"
local path_name path_dir
path_name="$(basename "${path}")"
path_dir="$(dirname "${path}")"
# If 'path' ends in '/' then path was intended to be a directory
if [ "${path:(-1):1}" == "/" ]; then
if [ "${path: -1:1}" = "/" ]; then # Note: space is required after : to distinguish from ${path:-...}
# Drop the trailing '/'
path_dir="${path:0:(-1)}"
path_dir="${path:0:-1}"
path_name="${default_fn}"
fi
@ -198,7 +204,6 @@ function normalized_path {
fi
}
function copy_to_iso {
local src="${1}"
local dest="${2}"
@ -208,9 +213,7 @@ function copy_to_iso {
local default_dest=
local final_dest=
local final_dest_dir=
local default_md5=
local final_md5=
local final_md5_dir=
if [ -z "${src}" ] || [ -z "${dest}" ]; then
log_error "Error: copy_to_iso: missing argument"
@ -227,9 +230,7 @@ function copy_to_iso {
final_dest="${BUILDDIR}/${dest}"
final_dest_dir="$(dirname "${final_dest}")"
if [ ! -z "${md5}" ]; then
default_md5="$(basename "${dest}.md5")"
if [ -n "${md5}" ]; then
case "${md5}" in
y | Y | yes | YES )
# Use a default name, in same dir as dest
@ -237,9 +238,7 @@ function copy_to_iso {
;;
esac
md5="$(normalized_path "${md5}" "${final_md5}")"
final_md5="${BUILDDIR}/${md5}"
final_md5_dir="$(dirname "${final_md5}")"
fi
if [ -z "${overwrite}" ] || [ "${overwrite}" == 'n' ]; then
@ -254,21 +253,14 @@ function copy_to_iso {
exit 1
fi
if [ ! -z "${final_md5_dir}" ]; then
if [ ! -d "${final_md5_dir}" ]; then
log_error "Error: copy_to_iso: md5 destination directory does not exist '${final_md5_dir}'"
exit 1
fi
fi
\cp -f "${src}" "${final_dest}"
cp -f "${src}" "${final_dest}"
if [ $? -ne 0 ]; then
log_error "Error: Failed to copy '${src}' to '${final_dest}'"
exit 1
fi
if [ ! -z "${final_md5}" ]; then
pushd ${final_dest_dir} > /dev/null
if [ -n "${final_md5}" ]; then
pushd "${final_dest_dir}" > /dev/null
md5sum "$(basename "${final_dest}")" >> "${final_md5}"
popd > /dev/null
fi
@ -371,12 +363,13 @@ function find_in_patch {
# make sure patch is an absolute path
patch="$(abspath "${patch}")"
patchdir=$(mktemp -d -p $PWD updateiso_build_patch_XXXXXX)
patchdir=$(mktemp -d -p "${PWD}" updateiso_build_patch_XXXXXX)
pushd "${patchdir}" > /dev/null
extract_patch "${patch}"
# shellcheck disable=2044
for rpm in $(find . -name '*.rpm'); do
if path="$(find_in_rpm "${rpm}" "${target}")"; then
found_rpm="$(basename ${rpm})"
found_rpm="$(basename "${rpm}")"
break
fi
done
@ -411,14 +404,14 @@ function copy_rpm_file_to_iso {
# make sure patch is an absolute path
rpm="$(abspath "${rpm}")"
patchdir=$(mktemp -d -p $PWD updateiso_build_rpm_XXXXXX)
patchdir=$(mktemp -d -p "${PWD}" updateiso_build_rpm_XXXXXX)
pushd "${patchdir}" > /dev/null
rpm2cpio "${rpm}" | cpio -imdv ${src}
rpm2cpio "${rpm}" | cpio -imdv "${src}"
if [ $? -ne 0 ]; then
log_error "Error: copy_rpm_file_to_iso: extraction error from rpm '$(basename ${rpm})'"
log_error "copy_rpm_file_to_iso: extraction error from rpm '$(basename "${rpm}")'"
rc=1
elif [ ! -e ${src} ]; then
log_error "Error: copy_rpm_file_to_iso: file '${src}' not found in rpm '$(basename {rpm})'"
elif [ ! -e "${src}" ]; then
log_error "copy_rpm_file_to_iso: file '${src}' not found in rpm '$(basename "${rpm}")'"
rc=1
else
# we do not need an md5 here, so leaving third argument empty
@ -453,11 +446,11 @@ function copy_patch_file_to_iso {
# make sure patch is an absolute path
patch="$(abspath "${patch}")"
rpmdir=$(mktemp -d -p $PWD updateiso_build_patch_XXXXXX)
rpmdir=$(mktemp -d -p "${PWD}" updateiso_build_patch_XXXXXX)
pushd "${rpmdir}" > /dev/null
extract_patch "${patch}"
if [ ! -f "${rpm}" ]; then
log_error "Error: copy_patch_file_to_iso: rpm '${rpm}' not found in patch '$(basename ${patch})'"
log_error "copy_patch_file_to_iso: rpm '${rpm}' not found in patch '$(basename "${patch}")'"
rc=1
else
copy_rpm_file_to_iso "${rpm}" "${src}" "${dest}" "${overwrite}"
@ -474,28 +467,31 @@ function copy_patch_file_to_iso {
}
function generate_boot_cfg {
log_info "Generating boot config"
local isodir=$1
if [ -z "${EFI_MOUNT}" ]; then
mount_efiboot_img ${isodir}
mount_efiboot_img "${isodir}"
fi
local COMMON_ARGS="inst.text inst.gpt boot_device=sda rootfs_device=sda"
COMMON_ARGS="${COMMON_ARGS} biosdevname=0 usbcore.autosuspend=-1"
COMMON_ARGS="${COMMON_ARGS} security_profile=standard user_namespace.enable=1"
COMMON_ARGS="${COMMON_ARGS} inst.stage2=hd:LABEL=${VOLUME_LABEL} inst.ks=hd:LABEL=${VOLUME_LABEL}:/${PRESTAGED_KICKSTART}"
if [[ "${FORCE_INSTALL}" == true ]]; then
if [ -n "${FORCE_INSTALL}" ]; then
COMMON_ARGS="${COMMON_ARGS} force_install"
fi
log_info "COMMON_ARGS: ${COMMON_ARGS}"
for f in ${isodir}/isolinux.cfg ${isodir}/syslinux.cfg; do
cat <<EOF > ${f}
for f in "${isodir}/isolinux.cfg" "${isodir}/syslinux.cfg"; do
cat <<EOF > "${f}"
display splash.cfg
timeout ${TIMEOUT}
F1 help.txt
F2 devices.txt
F3 splash.cfg
serial 0 115200
ui vesamenu.c32
menu background #ff555555
default ${DEFAULT_SYSLINUX_ENTRY}
@ -521,7 +517,7 @@ menu end
EOF
done
for f in ${isodir}/EFI/BOOT/grub.cfg ${EFI_MOUNT}/EFI/BOOT/grub.cfg; do
cat <<EOF > ${f}
cat <<EOF > "${f}"
default=${DEFAULT_GRUB_ENTRY}
timeout=${GRUB_TIMEOUT}
search --no-floppy --set=root -l '${VOLUME_LABEL}'
@ -540,34 +536,46 @@ menuentry 'Graphical Console' --id=graphical {
initrdefi /initrd.img
}
EOF
done
}
# Source shared utility functions
DIR_NAME=$(dirname "$0")
if [ ! -e "${DIR_NAME}"/stx-iso-utils-centos.sh ]; then
echo "${DIR_NAME}/stx-iso-utils-centos.sh does not exist" >&2
exit 1
else
source "${DIR_NAME}"/stx-iso-utils-centos.sh
fi
# Required variables
declare INPUT_ISO=
declare OUTPUT_ISO=
declare -a IMAGES
declare ORIG_PWD=$PWD
declare KS_SETUP=
declare KS_ADDON=
declare UPDATE_TIMEOUT="no"
declare -i FOREVER_GRUB_TIMEOUT=-1
declare -i DEFAULT_GRUB_TIMEOUT=30
declare -i DEFAULT_TIMEOUT=$(( DEFAULT_GRUB_TIMEOUT*10 ))
declare -i TIMEOUT=${DEFAULT_TIMEOUT}
declare -i GRUB_TIMEOUT=${DEFAULT_GRUB_TIMEOUT}
declare -a PARAMS
declare -a PATCHES
declare -a KICKSTART_PATCHES
declare DEFAULT_LABEL=
declare DEFAULT_SYSLINUX_ENTRY=1
declare DEFAULT_GRUB_ENTRY="graphical"
declare UPDATE_TIMEOUT="no"
declare FOREVER_GRUB_TIMEOUT=-1
declare DEFAULT_GRUB_TIMEOUT=30
declare -i DEFAULT_TIMEOUT=(DEFAULT_GRUB_TIMEOUT*10)
declare -i TIMEOUT=${DEFAULT_TIMEOUT}
declare GRUB_TIMEOUT=${DEFAULT_GRUB_TIMEOUT}
declare FORCE_INSTALL=
declare PLATFORM_ROOT="opt/platform-backup"
declare MD5_FILE="container-image.tar.gz.md5"
declare VOLUME_LABEL="oe_prestaged_iso_boot"
declare PRESTAGED_KICKSTART="prestaged_installer_ks.cfg"
declare MENU_NAME="Prestaged Local Installer"
declare FORCE_INSTALL=false
###############################################################################
# Get the command line arguments.
###############################################################################
SHORTOPTS=""; LONGOPTS=""
SHORTOPTS+="i:"; LONGOPTS+="input:,"
@ -583,17 +591,26 @@ SHORTOPTS+="I:"; LONGOPTS+="images:,"
SHORTOPTS+="f"; LONGOPTS+="force-install,"
SHORTOPTS+="h"; LONGOPTS+="help"
declare -i rc
OPTS=$(getopt -o "${SHORTOPTS}" --long "${LONGOPTS}" --name "$0" -- "$@")
if [ $? -ne 0 ]; then
usage
exit 1
log_fatal "Options to $0 not properly parsed"
fi
eval set -- "${OPTS}"
if [ $# = 1 ]; then
usage
log_fatal "No arguments were provided"
fi
while :; do
case $1 in
-h | --help)
usage
exit 0
;;
-i | --input)
INPUT_ISO=$2
shift 2
@ -611,24 +628,27 @@ while :; do
shift 2
;;
-p | --param)
# shellcheck disable=2206
PARAMS+=(${2//,/ })
shift 2
;;
-P | --patch)
# shellcheck disable=2206
PATCHES+=(${2//,/ })
shift 2
;;
-K | --kickstart-patch)
# shellcheck disable=2206
KICKSTART_PATCHES+=(${2//,/ })
shift 2
;;
-I | --images)
# shellcheck disable=2206
IMAGES+=(${2//,/ })
shift 2
;;
-d | --default-boot)
DEFAULT_LABEL=${2}
case ${DEFAULT_LABEL} in
0)
DEFAULT_SYSLINUX_ENTRY=0
@ -639,18 +659,16 @@ while :; do
DEFAULT_GRUB_ENTRY="graphical"
;;
*)
log_error "Invalid default boot menu option: ${DEFAULT_LABEL}"
usage
exit 1
log_fatal "Invalid default boot menu option: ${DEFAULT_LABEL}"
;;
esac
shift 2
;;
-t | --timeout)
let -i timeout_arg=${2}
if [ ${timeout_arg} -gt 0 ]; then
let -i TIMEOUT=${timeout_arg}*10
declare -i timeout_arg=${2}
if [ "${timeout_arg}" -gt 0 ]; then
TIMEOUT=$(( timeout_arg * 10 ))
GRUB_TIMEOUT=${timeout_arg}
elif [ ${timeout_arg} -eq 0 ]; then
TIMEOUT=0
@ -659,7 +677,6 @@ while :; do
TIMEOUT=0
GRUB_TIMEOUT=${FOREVER_GRUB_TIMEOUT}
fi
UPDATE_TIMEOUT="yes"
shift 2
;;
@ -673,111 +690,109 @@ while :; do
;;
*)
usage
exit 1
log_fatal "Unexpected argument: $*"
;;
esac
done
if [ $# -ne 0 ]; then
log_error "Error: Unexpected arguments: $@"
usage
exit 1
fi
###############################################################################
# Generate prestage iso.
#
###############################################################################
log_info "Checking system requirements"
check_requirements
## Check for mandatory parameters
check_required_param "--input" "${INPUT_ISO}"
check_required_param "--output" "${OUTPUT_ISO}"
# shellcheck disable=2068
check_files_exist ${INPUT_ISO} ${IMAGES[@]} ${PATCHES[@]} ${KICKSTART_PATCHES[@]} ${KS_SETUP} ${KS_ADDON}
# shellcheck disable=2068
check_files_size ${INPUT_ISO} ${IMAGES[@]} ${PATCHES[@]} ${KICKSTART_PATCHES[@]} ${KS_SETUP} ${KS_ADDON}
if [ -f ${OUTPUT_ISO} ]; then
log_error "Output file already exists: ${OUTPUT_ISO}"
exit 1
if [ -e "${OUTPUT_ISO}" ]; then
log_fatal "${OUTPUT_ISO} exists. Delete before you execute this script."
fi
shift $((OPTIND-1))
## Catch Control-C and handle.
trap cleanup EXIT
BUILDDIR=$(mktemp -d -p $PWD updateiso_build_XXXXXX)
if [ -z "${BUILDDIR}" -o ! -d ${BUILDDIR} ]; then
log_error "Failed to create builddir. Aborting..."
exit $rc
# Create a temporary build directory.
BUILDDIR=$(mktemp -d -p "${PWD}" updateiso_build_XXXXXX)
if [ -z "${BUILDDIR}" ] || [ ! -d "${BUILDDIR}" ]; then
log_fatal "Failed to create builddir. Aborting..."
fi
mount_iso ${INPUT_ISO}
log_info "Using BUILDDIR=${BUILDDIR}"
mount_iso "${INPUT_ISO}"
#
# prestaging kickstart
#
# Verify prestaging kickstart is present, and where. An original 21.05 iso
# won't have the kickstart. It must be provided by a patch.
# KICKSTART_PATCHES take presedence over a platform PATCHES, which in
# turn take presedence over any content from the ISO.
PRESTAGED_KICKSTART_FOUND_IN=""
PRESTAGED_KICKSTART_PATH=""
# Verify prestaging kickstart is present, and where.
# KICKSTART_PATCHES take precedence over a platform PATCHES, which in
# turn take precedence over any content from the ISO.
PRESTAGED_KICKSTART_PATCH=
PRESTAGED_KICKSTART_PATH=
# scan patches last to first.
for PATCH in $(printf '%s\n' "${KICKSTART_PATCHES[@]}" | tac); do
if PRESTAGED_KICKSTART_PATH="$(find_in_patch "${PATCH}" "${PRESTAGED_KICKSTART}")" ; then
PRESTAGED_KICKSTART_FOUND_IN="${PATCH}"
# Scan KICKSTART_PATCHES last to first.
for patch in $(printf '%s\n' "${KICKSTART_PATCHES[@]}" | tac); do
if PRESTAGED_KICKSTART_PATH="$(find_in_patch "${patch}" "${PRESTAGED_KICKSTART}")" ; then
PRESTAGED_KICKSTART_PATCH="${patch}"
break
fi
done
# scan patches last to first. We want to prefer the most recent patch.
# Scan PATCHES last to first. Prefer the most recent patch.
# Assumes patches will be listed in order 0001, 0002, .... when given as args.
if [ -z "${PRESTAGED_KICKSTART_FOUND_IN}" ]; then
for PATCH in $(printf '%s\n' "${PATCHES[@]}" | tac); do
if PRESTAGED_KICKSTART_PATH="$(find_in_patch "${PATCH}" "${PRESTAGED_KICKSTART}")" ; then
PRESTAGED_KICKSTART_FOUND_IN="${PATCH}"
if [ -z "${PRESTAGED_KICKSTART_PATCH}" ]; then
for patch in $(printf '%s\n' "${PATCHES[@]}" | tac); do
if PRESTAGED_KICKSTART_PATH="$(find_in_patch "${patch}" "${PRESTAGED_KICKSTART}")" ; then
PRESTAGED_KICKSTART_PATCH="${patch}"
break
fi
done
fi
if [ -z "${PRESTAGED_KICKSTART_FOUND_IN}" ]; then
if [ -z "${PRESTAGED_KICKSTART_PATCH}" ]; then
if PRESTAGED_KICKSTART_PATH="$(find_in_mounted_iso "${PRESTAGED_KICKSTART}")" ; then
PRESTAGED_KICKSTART_FOUND_IN="iso"
log_info "Using ${PRESTAGED_KICKSTART} from original ISO"
else
log_fatal "Failed to find required file '${PRESTAGED_KICKSTART}' in the supplied iso and patches."
fi
fi
if [ -z "${PRESTAGED_KICKSTART_FOUND_IN}" ]; then
log_error "Failed to find required file '${PRESTAGED_KICKSTART}' in the supplied iso and patches."
exit 1
fi
#
# Determine release version from ISO
#
if [ ! -f ${MNTDIR}/upgrades/version ]; then
if [ ! -f "${MNTDIR}"/upgrades/version ]; then
log_error "Version info not found on ${INPUT_ISO}"
exit 1
fi
ISO_VERSION=$(source ${MNTDIR}/upgrades/version && echo ${VERSION})
ISO_VERSION=$(source "${MNTDIR}/upgrades/version" && echo "${VERSION}")
if [ -z "${ISO_VERSION}" ]; then
log_error "Failed to determine version of installation ISO"
exit 1
fi
# Copy the contents of the input iso to the build directory.
#
# copy content
#
rsync -a ${MNTDIR}/ ${BUILDDIR}/
log_info "Copying input ISO"
rsync -av "${MNTDIR}/" "${BUILDDIR}/"
rc=$?
if [ $rc -ne 0 ]; then
log_error "Call to rsync ISO content. Aborting..."
exit $rc
if [ "${rc}" -ne 0 ]; then
unmount_iso
log_fatal "Unable to rsync content from the ISO: Error rc=${rc}"
fi
# copy kickstart
if [ "${PRESTAGED_KICKSTART_FOUND_IN}" != "iso" ]; then
copy_patch_file_to_iso "${PRESTAGED_KICKSTART_FOUND_IN}" "${PRESTAGED_KICKSTART_PATH%%:*}" "${PRESTAGED_KICKSTART_PATH##*:}" "/" "y"
# Copy kickstart if it is anywhere outside of the mounted ISO (otherwise it will already have been copied by the above)
if [ -n "${PRESTAGED_KICKSTART_PATCH}" ]; then
log_info "Prestaging kickstart from ${PRESTAGED_KICKSTART_PATCH}"
copy_patch_file_to_iso "${PRESTAGED_KICKSTART_PATCH}" "${PRESTAGED_KICKSTART_PATH%%:*}" "${PRESTAGED_KICKSTART_PATH##*:}" "/" "y"
fi
unmount_iso
@ -785,31 +800,31 @@ unmount_iso
#
# Setup syslinux and grub cfg files
#
generate_boot_cfg ${BUILDDIR}
generate_boot_cfg "${BUILDDIR}"
#
# Set/update boot parameters
#
log_info "Updating boot parameters"
if [ ${#PARAMS[@]} -gt 0 ]; then
for p in ${PARAMS[@]}; do
for p in "${PARAMS[@]}"; do
param=${p%%=*} # Strip from the first '=' on
value=${p#*=} # Strip to the first '='
update_parameter ${BUILDDIR} "${param}" "${value}"
update_parameter "${BUILDDIR}" "${param}" "${value}"
done
fi
if [ -n "${DEFAULT_LABEL}" ]; then
set_default_label ${BUILDDIR}
set_default_label "${BUILDDIR}"
fi
if [ "${UPDATE_TIMEOUT}" = "yes" ]; then
set_timeout ${BUILDDIR}
set_timeout "${BUILDDIR}"
fi
if [ -n "${KS_SETUP}" ]; then
\rm -f ${BUILDDIR}/ks-setup.cfg
\cp ${KS_SETUP} ${BUILDDIR}/ks-setup.cfg
\rm -f "${BUILDDIR}"/ks-setup.cfg
\cp "${KS_SETUP}" "${BUILDDIR}"/ks-setup.cfg
if [ $? -ne 0 ]; then
log_error "Error: Failed to copy ${KS_SETUP}"
exit 1
@ -817,8 +832,8 @@ if [ -n "${KS_SETUP}" ]; then
fi
if [ -n "${KS_ADDON}" ]; then
\rm -f ${BUILDDIR}/ks-addon.cfg
\cp ${KS_ADDON} ${BUILDDIR}/ks-addon.cfg
\rm -f "${BUILDDIR}"/ks-addon.cfg
\cp "${KS_ADDON}" "${BUILDDIR}"/ks-addon.cfg
if [ $? -ne 0 ]; then
log_error "Error: Failed to copy ${KS_ADDON}"
exit 1
@ -836,32 +851,36 @@ unmount_efiboot_img
PLATFORM_PATH="${PLATFORM_ROOT}/${ISO_VERSION}"
mkdir_on_iso "${PLATFORM_PATH}"
INPUT_ISO_NAME="$(basename "${INPUT_ISO}")"
INPUT_ISO_NAME="$(basename "${INPUT_ISO}")"
copy_to_iso "${INPUT_ISO}" "${PLATFORM_PATH}/${INPUT_ISO_NAME}" "${PLATFORM_PATH}/${INPUT_ISO_NAME/%.iso/.md5}"
for PATCH in ${PATCHES[@]}; do
copy_to_iso "${PATCH}" "${PLATFORM_PATH}/"
done
if [ -n "${PATCHES[*]}" ]; then
log_info "Including patches: ${PATCHES[*]}"
for patch in "${PATCHES[@]}"; do
copy_to_iso "${patch}" "${PLATFORM_PATH}/"
done
fi
for IMAGE in ${IMAGES[@]}; do
copy_to_iso "${IMAGE}" "${PLATFORM_PATH}/" "${PLATFORM_PATH}/${MD5_FILE}"
done
if [ -n "${IMAGES[*]}" ]; then
log_info "Including images: ${IMAGES[*]}"
for IMAGE in "${IMAGES[@]}"; do
copy_to_iso "${IMAGE}" "${PLATFORM_PATH}/" "${PLATFORM_PATH}/${MD5_FILE}"
done
fi
#
# Rebuild the ISO
#
mkisofs -o ${OUTPUT_ISO} \
-R -D -A "${VOLUME_LABEL}" -V "${VOLUME_LABEL}" \
-quiet \
-b isolinux.bin -c boot.cat -no-emul-boot \
-boot-load-size 4 -boot-info-table \
-eltorito-alt-boot \
-e images/efiboot.img \
-no-emul-boot \
${BUILDDIR}
# we are ready to create the prestage iso.
log_info "Creating ${OUTPUT_ISO}"
mkisofs -o "${OUTPUT_ISO}" \
-R -D -A "${VOLUME_LABEL}" -V "${VOLUME_LABEL}" \
-quiet \
-b isolinux.bin -c boot.cat -no-emul-boot \
-boot-load-size 4 -boot-info-table \
-eltorito-alt-boot \
-e images/efiboot.img \
-no-emul-boot \
"${BUILDDIR}"
isohybrid --uefi ${OUTPUT_ISO}
implantisomd5 ${OUTPUT_ISO}
echo "Created ISO: ${OUTPUT_ISO}"
isohybrid --uefi "${OUTPUT_ISO}"
implantisomd5 "${OUTPUT_ISO}"
log_info "Prestage ISO created successfully: ${OUTPUT_ISO}"

@ -1,6 +1,6 @@
#!/bin/bash
#
# Copyright (c) 2022 Wind River Systems, Inc.
# Copyright (c) 2022-2023 Wind River Systems, Inc.
#
# SPDX-License-Identifier: Apache-2.0
#
@ -14,29 +14,34 @@
# exceed 4 GB. Multiple archives can be provided. All archives
# must have the suffix 'tar.gz'.
# shellcheck disable=1091 # don't warn about following 'source <file>'
# shellcheck disable=2164 # don't warn about pushd/popd failures
# shellcheck disable=2181 # don't warn about using rc=$?
# Error log print
function log_fatal {
echo "ERROR: $@" >&2 && exit 1
echo "$(date "+%F %H:%M:%S") FATAL: $*" >&2
exit 1
}
function log_error {
echo "ERROR: $@" >&2
echo "$(date "+%F %H:%M:%S"): ERROR: $*" >&2
}
# Info log
function log {
echo "INFO: $@" >&2
function log_warn {
echo "$(date "+%F %H:%M:%S"): WARN: $*" >&2
}
function log_info {
echo "$(date "+%F %H:%M:%S"): INFO: $*" >&2
}
# Usage manual.
function usage {
cat <<ENDUSAGE
Utility to convert a StarlingX installation iso into a Debian prestaged
subcloud installation iso.
Utility to convert a StarlingX installation iso into a Debian prestaged subcloud installation iso.
Usage:
$(basename $0) --input <input bootimage.iso>
$(basename "$0") --input <input bootimage.iso>
--output <output bootimage.iso>
[ --images <images.tar.gz> ]
[ --patch <patch-name.patch> ]
@ -110,13 +115,14 @@ function normalized_path {
local path="${1}"
local default_fn="${2}"
local path_name="$(basename "${path}")"
local path_dir="$(dirname "${path}")"
local path_name path_dir
path_name="$(basename "${path}")"
path_dir="$(dirname "${path}")"
# If 'path' ends in '/' then path was intended to be a directory
if [ "${path:(-1):1}" == "/" ]; then
if [ "${path: -1:1}" == "/" ]; then # Note: space is required after : to distinguish from ${path:-...}
# Drop the trailing '/'
path_dir="${path:0:(-1)}"
path_dir="${path:0:-1}"
path_name="${default_fn}"
fi
@ -147,7 +153,6 @@ function copy_to_iso {
local final_dest=
local final_dest_dir=
local final_md5=
local final_md5_dir=
if [ -z "${src}" ] || [ -z "${dest}" ]; then
log_error "Error: copy_to_iso: missing argument"
@ -164,8 +169,7 @@ function copy_to_iso {
final_dest="${BUILDDIR}/${dest}"
final_dest_dir="$(dirname "${final_dest}")"
if [ ! -z "${md5}" ]; then
if [ -n "${md5}" ]; then
case "${md5}" in
y | Y | yes | YES )
# Use a default name, in same dir as dest
@ -194,47 +198,47 @@ function copy_to_iso {
exit 1
fi
if [ ! -z "${final_md5}" ]; then
pushd ${final_dest_dir} > /dev/null
if [ -n "${final_md5}" ]; then
pushd "${final_dest_dir}" > /dev/null
md5sum "$(basename "${final_dest}")" >> "${final_md5}"
popd > /dev/null
fi
}
function generate_boot_cfg {
log_info "Generating boot config"
local isodir=$1
if [ -z "${EFI_MOUNT}" ]; then
mount_efiboot_img ${isodir}
mount_efiboot_img "${isodir}"
fi
local PARAM_LIST=
log "Generating prestage.iso from params: ${PARAMS[*]}"
# Set/update boot parameters
if [ ${#PARAMS[@]} -gt 0 ]; then
log_info "Pre-parsing params: ${PARAMS[*]}"
for p in "${PARAMS[@]}"; do
param=${p%%=*}
value=${p#*=}
# Pull the boot device out of PARAMS and convert to instdev
if [[ "${param}" == "boot_device" ]]; then
log "Setting instdev=${value} from boot_device param"
if [ "${param}" = "boot_device" ]; then
log_info "Setting instdev=${value} from boot_device param"
instdev=${value}
elif [[ "${param}" == "rootfs_device" ]]; then
log "Setting instdev=${value} from boot_device param"
elif [ "${param}" = "rootfs_device" ]; then
log_info "Setting instdev=${value} from boot_device param"
instdev=${value}
fi
PARAM_LIST="${PARAM_LIST} ${param}=${value}"
done
log_info "Using parameters: ${PARAM_LIST}"
fi
log "Parameters: ${PARAM_LIST}"
if [[ "${KS_PATCH}" == "true" ]]; then
log "Setting Kickstart patch from the kickstart_patches directory"
log_info "Setting Kickstart patch from the kickstart_patches directory"
ks="${KICKSTART_PATCH_DIR}"/kickstart.cfg
else
log "Setting Kickstart patch from the kickstart directory"
log_info "Setting Kickstart patch from the kickstart directory"
ks=kickstart/kickstart.cfg
fi
@ -248,14 +252,14 @@ function generate_boot_cfg {
COMMON_ARGS="${COMMON_ARGS} inst_ostree_var=/dev/mapper/cgts--vg-var--lv"
COMMON_ARGS="${COMMON_ARGS} defaultkernel=vmlinuz*[!t]-amd64"
if [[ -n "${FORCE_INSTALL}" ]]; then
if [ -n "${FORCE_INSTALL}" ]; then
COMMON_ARGS="${COMMON_ARGS} force_install"
fi
# Uncomment for LAT debugging:
#COMMON_ARGS="${COMMON_ARGS} instsh=2"
COMMON_ARGS="${COMMON_ARGS} ${PARAM_LIST}"
log "COMMON_ARGS: $COMMON_ARGS"
log_info "COMMON_ARGS: ${COMMON_ARGS}"
for f in ${isodir}/isolinux/isolinux.cfg; do
cat <<EOF > "${f}"
@ -283,8 +287,7 @@ LABEL 1
append ${COMMON_ARGS} traits=controller console=tty0
EOF
done
done
for f in ${isodir}/EFI/BOOT/grub.cfg ${EFI_MOUNT}/EFI/BOOT/grub.cfg; do
cat <<EOF > "${f}"
default=${DEFAULT_GRUB_ENTRY}
@ -323,18 +326,19 @@ function generate_ostree_checkum {
fi
(
# subshell:
log "Calculating new checksum for ostree_repo at ${dest_dir}"
log_info "Calculating new checksum for ostree_repo at ${dest_dir}"
cd "${dest_dir}" || log_fatal "generate_ostree_checkum: cd ${dest_dir} failed"
find ostree_repo -type f -exec md5sum {} + | LC_ALL=C sort | md5sum | awk '{ print $1; }' \
> .ostree_repo_checksum
log "ostree_repo checksum: $(cat .ostree_repo_checksum)"
log_info "ostree_repo checksum: $(cat .ostree_repo_checksum)"
)
}
# Constants
DIR_NAME=$(dirname "$0")
if [[ ! -e "${DIR_NAME}"/stx-iso-utils.sh ]]; then
log_fatal "${DIR_NAME}/stx-iso-utils.sh does not exist"
if [ ! -e "${DIR_NAME}"/stx-iso-utils.sh ]; then
echo "${DIR_NAME}/stx-iso-utils.sh does not exist" >&2
exit 1
else
source "${DIR_NAME}"/stx-iso-utils.sh
fi
@ -343,13 +347,12 @@ fi
declare INPUT_ISO=
declare OUTPUT_ISO=
declare -a IMAGES
declare ORIG_PWD=$PWD
declare KS_SETUP=
declare KS_ADDON=
declare UPDATE_TIMEOUT="no"
declare -i FOREVER_GRUB_TIMEOUT=-1
declare -i DEFAULT_GRUB_TIMEOUT=30
declare -i DEFAULT_TIMEOUT=(DEFAULT_GRUB_TIMEOUT*10)
declare -i DEFAULT_TIMEOUT=$(( DEFAULT_GRUB_TIMEOUT*10 ))
declare -i TIMEOUT=${DEFAULT_TIMEOUT}
declare -i GRUB_TIMEOUT=${DEFAULT_GRUB_TIMEOUT}
declare -a PARAMS
@ -381,97 +384,109 @@ SHORTOPTS+="I:"; LONGOPTS+="images:,"
SHORTOPTS+="f"; LONGOPTS+="force-install,"
SHORTOPTS+="h"; LONGOPTS+="help"
declare -i rc
OPTS=$(getopt -o "${SHORTOPTS}" --long "${LONGOPTS}" --name "$0" -- "$@")
if [[ "$?" -ne 0 ]]; then
if [ $? -ne 0 ]; then
usage
log_fatal "Options to $0 not properly parsed"
fi
eval set -- "${OPTS}"
if [[ $# == 1 ]]; then
if [ $# = 1 ]; then
usage
log_fatal "No arguments were provided"
fi
while :; do
case $1 in
-i | --input)
INPUT_ISO="$2"
shift 2
;;
-o | --output)
OUTPUT_ISO=$2
shift 2
;;
-s | --setup)
KS_SETUP=$2
shift 2
;;
-a | --addon)
KS_ADDON=$2
shift 2
;;
-p | --param)
PARAMS+=(${2//,/ })
shift 2
;;
-P | --patch)
PATCHES+=(${2//,/ })
shift 2
;;
-K | --kickstart-patch)
KICKSTART_PATCHES+=(${2//,/ })
shift 2
;;
-I | --images)
IMAGES+=(${2//,/ })
shift 2
;;
-d | --default-boot)
DEFAULT_LABEL=$2
case ${DEFAULT_LABEL} in
0)
DEFAULT_SYSLINUX_ENTRY=0
DEFAULT_GRUB_ENTRY="serial"
;;
1)
DEFAULT_SYSLINUX_ENTRY=1
DEFAULT_GRUB_ENTRY="graphical"
;;
*)
usage
log_fatal "Invalid default boot menu option: ${DEFAULT_LABEL}"
;;
esac
shift 2
;;
-t | --timeout)
let -i timeout_arg=$2
if [[ "${timeout_arg}" -gt 0 ]]; then
let -i "TIMEOUT=${timeout_arg}*10"
GRUB_TIMEOUT="${timeout_arg}"
elif [[ "${timeout_arg}" -eq 0 ]]; then
TIMEOUT=0
GRUB_TIMEOUT=0.001
elif [[ "${timeout_arg}" -lt 0 ]]; then
TIMEOUT=0
GRUB_TIMEOUT=${FOREVER_GRUB_TIMEOUT}
fi
UPDATE_TIMEOUT="yes"
shift 2
;;
-f | --force-install)
FORCE_INSTALL="true"
shift
;;
--)
break
;;
*)
shift
break
;;
-h | --help)
usage
exit 0
;;
-i | --input)
INPUT_ISO=$2
shift 2
;;
-o | --output)
OUTPUT_ISO=$2
shift 2
;;
-s | --setup)
KS_SETUP=$2
shift 2
;;
-a | --addon)
KS_ADDON=$2
shift 2
;;
-p | --param)
# shellcheck disable=2206
PARAMS+=(${2//,/ })
shift 2
;;
# TODO(kmacleod) Does providing patches make sense?
-P | --patch)
# shellcheck disable=2206
PATCHES+=(${2//,/ })
shift 2
;;
-K | --kickstart-patch)
# shellcheck disable=2206
KICKSTART_PATCHES+=(${2//,/ })
shift 2
;;
-I | --images)
# shellcheck disable=2206
IMAGES+=(${2//,/ })
shift 2
;;
-d | --default-boot)
DEFAULT_LABEL=${2}
case ${DEFAULT_LABEL} in
0)
DEFAULT_SYSLINUX_ENTRY=0
DEFAULT_GRUB_ENTRY="serial"
;;
1)
DEFAULT_SYSLINUX_ENTRY=1
DEFAULT_GRUB_ENTRY="graphical"
;;
*)
usage
log_fatal "Invalid default boot menu option: ${DEFAULT_LABEL}"
;;
esac
shift 2
;;
-t | --timeout)
declare -i timeout_arg=${2}
if [ "${timeout_arg}" -gt 0 ]; then
TIMEOUT=$(( timeout_arg * 10 ))
GRUB_TIMEOUT=${timeout_arg}
elif [ ${timeout_arg} -eq 0 ]; then
TIMEOUT=0
GRUB_TIMEOUT=0.001
elif [ ${timeout_arg} -lt 0 ]; then
TIMEOUT=0
GRUB_TIMEOUT=${FOREVER_GRUB_TIMEOUT}
fi
# TODO(kmacleod): UPDATE_TIMEOUT is not used, why is that?
UPDATE_TIMEOUT="yes"
shift 2
;;
-f | --force-install)
FORCE_INSTALL=true
shift
;;
--)
shift
break
;;
*)
usage
log_fatal "Unexpected argument: $*"
;;
esac
done
@ -480,51 +495,78 @@ done
# Generate prestage iso.
#
###############################################################################
log_info "Checking system requirements"
check_requirements
## Check for mandatory parameters
check_required_param "--input" "${INPUT_ISO}"
check_required_param "--output" "${OUTPUT_ISO}"
# shellcheck disable=2068
check_files_exist ${INPUT_ISO} ${PATCHES[@]} ${IMAGES[@]} ${KS_SETUP} ${KS_ADDON} ${KICKSTART_PATCHES[@]}
# shellcheck disable=2068
check_files_size ${PATCHES[@]} ${IMAGES[@]} ${KS_SETUP} ${KS_ADDON} ${KICKSTART_PATCHES[@]}
if [[ -e "${OUTPUT_ISO}" ]]; then
if [ -e "${OUTPUT_ISO}" ]; then
log_fatal "${OUTPUT_ISO} exists. Delete before you execute this script."
fi
# Check for rootfs_device/boot_device and warn if not present
found_rootfs_device=
found_boot_device=
if [ ${#PARAMS[@]} -gt 0 ]; then
for p in "${PARAMS[@]}"; do
param=${p%%=*}
case "${param}" in
rootfs_device)
found_rootfs_device=1
;;
boot_device)
found_boot_device=1
;;
esac
done
fi
if [ -z "${found_rootfs_device}" ]; then
log_warn "Missing '--param rootfs_device=...'. A default device will be selected during install, which may not be desired"
fi
if [ -z "${found_boot_device}" ]; then
log_warn "Missing '--param boot_device=...'. A default device will be selected during install, which may not be desired"
fi
## Catch Control-C and handle.
trap cleanup EXIT
# Create a temporary build directory.
BUILDDIR=$(mktemp -d -p $PWD updateiso_build_XXXXXX)
if [ -z "${BUILDDIR}" -o ! -d ${BUILDDIR} ]; then
BUILDDIR=$(mktemp -d -p "${PWD}" updateiso_build_XXXXXX)
if [ -z "${BUILDDIR}" ] || [ ! -d "${BUILDDIR}" ]; then
log_fatal "Failed to create builddir. Aborting..."
fi
echo ${BUILDDIR}
log_info "Using BUILDDIR=${BUILDDIR}"
mount_iso "${INPUT_ISO}"
#
# Determine release version from ISO
#
if [ ! -f ${MNTDIR}/upgrades/version ]; then
if [ ! -f "${MNTDIR}"/upgrades/version ]; then
log_error "Version info not found on ${INPUT_ISO}"
exit 1
fi
ISO_VERSION=$(source ${MNTDIR}/upgrades/version && echo ${VERSION})
ISO_VERSION=$(source "${MNTDIR}/upgrades/version" && echo "${VERSION}")
if [ -z "${ISO_VERSION}" ]; then
log_error "Failed to determine version of installation ISO"
exit 1
fi
# Copy the contents of the input iso to the build directory.
# This ensures that the ostree, kernel and the initramfs are all copied over
# This ensures that the ostree_repo, kernel and the initramfs are all copied over
# to the prestage iso.
log_info "Copying input ISO"
rsync -a --exclude "pxeboot" "${MNTDIR}/" "${BUILDDIR}/"
rc=$?
if [[ "${rc}" -ne 0 ]]; then
if [ "${rc}" -ne 0 ]; then
unmount_iso
log_fatal "Unable to rsync content from the ISO: Error rc=${rc}"
fi
@ -541,27 +583,32 @@ unmount_iso
PLATFORM_PATH="${PLATFORM_ROOT}/${ISO_VERSION}"
mkdir_on_iso "${PLATFORM_PATH}"
for PATCH in ${PATCHES[@]}; do
copy_to_iso "${PATCH}" "${PLATFORM_PATH}/"
done
if [ -n "${PATCHES[*]}" ]; then
log_info "Including patches: ${PATCHES[*]}"
for PATCH in "${PATCHES[@]}"; do
copy_to_iso "${PATCH}" "${PLATFORM_PATH}/"
done
fi
for IMAGE in ${IMAGES[@]}; do
copy_to_iso "${IMAGE}" "${PLATFORM_PATH}/" "${PLATFORM_PATH}/${MD5_FILE}"
done
if [ -n "${IMAGES[*]}" ]; then
log_info "Including images: ${IMAGES[*]}"
for IMAGE in "${IMAGES[@]}"; do
copy_to_iso "${IMAGE}" "${PLATFORM_PATH}/" "${PLATFORM_PATH}/${MD5_FILE}"
done
fi
KICKSTART_PATCH_DIR="kickstart_patch"
mkdir_on_iso "${KICKSTART_PATCH_DIR}"
for PATCH in ${KICKSTART_PATCHES[@]}; do
log "Found kickstart patch"
for PATCH in "${KICKSTART_PATCHES[@]}"; do
log_info "Including kickstart patch: ${PATCH}"
copy_to_iso "${PATCH}" "${KICKSTART_PATCH_DIR}"
KS_PATCH="true"
done
# generate the grub and isolinux cmd line parameters
generate_boot_cfg "${BUILDDIR}"
# copy the addon and setup files to the BUILDDIR
# copy the addon and setup files to the BUILDDIR
if [[ -e "${KS_SETUP}" ]]; then
cp "${KS_SETUP}" "${BUILDDIR}"
fi
@ -584,4 +631,4 @@ mkisofs -o "${OUTPUT_ISO}" \
isohybrid --uefi "${OUTPUT_ISO}"
log "Prestage ISO created successfully"
log_info "Prestage ISO created successfully: ${OUTPUT_ISO}"

@ -1,31 +1,49 @@
#!/bin/bash
#
# Copyright (c) 2020 Wind River Systems, Inc.
# Copyright (c) 2020-2023 Wind River Systems, Inc.
#
# SPDX-License-Identifier: Apache-2.0
#
# Common bash utility functions for StarlingX ISO tools
#
# Global shellcheck ignores:
# shellcheck disable=2181
declare BUILDDIR=
declare EFIBOOT_IMG_LOOP=
declare EFI_MOUNT=
declare MNTDIR=
declare WORKDIR=
declare VERBOSE=
function ilog {
echo "$(date "+%F %H:%M:%S"): $*" >&2
}
function elog {
echo "$(date "+%F %H:%M:%S") Error: $*" >&2
exit 1
}
function vlog {
[ "${VERBOSE}" = true ] && echo "$(date "+%F %H:%M:%S"): $*" >&2
}
function common_cleanup {
unmount_efiboot_img
if [ -n "$MNTDIR" -a -d "$MNTDIR" ]; then
if [ -n "${MNTDIR}" ] && [ -d "${MNTDIR}" ]; then
unmount_iso
fi
if [ -n "$BUILDDIR" -a -d "$BUILDDIR" ]; then
\rm -rf $BUILDDIR
if [ -n "${BUILDDIR}" ] && [ -d "${BUILDDIR}" ]; then
chmod -R 755 "${BUILDDIR}"
rm -rf "${BUILDDIR}"
fi
if [ -n "$WORKDIR" -a -d "$WORKDIR" ]; then
\rm -rf $WORKDIR
if [ -n "${WORKDIR}" ] && [ -d "${WORKDIR}" ]; then
chmod -R 755 "${WORKDIR}"
rm -rf "${WORKDIR}"
fi
}
@ -58,27 +76,26 @@ function common_check_requirements {
)
fi
required_utils+=( $@ )
required_utils+=( "$@" )
local -i missing=0
which which >&/dev/null
if [ $? -ne 0 ]; then
log_error "Unable to find 'which' utility. Aborting..."
exit 1
if which which >&/dev/null -ne 0 ; then
elog "unable to find 'which' utility. Aborting..."
fi
for req in ${required_utils[@]}; do
which ${req} >&/dev/null
if [ $? -ne 0 ]; then
log_error "Unable to find required utility: ${req}"
let -i missing++
for req in "${required_utils[@]}"; do
which "${req}" >&/dev/null
if [ $? -ne 0 ] ; then
ilog "unable to find required utility: ${req}"
(( missing++ ))
fi
done
if [ ${missing} -gt 0 ]; then
log_error "One or more required utilities are missing. Aborting..."
exit 1
if [ "${missing}" -gt 0 ]; then
elog "one or more required utilities are missing. Aborting..."
else
ilog "all required iso utilities present"
fi
}
@ -87,16 +104,14 @@ function check_required_param {
local value="${2}"
if [ -z "${value}" ]; then
log_error "Required parameter ${param} is not set"
exit 1
elog "required parameter ${param} is not set"
fi
}
function check_files_exist {
for value in "$@"; do
if [ ! -f "${value}" ]; then
log_error "file path '${value}' is invalid"
exit 1
elog "file path '${value}' is invalid"
fi
done
}
@ -108,10 +123,9 @@ function check_files_size {
local file_size_limit=4000000000
for value in "$@"; do
file_size=$(stat --printf="%s" ${value})
if [ ${file_size} -gt ${file_size_limit} ]; then
log_error "file size of '${value}' exceeds 4 GB limit"
exit 1
file_size=$(stat --printf="%s" "${value}")
if [ "${file_size}" -ge "${file_size_limit}" ]; then
elog "file size of '${value}' exceeds 4 GB limit"
fi
done
}
@ -119,54 +133,61 @@ function check_files_size {
function mount_iso {
local input_iso=$1
local basedir=${2:-$PWD}
local guestmount_dev=${3:-"/dev/sda1"}
MNTDIR=$(mktemp -d -p "$basedir" stx-iso-utils_mnt_XXXXXX)
if [ -z "${MNTDIR}" -o ! -d ${MNTDIR} ]; then
log_error "Failed to create mntdir $MNTDIR. Aborting..."
exit 1
if [ -z "${MNTDIR}" ] || [ ! -d "${MNTDIR}" ]; then
elog "Failed to create mntdir $MNTDIR. Aborting..."
fi
ilog "mount_iso input_iso=${input_iso} basedir=${basedir} MNTDIR=${MNTDIR}"
if [ $UID -eq 0 ]; then
# Mount the ISO
mount -o loop ${input_iso} ${MNTDIR}
ilog "mounting ${input_iso} to ${MNTDIR}"
mount -o loop "${input_iso}" "${MNTDIR}" >&/dev/null
if [ $? -ne 0 ]; then
echo "Failed to mount ${input_iso}" >&2
exit 1
elog "Failed to mount ${input_iso}" >&2
fi
else
# As non-root user, mount the ISO using guestmount
guestmount -a ${input_iso} -m /dev/sda1 --ro ${MNTDIR}
rc=$?
if [ $rc -ne 0 ]; then
# Add a retry
echo "Call to guestmount failed with rc=$rc. Retrying once..."
ilog "guestmounting ${input_iso} using ${guestmount_dev} to ${MNTDIR}"
guestmount -a ${input_iso} -m /dev/sda1 --ro ${MNTDIR}
guestmount -a "${input_iso}" -m "${guestmount_dev}" --ro "${MNTDIR}"
rc=$?
if [ "${rc}" -ne 0 ]; then
# Add a retry
ilog "guestmount failed with rc=${rc}. Retrying once..."
guestmount -a "${input_iso}" -m "${guestmount_dev}" --ro "${MNTDIR}" >&/dev/null
rc=$?
if [ $rc -ne 0 ]; then
echo "Call to guestmount failed with rc=$rc. Aborting..."
exit $rc
if [ ${rc} -ne 0 ]; then
elog "guestmount retry failed with rc=$rc. Aborting..."
else
vlog "guestmount retry succeeded"
fi
else
vlog "guestmount succeeded."
fi
fi
}
function unmount_iso {
if [ $UID -eq 0 ]; then
umount ${MNTDIR}
if [ "${UID}" -eq 0 ]; then
ilog "unmounting ${MNTDIR}"
umount "${MNTDIR}" >&/dev/null
else
guestunmount ${MNTDIR}
guestunmount "${MNTDIR}" >&/dev/null
fi
rmdir ${MNTDIR}
rmdir "${MNTDIR}"
}
function mount_efiboot_img {
local isodir=$1
if [ -e ${isodir}/images/efiboot.img ]; then
local efiboot_img=${isodir}/images/efiboot.img
if [ -e "${isodir}/images/efiboot.img" ]; then
local efiboot_img="${isodir}/images/efiboot.img"
else
local efiboot_img=${isodir}/efi.img
local efiboot_img="${isodir}/efi.img"
fi
local loop_setup_output=
@ -174,45 +195,42 @@ function mount_efiboot_img {
if [ $UID -eq 0 ]; then
# As root, setup a writeable loop device for the
# efiboot.img file and mount it
loop_setup_output=$(losetup --show -f ${efiboot_img})
loop_setup_output=$(losetup --show -f "${efiboot_img}")
if [ $? -ne 0 ]; then
echo "Failed losetup" >&2
exit 1
elog "Failed losetup" >&2
fi
EFIBOOT_IMG_LOOP=${loop_setup_output}
EFI_MOUNT=$(mktemp -d -p /mnt -t EFI-noudev.XXXXXX)
mount ${EFIBOOT_IMG_LOOP} ${EFI_MOUNT}
mount "${EFIBOOT_IMG_LOOP}" "${EFI_MOUNT}"
if [ $? -ne 0 ]; then
echo "Failed to mount loop device ${EFIBOOT_IMG_LOOP}" >&2
exit 1
elog "Failed to mount loop device ${EFIBOOT_IMG_LOOP}" >&2
fi
else
# As non-root user, we can use the udisksctl to setup a loop device
# and mount the efiboot.img, with read/write access.
loop_setup_output=$(udisksctl loop-setup -f ${efiboot_img} --no-user-interaction)
loop_setup_output=$(udisksctl loop-setup -f "${efiboot_img}" --no-user-interaction)
if [ $? -ne 0 ]; then
echo "Failed udisksctl loop-setup" >&2
exit 1
elog "Failed udisksctl loop-setup" >&2
fi
EFIBOOT_IMG_LOOP=$(echo ${loop_setup_output} | awk '{print $5;}' | sed -e 's/\.$//g')
EFIBOOT_IMG_LOOP=$(echo "${loop_setup_output}" | awk '{print $5;}' | sed -e 's/\.$//g')
if [ -z "${EFIBOOT_IMG_LOOP}" ]; then
echo "Failed to determine loop device from command output:" >&2
echo "Error: Failed to determine loop device from command output:" >&2
echo "${loop_setup_output}" >&2
exit 1
fi
udisksctl mount -b ${EFIBOOT_IMG_LOOP}
udisksctl mount -b "${EFIBOOT_IMG_LOOP}" >&/dev/null
if [ $? -ne 0 ]; then
echo "Failed udisksctl mount" >&2
echo "Error: Failed udisksctl mount" >&2
exit 1
fi
EFI_MOUNT=$(udisksctl info -b ${EFIBOOT_IMG_LOOP} | grep MountPoints | awk '{print $2;}')
EFI_MOUNT=$(udisksctl info -b "${EFIBOOT_IMG_LOOP}" | grep MountPoints | awk '{print $2;}')
if [ -z "${EFI_MOUNT}" ]; then
echo "Failed to determine mount point from udisksctl info command" >&2
echo "Error: Failed to determine mount point from udisksctl info command" >&2
exit 1
fi
fi
@ -221,19 +239,19 @@ function mount_efiboot_img {
function unmount_efiboot_img {
if [ $UID -eq 0 ]; then
if [ -n "${EFI_MOUNT}" ]; then
mountpoint -q ${EFI_MOUNT} && umount ${EFI_MOUNT}
rmdir ${EFI_MOUNT}
mountpoint -q "${EFI_MOUNT}" && umount "${EFI_MOUNT}"
rmdir "${EFI_MOUNT}"
EFI_MOUNT=
fi
if [ -n "${EFIBOOT_IMG_LOOP}" ]; then
losetup -d ${EFIBOOT_IMG_LOOP}
losetup -d "${EFIBOOT_IMG_LOOP}"
EFIBOOT_IMG_LOOP=
fi
else
if [ -n "${EFIBOOT_IMG_LOOP}" ]; then
udisksctl unmount -b ${EFIBOOT_IMG_LOOP}
udisksctl loop-delete -b ${EFIBOOT_IMG_LOOP}
udisksctl unmount -b "${EFIBOOT_IMG_LOOP}" >&/dev/null
udisksctl loop-delete -b "${EFIBOOT_IMG_LOOP}"
EFI_MOUNT=
EFIBOOT_IMG_LOOP=
fi
@ -245,44 +263,41 @@ function update_parameter {
local param=$2
local value=$3
ilog "updating parameter ${param} to ${param}=${value}"
if [ -z "${EFI_MOUNT}" ]; then
mount_efiboot_img ${isodir}
mount_efiboot_img "${isodir}"
fi
for f in ${isodir}/isolinux.cfg ${isodir}/syslinux.cfg; do
grep -q "^[[:space:]]*append\>.*[[:space:]]${param}=" ${f}
for f in "${isodir}"/isolinux.cfg "${isodir}"/syslinux.cfg ; do
grep -q "^[[:space:]]*append\>.*[[:space:]]${param}=" "${f}"
if [ $? -eq 0 ]; then
# Parameter already exists. Update the value
sed -i -e "s#^\([[:space:]]*append\>.*${param}\)=[^[:space:]]*#\1=${value}#" ${f}
sed -i -e "s#^\([[:space:]]*append\>.*${param}\)=[^[:space:]]*#\1=${value}#" "${f}"
if [ $? -ne 0 ]; then
log_error "Failed to update parameter ($param)"
exit 1
elog "Failed to update parameter ($param)"
fi
else
# Parameter doesn't exist. Add it to the cmdline
sed -i -e "s|^\([[:space:]]*append\>.*\)|\1 ${param}=${value}|" ${f}
sed -i -e "s|^\([[:space:]]*append\>.*\)|\1 ${param}=${value}|" "${f}"
if [ $? -ne 0 ]; then
log_error "Failed to add parameter ($param)"
exit 1
elog "Failed to add parameter ($param)"
fi
fi
done
for f in ${isodir}/EFI/BOOT/grub.cfg ${EFI_MOUNT}/EFI/BOOT/grub.cfg; do
grep -q "^[[:space:]]*linuxefi\>.*[[:space:]]${param}=" ${f}
for f in "${isodir}/EFI/BOOT/grub.cfg" "${EFI_MOUNT}/EFI/BOOT/grub.cfg" ; do
grep -q "^[[:space:]]*linuxefi\>.*[[:space:]]${param}=" "${f}"
if [ $? -eq 0 ]; then
# Parameter already exists. Update the value
sed -i -e "s#^\([[:space:]]*linuxefi\>.*${param}\)=[^[:space:]]*#\1=${value}#" ${f}
sed -i -e "s#^\([[:space:]]*linuxefi\>.*${param}\)=[^[:space:]]*#\1=${value}#" "${f}"
if [ $? -ne 0 ]; then
log_error "Failed to update parameter ($param)"
exit 1
elog "Failed to update parameter ($param)"
fi
else
# Parameter doesn't exist. Add it to the cmdline
sed -i -e "s|^\([[:space:]]*linuxefi\>.*\)|\1 ${param}=${value}|" ${f}
sed -i -e "s|^\([[:space:]]*linuxefi\>.*\)|\1 ${param}=${value}|" "${f}"
if [ $? -ne 0 ]; then
log_error "Failed to add parameter ($param)"
exit 1
elog "Failed to add parameter ($param)"
fi
fi
done

@ -1,29 +1,32 @@
#!/bin/bash
#
# Copyright (c) 2020,2022 Wind River Systems, Inc.
# Copyright (c) 2020-2023 Wind River Systems, Inc.
#
# SPDX-License-Identifier: Apache-2.0
#
# Common bash utility functions for StarlingX ISO tools
#
# Global shellcheck ignores:
# shellcheck disable=2181
declare BUILDDIR=
declare EFIBOOT_IMG_LOOP=
declare EFI_MOUNT=
declare MNTDIR=
declare WORKDIR=
declare VERBOSE=
function ilog {
echo "$(date "+%F %H-%M-%S"): $*" >&2
echo "$(date "+%F %H:%M:%S"): $*" >&2
}
function elog {
echo "$(date "+%F %H-%M-%S") Error: $*" >&2
echo "$(date "+%F %H:%M:%S") Error: $*" >&2
exit 1
}
function vlog {
[ "${VERBOSE}" = true ] && echo "$(date "+%F %H-%M-%S"): $*" >&2
[ "${VERBOSE}" = true ] && echo "$(date "+%F %H:%M:%S"): $*" >&2
}
function common_cleanup {
@ -130,12 +133,13 @@ function check_files_size {
function mount_iso {
local input_iso=$1
local basedir=${2:-$PWD}
local mount=${3:-"/dev/sda1"}
local guestmount_dev=${3:-"/dev/sda1"}
MNTDIR=$(mktemp -d -p "$basedir" stx-iso-utils_mnt_XXXXXX)
if [ -z "${MNTDIR}" ] || [ ! -d "${MNTDIR}" ]; then
elog "Failed to create mntdir $MNTDIR. Aborting..."
fi
ilog "mount_iso input_iso=${input_iso} basedir=${basedir} MNTDIR=${MNTDIR}"
if [ $UID -eq 0 ]; then
# Mount the ISO
@ -146,15 +150,15 @@ function mount_iso {
fi
else
# As non-root user, mount the ISO using guestmount
ilog "guestmounting ${input_iso} using ${mount} to ${MNTDIR}"
ilog "guestmounting ${input_iso} using ${guestmount_dev} to ${MNTDIR}"
guestmount -a "${input_iso}" -m "${mount}" --ro "${MNTDIR}"
guestmount -a "${input_iso}" -m "${guestmount_dev}" --ro "${MNTDIR}"
rc=$?
if [ "${rc}" -ne 0 ]; then
# Add a retry
ilog "guestmount failed with rc=${rc}. Retrying once..."
guestmount -a "${input_iso}" -m "${mount}" --ro "${MNTDIR}" >&/dev/null
guestmount -a "${input_iso}" -m "${guestmount_dev}" --ro "${MNTDIR}" >&/dev/null
rc=$?
if [ ${rc} -ne 0 ]; then
elog "guestmount retry failed with rc=$rc. Aborting..."
@ -286,7 +290,7 @@ function update_parameter {
fi
done
for f in ${isodir}/EFI/BOOT/grub.cfg ${EFI_MOUNT}/EFI/BOOT/grub.cfg ; do
for f in "${isodir}/EFI/BOOT/grub.cfg" "${EFI_MOUNT}/EFI/BOOT/grub.cfg" ; do
grep -q "^[[:space:]]*linux\>.*[[:space:]]${param}=" "${f}"
if [ $? -eq 0 ]; then
# Parameter already exists. Update the value

@ -0,0 +1,3 @@
/input
/output
/shunit2

@ -0,0 +1,24 @@
Testing ISO generation scripts
==============================
This directory contains unit test cases for the `gen-*.sh` scripts:
## Running tests
Run all available tests via the `run-tests.sh` script.
You can also run the individual `gen-*-test.sh` scripts manually.
The shunit2 bash unit test framework is used. It is automatically retrieved if it doesn't exist.
## Directories
Directories used by the tests:
input/
- Contents of ISO/image/patch files used for the tests
- The contents of this directory are either downloaded or generated by the tests
output/
- Temporary test output directory

@ -0,0 +1,300 @@
#!/bin/bash
# vim:ft=sh:sts=4:sw=4
# This is a shunit2 test file.
# See https://github.com/kward/shunit2
# Run the tests by executing this script.
# shellcheck disable=SC2016
# shellcheck disable=SC1090
# shellcheck disable=SC1091
NAME=gen-prestaged-iso-centos-test
# shellcheck disable=SC2155,SC2034
readonly SCRIPTDIR=$(readlink -m "$(dirname "$0")")
# shellcheck disable=SC2155,SC2034
readonly TARGET_SCRIPTDIR=$(readlink -m "${SCRIPTDIR}/..")
INPUT_DIR="${SCRIPTDIR}"/input/centos
IMAGES_DIR="${INPUT_DIR}/images"
PATCHES_DIR="${INPUT_DIR}/patches"
ISOFILE=${ISOFILE:-$INPUT_DIR/bootimage.iso}
#ISOFILE=/localdisk/designer/kmacleod/dc-libvirt/isofiles/wrcp-22.12-release/starlingx-intel-x86-64-cd.iso
#ISOFILE=/localdisk/designer/kmacleod/dc-libvirt/isofiles/WRCP-21.12-formal-patch/bootimage.iso
# source the script under test
. "${TARGET_SCRIPTDIR}"/stx-iso-utils-centos.sh
. "${SCRIPTDIR}/shunit2_helper.sh"
KEEP_ARTIFACTS=${KEEP_ARTIFACTS:-}
BUILDDIR=${SCRIPTDIR}/output/${NAME}
OUTPUT_ISO=${BUILDDIR}/generated.iso
_create_fake_image() {
local imagename=$1
local targetdir=$2
if hash docker 2>/dev/null; then
echo "Creating fake image ${imagename} using docker"
tar cv --files-from /dev/null | docker import - "${imagename}:latest"
docker save -o "${targetdir}/${imagename}.tar.gz" "${imagename}:latest"
docker rmi "${imagename}:latest"
else
echo "Creating fake empty image ${imagename}"
touch "${targetdir}/${imagename}.tar.gz"
fi
}
_create_fake_images() {
if [ ! -d "${IMAGES_DIR}" ]; then
echo "Creating fake images"
mkdir -p "${IMAGES_DIR}" || fail "mkdir failed"
local image
for image in image1 image2 image3; do
_create_fake_image "${image}" "${IMAGES_DIR}"
done
fi
}
_fetch_iso_and_patches() {
# Fetch CentOS ISO and test patches from yow-cgts4-lx
[ -d "${INPUT_DIR}" ] || mkdir -p "${INPUT_DIR}" || fail "mkdir failed"
if [ ! -f "${INPUT_DIR}/bootimage.iso" ]; then
echo "Fetching ISO"
scp 'yow-cgts4-lx:/localdisk/loadbuild/jenkins/WRCP_21.12_Build/last_build_with_test_patches/export/bootimage.{iso,sig}' "${INPUT_DIR}/"
fi
if [ ! -d "${PATCHES_DIR}" ]; then
echo "Fetching patches"
mkdir -p "${PATCHES_DIR}" || fail "mkdir failed"
scp 'yow-cgts4-lx:/localdisk/loadbuild/jenkins/WRCP_21.12_Build/last_build_with_test_patches/test_patches/*{A,B,C}.patch' "${PATCHES_DIR}/"
fi
}
# Executed at start of all tests
oneTimeSetUp() {
th_info oneTimeSetUp
if [ -d "${BUILDDIR}" ]; then
th_debug "Cleaning ${BUILDDIR}"
rm -rf "${BUILDDIR}"
fi
mkdir -p "${BUILDDIR}" || fail "Failed to create ${BUILDDIR}"
_create_fake_images
_fetch_iso_and_patches
}
# Executed at start of each tests
setUp() {
th_info setUp
}
oneTimeTearDown() {
th_info oneTimeTearDown
if [ -z "${KEEP_ARTIFACTS}" ]; then
if [ -n "${BUILDDIR}" ] && [ -d "${BUILDDIR}" ]; then
th_debug "Cleaning ${BUILDDIR}"
rm -rf "${BUILDDIR}"
fi
fi
}
# Executed at completion of each tests
tearDown() {
th_info tearDown
if [ -n "${MNTDIR}" ] && [ -d "${MNTDIR}" ]; then
th_info "tearDown: unmounting ${MNTDIR}"
sudo umount "${MNTDIR}" 2>/dev/null || th_warn "umount failed for ${MNTDIR}"
fi
if [ -f "${OUTPUT_ISO}" ]; then
sudo rm "${OUTPUT_ISO}"
fi
}
create_ks_addon_file() {
cat <<EOF > "${BUILDDIR}/ks-addon.cfg"
ilog "Executing ks-addon.cfg"
EOF
}
validate_generated_iso() {
local syslinux_boot=1
local grub_boot=graphical
local param=
local syslinux_timeout=300
local grub_timeout=30
local ks_addon=
while [ $# -gt 0 ] ; do
case "${1:-""}" in
--syslinux-boot)
shift
syslinux_boot=$1
;;
--grub-boot)
shift
grub_boot=$1
;;
--param)
shift
param=$1
;;
--syslinux-timeout)
shift
syslinux_timeout=$1
;;
--grub-timeout)
shift
grub_timeout=$1
;;
--ks-addon)
shift
ks_addon=ks-addon.cfg
;;
*)
echo "Invalid expected value '$1'"
exit 1
;;
esac
shift
done
# Mount the ISO
[ -f "${OUTPUT_ISO}" ] || fail "${OUTPUT_ISO} does not exist"
MNTDIR=${BUILDDIR}/mnt
[ -d "${MNTDIR}" ] || mkdir "${MNTDIR}" || fail "mkdir failed"
sudo mount "${OUTPUT_ISO}" "${MNTDIR}" || fail "Failed to mount ${OUTPUT_ISO}"
# Check that images are included:
th_info "Image check: validating images are in ISO"
for image in "${IMAGES_DIR}"/*.tar.gz; do
[ "$(find "${MNTDIR}"/opt/platform-backup -name "$(basename "${image}")" | wc -l)" -eq 1 ] \
|| fail "Missing expected image ${image}"
th_info "Found expected image: ${image}"
done
th_info "Image check passed"
# Check that patches are included:
th_info "Patch check: validating patches are in ISO"
for patch in "${PATCHES_DIR}"/*.patch; do
[ "$(find "${MNTDIR}"/opt/platform-backup -name "$(basename "${patch}")" | wc -l)" -eq 1 ] \
|| fail "Missing expected patch ${patch}"
th_info "Found expected patch: ${patch}"
done
th_info "Patch check passed"
local syslinux_cfg=${MNTDIR}/syslinux.cfg
local grub_cfg=${MNTDIR}/EFI/BOOT/grub.cfg
if [ -n "${syslinux_boot}" ]; then
grep -q -i "default ${syslinux_boot}" "${syslinux_cfg}" \
|| fail "Incorrect syslinux boot: ${syslinux_boot} in ${syslinux_cfg}"
fi
if [ -n "${syslinux_timeout}" ]; then
grep -q "timeout ${syslinux_timeout}" "${syslinux_cfg}" \
|| fail "Incorrect syslinux timeout: (expected ${syslinux_timeout}) in ${syslinux_cfg}"
fi
if [ -n "${grub_boot}" ]; then
grep 'default=' "${grub_cfg}" | grep -q "${grub_boot}" \
|| fail "Incorrect grub boot (expected ${grub_boot}) in EFI/BOOT/grub.cfg"
fi
if [ -n "${grub_timeout}" ]; then
grep -q "timeout=${grub_timeout}" "${grub_cfg}" \
|| fail "Incorrect grub timeout: ${grub_timeout} in EFI/BOOT/grub.cfg"
fi
if [ -n "${param}" ]; then
# There should be two boot entries containing param (graphical + serial)
[ "$(grep -c "${param}" "${syslinux_cfg}")" -eq 2 ] \
|| fail "Incorrect param value (expected ${param}) in ${syslinux_cfg}"
[ "$(grep -c "${param}" "${grub_cfg}")" -eq 2 ] \
|| fail "Incorrect param value (expected ${param}) in EFI/BOOT/grub.cfg"
fi
if [ -n "${ks_addon}" ]; then
[ -f "${MNTDIR}/${ks_addon}" ] || fail "Expected ks-addon ${ks_addon} not found"
fi
}
test_generate_prestaged_iso_1() {
th_info "Running test_generate_prestaged_iso_1"
( # subshell
cd "${TARGET_SCRIPTDIR}"
local images=""
local image
for image in "${IMAGES_DIR}"/*.tar.gz; do
images="${images} --image ${image}"
done
local patches=""
local patch
for patch in "${PATCHES_DIR}"/*.patch; do
patches="${patches} --patch ${patch}"
done
# shellcheck disable=2086
sudo ./gen-prestaged-iso-centos.sh --input "${ISOFILE}" \
--output "${OUTPUT_ISO}" \
${images} ${patches}
) || fail "gen-prestaged-iso-centos.sh failed"
th_info "Generated ${OUTPUT_ISO}"
if [ -n "${KEEP_ARTIFACTS}" ]; then
th_info "Preserving ISO in ${SCRIPTDIR}/generated_centos_1.iso"
cp "${OUTPUT_ISO}" "${SCRIPTDIR}"/generated_centos_1.iso
fi
validate_generated_iso --syslinux-boot 1 --grub-boot graphical \
--syslinux-timeout 300 --grub-timeout 30
}
test_generate_prestaged_iso_2() {
th_info "Running test_generate_prestaged_iso_2"
( # subshell
cd "${TARGET_SCRIPTDIR}"
local images=""
local image
for image in "${IMAGES_DIR}"/*.tar.gz; do
if [ -z "${images}" ]; then
images="--image ${image}"
else
images="${images},${image}"
fi
done
local patches=""
local patch
for patch in "${PATCHES_DIR}"/*.patch; do
if [ -z "${patches}" ]; then
patches="--patch ${patch}"
else
patches="${patches},${patch}"
fi
done
create_ks_addon_file
# shellcheck disable=2086
sudo ./gen-prestaged-iso-centos.sh --input "${ISOFILE}" \
--output "${OUTPUT_ISO}" \
--addon "${BUILDDIR}/ks-addon.cfg" \
--default-boot 0 \
--timeout 90 \
--force-install \
--param "param1=1,param2=2" \
${images} ${patches}
) || fail "gen-prestaged-iso-centos.sh failed"
th_info "Generated ${OUTPUT_ISO}"
if [ -n "${KEEP_ARTIFACTS}" ]; then
th_info "Preserving ISO in ${SCRIPTDIR}/generated_centos_2.iso"
cp "${OUTPUT_ISO}" "${SCRIPTDIR}"/generated_centos_2.iso
fi
validate_generated_iso --syslinux-boot 0 --grub-boot serial \
--syslinux-timeout 900 --grub-timeout 90 \
--param "param1=1 param2=2" --ks-addon ks-addon.cfg
}
# shellcheck disable=SC2154
trap 'rc=$?; echo "Caught abnormal signal rc=$rc"; exit $rc' 2 3 15
th_info "Running shunit2"
# Load and run shunit2.
# shellcheck disable=SC2034
[ -n "${ZSH_VERSION:-}" ] && SHUNIT_PARENT=$0
. "${TH_SHUNIT}"

@ -0,0 +1,302 @@
#!/bin/bash
# vim:ft=sh:sts=4:sw=4
# This is a shunit2 test file.
# See https://github.com/kward/shunit2
# Run the tests by executing this script.
# shellcheck disable=SC2016
# shellcheck disable=SC1090
# shellcheck disable=SC1091
NAME=gen-prestaged-iso-test
# shellcheck disable=SC2155,SC2034
readonly SCRIPTDIR=$(readlink -m "$(dirname "$0")")
# shellcheck disable=SC2155,SC2034
readonly TARGET_SCRIPTDIR=$(readlink -m "${SCRIPTDIR}/..")
INPUT_DIR="${SCRIPTDIR}"/input/debian
IMAGES_DIR="${INPUT_DIR}/images"
PATCHES_DIR="${INPUT_DIR}/patches"
ISOFILE=${ISOFILE:-$INPUT_DIR/starlingx-intel-x86-64-cd.iso}
#ISOFILE=/localdisk/designer/kmacleod/dc-libvirt/isofiles/wrcp-22.12-release/starlingx-intel-x86-64-cd.iso
# source the script under test
. "${TARGET_SCRIPTDIR}"/stx-iso-utils.sh
. "${SCRIPTDIR}/shunit2_helper.sh"
KEEP_ARTIFACTS=${KEEP_ARTIFACTS:-}
BUILDDIR=${SCRIPTDIR}/output/${NAME}
OUTPUT_ISO=${BUILDDIR}/generated.iso
_create_fake_image() {
local imagename=$1
local targetdir=$2
if hash docker 2>/dev/null; then
echo "Creating fake image ${imagename} using docker"
tar cv --files-from /dev/null | docker import - "${imagename}:latest"
docker save -o "${targetdir}/${imagename}.tar.gz" "${imagename}:latest"
docker rmi "${imagename}:latest"
else
echo "Creating fake empty image ${imagename}"
touch "${targetdir}/${imagename}.tar.gz"
fi
}
_create_fake_images() {
if [ ! -d "${IMAGES_DIR}" ]; then
echo "Creating fake images"
mkdir -p "${IMAGES_DIR}" || fail "mkdir failed"
local image
for image in image1 image2 image3; do
_create_fake_image "${image}" "${IMAGES_DIR}"
done
fi
}
_fetch_iso_and_patches() {
# Fetch Debian ISO and test patches from yow-wrcp-lx
[ -d "${INPUT_DIR}" ] || mkdir -p "${INPUT_DIR}" || fail "mkdir failed"
if [ ! -f "${ISOFILE}" ]; then
echo "Fetching ISO"
scp 'yow-wrcp-lx:/localdisk/loadbuild/jenkins/wrcp-master-debian/latest_build/export/outputs/iso/starlingx-intel-x86-64-2*-cd.*' "${INPUT_DIR}/" || fail "scp iso failed"
ln -s "${INPUT_DIR}"/starlingx-intel-x86-64-2*-cd.iso "${INPUT_DIR}"/starlingx-intel-x86-64-cd.iso
ln -s "${INPUT_DIR}"/starlingx-intel-x86-64-2*-cd.sig "${INPUT_DIR}"/starlingx-intel-x86-64-cd.sig
fi
if [ ! -d "${PATCHES_DIR}" ]; then
echo "Fetching patches"
mkdir -p "${PATCHES_DIR}" || fail "mkdir failed"
scp 'yow-wrcp-lx:/localdisk/loadbuild/jenkins/wrcp-master-debian/latest_build/test_patches/*{NRR_INSVC,RR_ALL_NODES,_RR_ALL_NODES_REQUIRES}.patch' "${INPUT_DIR}/patches/" || fail "scp iso failed"
fi
}
# Executed at start of all tests
oneTimeSetUp() {
th_info oneTimeSetUp
if [ -d "${BUILDDIR}" ]; then
th_debug "Cleaning ${BUILDDIR}"
rm -rf "${BUILDDIR}"
fi
mkdir -p "${BUILDDIR}" || fail "Failed to create ${BUILDDIR}"
_create_fake_images
_fetch_iso_and_patches
}
# Executed at start of each tests
setUp() {
th_info setUp
}
oneTimeTearDown() {
th_info oneTimeTearDown
if [ -z "${KEEP_ARTIFACTS}" ]; then
if [ -n "${BUILDDIR}" ] && [ -d "${BUILDDIR}" ]; then
th_debug "Cleaning ${BUILDDIR}"
rm -rf "${BUILDDIR}"
fi
fi
}
# Executed at completion of each tests
tearDown() {
th_info tearDown
if [ -n "${MNTDIR}" ] && [ -d "${MNTDIR}" ]; then
th_info "tearDown: unmounting ${MNTDIR}"
sudo umount "${MNTDIR}" 2>/dev/null || th_warn "umount failed for ${MNTDIR}"
fi
if [ -f "${OUTPUT_ISO}" ]; then
sudo rm "${OUTPUT_ISO}"
fi
}
create_ks_addon_file() {
cat <<EOF > "${BUILDDIR}/ks-addon.cfg"
ilog "Executing ks-addon.cfg"
EOF
}
validate_generated_iso() {
local syslinux_boot=1
local grub_boot=graphical
local param=
local syslinux_timeout=300
local grub_timeout=30
local ks_addon=
while [ $# -gt 0 ] ; do
case "${1:-""}" in
--syslinux-boot)
shift
syslinux_boot=$1
;;
--grub-boot)
shift
grub_boot=$1
;;
--param)
shift
param=$1
;;
--syslinux-timeout)
shift
syslinux_timeout=$1
;;
--grub-timeout)
shift
grub_timeout=$1
;;
--ks-addon)
shift
ks_addon=ks-addon.cfg
;;
*)
echo "Invalid expected value '$1'"
exit 1
;;
esac
shift
done
# Mount the ISO
[ -f "${OUTPUT_ISO}" ] || fail "${OUTPUT_ISO} does not exist"
MNTDIR=${BUILDDIR}/mnt
[ -d "${MNTDIR}" ] || mkdir "${MNTDIR}" || fail "mkdir failed"
sudo mount "${OUTPUT_ISO}" "${MNTDIR}" || fail "Failed to mount ${OUTPUT_ISO}"
# Check that images are included:
th_info "Image check: validating images are in ISO"
for image in "${IMAGES_DIR}"/*.tar.gz; do
[ "$(find "${MNTDIR}"/opt/platform-backup -name "$(basename "${image}")" | wc -l)" -eq 1 ] \
|| fail "Missing expected image ${image}"
th_info "Found expected image: ${image}"
done
th_info "Image check passed"
# Check that patches are included:
th_info "Patch check: validating patches are in ISO"
for patch in "${PATCHES_DIR}"/*.patch; do
[ "$(find "${MNTDIR}"/opt/platform-backup -name "$(basename "${patch}")" | wc -l)" -eq 1 ] \
|| fail "Missing expected patch ${patch}"
th_info "Found expected patch: ${patch}"
done
th_info "Patch check passed"
local syslinux_cfg=${MNTDIR}/isolinux/isolinux.cfg
local grub_cfg=${MNTDIR}/EFI/BOOT/grub.cfg
if [ -n "${syslinux_boot}" ]; then
grep -q -i "default ${syslinux_boot}" "${syslinux_cfg}" \
|| fail "Incorrect syslinux boot: ${syslinux_boot} in ${syslinux_cfg}"
fi
if [ -n "${syslinux_timeout}" ]; then
grep -q "timeout ${syslinux_timeout}" "${syslinux_cfg}" \
|| fail "Incorrect syslinux timeout: (expected ${syslinux_timeout}) in ${syslinux_cfg}"
fi
if [ -n "${grub_boot}" ]; then
grep 'default=' "${grub_cfg}" | grep -q "${grub_boot}" \
|| fail "Incorrect grub boot (expected ${grub_boot}) in EFI/BOOT/grub.cfg"
fi
if [ -n "${grub_timeout}" ]; then
grep -q "timeout=${grub_timeout}" "${grub_cfg}" \
|| fail "Incorrect grub timeout: ${grub_timeout} in EFI/BOOT/grub.cfg"
fi
if [ -n "${param}" ]; then
# There should be two boot entries containing param (graphical + serial)
[ "$(grep -c "${param}" "${syslinux_cfg}")" -eq 2 ] \
|| fail "Incorrect param value (expected ${param}) in ${syslinux_cfg}"
[ "$(grep -c "${param}" "${grub_cfg}")" -eq 2 ] \
|| fail "Incorrect param value (expected ${param}) in EFI/BOOT/grub.cfg"
fi
if [ -n "${ks_addon}" ]; then
[ -f "${MNTDIR}/${ks_addon}" ] || fail "Expected ks-addon ${ks_addon} not found"
fi
}
test_generate_prestaged_iso_1() {
th_info "Running test_generate_prestaged_iso_1"
(
cd "${TARGET_SCRIPTDIR}"
local images=""
local image
for image in "${IMAGES_DIR}"/*.tar.gz; do
images="${images} --image ${image}"
done
local patches=""
local patch
for patch in "${PATCHES_DIR}"/*.patch; do
patches="${patches} --patch ${patch}"
done
# shellcheck disable=2086
sudo ./gen-prestaged-iso.sh --input "${ISOFILE}" \
--output "${OUTPUT_ISO}" \
${images} ${patches}
) || fail "gen-prestaged-iso.sh failed"
th_info "Generated ${OUTPUT_ISO}"
if [ -n "${KEEP_ARTIFACTS}" ]; then
th_info "Preserving ISO in ${SCRIPTDIR}/generated_debian_1.iso"
cp "${OUTPUT_ISO}" "${SCRIPTDIR}"/generated_debian_debian_1.iso
fi
validate_generated_iso --syslinux-boot 1 --grub-boot graphical \
--syslinux-timeout 300 --grub-timeout 30
}
test_generate_prestaged_iso_2() {
th_info "Running test_generate_prestaged_iso_2"
( # subshell
cd "${TARGET_SCRIPTDIR}"
local images=""
local image
for image in "${IMAGES_DIR}"/*.tar.gz; do
if [ -z "${images}" ]; then
images="--image ${image}"
else
images="${images},${image}"
fi
done
local patches=""
local patch
for patch in "${PATCHES_DIR}"/*.patch; do
if [ -z "${patches}" ]; then
patches="--patch ${patch}"
else
patches="${patches},${patch}"
fi
done
create_ks_addon_file
# shellcheck disable=2086
sudo ./gen-prestaged-iso.sh --input "${ISOFILE}" \
--output "${OUTPUT_ISO}" \
--addon "${BUILDDIR}/ks-addon.cfg" \
--default-boot 0 \
--timeout 90 \
--force-install \
--param "param1=1,param2=2" \
${images} ${patches} \
) || fail "gen-prestaged-iso.sh failed"
th_info "Generated ${OUTPUT_ISO}"
if [ -n "${KEEP_ARTIFACTS}" ]; then
th_info "Preserving ISO in ${SCRIPTDIR}/generated_debian_2.iso"
cp "${OUTPUT_ISO}" "${SCRIPTDIR}"/generated_debian_2.iso
fi
validate_generated_iso --syslinux-boot 0 --grub-boot serial \
--syslinux-timeout 900 --grub-timeout 90 \
--param "param1=1 param2=2" --ks-addon ks-addon.cfg
}
# shellcheck disable=SC2154
trap 'rc=$?; echo "Caught abnormal signal rc=$rc"; exit $rc' 2 3 15
th_info "Running shunit2"
# Load and run shunit2.
# shellcheck disable=SC2034
[ -n "${ZSH_VERSION:-}" ] && SHUNIT_PARENT=$0
. "${TH_SHUNIT}"

@ -0,0 +1,24 @@
#!/bin/bash
echo "Running all unit tests"
# shellcheck disable=SC2155,SC2034
readonly SCRIPTDIR=$(readlink -m "$(dirname "$0")")
cd "${SCRIPTDIR}" || { echo "cd failed"; exit 1; }
TESTS="./gen-prestaged-iso-test.sh ./gen-prestaged-iso-test.sh"
log_progress() { echo -e "$(tput setaf 2)$*$(tput sgr0)"; }
log_error() { echo -e "$(tput setaf 1)ERROR: $*$(tput sgr0)"; }
declare -i rc
for testscript in ${TESTS}; do
log_progress "--------------------------------------------------------------------------------"
log_progress "Executing ${testscript}"
${testscript}
rc=$?
if [ $rc -ne 0 ]; then
log_error "failure in ${testscript}, rc=${rc}"
exit $rc
fi
done

@ -0,0 +1,68 @@
#!/bin/bash
# -----------------------------------------------------------------------------
# Helper stuff taken from https://github.com/kward/shunit2/blob/master/shunit2_test_helpers
# Note: the last release, 2.1.8 is buggy/not working. Checkout the git repo and use that instead.
SHUNIT_DIR="${SCRIPTDIR:-.}/shunit2"
if [ ! -d "${SHUNIT_DIR}" ]; then
( # subprocess
cd "$SCRIPTDIR"
git clone "https://github.com/kward/shunit2.git" || { echo "ERROR: failed to clone shunit2"; exit 1; }
)
fi
# Path to shunit2 library. Can be overridden by setting SHUNIT_INC.
TH_SHUNIT=${SHUNIT_DIR}/shunit2 export TH_SHUNIT
set -e # Exit immediately if a simple command exits with a non-zero status.
set -u # Treat unset variables as an error when performing parameter expansion.
# Set shwordsplit for zsh.
[ -n "${ZSH_VERSION:-}" ] && setopt shwordsplit
#
# Constants.
#
# Configure debugging. Set the DEBUG environment variable to any
# non-empty value to enable debug output, or TRACE to enable trace
# output.
TRACE=${TRACE:+'th_trace '}
[ -n "${TRACE}" ] && DEBUG=1
[ -z "${TRACE}" ] && TRACE=':'
DEBUG=${DEBUG:+'th_debug '}
[ -z "${DEBUG}" ] && DEBUG=':'
#
# Functions.
#
# Logging functions.
th_trace() { echo "test:TRACE $*" >&2; }
th_debug() { echo "test:DEBUG $*" >&2; }
th_info() { echo "test:INFO $*" >&2; }
th_warn() { echo "test:WARN $*" >&2; }
th_error() { echo "test:ERROR $*" >&2; }
th_fatal() { echo "test:FATAL $*" >&2; }
# Output subtest name.
th_subtest() { echo " $*" >&2; }
#
# Bind in our own non-exiting functions. These overwrite the functions from stx-iso-utils.sh:
#
function elog {
echo "$(date "+%F %H-%M-%S") Error: $*" >&2
return 1
}
function check_rc_die {
local -i rc=$1; shift
if [ $rc -ne 0 ]; then
echo "$(date "+%F %H-%M-%S") Error: $*" >&2
return $rc
fi
}