X-Git-Url: https://code.grnet.gr/git/snf-image/blobdiff_plain/ec728294268a152a2c61a78c7a27581773cec0b7..7175d8446f2358ee1dc8a2deba30713e2df87582:/snf-image-host/common.sh.in diff --git a/snf-image-host/common.sh.in b/snf-image-host/common.sh.in index ae17b81..ca036c0 100644 --- a/snf-image-host/common.sh.in +++ b/snf-image-host/common.sh.in @@ -1,45 +1,42 @@ -# Copyright 2011 GRNET S.A. All rights reserved. +# Copyright (C) 2011 GRNET S.A. +# Copyright (C) 2007, 2008, 2009 Google Inc. # -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. # -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. # -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND -# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -# ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE -# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS -# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -# SUCH DAMAGE. -# -# The views and conclusions contained in the software and documentation are -# those of the authors and should not be interpreted as representing official -# policies, either expressed or implied, of GRNET S.A. +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301, USA. AWK="awk" -KPARTX="kpartx" LOSETUP="losetup" +KPARTX="kpartx" SFDISK="sfdisk" QEMU_IMG="qemu-img" INSTALL_MBR="install-mbr" -TIMELIMIT="timelimit" +TIMEOUT="timeout" CURL="curl" -PROGRESS_MONITOR="snf-progress-monitor" +TAR="tar" +DATE="date -u" # Time in UTC + +# Temporary use stderr as monitoring file descriptor. +# `create' will overwrite this +MONITOR_FD="2" -progress_monitor_support="@progress_monitor_support@" +MSG_TYPE_ERROR="image-error" +MSG_TYPE_INFO="image-info" CLEANUP=( ) +ERROR_MSGS=( ) + add_cleanup() { local cmd="" @@ -48,7 +45,39 @@ add_cleanup() { } log_error() { - echo "$@" >&2 + echo "[ERROR] $*" >&2 +} + +report_error() { + ERROR_MSGS+=("$@") +} + +report_info() { + local report + echo "[INFO] $*" >&2 + report="$(./host-monitor.py info <<< "$*")" + eval "echo $(printf "%q" "$report") >&${MONITOR_FD}" +} + + +close_fd() { + local fd="$1" + exec {fd}>&- +} + +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}" } get_api5_arguments() { @@ -90,6 +119,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" @@ -97,12 +133,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 @@ -110,36 +148,35 @@ 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 - if [ -z "$OSP_IMG_PROPERTIES" ]; then - log_error "Missing OS API Parameter: OSP_IMG_PROPERTIES" - exit 1 - fi - IMG_ID=$OSP_IMG_ID - IMG_FORMAT=$OSP_IMG_FORMAT - IMG_PASSWD=$OSP_IMG_PASSWD - IMG_PROPERTIES=$OSP_IMG_PROPERTIES - if [ -n "$OSP_IMG_PERSONALITY" ]; then - IMG_PERSONALITY=$OSP_IMG_PERSONALITY + 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 + 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 } map_disk0() { @@ -181,21 +218,45 @@ EOF } create_floppy() { - local img=$1 + local img target + + img=$1 - local target=$(mktemp -d) + target=$(mktemp -d) add_cleanup rmdir "$target" dd bs=512 count=2880 if=/dev/zero of="$img" mkfs.ext2 -F "$img" > /dev/null mount "$img" "$target" -o loop - set | egrep ^snf_export_\\w+=|sed -e 's/^snf_export_/SNF_IMAGE_/' | \ - while read line; do - echo "export $line" >> "$target/rules" - done + set | egrep ^snf_export_\\w+= | sed -e 's/^snf_export_/export SNF_IMAGE_/' \ + > "$target/rules" + if [ -n "$UNATTEND" ]; then + if [ -f "$UNATTEND" ]; then + cat "$UNATTEND" > "$target/unattend.xml" + else + log_error "Unattend file: \`"$UNATTEND"' does not exist" + exit 1 + fi + fi umount "$target" } +get_backend_type() { + local id=$1 + + if [[ "$id" =~ ^pithos: ]]; then + echo "pithos" + elif [[ "$id" =~ ^pithosmap: ]]; then + echo "pithos" + elif [[ "$id" =~ ^(http|ftp)s?: ]]; then + echo "network" + elif [ "$id" = "null" ]; then + echo "null" + else + echo "local" + fi +} + # this one is only to be called by create ganeti_os_main() { if [ -z "$OS_API_VERSION" -o "$OS_API_VERSION" = "5" ]; then @@ -207,8 +268,9 @@ ganeti_os_main() { get_api10_arguments elif [ "$OS_API_VERSION" = "20" ]; then get_api20_arguments - IMAGE_NAME=$IMG_ID - IMAGE_TYPE=$IMG_FORMAT + IMAGE_NAME="$IMG_ID" + IMAGE_TYPE="$IMG_FORMAT" + BACKEND_TYPE=$(get_backend_type $IMG_ID) else log_error "Unknown OS API VERSION $OS_API_VERSION" exit 1 @@ -240,12 +302,81 @@ ganeti_os_main() { exit 1 fi fi +} + +do_multistrap() { + local target="$1" + local cache="$2" + local pkgs="$3" + + # 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" + cat > "$target/usr/sbin/policy-rc.d" <&1 | sed -u -e 's/^/MULTISTRAP: /g' + + rm "$target/usr/sbin/policy-rc.d" + rm -rf "$target/etc/apt/preferences.d" +} + +report_and_cleanup() { + send_errors + cleanup +} + +suppress_errors() { + "$@" &> /dev/null || true +} + +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 +} + +check_helper_result() { + local result=$1 + if [ "x$result" != "xSUCCESS" ]; then + log_error "Image customization failed." + report_error "Image customization failed." + exit 1 + fi } cleanup() { -# if something fails here, it souldn't call cleanup again... + # if something fails here, it souldn't call cleanup again... trap - EXIT + if [ ${#CLEANUP[*]} -gt 0 ]; then LAST_ELEMENT=$((${#CLEANUP[*]}-1)) REVERSE_INDEXES=$(seq ${LAST_ELEMENT} -1 0) @@ -254,11 +385,12 @@ cleanup() { # before we give up with an error. This is needed for kpartx when # dealing with ntfs partitions mounted through fuse. umount is not # synchronous and may return while the partition is still busy. A - # premature attempt to delete partition mappings through kpartx on a - # device that hosts previously mounted ntfs partition may fail with - # an `device-mapper: remove ioctl failed: Device or resource busy' - # error. A sensible workaround for this is to wait for a while and - # then try again. + # premature attempt to delete partition mappings through kpartx on + # a device that hosts previously mounted ntfs partition may fail + # with errors like this one: + # `device-mapper: remove ioctl failed: Device or resource busy' + # A sensible workaround for this is to wait for a while and then + # retry it. local cmd=${CLEANUP[$i]} $cmd || for interval in 0.25 0.5 1 2 4; do echo "Command $cmd failed!" @@ -281,39 +413,24 @@ if [ -f "$DEFAULT_FILE" ]; then . "$DEFAULT_FILE" fi -: ${ARCH:="x86_64"} : ${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:=15} +: ${HELPER_URL:="@HELPER_URL@"} +: ${HELPER_SIZE:="600"} +: ${HELPER_SOFT_TIMEOUT:=120} : ${HELPER_HARD_TIMEOUT:=5} : ${HELPER_USER:="nobody"} -: ${HELPER_CACHE_FILE:="@HELPER_DIR@/cache.tar"} -: ${HELPER_EXTRA_PKGS:="linux-image-amd64,e2fsprogs,ntfs-3g,ntfsprogs,xmlstarlet,python,parted,reglookup,chntpw"} -: ${HELPER_MIRROR:=""} - +: ${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) -if [ -f /sbin/blkid -a -x /sbin/blkid ]; then - VOL_ID="/sbin/blkid -c /dev/null -o value -s UUID" - VOL_TYPE="/sbin/blkid -c /dev/null -o value -s TYPE" -else - for dir in /lib/udev /sbin; do - if [ -f $dir/vol_id -a -x $dir/vol_id ]; then - VOL_ID="$dir/vol_id -u" - VOL_TYPE="$dir/vol_id -t" - fi - done -fi - -if [ -z "$VOL_ID" ]; then - log_error "vol_id or blkid not found, please install udev or util-linux" - exit 1 -fi - # vim: set sta sts=4 shiftwidth=4 sw=4 et ai :