From a69c15f4065017bcacd1d8cefba40bd1e4c956ba Mon Sep 17 00:00:00 2001 From: Don Penney Date: Fri, 7 Aug 2020 10:56:25 -0400 Subject: [PATCH] Use host patches for subcloud install setup This update enhances gen-bootloader-iso.sh to use patches applied on the host controller when setting up the subcloud installation bootloader. This checks the release version from the ISO to look for patches for that release only, copying applied and committed patches to the installation setup. This update also adds cleanup of partial setup on failure. Change-Id: I4eeb0141b75e48ce53c132b89e19e07c68cc49d2 Story: 2007994 Task: 40631 Signed-off-by: Don Penney --- .../scripts/gen-bootloader-iso.sh | 237 ++++++++++++++++-- 1 file changed, 220 insertions(+), 17 deletions(-) diff --git a/utilities/platform-util/scripts/gen-bootloader-iso.sh b/utilities/platform-util/scripts/gen-bootloader-iso.sh index cef72e73..bcba66ac 100755 --- a/utilities/platform-util/scripts/gen-bootloader-iso.sh +++ b/utilities/platform-util/scripts/gen-bootloader-iso.sh @@ -29,20 +29,25 @@ declare BOOT_HOSTNAME= declare BOOT_INTERFACE= declare BOOT_IP= declare BOOT_NETMASK= +declare CLEAN_NODE_DIR="no" +declare CLEAN_SHARED_DIR="no" declare DEFAULT_GRUB_ENTRY= declare DEFAULT_LABEL= declare DEFAULT_SYSLINUX_ENTRY= declare DELETE="no" declare GRUB_TIMEOUT=-1 declare INPUT_ISO= +declare ISO_VERSION= declare KS_NODETYPE= declare -i LOCK_TMOUT=600 # Wait up to 10 minutes, by default declare NODE_ID= declare ORIG_PWD=$PWD declare OUTPUT_ISO= declare -a PARAMS +declare PATCHES_FROM_HOST="yes" declare -i TIMEOUT=0 declare UPDATE_TIMEOUT="no" +declare WORKDIR= declare WWW_ROOT_DIR= function usage { @@ -74,6 +79,7 @@ Optional parameters for setup: --boot-gateway : Specify gateway for boot interface --timeout : Specify boot menu timeout, in seconds --lock-timeout : Specify time to wait for mutex lock before aborting + --patches-from-iso: Use patches from the ISO, if any, rather than host --param : Specify boot parameter customization Examples: --param rootfs_device=nvme0n1 --param boot_device=nvme0n1 @@ -115,7 +121,7 @@ ENDUSAGE # # Parse cmdline arguments # -LONGOPTS="input:,addon:,param:,default-boot:,timeout:,lock-timeout:" +LONGOPTS="input:,addon:,param:,default-boot:,timeout:,lock-timeout:,patches-from-iso" LONGOPTS="${LONGOPTS},base-url:,www-root:,id:,delete" LONGOPTS="${LONGOPTS},boot-gateway:,boot-hostname:,boot-interface:,boot-ip:,boot-netmask:" LONGOPTS="${LONGOPTS},help" @@ -242,6 +248,10 @@ while :; do DELETE="yes" shift ;; + --patches-from-iso) + PATCHES_FROM_HOST="no" + shift + ;; --) shift break @@ -332,6 +342,11 @@ EOF } function cleanup { + if [ $? -ne 0 ]; then + # Clean up from failure + handle_delete + fi + common_cleanup } @@ -346,13 +361,101 @@ function handle_delete { fi # If there are no more nodes, cleanup everything else - if [ -z "$(ls -A ${NODE_DIR_BASE})" ]; then - rmdir ${NODE_DIR_BASE} + if [ $(ls -A ${NODE_DIR_BASE} | wc -l) = 0 ]; then + if [ -d ${NODE_DIR_BASE} ]; then + rmdir ${NODE_DIR_BASE} + fi - rm -rf ${SHARED_DIR} + if [ -d ${SHARED_DIR} ]; then + rm -rf ${SHARED_DIR} + fi fi } +function get_patches_from_host { + local host_patch_repo=/www/pages/updates/rel-${ISO_VERSION} + + if [ ! -d ${host_patch_repo} ]; then + log_error "Patch repo not found: ${host_patch_repo}" + # Don't fail, as there could be scenarios where there's nothing on + # the host related to the release on the ISO + return + fi + + mkdir -p ${SHARED_DIR}/patches + if [ $? -ne 0 ]; then + log_error "Failed to create directory: ${SHARED_DIR}/patches" + exit 1 + fi + + rsync -a ${host_patch_repo}/repodata ${host_patch_repo}/Packages ${SHARED_DIR}/patches/ + if [ $? -ne 0 ]; then + log_error "Failed to copy patches repo from ${host_patch_repo}" + exit 1 + fi + + mkdir -p \ + ${SHARED_DIR}/patches/metadata/available \ + ${SHARED_DIR}/patches/metadata/applied \ + ${SHARED_DIR}/patches/metadata/committed + if [ $? -ne 0 ]; then + log_error "Failed to create directory: ${SHARED_DIR}/patches/metadata/${state}" + exit 1 + fi + + local metadata_to_copy= + for state in applied committed; do + if [ ! -d /opt/patching/metadata/${state} ]; then + continue + fi + + metadata_to_copy=$(find /opt/patching/metadata/${state} -type f -exec grep -q "${ISO_VERSION}" {} \; -print) + if [ -n "${metadata_to_copy}" ]; then + rsync -a ${metadata_to_copy} ${SHARED_DIR}/patches/metadata/${state}/ + if [ $? -ne 0 ]; then + log_error "Failed to copy ${state} patch metadata" + exit 1 + fi + fi + done +} + +function query_patched_pkg { + local pkg=$1 + local pkg_location= + local shared_patch_repo=${SHARED_DIR}/patches + + pkg_location=$(dnf repoquery --disablerepo=* --repofrompath local,file:///${shared_patch_repo} --latest-limit=1 --location -q ${pkg}) + if [ $? -eq 0 -a -n "${pkg_location}" ]; then + echo ${pkg_location/file:\/\/\//} + fi +} + +function extract_pkg_to_workdir { + local pkg=$1 + local pkgfile= + + pkgfile=$(query_patched_pkg ${pkg}) + if [ -z "${pkgfile}" ]; then + # Nothing to do + return + fi + + if [ ! -f "${pkgfile}" ]; then + log_error "File doesn't exist, unable to extract: ${pkgfile}" + exit 1 + fi + + pushd ${WORKDIR} >/dev/null + echo "Extracting files from ${pkgfile}" + rpm2cpio ${pkgfile} | cpio -idmv + if [ $? -ne 0 ]; then + log_error "Failed to extract files from ${pkgfile}" + exit 1 + fi + popd >/dev/null +} + function extract_shared_files { if [ -d ${SHARED_DIR} ]; then # If the shared dir already exists, assume we don't need to re-extract @@ -371,13 +474,56 @@ function extract_shared_files { exit 1 fi - rsync -a ${MNTDIR}/LiveOS/ ${SHARED_DIR}/LiveOS/ + # Setup shared patch data + if [ ${PATCHES_FROM_HOST} = "yes" ]; then + get_patches_from_host + else + if [ -d ${MNTDIR}/patches ]; then + rsync -a ${MNTDIR}/patches/ ${SHARED_DIR}/patches/ + if [ $? -ne 0 ]; then + log_error "Failed to copy patches repo from ${INPUT_ISO}" + exit 1 + fi + fi + fi + + local squashfs_img_file=${MNTDIR}/LiveOS/squashfs.img + if [ ${PATCHES_FROM_HOST} = "yes" ]; then + extract_pkg_to_workdir 'pxe-network-installer' + + local patched_squashfs_img_file=${WORKDIR}/www/pages/feed/rel-${ISO_VERSION}/LiveOS/squashfs.img + if [ -f ${patched_squashfs_img_file} ]; then + # Use the patched squashfs.img + squashfs_img_file=${patched_squashfs_img_file} + fi + fi + + mkdir ${SHARED_DIR}/LiveOS + rsync -a ${squashfs_img_file} ${SHARED_DIR}/LiveOS/ if [ $? -ne 0 ]; then - log_error "Failed to copy rootfs from ${INPUT_ISO}" + log_error "Failed to copy rootfs: ${patched_squashfs_img_file}" exit 1 fi - rsync ${MNTDIR}/isolinux.cfg ${SHARED_DIR}/ + local pxeboot_files_dir=${MNTDIR}/pxeboot + if [ ${PATCHES_FROM_HOST} = "yes" ]; then + extract_pkg_to_workdir 'platform-kickstarts-pxeboot' + + local patched_pxeboot_files_dir=${WORKDIR}/pxeboot + if [ -d ${patched_pxeboot_files_dir} ]; then + # Use the patched pxeboot files + pxeboot_files_dir=${patched_pxeboot_files_dir} + fi + fi + + mkdir ${SHARED_DIR}/pxeboot/ + rsync -a ${pxeboot_files_dir}/pxeboot_*.cfg ${SHARED_DIR}/pxeboot/ + if [ $? -ne 0 ]; then + log_error "Failed to copy pxeboot files from ${pxeboot_files_dir}" + exit 1 + fi + + rsync -a ${MNTDIR}/isolinux.cfg ${SHARED_DIR}/ if [ $? -ne 0 ]; then log_error "Failed to copy isolinux.cfg from ${INPUT_ISO}" exit 1 @@ -395,11 +541,15 @@ function extract_shared_files { exit 1 fi - if [ -d ${MNTDIR}/patches ]; then - rsync -a ${MNTDIR}/patches/ ${SHARED_DIR}/patches/ - if [ $? -ne 0 ]; then - log_error "Failed to copy patches repo from ${INPUT_ISO}" - exit 1 + if [ ${PATCHES_FROM_HOST} = "yes" ]; then + get_patches_from_host + else + if [ -d ${MNTDIR}/patches ]; then + rsync -a ${MNTDIR}/patches/ ${SHARED_DIR}/patches/ + if [ $? -ne 0 ]; then + log_error "Failed to copy patches repo from ${INPUT_ISO}" + exit 1 + fi fi fi } @@ -424,6 +574,35 @@ function extract_node_files { exit $rc fi + if [ ${PATCHES_FROM_HOST} = "yes" ]; then + local patched_initrd_file=${WORKDIR}/pxeboot/rel-${ISO_VERSION}/installer-intel-x86-64-initrd_1.0 + local patched_vmlinuz_file=${WORKDIR}/pxeboot/rel-${ISO_VERSION}/installer-bzImage_1.0 + + # First, check to see if pxe-network-installer is already extracted. + # If this is the first setup for this ISO, it will have been extracted + # during the shared setup, and we don't need to do it again. + if [ ! -f ${patched_initrd_file} ]; then + extract_pkg_to_workdir 'pxe-network-installer' + fi + + # Copy patched files, as appropriate + if [ -f ${patched_initrd_file} ]; then + rsync -a ${patched_initrd_file} ${BUILDDIR}/initrd.img + if [ $? -ne 0 ]; then + log_error "Failed to copy ${patched_initrd_file}" + exit 1 + fi + fi + + if [ -f ${patched_vmlinuz_file} ]; then + rsync -a ${patched_vmlinuz_file} ${BUILDDIR}/vmlinuz + if [ $? -ne 0 ]; then + log_error "Failed to copy ${patched_vmlinuz_file}" + exit 1 + fi + fi + fi + # Setup syslinux and grub cfg files generate_boot_cfg ${BUILDDIR} @@ -466,7 +645,13 @@ function extract_node_files { implantisomd5 ${OUTPUT_ISO} # Setup the kickstart - cp ${MNTDIR}/pxeboot/pxeboot_${KS_NODETYPE}.cfg ${NODE_DIR}/miniboot_${KS_NODETYPE}.cfg + local ksfile=${SHARED_DIR}/pxeboot/pxeboot_${KS_NODETYPE}.cfg + + cp ${ksfile} ${NODE_DIR}/miniboot_${KS_NODETYPE}.cfg + if [ $? -ne 0 ]; then + log_error "Failed to copy ${ksfile} to ${NODE_DIR}/miniboot_${KS_NODETYPE}.cfg" + exit 1 + fi # Number of dirs in the NODE_URL: Count the / characters, subtracting 2 for http:// or https:// DIRS=$(($(grep -o "/" <<< "$NODE_URL" | wc -l) - 2)) @@ -499,9 +684,6 @@ EOF # Main # -# Run cleanup on any exit -trap cleanup EXIT - # Check script dependencies check_requirements @@ -556,14 +738,35 @@ if [ -d ${NODE_DIR} ]; then exit 1 fi -BUILDDIR=$(mktemp -d -p $PWD updateiso_build_XXXXXX) +# Run cleanup on any exit +trap cleanup EXIT + +BUILDDIR=$(mktemp -d -p /scratch gen_bootloader_build_XXXXXX) if [ -z "${BUILDDIR}" -o ! -d ${BUILDDIR} ]; then log_error "Failed to create builddir. Aborting..." exit 1 fi +WORKDIR=$(mktemp -d -p /scratch gen_bootloader_workdir_XXXXXX) +if [ -z "${WORKDIR}" -o ! -d ${WORKDIR} ]; then + log_error "Failed to create builddir. Aborting..." + exit 1 +fi + mount_iso ${INPUT_ISO} +# Determine release version from ISO +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}) +if [ -z "${ISO_VERSION}" ]; then + log_error "Failed to determine version of installation ISO" + exit 1 +fi + # Copy the common files from the ISO, if needed extract_shared_files