Hello World

File build-vm-openstack of Package build

#
# Openstack specific functions
#
################################################################
#
# Copyright (c) 2017 SUSE Linux Products GmbH
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2 or 3 as
# published by the Free Software Foundation.
#
# 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.
#
# You should have received a copy of the GNU General Public License
# along with this program (see the file COPYING); if not, write to the
# Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
#
################################################################


OPENSTACK_BUILD_ID=

OPENSTACK_VOLUME_GRUB=
OPENSTACK_VOLUME_ROOT=
OPENSTACK_VOLUME_SWAP=
OPENSTACK_ROOT_ATTACH_INFO=
OPENSTACK_SWAP_ATTACH_INFO=

openstack_get_field() {
    echo -n "$1"|perl -n -e "\$_ =~ /^\|\s+$2\s+\|\s+(\S*)\s+\|\$/ && print \$1"
}

openstack_get_disk_state() {
    local OUT=$($CINDERCLIENT show "$1")
    openstack_get_field "$OUT" status
}

openstack_cinder_volume2id() {
    local OUT=$($CINDERCLIENT show "$1")
    openstack_get_field "$OUT" id
}

# sets OPENSTACK_ATTACH_INFO
cloud_volume_attach_openstack() {
    local VM_SERVER="$1"
    local VM_VOL_NAME="$2"
    local VM_VOL_ID=$(openstack_cinder_volume2id $VM_VOL_NAME)

    # Example output of "nova volume-attach
    # +----------+--------------------------------------+
    # | Property | Value                                |
    # +----------+--------------------------------------+
    # | device   | /dev/vdb                             |
    # | id       | 793e9a04-7068-4cf1-86e7-26509f709b54 |
    # | serverId | 175e470c-5869-4425-988a-6b334a2fa655 |
    # | volumeId | 793e9a04-7068-4cf1-86e7-26509f709b54 |
    # +----------+--------------------------------------+
    local OUT=$($NOVACLIENT volume-attach "$VM_SERVER" "$VM_VOL_ID")
    test $? -gt 0 && cleanup_and_exit 3 "ERROR: nova volume-attach failed. $?"

    local device_path=`openstack_get_field "$OUT" device`
    local serverId=`openstack_get_field "$OUT" serverId`
    while true ; do
	local state=`openstack_get_disk_state "$VM_VOL_NAME"`
	test "$state" = "in-use" && break
        test -z "$state" && cleanup_and_exit 3 "ERROR: unable to find state of volume $VM_VOL_NAME"
        if test "$state" = available ; then
	    echo "WARNING: volume $VM_VOL_NAME got not attached, retrying" >&2
	    OUT=`$NOVACLIENT volume-attach "$VM_SERVER" "$VM_VOL_ID"`
	    test $? -gt 0 && cleanup_and_exit 3 "ERROR: nova attach failed. $?"
	    device_path=`openstack_get_field "$OUT" device`
        fi
        sleep 3
    done
    test "${device_path:0:5}" = "/dev/" || cleanup_and_exit 3 "device path not starting with /dev/: $device_path"

    if ! test -e "$device_path" ; then
	echo "waiting for $device_path to appear"
	for i in 1 2 3 4 5 6 7 8 9 10 ; do
	    sleep 1
	    test -e "$device_path" && break
	done
	test -b "$device_path" || cleanup_and_exit 3 "$device_path did not appear"
    fi

    # return attach info. Example:
    # 793e9a04-7068-4cf1-86e7-26509f709b54:175e470c-5869-4425-988a-6b334a2fa655:/dev/vdb
    OPENSTACK_ATTACH_INFO="$VM_VOL_ID:$serverId:$device_path"
}

cloud_volume_detach_openstack() {
    local VM_SERVER=${1:37:36}
    local VM_VOL_ID=${1:0:36}

    test -z "$VM_SERVER" -o -z "$VM_VOL_ID" && cleanup_and_exit 1 "cloud_volume_detach_openstack: bad attach info"

    # needed at all?
    $NOVACLIENT volume-detach "$VM_SERVER" "$VM_VOL_ID"

    state=`openstack_get_disk_state $VM_VOL_ID`
    while test "$state" = detaching ; do
        sleep 1
        state=`openstack_get_disk_state $VM_VOL_ID`
    done

    if test "$state" = "available" ; then
        return 0
    fi
    
    if ! $NOVACLIENT volume-detach "$VM_SERVER" "$VM_VOL_ID" ; then
	cleanup_and_exit 3 "ERROR: nova detach of $VM_VOL_ID failed."
    fi
    while test "$state" != "available" ; do
        state=`openstack_get_disk_state $VM_VOL_ID`
	sleep 3
    done
}

vm_verify_options_openstack() {
    OPENSTACK_VOLUME_ROOT="$VM_ROOT"
    OPENSTACK_VOLUME_SWAP="$VM_SWAP"
    VM_ROOT_TYPE=unattached
    VM_SWAP_TYPE=unattached

    # Checking for required tools (nova and cinder)
    NOVACLIENT=`type -p nova`
    if test -z "$NOVACLIENT" ; then
        cleanup_and_exit 3 "ERROR: nova not installed. Please install nova and try again"
    fi

    CINDERCLIENT=`type -p cinder`
    if test -z "$CINDERCLIENT" ; then
        cleanup_and_exit 3 "ERROR: nova not installed. Please install cinder and try again"
    fi

    if test -n "$KILL" -o -n "$DO_WIPE" ; then
        return
    fi

    # verify options
    if test -z "$OS_AUTH_URL" ; then
	cleanup_and_exit 3 "ERROR: No openstack environment set. This vm-type works only inside of an openstack VM."
    fi
    if test -z "$VM_KERNEL" ; then
	cleanup_and_exit 3 "ERROR: No worker boot VM volume name specified."
    fi
    if test -z "$VM_ROOT" ; then
	cleanup_and_exit 3 "ERROR: No worker root VM volume name specified."
    fi
    if test -z "$VM_SWAP" ; then
	cleanup_and_exit 3 "ERROR: No worker swap VM volume name specified."
    fi
    if test -z "$VM_SERVER" ; then
	cleanup_and_exit 3 "ERROR: No VM server node name specified (usually this instance)."
    fi
    if test -z "$VM_WORKER" ; then
	cleanup_and_exit 3 "ERROR: No VM worker node name specified (the instance to be created)."
    fi

    if test -z "$VM_OPENSTACK_FLAVOR" ; then
	cleanup_and_exit 3 "ERROR: No VM openstack flavor set (--openstack-flavor <FLAVOR-NAME|FLAVOR-ID>)."
    fi

    # set default values
    VM_ROOTDEV="LABEL=obsrootfs"
    VM_SWAPDEV="LABEL=obsswapfs"

    # hack: mis-use kernel parameter
    OPENSTACK_VOLUME_GRUB="$VM_KERNEL"
    VM_KERNEL=
}

vm_attach_root_openstack() {
    test -n "$OPENSTACK_ROOT_ATTACH_INFO" && cleanup_and_exit 1 "root is already attached"
    local OPENSTACK_ATTACH_INFO
    cloud_volume_attach_openstack "$VM_SERVER" "$OPENSTACK_VOLUME_ROOT"
    OPENSTACK_ROOT_ATTACH_INFO=$OPENSTACK_ATTACH_INFO
    VM_ROOT=${OPENSTACK_ATTACH_INFO:74}
    VM_ROOT_TYPE=device
}

vm_attach_swap_openstack() {
    test -n "$OPENSTACK_SWAP_ATTACH_INFO" && cleanup_and_exit 1 "root is already attached"
    local OPENSTACK_ATTACH_INFO
    cloud_volume_attach_openstack "$VM_SERVER" "$OPENSTACK_VOLUME_SWAP"
    OPENSTACK_SWAP_ATTACH_INFO=$OPENSTACK_ATTACH_INFO
    VM_SWAP=${OPENSTACK_ATTACH_INFO:74}
    VM_SWAP_TYPE=device
}

vm_detach_root_openstack() {
    test -z "$OPENSTACK_ROOT_ATTACH_INFO" && cleanup_and_exit 1 "root is not attached"
    local OPENSTACK_ATTACH_INFO=$OPENSTACK_ROOT_ATTACH_INFO
    OPENSTACK_ROOT_ATTACH_INFO=
    cloud_volume_detach_openstack "$OPENSTACK_ATTACH_INFO" || cleanup_and_exit 3
    VM_ROOT=$OPENSTACK_VOLUME_ROOT
    VM_ROOT_TYPE=unattached
}

vm_detach_swap_openstack() {
    test -z "$OPENSTACK_SWAP_ATTACH_INFO" && cleanup_and_exit 1 "swap is not attached"
    local OPENSTACK_ATTACH_INFO=$OPENSTACK_SWAP_ATTACH_INFO
    OPENSTACK_SWAP_ATTACH_INFO=
    cloud_volume_detach_openstack "$OPENSTACK_ATTACH_INFO" || cleanup_and_exit 3
    VM_SWAP=$OPENSTACK_VOLUME_SWAP
    VM_SWAP_TYPE=unattached
}

vm_cleanup_openstack() {
    test -n "$OPENSTACK_ROOT_ATTACH_INFO" && vm_detach_root_openstack
    test -n "$OPENSTACK_SWAP_ATTACH_INFO" && vm_detach_swap_openstack
}

vm_fixup_openstack() {
    # No way to handle this via init= parameter here....
    rm -rf "$BUILD_ROOT/sbin/init"
    echo "#!/bin/sh"               >  "$BUILD_ROOT/sbin/init"
    echo 'echo "exec /.build/build \"$@\""' >> "$BUILD_ROOT/sbin/init"
    echo 'exec /.build/build "$@"' >> "$BUILD_ROOT/sbin/init"
    echo 'echo "Waiting for input"' >> "$BUILD_ROOT/sbin/init"
    echo 'read' >> "$BUILD_ROOT/sbin/init"
    chmod 0755 "$BUILD_ROOT/sbin/init"
}

vm_sysrq_openstack() {
    :
}

vm_wipe_openstack() {
    if test -n "$VM_WORKER" ; then
         $NOVACLIENT delete $VM_WORKER
    fi
}

vm_kill_openstack() {
    if $NOVACLIENT show "$VM_WORKER" >/dev/null 2>&1 ; then
	if ! $NOVACLIENT delete "$VM_WORKER" ; then
            cleanup_and_exit 1 "could not kill openstack vm build $VM_WORKER"
	fi
    fi
}

openstack_wait_for_delete_instance() {
    while test -n "$($NOVACLIENT list|grep $VM_WORKER)" ; do
         sleep 1
    done
}

vm_startup_openstack() {
    local VM_VOL_ROOT_ID=`openstack_cinder_volume2id ${VM_ROOT}`    
    local VM_VOL_SWAP_ID=`openstack_cinder_volume2id ${VM_SWAP}`
    local VM_VOL_BOOT_ID=`openstack_cinder_volume2id ${OPENSTACK_VOLUME_GRUB}`

    local OUTPUT=`\
      $NOVACLIENT boot \
	--flavor $VM_OPENSTACK_FLAVOR \
	--block-device source=volume,dest=volume,bootindex=0,id=${VM_VOL_BOOT_ID}\
	--block-device source=volume,dest=volume,bootindex=1,id=${VM_VOL_ROOT_ID}\
	--block-device source=volume,dest=volume,bootindex=2,id=${VM_VOL_SWAP_ID}\
	--poll "$VM_WORKER" || cleanup_and_exit 3\
    `
    OPENSTACK_BUILD_ID=`openstack_get_field "$OUTPUT" id`

    for try in 1 2 3 4 5 ; do
        WS_URL=`$NOVACLIENT get-serial-console $VM_WORKER|grep serial |perl -p -e 's#.*(ws://.*) \|#$1#'`
	test -n "$WS_URL" && break
        sleep 1
    done

    if ! python $BUILD_DIR/openstack-console "${WS_URL}" ; then
        $NOVACLIENT delete $OPENSTACK_BUILD_ID
        cleanup_and_exit 3
    else
        $NOVACLIENT delete $OPENSTACK_BUILD_ID
        openstack_wait_for_delete_instance
    fi
}