#!/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 )." 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 }