#!/bin/env bash # # Copyright (c) 2018 Wind River Systems, Inc. # # SPDX-License-Identifier: Apache-2.0 # # # Build the tis-centos-image.img or tis-centos-image-rt.img file # BUILD_GUEST_DIR="$(dirname "$(readlink -f "${BASH_SOURCE[0]}" )" )" source "${BUILD_GUEST_DIR}/image-utils.sh" # Remind folks then need to be in the correct group to run mock commands # Note: cgts is our current alias for the mock group. Should probably be # renamed as stx-build in a future update NEED_GROUP=cgts CURRENT_GID=$(id -g) NEED_GID=$(getent group $NEED_GROUP | cut -d: -f3) if [ $CURRENT_GID != $NEED_GID ]; then echo "This command must be run using group '$NEED_GROUP'." echo "Please run:" echo " newgrp $NEED_GROUP" echo "" echo "Then try again." exit 1 fi # NOTE: TMP_DIR must end in '/' # NOTE: /tmp/ is now tmpfs like. Can't be trusted across multiple mock commands # TMP_DIR=/tmp/ TMP_DIR=/ # Use RPMs from the std build only, for now export BUILD_TYPE=std export MY_BUILD_DIR_TOP=$MY_BUILD_DIR function init_vars { # Output path (current dir unless MY_WORKSPACE defined) OUTPUT_DIR="$PWD/export" if [ ! -z "$MY_WORKSPACE" ] && [ -d "$MY_WORKSPACE" ] ; then OUTPUT_DIR="$MY_WORKSPACE/export" CGCS_REPO_DIR="$MY_WORKSPACE/rpmbuild/RPMS" fi if [ -n "$MY_GUEST_DIR" ]; then GUEST_DIR=$MY_GUEST_DIR else GUEST_DIR=$MY_WORKSPACE/guest fi MOCK=/usr/bin/mock if [ $VERBOSE -eq 0 ]; then MOCK="$MOCK -q" fi # Path to guest configuration GUEST_BUILD_DIR="${BUILD_GUEST_DIR}/build_guest" GUEST_BUILD_CMD=$GUEST_BUILD_DIR/build-guest-image.py if [ $VERBOSE -eq 1 ]; then GUEST_BUILD_CMD="$GUEST_BUILD_CMD -x" fi if [ $BUILD_MODE == 'std' ]; then OUTPUT_FILE=$OUTPUT_DIR/tis-centos-guest.img elif [ $BUILD_MODE == 'rt' ]; then OUTPUT_FILE=$OUTPUT_DIR/tis-centos-guest-rt.img else printf " Error -- unknown BUILD_MODE '$BUILD_MODE'\n"; exit 1 fi } function check_vars { # Where to store data printf "Finding cgcs-root\n" printf " Checking \$MY_REPO (value \"$MY_REPO\")\n" if [ ! -z "$MY_REPO" ] && [ -d "$MY_REPO" ] ; then INTERNAL_REPO_ROOT=$MY_REPO printf " Found!\n" fi if [ -z "$INTERNAL_REPO_ROOT" ] ; then printf " No joy -- checking \$MY_REPO_ROOT_DIR (value \"$MY_REPO_ROOT_DIR\")\n" if [ ! -z "$MY_REPO_ROOT_DIR" ] && [ -d "$MY_REPO_ROOT_DIR/cgcs-root" ] ; then INTERNAL_REPO_ROOT=$MY_REPO_ROOT_DIR/cgcs-root printf " Found!\n" fi fi if [ -z "$INTERNAL_REPO_ROOT" ] ; then printf " No joy -- checking for \$MY_WORKSPACE/cgcs-root\n" if [ -d "$MY_WORKSPACE/cgcs-root" ] ; then INTERNAL_REPO_ROOT=$MY_WORKSPACE/cgcs-root printf " Found!\n" fi fi if [ -z "$INTERNAL_REPO_ROOT" ] ; then printf " Error -- could not locate cgcs-root repo.\n" exit 1 fi STX_DIR=$INTERNAL_REPO_ROOT/stx if [ "x$MY_BUILD_CFG" == "x" ];then printf " Error -- reqiure MY_BUILD_CFG to be defined.\n" exit 1 fi RELEASE_INFO="$(get_release_info)" if [ $? -ne 0 ]; then echo "ERROR: failed to find a release info file." exit 1 fi export PLATFORM_RELEASE=$(source "$RELEASE_INFO" && echo $PLATFORM_RELEASE) } function create_rootfs { printf "\nCreating guest file system\n" mkdir -p $GUEST_DIR if [ $? -ne 0 ]; then printf " Error -- Could not create $GUEST_DIR\n"; exit 1 fi # Place build-time environment variables in mock configuration GUEST_ENV="${MY_BUILD_ENVIRONMENT}-guest" GUEST_CFG=$GUEST_DIR/$MY_BUILD_ENVIRONMENT_FILE MY_BUILD_ENVIRONMENT=$GUEST_ENV "${BUILD_GUEST_DIR}/modify-build-cfg" $GUEST_CFG if [ $? -ne 0 ]; then printf " Error -- Could not update $GUEST_CFG\n"; exit 1 fi # Setup mock directories for the guest if [ -d /localdisk/loadbuild/mock ]; then LNK=/localdisk/loadbuild/mock/$GUEST_ENV if [ ! -L $LNK ]; then ln -s $GUEST_DIR $LNK fi fi if [ -d /localdisk/loadbuild/mock-cache ]; then mkdir -p $GUEST_DIR/cache LNK=/localdisk/loadbuild/mock-cache/$GUEST_ENV if [ ! -L $LNK ]; then ln -s $GUEST_DIR/cache $LNK fi fi # Setup mock chroot environment $MOCK -r $GUEST_CFG --clean && $MOCK -r $GUEST_CFG --init if [ $? -ne 0 ]; then printf " Error -- Failed to setup guest mock chroot\n"; exit 1 fi # Install the RPMs to the root filesystem # Note that the "rt" build needs access to both local-std and local-rt repos local EXTRA_REPOS="" if [ $BUILD_MODE == 'std' ]; then INC_RPM_LIST=$(grep -v '^#' ${GUEST_BUILD_DIR}/rpm-install-list.txt) TIS_RPM_LIST=$(image_inc_list guest std centos) elif [ $BUILD_MODE == 'rt' ]; then INC_RPM_LIST=$(grep -v '^#' ${GUEST_BUILD_DIR}/rpm-install-list-rt.txt) TIS_RPM_LIST=$(image_inc_list guest rt centos) EXTRA_REPOS="--enablerepo local-rt" else printf " Error -- unknown BUILD_MODE '$BUILD_MODE'\n"; exit 1 fi $MOCK -r $GUEST_CFG --install ${INC_RPM_LIST} ${TIS_RPM_LIST} ${EXTRA_REPOS} if [ $? -ne 0 ]; then printf "=====\n" cat $GUEST_DIR/mock/result/root.log | sed -n '/Error:/,$p' | sed '/Child return code was:/q' printf "=====\n" printf " Error -- Failed to install RPM packages\n"; exit 1 fi # Remove RPMs that are not required in image (pruned package list) # NOTE: these are automatically installed from the mock init not # through dependencies. EXC_RPM_LIST=$(grep -v '^#' ${GUEST_BUILD_DIR}/rpm-remove-list.txt) $MOCK -r $GUEST_CFG --remove ${EXC_RPM_LIST} if [ $? -ne 0 ]; then printf " Error -- Failed to remove RPM packages\n"; exit 1 fi printf " Done\n" } function update_rootfs { printf "\nCustomizing guest file system\n" # Copy over skeleton configuration files for GUEST_ROOTFS in $GUEST_BUILD_DIR/rootfs $GUEST_BUILD_DIR/rootfs-$BUILD_MODE; do for f in $(cd $GUEST_ROOTFS && find . -type f | cut -c3-); do echo "$MOCK -r $GUEST_CFG --copyin $GUEST_ROOTFS/$f $f" $MOCK -r $GUEST_CFG --copyin $GUEST_ROOTFS/$f $f if [ $? -ne 0 ]; then printf " Error -- Failed to copyin file $f\n"; exit 1 fi done done # Run the root file system setup script inside the chroot ROOTFS_SETUP=rootfs-setup.sh $MOCK -r $GUEST_CFG --copyin $GUEST_BUILD_DIR/$ROOTFS_SETUP $TMP_DIR && \ if [ $BUILD_MODE == 'rt' ]; then ROOTFS_SETUP_CMD="$TMP_DIR$ROOTFS_SETUP --rt" elif [ $BUILD_MODE == 'std' ]; then ROOTFS_SETUP_CMD="$TMP_DIR$ROOTFS_SETUP --std" else ROOTFS_SETUP_CMD="$TMP_DIR$ROOTFS_SETUP" fi $MOCK -r $GUEST_CFG --chroot "$ROOTFS_SETUP_CMD" if [ $? -ne 0 ]; then printf " Error -- Failed to run guest $ROOTFS_SETUP\n"; exit 1 fi $MOCK -r $GUEST_CFG --chroot "rm -f $TMP_DIR$ROOTFS_SETUP" if [ $? -ne 0 ]; then printf " Error -- Failed to delete $ROOTFS_SETUP from guest\n"; exit 1 fi printf " Done\n" } function build_image { # Build the image printf "\nBuilding guest image $OUTPUT_FILE\n" mkdir -p $OUTPUT_DIR if [ $? -ne 0 ]; then printf " Error -- Could not create $OUTPUT_DIR\n"; exit 1 fi # Build guest rootfs archive ROOTFS_SPACE=$((500*1024*1024)) ROOTFS_TAR=rootfs.tar ROOTFS_EXCLUDE=rootfs-exclude.txt $MOCK -r $GUEST_CFG --copyin $GUEST_BUILD_DIR/$ROOTFS_EXCLUDE $TMP_DIR $MOCK -r $GUEST_CFG --chroot -- tar -cf $TMP_DIR$ROOTFS_TAR -X $TMP_DIR$ROOTFS_EXCLUDE --numeric-owner / $MOCK -r $GUEST_CFG --copyout $TMP_DIR$ROOTFS_TAR $GUEST_DIR $MOCK -r $GUEST_CFG --chroot -- rm -f $TMP_DIR$ROOTFS_TAR $GUEST_BUILD_CMD -i $GUEST_DIR/$ROOTFS_TAR -o $OUTPUT_FILE -s $ROOTFS_SPACE if [ $? -ne 0 ]; then printf " Error -- Failed to build guest image\n"; exit 1 fi printf " Done\n" } function clean_guest { printf "\nCleaning the guest $GUEST_DIR\n" if [ ! -e $GUEST_DIR ]; then printf " Done...nothing to do\n"; exit 0 fi # Place build-time environment variables in mock configuration GUEST_ENV="${MY_BUILD_ENVIRONMENT}-guest" GUEST_CFG=$GUEST_DIR/$MY_BUILD_ENVIRONMENT_FILE if [ ! -e $GUEST_CFG ]; then MY_BUILD_ENVIRONMENT=$GUEST_ENV "${BUILD_GUEST_DIR}/modify-build-cfg" $GUEST_CFG if [ $? -ne 0 ]; then printf " Error -- Could not update $GUEST_CFG\n"; exit 1 fi fi $MOCK -r $GUEST_CFG --clean $MOCK -r $GUEST_CFG --scrub=cache rm -rf $GUEST_DIR if [ $? -ne 0 ]; then printf " Error -- Failed to remove guest $GUEST_DIR\n"; exit 1 fi printf " Done\n" } ############################################# # Main code ############################################# usage () { echo "" echo "Usage: " echo " build-guest [--rt | --std] [--verbose]" echo " build-guest [--help]" echo " build-guest [--clean]" echo "" } # Default argument values HELP=0 CLEAN=0 VERBOSE=0 BUILD_MODE='std' # read the options TEMP=`getopt -o h --long clean --long rt --long std --long verbose -n 'test.sh' -- "$@"` eval set -- "$TEMP" # extract options and their arguments into variables. while true ; do case "$1" in -h|--help) HELP=1 ; shift ;; --clean) CLEAN=1 ; shift ;; --verbose) VERBOSE=1 ; shift ;; --rt) BUILD_MODE='rt' ; shift ;; --std) BUILD_MODE='std' ; shift ;; --) shift ; break ;; *) echo "Internal error!" ; exit 1 ;; esac done if [ $HELP -eq 1 ]; then usage exit 0 fi ( printf "\n*****************************\n" printf "Create Titanium Cloud/CentOS Guest Image\n" printf "*****************************\n\n" init_vars check_vars if [ $CLEAN -eq 1 ]; then clean_guest exit 0 fi create_rootfs update_rootfs build_image ) 2>&1 | stdbuf -o0 awk '{ print strftime("%H:%M:%S"), $0; fflush(); }' ; exit ${PIPESTATUS[0]}