| package com.mirantis.mk |
| |
| /** |
| * |
| * Virsh functions |
| * |
| */ |
| |
| /** |
| * Ensures that the live snapshot exists |
| * |
| * @param nodeProvider KVM node that hosts the VM |
| * @param target Unique identification of the VM being snapshoted without domain (for ex. ctl01) |
| * @param snapshotName Snapshot name |
| * @param path Path where snapshot image and dumpxml are being put |
| * @param diskName Disk name of the snapshot |
| */ |
| def liveSnapshotPresent(master, nodeProvider, target, snapshotName, path='/var/lib/libvirt/images', diskName='vda') { |
| def salt = new com.mirantis.mk.Salt() |
| def common = new com.mirantis.mk.Common() |
| def snapshotPresent = "" |
| def domain = salt.getDomainName(master) |
| try { |
| snapshotPresent = salt.getReturnValues(salt.cmdRun(master, "${nodeProvider}*", "virsh snapshot-list ${target}.${domain} | grep ${snapshotName}")).split("\n")[0] |
| } catch (Exception er) { |
| common.infoMsg('snapshot not present') |
| } |
| if (!snapshotPresent.contains(snapshotName)) { |
| def dumpxmlPresent = '' |
| try { |
| dumpxmlPresent = salt.getReturnValues(salt.cmdRun(master, "${nodeProvider}*", "ls -la ${path}/${target}.${domain}.xml")).split("\n")[0] |
| } catch (Exception er) { |
| common.infoMsg('dumpxml file not present') |
| } |
| if (!dumpxmlPresent?.trim()) { |
| salt.cmdRun(master, "${nodeProvider}*", "virsh dumpxml ${target}.${domain} > ${path}/${target}.${domain}.xml") |
| } |
| salt.cmdRun(master, "${nodeProvider}*", "virsh snapshot-create-as --domain ${target}.${domain} ${snapshotName} --diskspec ${diskName},file=${path}/${target}.${domain}.${snapshotName}.qcow2 --disk-only --atomic") |
| } |
| } |
| |
| /** |
| * Ensures that the live snapshot does not exist |
| * |
| * @param nodeProvider KVM node that hosts the VM |
| * @param target Unique identification of the VM being snapshoted without domain (for ex. ctl01) |
| * @param snapshotName Snapshot name |
| * @param path Path where snapshot image and dumpxml are being put |
| */ |
| def liveSnapshotAbsent(master, nodeProvider, target, snapshotName, path='/var/lib/libvirt/images') { |
| def salt = new com.mirantis.mk.Salt() |
| def common = new com.mirantis.mk.Common() |
| def domain = salt.getDomainName(master) |
| try { |
| salt.cmdRun(master, "${nodeProvider}*", "virsh snapshot-delete ${target}.${domain} --metadata ${snapshotName}") |
| } catch (Exception e) { |
| common.warningMsg("Snapshot ${snapshotName} for ${target}.${domain} does not exist or failed to be removed") |
| } |
| try { |
| salt.runSaltProcessStep(master, "${nodeProvider}*", 'file.remove', ["${path}/${target}.${domain}.${snapshotName}.qcow2"], null, true) |
| } catch (Exception e) { |
| common.warningMsg("Snapshot ${snapshotName} qcow2 file for ${target}.${domain} does not exist or failed to be removed") |
| } |
| try { |
| salt.runSaltProcessStep(master, "${nodeProvider}*", 'file.remove', ["${path}/${target}.${domain}.xml"], null, true) |
| } catch (Exception e) { |
| common.warningMsg("Dumpxml file for ${target}.${domain} does not exist or failed to be removed") |
| } |
| } |
| |
| /** |
| * Rollback |
| * |
| * @param nodeProvider KVM node that hosts the VM |
| * @param target Unique identification of the VM being snapshoted without domain (for ex. ctl01) |
| * @param snapshotName Snapshot name |
| * @param path Path where snapshot image and dumpxml are being put |
| */ |
| def liveSnapshotRollback(master, nodeProvider, target, snapshotName, path='/var/lib/libvirt/images') { |
| def salt = new com.mirantis.mk.Salt() |
| def common = new com.mirantis.mk.Common() |
| def domain = salt.getDomainName(master) |
| try { |
| salt.getReturnValues(salt.cmdRun(master, "${nodeProvider}*", "ls -la ${path}/${target}.${domain}.xml")) |
| salt.runSaltProcessStep(master, "${nodeProvider}*", 'virt.destroy', ["${target}.${domain}"], null, true) |
| salt.cmdRun(master, "${nodeProvider}*", "virsh define ${path}/${target}.${domain}.xml") |
| liveSnapshotAbsent(master, nodeProvider, target, snapshotName, path) |
| salt.runSaltProcessStep(master, "${nodeProvider}*", 'virt.start', ["${target}.${domain}"], null, true) |
| } catch (Exception er) { |
| common.infoMsg("No rollback for ${target}.${domain} was executed. Dumpxml file not present.") |
| } |
| } |
| |
| /** |
| * Merge snapshot while instance is running |
| * |
| * @param nodeProvider KVM node that hosts the VM |
| * @param target Unique identification of the VM being snapshoted without domain (for ex. ctl01) |
| * @param snapshotName Snapshot name |
| * @param path Path where snapshot image and dumpxml are being put |
| * @param diskName Disk name of the snapshot |
| */ |
| def liveSnapshotMerge(master, nodeProvider, target, snapshotName, path='/var/lib/libvirt/images', diskName='vda') { |
| def salt = new com.mirantis.mk.Salt() |
| def common = new com.mirantis.mk.Common() |
| def domain = salt.getDomainName(master) |
| try { |
| salt.cmdRun(master, "${nodeProvider}*", "virsh blockcommit ${target}.${domain} ${diskName} --active --verbose --pivot") |
| try { |
| salt.cmdRun(master, "${nodeProvider}*", "virsh snapshot-delete ${target}.${domain} --metadata ${snapshotName}") |
| } catch (Exception e) { |
| common.warningMsg("Snapshot ${snapshotName} for ${target}.${domain} does not exist or failed to be removed") |
| } |
| try { |
| salt.runSaltProcessStep(master, "${nodeProvider}*", 'file.remove', ["${path}/${target}.${domain}.${snapshotName}.qcow2"], null, true) |
| } catch (Exception e) { |
| common.warningMsg("Snapshot ${snapshotName} qcow2 file for ${target}.${domain} does not exist or failed to be removed") |
| } |
| try { |
| salt.runSaltProcessStep(master, "${nodeProvider}*", 'file.remove', ["${path}/${target}.${domain}.xml"], null, true) |
| } catch (Exception e) { |
| common.warningMsg("Dumpxml file for ${target}.${domain} does not exist or failed to be removed") |
| } |
| } catch (Exception e) { |
| common.errorMsg("The live snapshoted VM ${target}.${domain} failed to be merged, trying to fix it") |
| checkLiveSnapshotMerge(master, nodeProvider, target, snapshotName, path, diskName) |
| } |
| } |
| |
| |
| /** |
| * Check live snapshot merge failure due to known qemu issue not receiving message about merge completion |
| * |
| * @param nodeProvider KVM node that hosts the VM |
| * @param target Unique identification of the VM being snapshoted without domain (for ex. ctl01) |
| * @param snapshotName Snapshot name |
| * @param path Path where snapshot image and dumpxml are being put |
| * @param diskName Disk name of the snapshot |
| */ |
| def checkLiveSnapshotMerge(master, nodeProvider, target, snapshotName, path='/var/lib/libvirt/images', diskName='vda') { |
| def salt = new com.mirantis.mk.Salt() |
| def domain = salt.getDomainName(master) |
| def out = salt.getReturnValues(salt.cmdRun(master, "${nodeProvider}*", "virsh blockjob ${target}.${domain} ${diskName} --info")) |
| if (out.contains('Block Commit')) { |
| def blockJobs = salt.getReturnValues(salt.cmdRun(master, "{nodeProvider}*", "virsh qemu-monitor-command ${target}.${domain} --pretty -- '{ \"execute\": \"query-block-jobs\" }'")) |
| if (blockJobs.contains('offset')) { |
| // if Block Commit hangs on 100 and check offset - len = 0, then it is safe to merge the image |
| input message: "Please check if offset - len = 0, If so run: virsh qemu-monitor-command ${target}.${domain} --pretty -- '{ \"execute\": \"block-job-complete\", \"arguments\": { \"device\": \"drive-virtio-disk0\" } }', then virsh define ${path}/${target}.${domain}.xml, then virsh snapshot-delete ${target}.${domain} --metadata ${snapshotName} and remove ${path}/${target}.${domain}.${snapshotName}.qcow2 file. When you resolve this issue click on PROCEED." |
| } |
| } |
| } |
| |