1
0
Fork 0
mirror of https://github.com/retspen/webvirtcloud synced 2024-12-25 15:45:23 +00:00

experimental: external snapshot fixes

This commit is contained in:
catborise 2023-04-13 12:24:13 +03:00
parent 68b0494350
commit 33d49a68a7
5 changed files with 156 additions and 207 deletions

View file

@ -173,6 +173,10 @@ class Instance(models.Model):
def snapshots(self): def snapshots(self):
return sorted(self.proxy.get_snapshot(), reverse=True, key=lambda k: k["date"]) return sorted(self.proxy.get_snapshot(), reverse=True, key=lambda k: k["date"])
@cached_property
def external_snapshots(self):
return sorted(self.proxy.get_external_snapshots(), reverse=True, key=lambda k: k["date"])
@cached_property @cached_property
def inst_xml(self): def inst_xml(self):
return self.proxy._XMLDesc(VIR_DOMAIN_XML_SECURE) return self.proxy._XMLDesc(VIR_DOMAIN_XML_SECURE)

View file

@ -679,7 +679,7 @@
} }
}); });
} }
if (~$.inArray(hash, ['#resize', "resizevm_cpu", "resizevm_mem", "resizevm_disk"])) { if (~$.inArray(hash, ['#resize', "#resizevm_cpu", "#resizevm_mem", "#resizevm_disk"])) {
var btnsect = $('#navbtn>li>a'); var btnsect = $('#navbtn>li>a');
$(btnsect).each(function () { $(btnsect).each(function () {
if ($(this).attr('href') === '#resize') { if ($(this).attr('href') === '#resize') {
@ -702,7 +702,7 @@
} }
}); });
} }
if (~$.inArray(hash, ['#takesnapshot', '#managesnapshot'])) { if (~$.inArray(hash, ['#takesnapshot', "#takeextsnapshot", "#managesnapshot"])) {
var btnsect = $('#navbtn>li>a'); var btnsect = $('#navbtn>li>a');
$(btnsect).each(function () { $(btnsect).each(function () {
if ($(this).attr('href') === '#snapshots') { if ($(this).attr('href') === '#snapshots') {

View file

@ -5,7 +5,12 @@
<ul class="nav nav-tabs" role="tablist" aria-label="Instance snapshot menu"> <ul class="nav nav-tabs" role="tablist" aria-label="Instance snapshot menu">
<li class="nav-item" role="presentation"> <li class="nav-item" role="presentation">
<button class="nav-link active" data-bs-toggle="tab" data-bs-target="#takesnapshot" type="button" role="tab" aria-controls="takesnapshot" aria-selected="true"> <button class="nav-link active" data-bs-toggle="tab" data-bs-target="#takesnapshot" type="button" role="tab" aria-controls="takesnapshot" aria-selected="true">
{% trans "Take Snapshot" %} {% trans "Take Snapshot - Internal" %}
</button>
</li>
<li class="nav-item" role="presentation">
<button class="nav-link" data-bs-toggle="tab" data-bs-target="#takeextsnapshot" type="button" role="tab" aria-controls="externalSnapshot" aria-selected="false">
{% trans "Take Snapshot - External" %}
</button> </button>
</li> </li>
<li class="nav-item" role="presentation"> <li class="nav-item" role="presentation">
@ -13,16 +18,6 @@
{% trans "Manage Snapshots" %} {% trans "Manage Snapshots" %}
</button> </button>
</li> </li>
<li class="nav-item" role="presentation">
<button class="nav-link" data-bs-toggle="tab" data-bs-target="#externalSnapshot" type="button" role="tab" aria-controls="externalSnapshot" aria-selected="false">
External Snapshot
</button>
</li>
<li class="nav-item" role="presentation">
<button class="nav-link" data-bs-toggle="tab" data-bs-target="#manageExternalSnapshots" type="button" role="tab" aria-controls="manageExternalSnapshots" aria-selected="false">
Manage External Snapshots
</button>
</li>
</ul> </ul>
<!-- Tab panes --> <!-- Tab panes -->
<div class="tab-content"> <div class="tab-content">
@ -39,7 +34,7 @@
<input type="text" class="form-control form-control-lg" name="name" placeholder="{% trans "Snapshot Name" %}" maxlength="14"> <input type="text" class="form-control form-control-lg" name="name" placeholder="{% trans "Snapshot Name" %}" maxlength="14">
<span class="input-group-text">|</span> <span class="input-group-text">|</span>
<input type="text" class="form-control form-control-lg" name="description" placeholder="{% trans "Snapshot Description" %}" maxlength="45"> <input type="text" class="form-control form-control-lg" name="description" placeholder="{% trans "Snapshot Description" %}" maxlength="45">
{% if external_snapshots|length > 0 %} {% if instance.external_snapshots|length > 0 %}
<input type="submit" class="btn btn-lg btn-success disabled float-end" name="snapshot" value="{% trans "Take Snapshot" %}"> <input type="submit" class="btn btn-lg btn-success disabled float-end" name="snapshot" value="{% trans "Take Snapshot" %}">
{% else %} {% else %}
<input type="submit" class="btn btn-lg btn-success float-end" name="snapshot" value="{% trans "Take Snapshot" %}" onclick="showPleaseWaitDialog();"> <input type="submit" class="btn btn-lg btn-success float-end" name="snapshot" value="{% trans "Take Snapshot" %}" onclick="showPleaseWaitDialog();">
@ -47,24 +42,49 @@
</div> </div>
</form> </form>
<div class="clearfix"></div> <div class="clearfix"></div>
</div> <!-- Tab pane - takesnapshot -->
<div role="tabpanel" class="tab-pane tab-pane-bordered" id="takeextsnapshot">
{% if instance.status != 5 %}
<p>{% trans "You can get external snapshots within this tab." %}</p>
<p class="text-primary">{% trans "External snapshots are experimental in this stage, use it if you know what you are doing. It may require manual intervention." %}</p>
{% else %}
<p>{% trans "Create an external snapshot" %}</p>
{% endif %}
<p class="text-danger">{% trans "Give your External Snapshot a <b>distinctive description</b> so it wouldn't get mixed with other snapshots." %}</p>
<form action="{% url 'instances:create_external_snapshot' instance.id %}" method="post" role="form" aria-label="Create snapshot form">
{% csrf_token %}
<div class="input-group mb-3">
<input type="text" class="form-control form-control-lg" name="name" placeholder="{% trans "Snapshot Name" %}" maxlength="14">
<span class="input-group-text">|</span>
<input type="text" class="form-control form-control-lg" name="description" placeholder="{% trans "Snapshot Description" %}" maxlength="45">
{% if instance.external_snapshots|length > 0 or instance.snapshots|length > 0 %}
<input type="submit" class="btn btn-lg btn-success disabled float-end" name="snapshot" value="{% trans "Take Snapshot" %}">
{% else %}
<input type="submit" class="btn btn-lg btn-success float-end" name="snapshot" value="{% trans "Take Snapshot" %}" onclick="showPleaseWaitDialog();">
{% endif %}
</div> </div>
<p class="text-danger">{% trans "WebVirtCloud supports only one external snapshot at the moment." %}</p>
</form>
<div class="clearfix"></div>
</div> <!--tab pane takeextsnapshot-->
<div role="tabpanel" class="tab-pane tab-pane-bordered" id="managesnapshot"> <div role="tabpanel" class="tab-pane tab-pane-bordered" id="managesnapshot">
{% if instance.snapshots %} {% if instance.snapshots or instance.external_snapshots %}
<p>{% trans "Choose a snapshot for restore/delete" %}</p> <p>{% trans "Choose a snapshot for restore/delete" %}</p>
<div class="table-responsive"> <div class="table-responsive">
<table class="table"> <table class="table">
<thead> <thead>
<th scope="col">{% trans "Date" %}</th> <th scope="col">{% trans "Date" %}</th>
<th scope="col">{% trans "Name" %}</th> <th scope="col">{% trans "Name" %}</th>
<th scope="col">{% trans "Description" %}</th> <th scope="col">{% trans "Type - Description" %}</th>
<th scope="colgroup" colspan="2">{% trans "Action" %}</th> <th scope="colgroup" colspan="2">{% trans "Action" %}</th>
</thead> </thead>
<tbody> <tbody>
{% if instance.snapshots %}
{% for snap in instance.snapshots %} {% for snap in instance.snapshots %}
<tr> <tr>
<td>{{ snap.date|date:"M d H:i:s" }}</td> <td>{{ snap.date|date:"M d H:i:s" }}</td>
<td><strong>{{ snap.name }}</strong></td> <td><strong>{{ snap.name }}</strong></td>
<td>{{ snap.description }}</td> <td>({% trans "Internal" %}) - {{ snap.description }}</td>
<td style="width:30px;"> <td style="width:30px;">
<form action="{% url 'instances:revert_snapshot' instance.id %}" method="post" role="form" aria-label="Restore snapshot form"> <form action="{% url 'instances:revert_snapshot' instance.id %}" method="post" role="form" aria-label="Restore snapshot form">
{% csrf_token %} {% csrf_token %}
@ -91,93 +111,40 @@
</td> </td>
</tr> </tr>
{% endfor %} {% endfor %}
</tbody> {% elif instance.external_snapshots %}
</table> {% for ext_snap in instance.external_snapshots %}
</div>
{% else %}
<p>{% trans "You do not have any snapshots" %}</p>
{% endif %}
</div>
<div role="tabpanel" class="tab-pane tab-pane-bordered" id="externalSnapshot">
{% if instance.status != 5 %}
<p>You can get external snapshots within this tab.</p>
<p class="text-primary">External snapshots are experimental in this stage, use it if you know what you are doing.</p>
{% else %}
<p>Create an external snapshot</p>
{% endif %}
<p class="text-danger">Give your External Snapshot a <b>distinctive description</b> so it wouldn't get mixed with other snapshots.</p>
<form action="{% url 'instances:create_external_snapshot' instance.id %}" method="post" role="form" aria-label="Create snapshot form">
{% csrf_token %}
<div class="mb-3" style="white-space:pre-line">
<input type="text" class="form-control form-control-lg" name="name" placeholder="{% trans "Snapshot Name" %}" maxlength="14">
<input type="text" class="form-control form-control-lg" name="description" placeholder="{% trans "Snapshot Description" %}" maxlength="45">
{% if external_snapshots|length > 0 or instance.snapshots|length > 0 %}
<p class="text-danger">WebVirtCloud supports only one External Snapshot at the moment.</p>
<input type="submit" class="btn btn-lg btn-success disabled float-end" name="snapshot" value="{% trans "Take Snapshot" %}">
{% else %}
<input type="submit" class="btn btn-lg btn-success float-end" name="snapshot" value="{% trans "Take Snapshot" %}" onclick="showPleaseWaitDialog();">
{% endif %}
</div>
</form>
<div class="clearfix"></div>
</div>
<div role="tabpanel" class="tab-pane tab-pane-bordered" id="manageExternalSnapshots">
{% if external_snapshots %}
<div class="table-responsive">
<table class="table">
<thead>
<th scope="col">Name</th>
<th scope="col">Date</th>
<th scope="col">Description</th>
<th scope="colgroup" colspan="2">{% trans "Action" %}</th>
</thead>
<tbody>
{% for external_snapshot in external_snapshots %}
<tr> <tr>
{% for snapshot_cols in external_snapshot %} <td>{{ ext_snap.date|date:"M d H:i:s" }}</td>
<td>{{snapshot_cols}}</td> <td><strong>{{ ext_snap.name }}</strong></td>
{% endfor %} <td>({% trans "External" %}) - {{ ext_snap.description }}</td>
<td style="width:30px;"> <td style="width:30px;">
<form action="{% url 'instances:revert_external_snapshot' instance.id %}" method="post" role="form" aria-label="Restore external snapshot form"> <form action="{% url 'instances:revert_external_snapshot' instance.id %}" method="post" role="form" aria-label="Restore external snapshot form">
{% csrf_token %} {% csrf_token %}
<input type="hidden" name="name" value="{{ external_snapshot.0 }}"> <input type="hidden" name="name" value="{{ ext_snap.name }}">
<input type="hidden" name="date" value="{{ external_snapshot.1 }}"> <input type="hidden" name="date" value="{{ ext_snap.date }}">
<input type="hidden" name="desc" value="{{ external_snapshot.2 }}"> <input type="hidden" name="desc" value="{{ ext_snap.description }}">
{% if instance.status == 5 %}
<button type="submit" class="btn btn-sm btn-primary" name="revert_external_snapshot" title="{% trans 'Revert to this Snapshot' %}" onclick="return confirm('You are going to lose your unsaved work by reverting to this snapshot state. Are you sure?')"> <button type="submit" class="btn btn-sm btn-primary" name="revert_external_snapshot" title="{% trans 'Revert to this Snapshot' %}" onclick="return confirm('You are going to lose your unsaved work by reverting to this snapshot state. Are you sure?')">
<span class="fa fa-download"></span> <span class="fa fa-download"></span>
</button> </button>
{% else %}
<button type="button" class="btn btn-sm btn-primary disabled"
title="{% trans "To restore snapshots you need Power Off the instance." %}">
<span class="fa fa-download"></span>
</button>
{% endif %}
</form> </form>
</td> </td>
<td style="width:30px;"> <td style="width:30px;">
<form action="{% url 'instances:delete_external_snapshot' instance.id %}" method="post" role="form" aria-label="Delete external snapshot form">{% csrf_token %} <form action="{% url 'instances:delete_external_snapshot' instance.id %}" method="post" role="form" aria-label="Delete external snapshot form">{% csrf_token %}
<input type="hidden" name="name" value="{{ external_snapshot.0 }}"> <input type="hidden" name="name" value="{{ ext_snap.name }}">
{% if instance.status != 5 %}
<button type="submit" class="btn btn-sm btn-danger" name="delete_external_snapshot" title="{% trans 'Delete Snapshot' %}" onclick="return confirm('You are about to delete this snapshot and merge it with base image. Are you sure?')"> <button type="submit" class="btn btn-sm btn-danger" name="delete_external_snapshot" title="{% trans 'Delete Snapshot' %}" onclick="return confirm('You are about to delete this snapshot and merge it with base image. Are you sure?')">
{% icon 'trash' %} {% icon 'trash' %}
</button> </button>
{% else %}
<button type="submit" class="btn btn-sm btn-danger disabled" title="{% trans 'Delete Snapshot' %}">
{% icon 'trash' %}
</button>
{% endif %}
</form> </form>
</td> </td>
</tr> </tr>
{% endfor %} {% endfor %}
{% endif %}
</tbody> </tbody>
</table> </table>
</div> </div>
{% else %} {% else %}
<p>{% trans "You do not have any snapshots" %}</p> <p>{% trans "You do not have any snapshots" %}</p>
{% endif %} {% endif %}
</div> </div> <!--tab pane managesnapshot-->
</div> </div> <!-- Tab content-->
</div> </div> <!-- Tab panel-->

View file

@ -20,7 +20,9 @@ from django.http import Http404, HttpResponse, JsonResponse
from django.shortcuts import get_object_or_404, redirect, render from django.shortcuts import get_object_or_404, redirect, render
from django.urls import reverse from django.urls import reverse
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
from libvirt import (VIR_DOMAIN_UNDEFINE_KEEP_NVRAM, VIR_DOMAIN_UNDEFINE_NVRAM, from libvirt import (VIR_DOMAIN_UNDEFINE_KEEP_NVRAM,
VIR_DOMAIN_UNDEFINE_NVRAM,
VIR_DOMAIN_START_PAUSED,
libvirtError) libvirtError)
from logs.views import addlogmsg from logs.views import addlogmsg
from vrtManager import util from vrtManager import util
@ -146,8 +148,6 @@ def instance(request, pk):
instance.drbd = drbd_status(request, pk) instance.drbd = drbd_status(request, pk)
instance.save() instance.save()
external_snapshots = get_external_snapshots(request,pk)
return render(request, "instance.html", locals(),) return render(request, "instance.html", locals(),)
@ -1016,6 +1016,7 @@ def revert_snapshot(request, pk):
addlogmsg(request.user.username, instance.compute.name, instance.name, msg) addlogmsg(request.user.username, instance.compute.name, instance.name, msg)
return redirect(request.META.get("HTTP_REFERER") + "#managesnapshot") return redirect(request.META.get("HTTP_REFERER") + "#managesnapshot")
def create_external_snapshot(request, pk): def create_external_snapshot(request, pk):
instance = get_instance(request.user, pk) instance = get_instance(request.user, pk)
allow_admin_or_not_template = ( allow_admin_or_not_template = (
@ -1027,10 +1028,11 @@ def create_external_snapshot(request, pk):
): ):
name = request.POST.get("name", "") name = request.POST.get("name", "")
desc = request.POST.get("description", "") desc = request.POST.get("description", "")
instance.proxy.create_external_snapshot(name, instance, desc=desc) instance.proxy.create_external_snapshot("s1." + name, instance, desc=desc)
msg = _("Create external snapshot: %(snap)s") % {"snap": name} msg = _("Create external snapshot: %(snap)s") % {"snap": name}
addlogmsg(request.user.username, instance.compute.name, instance.name, msg) addlogmsg(request.user.username, instance.compute.name, instance.name, msg)
return redirect(request.META.get("HTTP_REFERER") + "#manageExternalSnapshots") return redirect(request.META.get("HTTP_REFERER") + "#managesnapshot")
def get_external_snapshots(request, pk): def get_external_snapshots(request, pk):
instance = get_instance(request.user, pk) instance = get_instance(request.user, pk)
@ -1044,6 +1046,7 @@ def get_external_snapshots(request, pk):
external_snapshots = instance.proxy.get_external_snapshots() external_snapshots = instance.proxy.get_external_snapshots()
return external_snapshots return external_snapshots
def revert_external_snapshot(request, pk): def revert_external_snapshot(request, pk):
instance = get_instance(request.user, pk) instance = get_instance(request.user, pk)
allow_admin_or_not_template = ( allow_admin_or_not_template = (
@ -1059,10 +1062,12 @@ def revert_external_snapshot(request, pk):
instance.proxy.revert_external_snapshot(name, instance, date, desc) instance.proxy.revert_external_snapshot(name, instance, date, desc)
msg = _("Revert external snapshot: %(snap)s") % {"snap": name} msg = _("Revert external snapshot: %(snap)s") % {"snap": name}
addlogmsg(request.user.username, instance.compute.name, instance.name, msg) addlogmsg(request.user.username, instance.compute.name, instance.name, msg)
return redirect(request.META.get("HTTP_REFERER") + "#manageExternalSnapshots") return redirect(request.META.get("HTTP_REFERER") + "#managesnapshot")
def delete_external_snapshot(request, pk): def delete_external_snapshot(request, pk):
instance = get_instance(request.user, pk) instance = get_instance(request.user, pk)
instance_state = True if instance.proxy.get_status() == 5 else False
allow_admin_or_not_template = ( allow_admin_or_not_template = (
request.user.is_superuser or request.user.is_staff or not instance.is_template request.user.is_superuser or request.user.is_staff or not instance.is_template
) )
@ -1071,10 +1076,18 @@ def delete_external_snapshot(request, pk):
"instances.snapshot_instances" "instances.snapshot_instances"
): ):
name = request.POST.get("name", "") name = request.POST.get("name", "")
instance.proxy.delete_external_snapshot(name, instance)
instance.proxy.start(VIR_DOMAIN_START_PAUSED) if instance_state else None
try:
instance.proxy.delete_external_snapshot(name)
msg = _("Delete external snapshot: %(snap)s") % {"snap": name} msg = _("Delete external snapshot: %(snap)s") % {"snap": name}
addlogmsg(request.user.username, instance.compute.name, instance.name, msg) addlogmsg(request.user.username, instance.compute.name, instance.name, msg)
return redirect(request.META.get("HTTP_REFERER") + "#manageExternalSnapshots") finally:
instance.proxy.force_shutdown() if instance_state else None
return redirect(request.META.get("HTTP_REFERER") + "#managesnapshot")
@superuser_only @superuser_only
def set_vcpu(request, pk): def set_vcpu(request, pk):

View file

@ -209,8 +209,8 @@ class wvmInstance(wvmConnect):
return info_results return info_results
def start(self): def start(self, flags=0):
self.instance.create() self.instance.createWithFlags(flags)
def shutdown(self): def shutdown(self):
self.instance.shutdown() self.instance.shutdown()
@ -1295,24 +1295,22 @@ class wvmInstance(wvmConnect):
) )
self._defineXML(xml_temp) self._defineXML(xml_temp)
def create_external_snapshot(self, name, instance, date=None, desc=None): def create_external_snapshot(self, name, date=None, desc=None):
if self.instance.isActive() == False:
result = self.instance.create()
if result < 0:
return 0
creation_time = time.time() creation_time = time.time()
state = "shutoff" if self.get_status() == 5 else "running" state = "shutoff" if self.get_status() == 5 else "running"
xml = """<domainsnapshot> xml = """<domainsnapshot>
<name>%s</name> <name>%s</name>
<description>%s</description> <description>%s</description>
<state>%s</state> <state>%s</state>
<creationTime>%d</creationTime>""" % ( <creationTime>%d</creationTime>
<seclabel type='none' model='dac' relabel='no'/>
""" % (
name, name,
desc, desc,
state, state,
creation_time, creation_time,
) )
self.change_snapshot_xml() self.change_snapshot_xml()
xml += self._XMLDesc(VIR_DOMAIN_XML_SECURE) xml += self._XMLDesc(VIR_DOMAIN_XML_SECURE)
xml += """<active>0</active> xml += """<active>0</active>
@ -1320,87 +1318,54 @@ class wvmInstance(wvmConnect):
self._snapshotCreateXML(xml, VIR_DOMAIN_SNAPSHOT_CREATE_DISK_ONLY) self._snapshotCreateXML(xml, VIR_DOMAIN_SNAPSHOT_CREATE_DISK_ONLY)
disk_info = self.get_disk_devices()
for disk in disk_info:
backing_file = disk["backing_file"]
vol_base = self.get_volume_by_path(backing_file)
pool = vol_base.storagePoolLookupByVolume()
pool.refresh(0)
def get_external_snapshots(self): def get_external_snapshots(self):
external_snapshots = [] return self.get_snapshot(VIR_DOMAIN_SNAPSHOT_LIST_EXTERNAL)
temp_snapshots = self.get_snapshot(VIR_DOMAIN_SNAPSHOT_LIST_EXTERNAL)
for temp_snapshot in temp_snapshots:
external_snapshot = []
external_snapshot.append(temp_snapshot['name'])
external_snapshot.append(temp_snapshot['date'])
external_snapshot.append(temp_snapshot['description'])
external_snapshots.append(external_snapshot)
return external_snapshots
def delete_external_snapshot(self, name, instance): def delete_external_snapshot(self, name):
disk_info = self.get_disk_devices() disk_info = self.get_disk_devices()
for disk in disk_info: for disk in disk_info:
target_dev = disk["dev"] target_dev = disk["dev"]
backing_file = disk["backing_file"] backing_file = disk["backing_file"]
source_file = disk["path"] snap_source_file = disk["path"]
self.instance.blockCommit(target_dev, backing_file, source_file, self.instance.blockCommit(target_dev, backing_file, snap_source_file,
flags=VIR_DOMAIN_BLOCK_COMMIT_DELETE|VIR_DOMAIN_BLOCK_COMMIT_ACTIVE) flags=VIR_DOMAIN_BLOCK_COMMIT_DELETE|
VIR_DOMAIN_BLOCK_COMMIT_ACTIVE)
while True: while True:
info = self.instance.blockJobInfo(target_dev, 0) info = self.instance.blockJobInfo(target_dev, 0)
if info.get('cur') == info.get('end'): if info.get('cur') == info.get('end'):
self.instance.blockJobAbort(target_dev,flags=VIR_DOMAIN_BLOCK_JOB_ABORT_PIVOT) self.instance.blockJobAbort(target_dev,flags=VIR_DOMAIN_BLOCK_JOB_ABORT_PIVOT)
break break
# Check again pool for snapshot delta volume; if it exist, remove it manually
snap = self.instance.snapshotLookupByName(name, 0) with contextlib.suppress(libvirtError):
snap.delete(VIR_DOMAIN_SNAPSHOT_DELETE_METADATA_ONLY) vol_snap = self.get_volume_by_path(snap_source_file)
pool = vol_snap.storagePoolLookupByVolume()
def revert_external_snapshot(self, name, instance, date, desc):
snap = self.instance.snapshotLookupByName(name, 0)
snapXML = ElementTree.fromstring(snap.getXMLDesc(0))
disks = []
for disk_backup in snapXML.findall('inactiveDomain/devices/disk'):
if disk_backup.get('device') == 'disk':
disk_dict = {}
if disk_backup.find('source') is not None:
disk_dict['backing_file'] = disk_backup.find('source').get('file')
if disk_backup.find('driver') is not None:
disk_dict['driver_name'] = disk_backup.find('driver').get('name')
disk_dict['driver_type'] = disk_backup.find('driver').get('type')
if disk_backup.find('target') is not None:
disk_dict['target_dev'] = disk_backup.find('target').get('dev')
disk_dict['target_bus'] = disk_backup.find('target').get('bus')
if disk_backup.find('boot') is not None:
disk_dict['boot_order'] = disk_backup.find('boot').get('order')
disks.append(disk_dict)
snap.delete(VIR_DOMAIN_SNAPSHOT_DELETE_METADATA_ONLY)
disk_info = self.get_disk_devices()
for disk in disk_info:
source_file = disk["path"]
backing_file = disk["backing_file"]
vol_base = self.get_volume_by_path(backing_file)
pool = vol_base.storagePoolLookupByVolume()
pool.refresh(0) pool.refresh(0)
vol_snap = self.get_volume_by_path(source_file)
vol_snap.wipe(0)
vol_snap.delete(0) vol_snap.delete(0)
for disk in disks: snap = self.instance.snapshotLookupByName(name, 0)
self.instance.updateDeviceFlags( snap.delete(VIR_DOMAIN_SNAPSHOT_DELETE_METADATA_ONLY)
"""<disk type='file' device='disk'>
<driver name='{}' type='{}'/>
<source file='{}'/>
<target dev='{}' bus='{}'/>
<boot order='{}'/>
</disk>""".format(disk["driver_name"],
disk["driver_type"],
disk["backing_file"],
disk["target_dev"],
disk["target_bus"],
disk["boot_order"]))
self.create_external_snapshot(name, instance, date, desc)
def revert_external_snapshot(self, name, date, desc):
snap = self.instance.snapshotLookupByName(name, 0)
snap_xml = snap.getXMLDesc(0)
snapXML = ElementTree.fromstring(snap_xml)
disks = snapXML.findall('inactiveDomain/devices/disk')
if not disks: disks = snapXML.findall('domain/devices/disk')
disk_info = self.get_disk_devices()
for disk in disk_info:
vol_snap = self.get_volume_by_path(disk["path"])
pool = vol_snap.storagePoolLookupByVolume()
pool.refresh(0)
vol_snap.delete(0)
snap.delete(VIR_DOMAIN_SNAPSHOT_DELETE_METADATA_ONLY)
for disk in disks:
self.instance.updateDeviceFlags(ElementTree.tostring(disk).decode("UTF-8"))
self.create_external_snapshot(name, date, desc)
def get_snapshot(self, flag=VIR_DOMAIN_SNAPSHOT_LIST_INTERNAL): def get_snapshot(self, flag=VIR_DOMAIN_SNAPSHOT_LIST_INTERNAL):
snapshots = [] snapshots = []