#!/bin/bash #migrate VM root and/or non-root gpfs to rbd-ec (ceph) #tested on OS 'Train' release, use with extreme care (DB dump + Volume backups) #https://bugs.launchpad.net/nova/+bug/1396965 #2020, High Performance Computing Center, University of Tartu, https://hpc.ut.ee vm_uuid="${1}" new_backend=rbd-ec migrate_root() { echo "Prepare root volume for migration" dev="$(openstack volume show -c attachments -f value ${root_disk_uuid} | grep -P -m 1 -o "/dev/[s]?[v]?da")" cinder reset-state --state available ${root_disk_uuid} mysql -e "delete from cinder.volume_attachment where volume_id=\"${root_disk_uuid}\" limit 1;" mysql nova -e "delete from block_device_mapping where not deleted and volume_id=\"${root_disk_uuid}\";" echo "Migrate root volume ${dev}, ${root_disk_uuid}" cinder retype --migration-policy on-demand ${root_disk_uuid} ${new_backend} while [ "$(openstack volume show -c migration_status -f value ${root_disk_uuid})" != "success" ] ;do sleep 5; echo -n "."; done nova volume-attach ${vm_uuid} ${root_disk_uuid} >/dev/null;sleep 15 mysql nova -e "update block_device_mapping SET device_name=\"${dev}\" where volume_id=\"${root_disk_uuid}\";" mysql nova -e "update block_device_mapping set boot_index=\"0\" where volume_id=\"${root_disk_uuid}\";" mysql cinder -e "update volume_attachment set mountpoint=\"${dev}\" where volume_id=\"${root_disk_uuid}\";" src="$(mysql cinder -sNe "select id from volumes where display_description=\"migration src for ${root_disk_uuid}\";")" mysql cinder -e "UPDATE volume_attachment SET connector = JSON_SET(connector, '$.mountpoint', \"${dev}\") WHERE volume_id=\"${root_disk_uuid}\";" echo -e "\nManually delete leftover migration source (unknown OS bug)." cinder reset-state --state error "${src}" cinder reset-state --reset-migration-status "${src}" mysql cinder -sNe "update volumes set attach_status='detached' where id=\"${src}\";" cinder delete "${src}" } echo -e "Detect if any migration is needed at all." vol_list=$(openstack server show -c volumes_attached -f value ${vm_uuid} | awk -F "'" '{print $2}') if [ -z "$(for i in ${vol_list} ;do echo -n "$(openstack volume show ${i} -c type -f value | grep -v "${new_backend}" )" ;done)" ];then echo "No illplaced volume detected"; exit 0; fi echo "VM stop" nova stop ${vm_uuid}; while [ "$(openstack server show ${vm_uuid} -c 'OS-EXT-STS:power_state' -f value)" != "Shutdown" ];do sleep 1;echo -n "."; done echo -e "\nDetach all non-root disks before migration." for i in ${vol_list} ;do nova volume-detach "${vm_uuid}" "${i}" 2>&1 | grep root >/dev/null && root_disk_uuid=${i};done echo "Detect if root disk migration is needed." if [ -n "${root_disk_uuid}" ] && [ "$(openstack volume show ${root_disk_uuid} -c type -f value)" != "${new_backend}" ];then migrate_root fi echo "Migrate all non-root volumes." for i in ${vol_list} ;do if [ "${i}" != "${root_disk_uuid}" ] && [ "$(openstack volume show ${i} -c type -f value)" != "${new_backend}" ];then cinder retype --migration-policy on-demand ${i} "${new_backend}" while [ "$(openstack volume show -c migration_status -f value ${i})" != "success" ] ;do sleep 5;echo -n ".";done fi done echo -e "\nRe-generate new libvirt configurtation." nova reboot --hard ${vm_uuid} echo "Attach all non-root volumes." while [ "$(openstack server show ${vm_uuid} -c 'OS-EXT-STS:power_state' -f value)" != "Running" ];do sleep 1;echo -n "."; done for i in ${vol_list} ;do test "${i}" != "${root_disk_uuid}" && nova volume-attach "${vm_uuid}" "${i}" >/dev/null done echo "Reboot VM" nova reboot ${vm_uuid}