Jiri Broulik | f8f9694 | 2018-02-15 10:03:42 +0100 | [diff] [blame] | 1 | package com.mirantis.mk |
| 2 | |
| 3 | /** |
| 4 | * |
| 5 | * Virsh functions |
| 6 | * |
| 7 | */ |
| 8 | |
| 9 | /** |
| 10 | * Ensures that the live snapshot exists |
| 11 | * |
| 12 | * @param nodeProvider KVM node that hosts the VM |
| 13 | * @param target Unique identification of the VM being snapshoted without domain (for ex. ctl01) |
| 14 | * @param snapshotName Snapshot name |
| 15 | * @param path Path where snapshot image and dumpxml are being put |
| 16 | * @param diskName Disk name of the snapshot |
| 17 | */ |
| 18 | def liveSnapshotPresent(master, nodeProvider, target, snapshotName, path='/var/lib/libvirt/images', diskName='vda') { |
| 19 | def salt = new com.mirantis.mk.Salt() |
| 20 | def common = new com.mirantis.mk.Common() |
| 21 | def snapshotPresent = "" |
| 22 | def domain = salt.getDomainName(master) |
| 23 | try { |
| 24 | snapshotPresent = salt.getReturnValues(salt.cmdRun(master, "${nodeProvider}*", "virsh snapshot-list ${target}.${domain} | grep ${snapshotName}")).split("\n")[0] |
| 25 | } catch (Exception er) { |
| 26 | common.infoMsg('snapshot not present') |
| 27 | } |
| 28 | if (!snapshotPresent.contains(snapshotName)) { |
| 29 | def dumpxmlPresent = '' |
| 30 | try { |
| 31 | dumpxmlPresent = salt.getReturnValues(salt.cmdRun(master, "${nodeProvider}*", "ls -la ${path}/${target}.${domain}.xml")).split("\n")[0] |
| 32 | } catch (Exception er) { |
| 33 | common.infoMsg('dumpxml file not present') |
| 34 | } |
| 35 | if (!dumpxmlPresent?.trim()) { |
| 36 | salt.cmdRun(master, "${nodeProvider}*", "virsh dumpxml ${target}.${domain} > ${path}/${target}.${domain}.xml") |
| 37 | } |
| 38 | salt.cmdRun(master, "${nodeProvider}*", "virsh snapshot-create-as --domain ${target}.${domain} ${snapshotName} --diskspec ${diskName},file=${path}/${target}.${domain}.${snapshotName}.qcow2 --disk-only --atomic") |
| 39 | } |
| 40 | } |
| 41 | |
| 42 | /** |
| 43 | * Ensures that the live snapshot does not exist |
| 44 | * |
| 45 | * @param nodeProvider KVM node that hosts the VM |
| 46 | * @param target Unique identification of the VM being snapshoted without domain (for ex. ctl01) |
| 47 | * @param snapshotName Snapshot name |
| 48 | * @param path Path where snapshot image and dumpxml are being put |
| 49 | */ |
| 50 | def liveSnapshotAbsent(master, nodeProvider, target, snapshotName, path='/var/lib/libvirt/images') { |
| 51 | def salt = new com.mirantis.mk.Salt() |
| 52 | def common = new com.mirantis.mk.Common() |
| 53 | def domain = salt.getDomainName(master) |
| 54 | try { |
| 55 | salt.cmdRun(master, "${nodeProvider}*", "virsh snapshot-delete ${target}.${domain} --metadata ${snapshotName}") |
| 56 | } catch (Exception e) { |
Jiri Broulik | d2a5055 | 2018-04-25 17:17:59 +0200 | [diff] [blame] | 57 | common.warningMsg("Snapshot ${snapshotName} for ${target}.${domain} does not exist or failed to be removed") |
Jiri Broulik | f8f9694 | 2018-02-15 10:03:42 +0100 | [diff] [blame] | 58 | } |
| 59 | try { |
| 60 | salt.runSaltProcessStep(master, "${nodeProvider}*", 'file.remove', ["${path}/${target}.${domain}.${snapshotName}.qcow2"], null, true) |
| 61 | } catch (Exception e) { |
Jiri Broulik | d2a5055 | 2018-04-25 17:17:59 +0200 | [diff] [blame] | 62 | common.warningMsg("Snapshot ${snapshotName} qcow2 file for ${target}.${domain} does not exist or failed to be removed") |
Jiri Broulik | f8f9694 | 2018-02-15 10:03:42 +0100 | [diff] [blame] | 63 | } |
| 64 | try { |
| 65 | salt.runSaltProcessStep(master, "${nodeProvider}*", 'file.remove', ["${path}/${target}.${domain}.xml"], null, true) |
| 66 | } catch (Exception e) { |
Jiri Broulik | d2a5055 | 2018-04-25 17:17:59 +0200 | [diff] [blame] | 67 | common.warningMsg("Dumpxml file for ${target}.${domain} does not exist or failed to be removed") |
Jiri Broulik | f8f9694 | 2018-02-15 10:03:42 +0100 | [diff] [blame] | 68 | } |
| 69 | } |
| 70 | |
| 71 | /** |
| 72 | * Rollback |
| 73 | * |
| 74 | * @param nodeProvider KVM node that hosts the VM |
| 75 | * @param target Unique identification of the VM being snapshoted without domain (for ex. ctl01) |
| 76 | * @param snapshotName Snapshot name |
| 77 | * @param path Path where snapshot image and dumpxml are being put |
| 78 | */ |
| 79 | def liveSnapshotRollback(master, nodeProvider, target, snapshotName, path='/var/lib/libvirt/images') { |
| 80 | def salt = new com.mirantis.mk.Salt() |
| 81 | def common = new com.mirantis.mk.Common() |
| 82 | def domain = salt.getDomainName(master) |
Jiri Broulik | 504cceb | 2018-02-22 13:26:49 +0100 | [diff] [blame] | 83 | try { |
| 84 | salt.getReturnValues(salt.cmdRun(master, "${nodeProvider}*", "ls -la ${path}/${target}.${domain}.xml")) |
| 85 | salt.runSaltProcessStep(master, "${nodeProvider}*", 'virt.destroy', ["${target}.${domain}"], null, true) |
| 86 | salt.cmdRun(master, "${nodeProvider}*", "virsh define ${path}/${target}.${domain}.xml") |
| 87 | liveSnapshotAbsent(master, nodeProvider, target, snapshotName, path) |
| 88 | salt.runSaltProcessStep(master, "${nodeProvider}*", 'virt.start', ["${target}.${domain}"], null, true) |
| 89 | } catch (Exception er) { |
Jiri Broulik | d2a5055 | 2018-04-25 17:17:59 +0200 | [diff] [blame] | 90 | common.infoMsg("No rollback for ${target}.${domain} was executed. Dumpxml file not present.") |
Jiri Broulik | 504cceb | 2018-02-22 13:26:49 +0100 | [diff] [blame] | 91 | } |
Jiri Broulik | f8f9694 | 2018-02-15 10:03:42 +0100 | [diff] [blame] | 92 | } |
| 93 | |
| 94 | /** |
| 95 | * Merge snapshot while instance is running |
| 96 | * |
| 97 | * @param nodeProvider KVM node that hosts the VM |
| 98 | * @param target Unique identification of the VM being snapshoted without domain (for ex. ctl01) |
| 99 | * @param snapshotName Snapshot name |
| 100 | * @param path Path where snapshot image and dumpxml are being put |
| 101 | * @param diskName Disk name of the snapshot |
| 102 | */ |
| 103 | def liveSnapshotMerge(master, nodeProvider, target, snapshotName, path='/var/lib/libvirt/images', diskName='vda') { |
| 104 | def salt = new com.mirantis.mk.Salt() |
| 105 | def common = new com.mirantis.mk.Common() |
| 106 | def domain = salt.getDomainName(master) |
| 107 | try { |
Jiri Broulik | 743c0ab | 2018-02-15 14:32:03 +0100 | [diff] [blame] | 108 | salt.cmdRun(master, "${nodeProvider}*", "virsh blockcommit ${target}.${domain} ${diskName} --active --verbose --pivot") |
Jiri Broulik | f8f9694 | 2018-02-15 10:03:42 +0100 | [diff] [blame] | 109 | try { |
Jiri Broulik | 743c0ab | 2018-02-15 14:32:03 +0100 | [diff] [blame] | 110 | salt.cmdRun(master, "${nodeProvider}*", "virsh snapshot-delete ${target}.${domain} --metadata ${snapshotName}") |
Jiri Broulik | f8f9694 | 2018-02-15 10:03:42 +0100 | [diff] [blame] | 111 | } catch (Exception e) { |
Jiri Broulik | d2a5055 | 2018-04-25 17:17:59 +0200 | [diff] [blame] | 112 | common.warningMsg("Snapshot ${snapshotName} for ${target}.${domain} does not exist or failed to be removed") |
Jiri Broulik | f8f9694 | 2018-02-15 10:03:42 +0100 | [diff] [blame] | 113 | } |
| 114 | try { |
Jiri Broulik | 743c0ab | 2018-02-15 14:32:03 +0100 | [diff] [blame] | 115 | salt.runSaltProcessStep(master, "${nodeProvider}*", 'file.remove', ["${path}/${target}.${domain}.${snapshotName}.qcow2"], null, true) |
Jiri Broulik | f8f9694 | 2018-02-15 10:03:42 +0100 | [diff] [blame] | 116 | } catch (Exception e) { |
Jiri Broulik | d2a5055 | 2018-04-25 17:17:59 +0200 | [diff] [blame] | 117 | common.warningMsg("Snapshot ${snapshotName} qcow2 file for ${target}.${domain} does not exist or failed to be removed") |
Jiri Broulik | f8f9694 | 2018-02-15 10:03:42 +0100 | [diff] [blame] | 118 | } |
| 119 | try { |
Jiri Broulik | 743c0ab | 2018-02-15 14:32:03 +0100 | [diff] [blame] | 120 | salt.runSaltProcessStep(master, "${nodeProvider}*", 'file.remove', ["${path}/${target}.${domain}.xml"], null, true) |
Jiri Broulik | f8f9694 | 2018-02-15 10:03:42 +0100 | [diff] [blame] | 121 | } catch (Exception e) { |
Jiri Broulik | d2a5055 | 2018-04-25 17:17:59 +0200 | [diff] [blame] | 122 | common.warningMsg("Dumpxml file for ${target}.${domain} does not exist or failed to be removed") |
Jiri Broulik | f8f9694 | 2018-02-15 10:03:42 +0100 | [diff] [blame] | 123 | } |
| 124 | } catch (Exception e) { |
| 125 | common.errorMsg("The live snapshoted VM ${target}.${domain} failed to be merged, trying to fix it") |
| 126 | checkLiveSnapshotMerge(master, nodeProvider, target, snapshotName, path, diskName) |
| 127 | } |
| 128 | } |
| 129 | |
| 130 | |
| 131 | /** |
| 132 | * Check live snapshot merge failure due to known qemu issue not receiving message about merge completion |
| 133 | * |
| 134 | * @param nodeProvider KVM node that hosts the VM |
| 135 | * @param target Unique identification of the VM being snapshoted without domain (for ex. ctl01) |
| 136 | * @param snapshotName Snapshot name |
| 137 | * @param path Path where snapshot image and dumpxml are being put |
| 138 | * @param diskName Disk name of the snapshot |
| 139 | */ |
| 140 | def checkLiveSnapshotMerge(master, nodeProvider, target, snapshotName, path='/var/lib/libvirt/images', diskName='vda') { |
| 141 | def salt = new com.mirantis.mk.Salt() |
| 142 | def domain = salt.getDomainName(master) |
Jiri Broulik | 743c0ab | 2018-02-15 14:32:03 +0100 | [diff] [blame] | 143 | def out = salt.getReturnValues(salt.cmdRun(master, "${nodeProvider}*", "virsh blockjob ${target}.${domain} ${diskName} --info")) |
Jiri Broulik | f8f9694 | 2018-02-15 10:03:42 +0100 | [diff] [blame] | 144 | if (out.contains('Block Commit')) { |
Jiri Broulik | 743c0ab | 2018-02-15 14:32:03 +0100 | [diff] [blame] | 145 | def blockJobs = salt.getReturnValues(salt.cmdRun(master, "{nodeProvider}*", "virsh qemu-monitor-command ${target}.${domain} --pretty -- '{ \"execute\": \"query-block-jobs\" }'")) |
Jiri Broulik | f8f9694 | 2018-02-15 10:03:42 +0100 | [diff] [blame] | 146 | if (blockJobs.contains('offset')) { |
| 147 | // if Block Commit hangs on 100 and check offset - len = 0, then it is safe to merge the image |
| 148 | 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." |
| 149 | } |
| 150 | } |
| 151 | } |
| 152 | |