#!/bin/bash # os-export-instance.sh, ABr, 20141010 # Export instance from one OpenStack to another # Provide usage function usage { echo "Usage: $0 [SRC_KEYSTONE_RC] [DST_KEYSTONE_RC] [VM_ID] [IMG_TYPE] [STEP]" echo " IMG_TYPE can be 'swift', 'rbd', or 'file'" echo " STEP should be 0 unless restarting a migration" return 0 } function do_exit { l_rc="$1" shift if [ $l_rc -ne 0 ]; then echo "Error: $*" | tee -a $l_log usage fi rm -f $l_tmp exit $l_rc } # work files l_tmp="/tmp/os-export-instance.$$" l_log="/tmp/os-export-instance.log" echo "$$: $(date +"%Y%d%m-%H%M"): Begin OS Export" | tee -a $l_log # check for usage [[ $# -ne 5 ]] && usage l_in_src_keystone_rc="$1" l_in_dst_keystone_rc="$2" l_in_vm_id="$3" l_in_img_type="$4" l_in_step="$5" # RC files must exist [ ! -f "$l_in_src_keystone_rc" ] && do_exit 1 "Source keystone RC does not exist" [ ! -f "$l_in_dst_keystone_rc" ] && do_exit 2 "Destination keystone RC does not exist" # get info l_rc=0 source "$l_in_src_keystone_rc" echo "$$: nova show \"$l_in_vm_id\" 2>/dev/null > $l_tmp" >> $l_log nova show "$l_in_vm_id" 2>/dev/null > $l_tmp l_rc=$? if [ $l_rc -ne 0 ]; then do_exit 3 "Invalid VM ID '$l_in_vm_id'" fi # get initial state of VM l_vm_id=$(cat $l_tmp | grep -e "^| id" | cut -d'|' -f 3 | sed -e 's#^ \+##; s#[ \t]*$##') l_vm_name=$(cat $l_tmp | grep -e "^| name" | cut -d'|' -f 3 | sed -e 's#^ \+##; s#[ \t]*$##') l_vm_tenant_id=$(cat $l_tmp | grep -e "^| tenant_id" | cut -d'|' -f 3 | sed -e 's#^ \+##; s#[ \t]*$##') l_vm_state=$(cat $l_tmp | grep -e "^| OS-EXT-STS:vm_state" | cut -d'|' -f 3 | sed -e 's#^ \+##; s#[ \t]*$##') l_vm_status=`cat "$l_tmp" | grep status | awk '{print $4}'` l_vm_tenant=$(keystone tenant-get $l_vm_tenant_id | grep -e ' name ' | cut -d'|' -f 3 | sed -e 's#^ \+##; s#[ \t]*$##') echo "$$: l_vm_id='$l_vm_id'" >> $l_log echo "$$: l_vm_name='$l_vm_name'" >> $l_log echo "$$: l_vm_tenant_id='$l_vm_tenant_id'" >> $l_log echo "$$: l_vm_state='$l_vm_state'" >> $l_log echo "$$: l_vm_status='$l_vm_status'" >> $l_log echo "$$: l_vm_tenant='$l_vm_tenant'" >> $l_log # determine what we can do l_state=0 case "$l_vm_status" in SHUTOFF) # we can migrate l_state=0 ;; *) # invalid state l_rc=4 ;; esac if [ $l_rc -ne 0 ]; then do_exit $l_rc "$l_vm_tenant:$l_vm_name ($l_vm_id); invalid status ($l_vm_status); cannot migrate" fi # start the run echo "$$: $(date +"%Y%d%m-%H%M"): Process '$l_vm_tenant:$l_vm_name' ($l_vm_id)..." | tee -a $l_log # tenant name on destination must be valid echo "$$: source \"$l_in_dst_keystone_rc\"" >> $l_log source "$l_in_dst_keystone_rc" echo -n "$$: $(date +"%Y%d%m-%H%M"): Verify tenant '$l_vm_tenant' on destination..." echo "$$: keystone tenant-list | grep \"$l_vm_tenant\" 2>&1" >> $l_log l_msg=$(keystone tenant-list | grep "$l_vm_tenant" 2>&1) l_rc=$? echo "$$: l_msg='$l_msg'" >> $l_log if [ $l_rc -eq 0 ]; then echo "OK"; else do_exit 5 "Create on destination"; fi # back into the source echo "$$: source \"$l_in_src_keystone_rc\"" >> $l_log source "$l_in_src_keystone_rc" # delete any existing snapshot l_snap_name="$l_vm_name-snap" l_snap_id="" l_continue=1 while [ $l_continue -eq 1 ]; do # check for an existing snapshot ID echo "$$: glance --os-tenant-name=\"$l_vm_tenant\" image-list | grep -e \"$l_snap_name\" | head -n 1 | cut -d'|' -f 2 | sed -e 's#^ \+##; s#[ \t]*$##'" >> $l_log l_snap_id=$(glance --os-tenant-name="$l_vm_tenant" image-list | grep -e "$l_snap_name" | head -n 1 | cut -d'|' -f 2 | sed -e 's#^ \+##; s#[ \t]*$##') if [[ "$l_snap_id" != "" ]]; then if [ "$l_in_step" -ge 1 ]; then echo "$$: $(date +"%Y%d%m-%H%M"): Step 0: Reuse old snapshot '$l_snap_id'" | tee -a $l_log l_continue=0 else echo -n "$$: $(date +"%Y%d%m-%H%M"): Step 0: Remove old snapshot '$l_snap_id'..." echo "$$: glance --os-tenant-name=\"$l_vm_tenant\" image-delete $l_snap_id 2>&1" >> $l_log l_msg=$(glance --os-tenant-name="$l_vm_tenant" image-delete $l_snap_id 2>&1) l_rc=$? echo "$$: l_msg='$l_msg'" >> $l_log if [ $l_rc -eq 0 ]; then echo "OK"; else do_exit 5 "Snapshot cleanup: $l_msg"; fi l_snap_id="" fi else l_continue=0 fi done # create snapshot unless already exists l_snap_container_format="" l_snap_disk_format="" if [ "$l_snap_id" = "" ]; then echo -n "$$: $(date +"%Y%d%m-%H%M"): Step 0: Create new snapshot..." echo "$$: nova --os-tenant-name=\"$l_vm_tenant\" image-create --poll $l_vm_id \"$l_snap_name\" 2>&1" >> $l_log l_msg=$(nova --os-tenant-name="$l_vm_tenant" image-create --poll $l_vm_id "$l_snap_name" 2>&1) l_rc=$? echo "$$: l_msg='$l_msg'" >> $l_log if [ $l_rc -ne 0 ]; then do_exit 5 "Snapshot creation: $l_msg"; fi # get the snapshot ID echo "$$: glance --os-tenant-name=\"$l_vm_tenant\" image-list | grep -e \"$l_snap_name\" | head -n 1 | cut -d'|' -f 2 | sed -e 's#^ \+##; s#[ \t]*$##'" >> $l_log l_snap_id=$(glance --os-tenant-name="$l_vm_tenant" image-list | grep -e "$l_snap_name" | head -n 1 | cut -d'|' -f 2 | sed -e 's#^ \+##; s#[ \t]*$##') l_rc=$? echo "$$: l_snap_id='$l_snap_id'" >> $l_log if [ $l_rc -eq 0 ]; then echo "OK ($l_snap_id)"; else do_exit 5 "Snapshot identification"; fi fi # get snapshot information echo -n "$$: $(date +"%Y%d%m-%H%M"): Step 1: Get snapshot info..." echo "$$: glance --os-tenant-name=\"$l_vm_tenant\" image-show $l_snap_id | grep -e 'container_format' | cut -d'|' -f 3 | sed -e 's#^ \+##; s#[ \t]*$##'" >> $l_log l_snap_container_format=$(glance --os-tenant-name="$l_vm_tenant" image-show $l_snap_id | grep -e 'container_format' | cut -d'|' -f 3 | sed -e 's#^ \+##; s#[ \t]*$##') echo "$$: glance --os-tenant-name=\"$l_vm_tenant\" image-show $l_snap_id | grep -e 'disk_format' | cut -d'|' -f 3 | sed -e 's#^ \+##; s#[ \t]*$##'" >> $l_log l_snap_disk_format=$(glance --os-tenant-name="$l_vm_tenant" image-show $l_snap_id | grep -e 'disk_format' | cut -d'|' -f 3 | sed -e 's#^ \+##; s#[ \t]*$##') echo "container_format=$l_snap_container_format, disk_format=$l_snap_disk_format" | tee -a $l_log # manage local file l_local_fname="$l_vm_name.$l_snap_disk_format" if [ -s "$l_local_fname" ]; then if [ "$l_in_step" -ge 2 ]; then echo "$$: $(date +"%Y%d%m-%H%M"): Step 1: Reuse local file '$l_local_fname'" | tee -a $l_log else echo -n "$$: $(date +"%Y%d%m-%H%M"): Step 1: Remove old local file '$l_local_fname'..." | tee -a $l_log rm -f "$l_local_fname" echo "OK" | tee -a $l_log fi else # remove just to be sure no zero file echo "$$: rm -f \"$l_local_fname\"" >> $l_log rm -f "$l_local_fname" fi # pull down if not exists if [ ! -f "$l_local_fname" ]; then echo -n "$$: $(date +"%Y%d%m-%H%M"): Step 1: Pull snapshot '$l_snap_id' to '$l_local_fname'..." echo "$$: glance --os-tenant-name=\"$l_vm_tenant\" image-download --file \"$l_local_fname\" $l_snap_id 2>&1" >> $l_log l_msg=$(glance --os-tenant-name="$l_vm_tenant" image-download --file "$l_local_fname" $l_snap_id 2>&1) l_rc=$? echo "$$: l_msg='$l_msg'" >> $l_log if [ $l_rc -eq 0 ]; then echo "OK"; else do_exit 5 "Snapshot pull: $l_msg"; fi fi # switch to destination echo "$$: source \"$l_in_dst_keystone_rc\"" >> $l_log source "$l_in_dst_keystone_rc" # check to see if the image is already uploaded to destination l_dst_image_name="$l_local_fname" l_dst_image_id="" l_continue=1 while [ $l_continue -eq 1 ]; do # check for an existing snapshot ID echo "$$: glance --os-tenant-name=\"$l_vm_tenant\" image-list | grep -e \"$l_dst_image_name\" | head -n 1 | cut -d'|' -f 2 | sed -e 's#^ \+##; s#[ \t]*$##'" >> $l_log l_dst_image_id=$(glance --os-tenant-name="$l_vm_tenant" image-list | grep -e "$l_dst_image_name" | head -n 1 | cut -d'|' -f 2 | sed -e 's#^ \+##; s#[ \t]*$##') if [[ "$l_dst_image_id" != "" ]]; then if [ "$l_in_step" -ge 3 ]; then echo "$$: $(date +"%Y%d%m-%H%M"): Step 2: Reuse old destination image '$l_dst_image_id'" | tee -a $l_log l_continue=0 else echo -n "$$: $(date +"%Y%d%m-%H%M"): Step 2: Remove old destination image '$l_dst_image_id'..." echo "$$: glance --os-tenant-name=\"$l_vm_tenant\" image-delete $l_dst_image_id 2>&1" >> $l_log l_msg=$(glance --os-tenant-name="$l_vm_tenant" image-delete $l_dst_image_id 2>&1) l_rc=$? if [ $l_rc -eq 0 ]; then echo "OK"; else do_exit 5 "Dst image cleanup: $l_msg"; fi echo "$$: l_msg='$l_msg'" >> $l_log l_dst_image_id="" fi else echo "$$: l_dst_image_id='$l_dst_image_id'" >> $l_log l_continue=0 fi done # upload the image to destination if necessary if [ "$l_dst_image_id" = "" ]; then echo -n "$$: $(date +"%Y%d%m-%H%M"): Step 2: Upload snapshot to destination..." echo "$$: glance --os-tenant-name=\"$l_vm_tenant\" image-create --store=$l_in_img_type --container-format=$l_snap_container_format --disk-format=$l_snap_disk_format --is-public=false --name=\"$l_dst_image_name\" < \"$l_local_fname\" 2>&1" >> $l_log l_msg=$(glance --os-tenant-name="$l_vm_tenant" image-create --store=$l_in_img_type --container-format=$l_snap_container_format --disk-format=$l_snap_disk_format --is-public=false --name="$l_dst_image_name" < "$l_local_fname" 2>&1) l_rc=$? echo "$$: l_msg='$l_msg'" >> $l_log if [ $l_rc -ne 0 ]; then do_exit 5 "Snapshot upload: $l_msg"; fi # get the uploaded image ID echo "$$: glance --os-tenant-name=\"$l_vm_tenant\" image-list | grep -e \"$l_local_fname\" | head -n 1 | cut -d'|' -f 2 | sed -e 's#^ \+##; s#[ \t]*$##'" >> $l_log l_dst_image_id=$(glance --os-tenant-name="$l_vm_tenant" image-list | grep -e "$l_local_fname" | head -n 1 | cut -d'|' -f 2 | sed -e 's#^ \+##; s#[ \t]*$##') l_rc=$? if [ $l_rc -eq 0 ]; then echo "OK ($l_dst_image_id)"; else do_exit 5 "Snapshot upload identification"; fi echo "$$: l_dst_image_id='$l_dst_image_id'" >> $l_log fi # it is not possible to create a VM which is initially stopped. we are done. echo "$$: $(date +"%Y%d%m-%H%M"): Process complete. In tenant '$l_vm_tenant' on destination, launch VM from image '$l_dst_image_name'" | tee -a $l_log do_exit 0