X-Git-Url: https://code.grnet.gr/git/snf-image/blobdiff_plain/a50a2bffcddf7e0de782b01758f6beeb9ea09e38..2dcbe945c84e239ee3c7e55f2330b84bd41b7492:/snf-image-host/common.sh.in diff --git a/snf-image-host/common.sh.in b/snf-image-host/common.sh.in index 985b56c..37affab 100644 --- a/snf-image-host/common.sh.in +++ b/snf-image-host/common.sh.in @@ -16,22 +16,30 @@ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA # 02110-1301, USA. +SNF_IMAGE_VERSION="@VERSION@" + AWK="awk" -KPARTX="kpartx" LOSETUP="losetup" +KPARTX="kpartx" SFDISK="sfdisk" QEMU_IMG="qemu-img" INSTALL_MBR="install-mbr" TIMEOUT="timeout" CURL="curl" +TAR="tar" +DATE="date -u" # Time in UTC -network_backend_support="@network_backend_support@" +# Temporary use stderr as monitoring file descriptor. +# `create' will overwrite this +MONITOR_FD="2" -MSG_TYPE_ERROR="error" +MSG_TYPE_ERROR="image-error" +MSG_TYPE_INFO="image-info" CLEANUP=( ) ERROR_MSGS=( ) + add_cleanup() { local cmd="" for arg; do cmd+=$(printf "%q " "$arg"); done @@ -39,41 +47,43 @@ add_cleanup() { } log_error() { - ERROR_MSGS+=("$@") - echo "$@" >&2 + echo "[ERROR] $*" >&2 } -close_fd() { - local fd="$1" - exec {fd}>&- +log_warning() { + echo "[WARNING] $*" >&2 } report_error() { - local error_file=$1 - local monitor_fd=$2 + ERROR_MSGS+=("$@") +} - local type="$MSG_TYPE_ERROR" - local location="host" +report_info() { + local report + echo "[INFO] $*" >&2 + report="$(./host-monitor.py info <<< "$*")" + eval "echo $(printf "%q" "$report") >&${MONITOR_FD}" +} - local msg="[" - for err in "${ERROR_MSGS[@]}"; do - msg+="\"$(sed 's/"/\\"/g' <<< "$err")\"," - done - if [ ${#msg} -gt 1 ]; then - # remove last comma (,) - msg="${msg%?}" - fi - msg+="]" - local stderr="$(cat "$error_file" | sed 's/"/\\"/g')" +close_fd() { + local fd="$1" + exec {fd}>&- +} - report="\"type\":\"$type\"," - report+="\"timestamp\":$(date +%s.%N)," - report+="\"location\":\"$location\"," - report+="\"messages\":$msg," - report+="\"stderr\":\"$stderr\"}" +send_errors() { + local report="" + if [ ${#ERROR_MSGS[@]} -gt 0 ]; then + local msg="" + for err in "${ERROR_MSGS[@]}"; do + msg+="$(echo "$err")" + done + report="$(./host-monitor.py error <<< "$msg")" + else + report=$(./host-monitor.py error <<< "Internal Error: Image deployment failed.") + fi - eval "echo $(printf "%q" "$report") >&${monitor_fd}" + eval "echo $(printf "%q" "$report") >&${MONITOR_FD}" } get_api5_arguments() { @@ -115,6 +125,13 @@ get_api10_arguments() { log_error "(INSTANCE_NAME HYPERVISOR or DISK_COUNT)" exit 1 fi + + case $HYPERVISOR in + xen-hvm|xen-pvm) . xen-common.sh ;; + kvm) . kvm-common.sh ;; + *) log_error "Unsupported hypervisor: \`$HYPERVISTOR'"; exit 1;; + esac + instance=$INSTANCE_NAME if [ $DISK_COUNT -lt 1 -o -z "$DISK_0_PATH" ]; then log_error "At least one disk is needed" @@ -122,12 +139,14 @@ get_api10_arguments() { fi if [ "$SCRIPT_NAME" = "export" ]; then if [ -z "$EXPORT_DEVICE" ]; then - log_error "Missing OS API Variable EXPORT_DEVICE" - fi - blockdev=$EXPORT_DEVICE + log_error "Missing OS API Variable EXPORT_DEVICE" + exit 1 + fi + blockdev=$EXPORT_DEVICE elif [ "$SCRIPT_NAME" = "import" ]; then if [ -z "$IMPORT_DEVICE" ]; then - log_error "Missing OS API Variable IMPORT_DEVICE" + log_error "Missing OS API Variable IMPORT_DEVICE" + exit 1 fi blockdev=$IMPORT_DEVICE else @@ -135,33 +154,37 @@ get_api10_arguments() { fi if [ "$SCRIPT_NAME" = "rename" -a -z "$OLD_INSTANCE_NAME" ]; then log_error "Missing OS API Variable OLD_INSTANCE_NAME" + exit 1 fi old_name=$OLD_INSTANCE_NAME } get_api20_arguments() { get_api10_arguments - if [ -z "$OSP_IMG_ID" ]; then - log_error "Missing OS API Parameter: OSP_IMG_ID" - exit 1 - fi - if [ -z "$OSP_IMG_FORMAT" ]; then - log_error "Missing OS API Parameter: OSP_IMG_FORMAT" - exit 1 - fi - if [ -z "$OSP_IMG_PASSWD" ]; then - log_error "Missing OS API Parameter: OSP_IMG_PASSWD" - exit 1 - fi - IMG_ID=$OSP_IMG_ID - IMG_FORMAT=$OSP_IMG_FORMAT - IMG_PASSWD=$OSP_IMG_PASSWD - if [ -n "$OSP_IMG_PROPERTIES" ]; then - IMG_PROPERTIES="$OSP_IMG_PROPERTIES" - fi - if [ -n "$OSP_IMG_PERSONALITY" ]; then - IMG_PERSONALITY="$OSP_IMG_PERSONALITY" + if [ "$SCRIPT_NAME" = "create" ]; then + local required_osparams="IMG_ID IMG_FORMAT IMG_PASSWD" + local osparams="$required_osparams IMG_PROPERTIES IMG_PERSONALITY CONFIG_URL" + + # Store OSP_VAR in VAR + for param in $osparams; do + eval $param=\"\$OSP_$param\" + done + + if [ -n "$CONFIG_URL" ]; then + local config config_params + echo "Downloading configuration parameters from: \`$CONFIG_URL'" >&2 + config=$($CURL -f "$CONFIG_URL") + config_params=$(./decode-config.py $osparams <<< "$config") + eval "$config_params" + fi + + for var in $required_osparams; do + if [ -z "${!var}" ]; then + log_error "Missing OS API Parameter: ${var}" + exit 1 + fi + done fi } @@ -204,9 +227,11 @@ EOF } create_floppy() { - local img=$1 + local img target - local target=$(mktemp -d) + img=$1 + + target=$(mktemp -d) add_cleanup rmdir "$target" dd bs=512 count=2880 if=/dev/zero of="$img" @@ -219,6 +244,7 @@ create_floppy() { cat "$UNATTEND" > "$target/unattend.xml" else log_error "Unattend file: \`"$UNATTEND"' does not exist" + exit 1 fi fi umount "$target" @@ -229,15 +255,35 @@ get_backend_type() { if [[ "$id" =~ ^pithos: ]]; then echo "pithos" + elif [[ "$id" =~ ^pithosmap: ]]; then + echo "pithos" elif [[ "$id" =~ ^(http|ftp)s?: ]]; then - if [ "$network_backend_support" = "yes" ]; then - echo "network"; - else - log_error "Retrieving images from the network is not supported." - exit 1 - fi + echo "network" + elif [ "$id" = "null" ]; then + echo "null" + else + echo "local" + fi +} + +canonicalize() { + local name="$1" + + if [ -d "$name" ]; then + name="$name/" + fi + + local dname="${name%/*}" + local fname="${name##*/}" + + if [ "x$dname" = "x" -a "${name:0:1}" = "/" ]; then + dname="/" + fi + + if [ -d "$dname" ]; then + (cd -- "$dname" && echo "${PWD%/}/$fname") else - echo "local"; + echo fi } @@ -286,13 +332,18 @@ ganeti_os_main() { exit 1 fi fi - } -do_debootstrap() { - local target="$1" +do_multistrap() { + local target="$1" + local cache="$2" + local pkgs="$3" - echo "Debootstraping to create a new root filesystem:" + # Create preferences.d for apt + mkdir -p "$target/etc/apt/preferences.d" + if [ -d "$MULTISTRAP_APTPREFDIR" ]; then + find "$MULTISTRAP_APTPREFDIR" -maxdepth 1 -type f -exec cp {} "$target/etc/apt/preferences.d" \; + fi # Create a policy-rc.d file to deny init script execution mkdir -p "$target/usr/sbin" @@ -302,33 +353,54 @@ exit 101 EOF chmod +x "$target/usr/sbin/policy-rc.d" - debootstrap --arch $(dpkg --print-architecture) \ - --include "$HELPER_EXTRA_PKGS" --variant=minbase stable "$target" \ - "$HELPER_MIRROR" 2>&1 | sed -e 's/^/DEBOOTSTRAP: /g' + multistrap -d "$target" -f "$MULTISTRAP_CONFIG" 2>&1 | sed -u -e 's/^/MULTISTRAP: /g' - # Save the package list - chroot "$target" dpkg-query -W -f "\${Package}\n" > "$HELPER_CACHE_PKGS" - - rm "$target/usr/sbin/policy-rc.d" + rm "$target/usr/sbin/policy-rc.d" + rm -rf "$target/etc/apt/preferences.d" +} - # remove the downloaded debs, as they are no longer needed - find "$target/var/cache/apt/archives" -type f -name '*.deb' -print0 | \ - xargs -r0 rm -f +report_and_cleanup() { + send_errors + cleanup +} - local tmp_cache=$(mktemp "$CACHE_FILE.XXXXXX") - tar cf "$tmp_cache" --one-file-system -C "$target" . || \ - { rm "$tmp_cache"; false; } - # Overwrite the default cache file. Not the user specified if present. - mv -f "$tmp_cache" "$HELPER_CACHE_FILE" +suppress_errors() { + "$@" &> /dev/null || true } -report_and_cleanup(){ +check_helper_rc() { + local rc=$1 + + if [ $rc -ne 0 ]; then + if [ $rc -eq 124 ]; then + log_error "Customization VM was terminated. Did not finish on time." + report_error "Image customization failed. Did not finish on time." + elif [ $rc -eq 137 ]; then # (128 + SIGKILL) + log_error "Customization VM was killed. Did not finish on time." + report_error "Image customization failed. Did not finish on time." + elif [ $rc -eq 141 ]; then # (128 + SIGPIPE) + log_error "Customization VM was terminated by a SIGPIPE." + log_error "Maybe progress monitor has died unexpectedly." + elif [ $rc -eq 125 ]; then + log_error "Internal Error. Image customization could not start." + log_error "timeout did not manage to run." + else + log_error "Customization VM died unexpectedly (return code $rc)." + fi + exit 1 + else + report_info "Customization VM exited normally." + fi +} - local err_file="$1" - local fd="$2" +check_helper_result() { + local result=$1 - report_error "$err_file" "$fd" - cleanup + if [ "x$result" != "xSUCCESS" ]; then + log_error "Image customization failed." + report_error "Image customization failed." + exit 1 + fi } cleanup() { @@ -373,22 +445,21 @@ fi : ${VARIANTS_DIR:="@sysconfdir@/ganeti/snf-image/variants"} : ${IMAGE_DIR:="@localstatedir@/lib/snf-image"} +: ${IMAGE_DEBUG:="no"} +: ${VERSION_CHECK:="@VERSION_CHECK@"} : ${HELPER_DIR:="@HELPER_DIR@"} -: ${HELPER_IMG:="@HELPER_IMG@"} -: ${HELPER_KERNEL:="@HELPER_KERNEL@"} -: ${HELPER_INITRD:="@HELPER_INITRD@"} -: ${HELPER_PKG:="@HELPER_DIR@/snf-image-helper.deb"} -: ${HELPER_SOFT_TIMEOUT:=20} +: ${HELPER_SIZE:="600"} +: ${HELPER_SOFT_TIMEOUT:=120} : ${HELPER_HARD_TIMEOUT:=5} : ${HELPER_USER:="nobody"} -: ${HELPER_CACHE_FILE:="@HELPER_DIR@/cache.tar"} -: ${HELPER_CACHE_PKGS:="@HELPER_DIR@/packages"} -: ${HELPER_EXTRA_PKGS:="linux-image-amd64,e2fsprogs,ntfs-3g,ntfsprogs,xmlstarlet,python,parted,reglookup,chntpw,util-linux"} -: ${HELPER_MIRROR:=""} +: ${HELPER_MEMORY:="256"} : ${PITHOS_DB:="sqlite:////@localstatedir@/lib/pithos/backend.db"} : ${PITHOS_DATA:="@localstatedir@/lib/pithos/data/"} : ${PROGRESS_MONITOR:="@PROGRESS_MONITOR@"} : ${UNATTEND:="@UNATTEND@"} +: ${XEN_SCRIPTS_DIR="@sysconfdir@/xen/scripts"} +: ${MULTISTRAP_CONFIG:="@MULTISTRAP_CONFIG@"} +: ${MULTISTRAP_APTPREFDIR:="@MULTISTRAP_APTPREFDIR@"} SCRIPT_NAME=$(basename $0)