diff options
Diffstat (limited to 'build-vm-openstack')
-rw-r--r-- | build-vm-openstack | 282 |
1 files changed, 282 insertions, 0 deletions
diff --git a/build-vm-openstack b/build-vm-openstack new file mode 100644 index 0000000..4bdb92f --- /dev/null +++ b/build-vm-openstack @@ -0,0 +1,282 @@ +#!/bin/bash +# +# 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.... + 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 ! $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 +} + |