#!/bin/bash # $HeadURL$ $LastChangedRevision$ # Properties MY_ID=system_hardware_vm_virsh_storage_iscsi PARENT_ID=system_hardware_vm_virsh_storage # Defaults for the questions we ask (should only used here) # Hooks # Support functions # Globals STORAGESERVER_HOSTNAME=macaroni STORAGESERVER_VOLUME_GROUP=vg0 DISK_NAME=os DOMAIN_REGISTRATION_DATE="1 May 2010" IOMODE=blockio loading main old_main() { local TARGET_HOSTNAME TARGET_ROOT_DISK_SIZE VMSERVER_HOSTNAME IGNORE_STATE_FILE_FLAG LIST_FILTER LIST_FORMAT MAILTO local LVCREATE_OUTPUT VIRSH_OUTPUT IETADM_OUTPUT NEXT_FREE_TID IETADM_CMDLINE TID IQN LV_NAME LV_PATH IETCONF_RECORD TARGET_ROOT_DISK_SIZE # Defaults for options VERBOSELEVEL=2 IGNORE_STATE_FILE_FLAG=false LIST_FORMAT=human LIST_FILTER=inprogress # Process options while [ "X$1" != X ]; do case $1 in # Application specific options --vmserver-hostname=*) VMSERVER_HOSTNAME=${1#*=} ;; --target-hostname=*) TARGET_HOSTNAME=${1#*=} ;; --target-root-disk-size=*) TARGET_ROOT_DISK_SIZE=${1#*=} ;; --ignore-state-file-flag=*) IGNORE_STATE_FILE_FLAG=${1#*=} ;; --list-format=*) LIST_FORMAT=${1#*=} ;; --list-filter=*) LIST_FILTER=${1#*=} ;; --mailto=*) MAILTO=${1#*=} ;; # General options --help|-h) usage 0 ;; --verbose|-v) VERBOSELEVEL=3 ;; -d) VERBOSELEVEL=$2; shift ;; --debug=*) VERBOSELEVEL=${1#*=} ;; --) shift; break ;; -*) usage ;; *) break ;; esac shift done # Process arguments [ $# -ge 1 ] || usage MODE=$1; shift debug 10 "main: MODE=$MODE" # Sanity checks and derivations [ $MODE = get-rootfs-volname ] || validate_vars MODE || return $? # Guts case $MODE in create) create --vmserver-hostname=$VMSERVER_HOSTNAME --target-hostname=$TARGET_HOSTNAME --target-root-disk-size=$TARGET_ROOT_DISK_SIZE --mailto=$MAILTO "$@" || return $? ;; delete) delete --target-hostname=$TARGET_HOSTNAME --ignore-state-file-flag=$IGNORE_STATE_FILE_FLAG "$@" || return $? ;; list) list --list-format=$LIST_FORMAT --list-filter=$LIST_FILTER "$@" ;; list-finished) list_finished "$@" || return $? ;; purge) purge "$@" || return $? ;; get-rootfs-volname) get_rootfs_volname --vmserver-hostname=$VMSERVER_HOSTNAME --target-hostname=$TARGET_HOSTNAME --target-root-disk-size=$TARGET_ROOT_DISK_SIZE "$@" || return $? ;; *) usage ;; esac return 0 } loading create old_create() { local TARGET_HOSTNAME TARGET_ROOT_DISK_SIZE VMSERVER_HOSTNAME MAILTO # Process options while [ "X$1" != X ]; do case $1 in # Application specific options --vmserver-hostname=*) VMSERVER_HOSTNAME=${1#*=} ;; --target-hostname=*) TARGET_HOSTNAME=${1#*=} ;; --target-root-disk-size=*) TARGET_ROOT_DISK_SIZE=${1#*=} ;; --mailto=*) MAILTO=${1#*=} ;; # General options --) shift; break ;; -*) internal "create: $1: invalid option" ;; *) break ;; esac shift done # Process arguments [ $# = 0 ] || internal "create: $#: wrong arg count" # Sanity checks and derivations validate_vars TARGET_HOSTNAME VMSERVER_HOSTNAME TARGET_ROOT_DISK_SIZE MAILTO debug 10 "create: TARGET_HOSTNAME=$TARGET_HOSTNAME, VMSERVER_HOSTNAME=$VMSERVER_HOSTNAME, TARGET_ROOT_DISK_SIZE=$TARGET_ROOT_DISK_SIZE, MAILTO=$MAILTO" IQN="iqn.$(date -d "$DOMAIN_REGISTRATION_DATE" +%Y-%m).$(echo ${STORAGESERVER_HOSTNAME%%.*}.$DNS_DOMAIN | sed 's/\./\n/g' | tac | paste -d. -s):storage.disk.$TARGET_HOSTNAME.$DISK_NAME" STORAGESERVER_IPADDR=$(host2ip $STORAGESERVER_HOSTNAME) || return $? ROOTFS_VOLNAME=/dev/disk/by-path/ip-$STORAGESERVER_IPADDR:3260-iscsi-$IQN-lun-0 LV_NAME=$TARGET_HOSTNAME LV_PATH=/dev/$STORAGESERVER_VOLUME_GROUP/$LV_NAME IETCONF_RECORD="Target $IQN\\n\\tLun 0 Path=$LV_PATH,Type=$IOMODE\\n" # Guts # Manage state file mkdir -p $VAR_DIR/$PROGNAME [ ! -f $VAR_DIR/$PROGNAME/$TARGET_HOSTNAME ] || { error "$TARGET_HOSTNAME: installation in progress"; return 1; } touch $VAR_DIR/$PROGNAME/$TARGET_HOSTNAME # Create volume info "creating storage volume ..." check_ssh_access $STORAGESERVER_HOSTNAME || return $? LVCREATE_OUTPUT=$(ssh -n $STORAGESERVER_HOSTNAME lvcreate --size ${TARGET_ROOT_DISK_SIZE}G --name $LV_NAME $STORAGESERVER_VOLUME_GROUP 2>&1) || { error "lvcreate: failed (output was: $LVCREATE_OUTPUT)"; return 1; } # Set some iSCSI vars NEXT_FREE_TID=$({ ssh -n $STORAGESERVER_HOSTNAME cat /proc/net/iet/volume | sed -n 's/tid:\([^ ]*\).*/\1/p'; echo 0; } | sort -un | tail -1 | xargs expr 1 +) debug 10 "create: NEXT_FREE_TID=$NEXT_FREE_TID, LV_PATH=$LV_PATH, IOMODE=$IOMODE, IETCONF_RECORD=[$IETCONF_RECORD]" # Configure later sharing via iSCSI info "sharing storage volume via iSCSI ..." debug 10 "create: adding an entry to the config file to share the volume via iSCSI ..." echo -en "$IETCONF_RECORD" | ssh $STORAGESERVER_HOSTNAME "cat >> /etc/ietd.conf" # Share it right now via iSCSI debug 10 "create: running commands to share the volume via iSCSI right now ..." # ietadm doesn't seem to provide good return codes so we must inspect output IETADM_OUTPUT=$(ssh -n $STORAGESERVER_HOSTNAME ietadm --op new --tid=$NEXT_FREE_TID --params Name=$IQN 2>&1) [ "X$IETADM_OUTPUT" = X ] || { error "ietadm: failed (output was: $IETADM_OUTPUT)"; return 1; } IETADM_OUTPUT=$(ssh -n $STORAGESERVER_HOSTNAME ietadm --op new --tid=$NEXT_FREE_TID --lun=0 --params Type=$IOMODE,Path=$LV_PATH 2>&1) [ "X$IETADM_OUTPUT" = X ] || { error "ietadm: failed (output was: $IETADM_OUTPUT)"; return 1; } # Define storage pool debug 10 "create: writing a config file for the storage pool ..." echo -e "\n$TARGET_HOSTNAME\n\n\n\n\n\n/dev/disk/by-path\n\n" | ssh $VMSERVER_HOSTNAME "cat > /tmp/$TARGET_HOSTNAME.xml" VIRSH_OUTPUT=$(ssh -n $VMSERVER_HOSTNAME virsh pool-define /tmp/$TARGET_HOSTNAME.xml 2>&1) debug 10 "create: loading the config file for the storage pool ..." [ "X$VIRSH_OUTPUT" = "XPool $TARGET_HOSTNAME defined from /tmp/$TARGET_HOSTNAME.xml" ] || { error "virsh: failed (1) (output was: $VIRSH_OUTPUT)"; return 1; } # Autostart the pool debug 10 "create: marking the storage pool for autostart ..." VIRSH_OUTPUT=$(ssh -n $VMSERVER_HOSTNAME virsh pool-autostart $TARGET_HOSTNAME 2>&1) [ "X$VIRSH_OUTPUT" = "XPool $TARGET_HOSTNAME marked as autostarted" ] || { error "virsh: failed (2) (output was: $VIRSH_OUTPUT)"; return 1; } # Activate the pool debug 10 "create: activating the storage pool ..." VIRSH_OUTPUT=$(ssh -n $VMSERVER_HOSTNAME virsh pool-start $TARGET_HOSTNAME 2>&1) [ "X$VIRSH_OUTPUT" = "XPool $TARGET_HOSTNAME started" ] || { error "virsh: failed (3) (output was: $VIRSH_OUTPUT)"; return 1; } # Refresh the pool (necessary for iSCSI) debug 10 "create: refreshing the storage pool ..." VIRSH_OUTPUT=$(ssh -n $VMSERVER_HOSTNAME virsh pool-refresh $TARGET_HOSTNAME 2>&1) [ "X$VIRSH_OUTPUT" = "XPool $TARGET_HOSTNAME refreshed" ] || { error "virsh: failed (4) (output was: $VIRSH_OUTPUT)"; return 1; } return 0 } loading delete old_delete() { local TARGET_HOSTNAME IGNORE_STATE_FILE_FLAG local LVCREATE_OUTPUT VIRSH_OUTPUT IETADM_OUTPUT NEXT_FREE_TID IETADM_CMDLINE TID IQN LV_NAME LV_PATH IETCONF_RECORD TARGET_ROOT_DISK_SIZE VMSERVER_HOSTNAME # Defaults for options IGNORE_STATE_FILE_FLAG=false # Process options while [ "X$1" != X ]; do case $1 in # Application specific options --target-hostname=*) TARGET_HOSTNAME=${1#*=} ;; --ignore-state-file-flag=*) IGNORE_STATE_FILE_FLAG=${1#*=} ;; # General options --) shift; break ;; -*) internal "delete: $1: invalid option" ;; *) break ;; esac shift done # Process arguments [ $# = 0 ] || internal "delete: $#: wrong arg count" # Sanity checks and derivations validate_vars TARGET_HOSTNAME IGNORE_STATE_FILE_FLAG debug 10 "delete: TARGET_HOSTNAME=$TARGET_HOSTNAME, IGNORE_STATE_FILE_FLAG=$IGNORE_STATE_FILE_FLAG" IQN="iqn.$(date -d "$DOMAIN_REGISTRATION_DATE" +%Y-%m).$(echo ${STORAGESERVER_HOSTNAME%%.*}.$DNS_DOMAIN | sed 's/\./\n/g' | tac | paste -d. -s):storage.disk.$TARGET_HOSTNAME.$DISK_NAME" STORAGESERVER_IPADDR=$(host2ip $STORAGESERVER_HOSTNAME) || return $? ROOTFS_VOLNAME=/dev/disk/by-path/ip-$STORAGESERVER_IPADDR:3260-iscsi-$IQN-lun-0 LV_NAME=$TARGET_HOSTNAME LV_PATH=/dev/$STORAGESERVER_VOLUME_GROUP/$LV_NAME IETCONF_RECORD="Target $IQN\\n\\tLun 0 Path=$LV_PATH,Type=$IOMODE\\n" # Guts # Manage state file mkdir -p $VAR_DIR/$PROGNAME $IGNORE_STATE_FILE_FLAG || [ -f $VAR_DIR/$PROGNAME/$TARGET_HOSTNAME ] || { warning "$TARGET_HOSTNAME: installation not in progress using this plugin"; return 0; } # Only delete the storage if not running from the releaser if [ "X$RELEASER_FLAG" != Xtrue ]; then for VMSERVER_HOSTNAME in $KNOWN_VMSERVER_HOSTNAMES; do # Stop pool (only if delete is not at request of releaser) ssh -n $VMSERVER_HOSTNAME "virsh pool-destroy $TARGET_HOSTNAME > /dev/null 2>&1 || true" # Undefine pool everywhere (vol-editor could do this, but since we did the define, we do ssh -n $VMSERVER_HOSTNAME "virsh pool-undefine $TARGET_HOSTNAME > /dev/null 2>&1 || true" done # Delete iSCSI share (if it exists) info "unsharing storage volume via iSCSI ..." TID=$(ssh -n $STORAGESERVER_HOSTNAME "cat /proc/net/iet/volume" | sed -n "s/tid:\(.*\) name:$IQN/\1/p") debug 10 "delete: TID=$TID, LV_PATH=$LV_PATH, IOMODE=$IOMODE, IETCONF_RECORD=[$IETCONF_RECORD]" if [ "X$TID" != X ]; then # Unshare it right now via iSCSI debug 10 "delete: unsharing right now via iSCSI ..." IETADM_CMDLINE="ietadm --op delete --tid=$TID" debug 10 "delete: IETADM_CMDLINE=[$IETADM_CMDLINE]" ssh -n $STORAGESERVER_HOSTNAME "$IETADM_CMDLINE || true" # Unconfigure later sharing via iSCSI debug 10 "delete: unconfiguring later sharing via iSCSI ..." # Too much stuff to escape, do it locally. scp -q $STORAGESERVER_HOSTNAME:/etc/ietd.conf /tmp perl -0777 -pi -e "s@^$IETCONF_RECORD@@ms" /tmp/ietd.conf scp -q /tmp/ietd.conf $STORAGESERVER_HOSTNAME:/etc fi # Delete volume info "deleting storage volume ..." ssh -n $STORAGESERVER_HOSTNAME "lvremove -f /dev/$STORAGESERVER_VOLUME_GROUP/$LV_NAME || true" fi # Manage state file rm -f $VAR_DIR/$PROGNAME/$TARGET_HOSTNAME return 0 } loading list old_list() { local TARGET_HOSTNAME LIST_FORMAT LIST_FILTER local CMDLINE # Defaults for options LIST_FORMAT=human LIST_FILTER=inprogress # Process options while [ "X$1" != X ]; do case $1 in # Application specific options --list-format=*) LIST_FORMAT=${1#*=} ;; --list-filter=*) LIST_FILTER=${1#*=} ;; # General options --) shift; break ;; -*) internal "list: $1: invalid option" ;; *) break ;; esac shift done # Process arguments [ $# = 0 ] || internal "list: $#: wrong arg count" # Sanity checks and derivations validate_vars LIST_FORMAT LIST_FILTER || return $? # Guts # Manage state file mkdir -p $VAR_DIR/$PROGNAME # Do the listing if [ $LIST_FORMAT = terse -a $LIST_FILTER = inprogress ]; then TARGET_HOSTNAMES=$(ls -1 $VAR_DIR/$PROGNAME) for TARGET_HOSTNAME in $TARGET_HOSTNAMES; do echo $TARGET_HOSTNAME done elif [ $LIST_FORMAT = human -a $LIST_FILTER = inprogress ]; then TARGET_HOSTNAMES=$(ls -1 $VAR_DIR/$PROGNAME) for TARGET_HOSTNAME in $TARGET_HOSTNAMES; do { ssh -n $STORAGESERVER_HOSTNAME "lvs $STORAGESERVER_VOLUME_GROUP" for VMSERVER_HOSTNAME in $KNOWN_VMSERVER_HOSTNAMES; do ssh -n $VMSERVER_HOSTNAME "virsh pool-list --all" done } | grep $TARGET_HOSTNAME || echo "flag file present, resources not" done elif [ $LIST_FORMAT = terse -a $LIST_FILTER = completed ]; then TARGET_HOSTNAMES=$({ ssh -n $STORAGESERVER_HOSTNAME lvs $STORAGESERVER_VOLUME_GROUP | sed -e '1d' | awk '{ print $1 }'; for VMSERVER_HOSTNAME in $KNOWN_VMSERVER_HOSTNAMES; do ssh -n $VMSERVER_HOSTNAME "virsh pool-list --all" | sed -e '1,2d' -e '$d' | awk '{ print $1 }'; done; } | sort -u | while read TARGET_HOSTNAME; do [ -f $VAR_DIR/$PROGNAME/$TARGET_HOSTNAME ] || echo $TARGET_HOSTNAME; done) for TARGET_HOSTNAME in $TARGET_HOSTNAMES; do echo $TARGET_HOSTNAME done elif [ $LIST_FORMAT = human -a $LIST_FILTER = completed ]; then TARGET_HOSTNAMES=$({ ssh -n $STORAGESERVER_HOSTNAME lvs $STORAGESERVER_VOLUME_GROUP | sed -e '1d' | awk '{ print $1 }'; for VMSERVER_HOSTNAME in $KNOWN_VMSERVER_HOSTNAMES; do ssh -n $VMSERVER_HOSTNAME "virsh pool-list --all" | sed -e '1,2d' -e '$d' | awk '{ print $1 }'; done; } | sort -u | while read TARGET_HOSTNAME; do [ -f $VAR_DIR/$PROGNAME/$TARGET_HOSTNAME ] || echo $TARGET_HOSTNAME; done) for TARGET_HOSTNAME in $TARGET_HOSTNAMES; do { ssh -n $STORAGESERVER_HOSTNAME "lvs $STORAGESERVER_VOLUME_GROUP" for VMSERVER_HOSTNAME in $KNOWN_VMSERVER_HOSTNAMES; do ssh -n $VMSERVER_HOSTNAME "virsh pool-list --all" done } | grep $TARGET_HOSTNAME || echo "flag file present, resources not" done fi return 0 } loading purge old_purge() { rm -f $VAR_DIR/$PROGNAME/* } loading get_rootfs_volname old_get_rootfs_volname() { local TARGET_HOSTNAME TARGET_ROOT_DISK_SIZE VMSERVER_HOSTNAME # Process options while [ "X$1" != X ]; do case $1 in # Application specific options --vmserver-hostname=*) VMSERVER_HOSTNAME=${1#*=} ;; --target-hostname=*) TARGET_HOSTNAME=${1#*=} ;; --target-root-disk-size=*) TARGET_ROOT_DISK_SIZE=${1#*=} ;; # General options --) shift; break ;; -*) internal "get_rootfs_volname: $1: invalid option" ;; *) break ;; esac shift done # Process arguments [ $# = 0 ] || internal "get_rootfs_volname: $#: wrong arg count" # Sanity checks and derivations validate_vars TARGET_HOSTNAME VMSERVER_HOSTNAME TARGET_ROOT_DISK_SIZE || return $? debug 10 "get_rootfs_volname: TARGET_HOSTNAME=$TARGET_HOSTNAME, VMSERVER_HOSTNAME=$VMSERVER_HOSTNAME, TARGET_ROOT_DISK_SIZE=$TARGET_ROOT_DISK_SIZE" IQN="iqn.$(date -d "$DOMAIN_REGISTRATION_DATE" +%Y-%m).$(echo ${STORAGESERVER_HOSTNAME%%.*}.$DNS_DOMAIN | sed 's/\./\n/g' | tac | paste -d. -s):storage.disk.$TARGET_HOSTNAME.$DISK_NAME" STORAGESERVER_IPADDR=$(host2ip $STORAGESERVER_HOSTNAME) || return $? ROOTFS_VOLNAME=/dev/disk/by-path/ip-$STORAGESERVER_IPADDR:3260-iscsi-$IQN-lun-0 # Guts debug 10 "get_rootfs_volname: ROOTFS_VOLNAME=$ROOTFS_VOLNAME" echo "path=$ROOTFS_VOLNAME" return 0 } loading usage old_usage() { local RC RC=${1:-1} { echo "Usage: $PROGNAME [ ] { create | delete | list | get-rootfs-volname }" } | if [ $RC = 0 ]; then cat else cat >&2 fi exit $RC }