diff --git a/instances/models.py b/instances/models.py
index 2946715..978d118 100644
--- a/instances/models.py
+++ b/instances/models.py
@@ -173,6 +173,10 @@ class Instance(models.Model):
def snapshots(self):
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
def inst_xml(self):
return self.proxy._XMLDesc(VIR_DOMAIN_XML_SECURE)
diff --git a/instances/templates/instance.html b/instances/templates/instance.html
index bf48bbe..748c0df 100644
--- a/instances/templates/instance.html
+++ b/instances/templates/instance.html
@@ -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');
$(btnsect).each(function () {
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');
$(btnsect).each(function () {
if ($(this).attr('href') === '#snapshots') {
diff --git a/instances/templates/instances/snapshots_tab.html b/instances/templates/instances/snapshots_tab.html
index 986bf90..5048e7e 100755
--- a/instances/templates/instances/snapshots_tab.html
+++ b/instances/templates/instances/snapshots_tab.html
@@ -5,7 +5,12 @@
-
+
+ -
+
-
@@ -13,16 +18,6 @@
{% trans "Manage Snapshots" %}
- -
-
-
- -
-
-
@@ -39,7 +34,7 @@
|
- {% if external_snapshots|length > 0 %}
+ {% if instance.external_snapshots|length > 0 %}
{% else %}
@@ -47,137 +42,109 @@
-
+
+
+ {% if instance.status != 5 %}
+
{% trans "You can get external snapshots within this tab." %}
+
{% trans "External snapshots are experimental in this stage, use it if you know what you are doing. It may require manual intervention." %}
+ {% else %}
+
{% trans "Create an external snapshot" %}
+ {% endif %}
+
{% trans "Give your External Snapshot a distinctive description so it wouldn't get mixed with other snapshots." %}
+
+
+
- {% if instance.snapshots %}
+ {% if instance.snapshots or instance.external_snapshots %}
{% trans "Choose a snapshot for restore/delete" %}
{% trans "Date" %} |
{% trans "Name" %} |
- {% trans "Description" %} |
+ {% trans "Type - Description" %} |
{% trans "Action" %} |
- {% for snap in instance.snapshots %}
-
- {{ snap.date|date:"M d H:i:s" }} |
- {{ snap.name }} |
- {{ snap.description }} |
-
-
- |
-
-
- |
-
- {% endfor %}
+ {% if instance.snapshots %}
+ {% for snap in instance.snapshots %}
+
+ {{ snap.date|date:"M d H:i:s" }} |
+ {{ snap.name }} |
+ ({% trans "Internal" %}) - {{ snap.description }} |
+
+
+ |
+
+
+ |
+
+ {% endfor %}
+ {% elif instance.external_snapshots %}
+ {% for ext_snap in instance.external_snapshots %}
+
+ {{ ext_snap.date|date:"M d H:i:s" }} |
+ {{ ext_snap.name }} |
+ ({% trans "External" %}) - {{ ext_snap.description }} |
+
+
+ |
+
+
+ |
+
+ {% endfor %}
+ {% endif %}
{% else %}
{% trans "You do not have any snapshots" %}
{% endif %}
-
-
- {% if instance.status != 5 %}
-
You can get external snapshots within this tab.
-
External snapshots are experimental in this stage, use it if you know what you are doing.
- {% else %}
-
Create an external snapshot
- {% endif %}
-
Give your External Snapshot a distinctive description so it wouldn't get mixed with other snapshots.
-
-
-
-
- {% if external_snapshots %}
-
-
-
- Name |
- Date |
- Description |
- {% trans "Action" %} |
-
-
- {% for external_snapshot in external_snapshots %}
-
- {% for snapshot_cols in external_snapshot %}
- {{snapshot_cols}} |
- {% endfor %}
-
-
- |
-
-
- |
-
- {% endfor %}
-
-
-
- {% else%}
-
{% trans "You do not have any snapshots" %}
- {% endif %}
-
-
-
+
+
+
diff --git a/instances/views.py b/instances/views.py
index 7bfd8ce..eb6d0bb 100755
--- a/instances/views.py
+++ b/instances/views.py
@@ -20,7 +20,9 @@ from django.http import Http404, HttpResponse, JsonResponse
from django.shortcuts import get_object_or_404, redirect, render
from django.urls import reverse
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)
from logs.views import addlogmsg
from vrtManager import util
@@ -146,8 +148,6 @@ def instance(request, pk):
instance.drbd = drbd_status(request, pk)
instance.save()
- external_snapshots = get_external_snapshots(request,pk)
-
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)
return redirect(request.META.get("HTTP_REFERER") + "#managesnapshot")
+
def create_external_snapshot(request, pk):
instance = get_instance(request.user, pk)
allow_admin_or_not_template = (
@@ -1027,10 +1028,11 @@ def create_external_snapshot(request, pk):
):
name = request.POST.get("name", "")
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}
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):
instance = get_instance(request.user, pk)
@@ -1044,6 +1046,7 @@ def get_external_snapshots(request, pk):
external_snapshots = instance.proxy.get_external_snapshots()
return external_snapshots
+
def revert_external_snapshot(request, pk):
instance = get_instance(request.user, pk)
allow_admin_or_not_template = (
@@ -1059,10 +1062,12 @@ def revert_external_snapshot(request, pk):
instance.proxy.revert_external_snapshot(name, instance, date, desc)
msg = _("Revert external snapshot: %(snap)s") % {"snap": name}
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):
instance = get_instance(request.user, pk)
+ instance_state = True if instance.proxy.get_status() == 5 else False
allow_admin_or_not_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"
):
name = request.POST.get("name", "")
- instance.proxy.delete_external_snapshot(name, instance)
- msg = _("Delete external snapshot: %(snap)s") % {"snap": name}
- addlogmsg(request.user.username, instance.compute.name, instance.name, msg)
- return redirect(request.META.get("HTTP_REFERER") + "#manageExternalSnapshots")
+
+ 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}
+ addlogmsg(request.user.username, instance.compute.name, instance.name, msg)
+ finally:
+ instance.proxy.force_shutdown() if instance_state else None
+
+ return redirect(request.META.get("HTTP_REFERER") + "#managesnapshot")
+
@superuser_only
def set_vcpu(request, pk):
diff --git a/vrtManager/instance.py b/vrtManager/instance.py
index f8658f6..680dd09 100644
--- a/vrtManager/instance.py
+++ b/vrtManager/instance.py
@@ -209,8 +209,8 @@ class wvmInstance(wvmConnect):
return info_results
- def start(self):
- self.instance.create()
+ def start(self, flags=0):
+ self.instance.createWithFlags(flags)
def shutdown(self):
self.instance.shutdown()
@@ -1295,24 +1295,22 @@ class wvmInstance(wvmConnect):
)
self._defineXML(xml_temp)
- def create_external_snapshot(self, name, instance, date=None, desc=None):
- if self.instance.isActive() == False:
- result = self.instance.create()
- if result < 0:
- return 0
-
+ def create_external_snapshot(self, name, date=None, desc=None):
creation_time = time.time()
state = "shutoff" if self.get_status() == 5 else "running"
xml = """
%s
%s
%s
- %d""" % (
+ %d
+
+ """ % (
name,
desc,
state,
creation_time,
)
+
self.change_snapshot_xml()
xml += self._XMLDesc(VIR_DOMAIN_XML_SECURE)
xml += """0
@@ -1320,87 +1318,54 @@ class wvmInstance(wvmConnect):
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):
- external_snapshots = []
- 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
+ return self.get_snapshot(VIR_DOMAIN_SNAPSHOT_LIST_EXTERNAL)
- def delete_external_snapshot(self, name, instance):
+ def delete_external_snapshot(self, name):
disk_info = self.get_disk_devices()
for disk in disk_info:
target_dev = disk["dev"]
backing_file = disk["backing_file"]
- source_file = disk["path"]
- self.instance.blockCommit(target_dev, backing_file, source_file,
- flags=VIR_DOMAIN_BLOCK_COMMIT_DELETE|VIR_DOMAIN_BLOCK_COMMIT_ACTIVE)
+ snap_source_file = disk["path"]
+ self.instance.blockCommit(target_dev, backing_file, snap_source_file,
+ flags=VIR_DOMAIN_BLOCK_COMMIT_DELETE|
+ VIR_DOMAIN_BLOCK_COMMIT_ACTIVE)
while True:
info = self.instance.blockJobInfo(target_dev, 0)
if info.get('cur') == info.get('end'):
self.instance.blockJobAbort(target_dev,flags=VIR_DOMAIN_BLOCK_JOB_ABORT_PIVOT)
break
+ # Check again pool for snapshot delta volume; if it exist, remove it manually
+ with contextlib.suppress(libvirtError):
+ vol_snap = self.get_volume_by_path(snap_source_file)
+ pool = vol_snap.storagePoolLookupByVolume()
+ pool.refresh(0)
+ vol_snap.delete(0)
snap = self.instance.snapshotLookupByName(name, 0)
snap.delete(VIR_DOMAIN_SNAPSHOT_DELETE_METADATA_ONLY)
+
- def revert_external_snapshot(self, name, instance, date, desc):
+ def revert_external_snapshot(self, name, 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_xml = snap.getXMLDesc(0)
+ snapXML = ElementTree.fromstring(snap_xml)
+ disks = snapXML.findall('inactiveDomain/devices/disk')
+ if not disks: disks = snapXML.findall('domain/devices/disk')
- 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()
+ vol_snap = self.get_volume_by_path(disk["path"])
+ pool = vol_snap.storagePoolLookupByVolume()
pool.refresh(0)
- vol_snap = self.get_volume_by_path(source_file)
- vol_snap.wipe(0)
vol_snap.delete(0)
+ snap.delete(VIR_DOMAIN_SNAPSHOT_DELETE_METADATA_ONLY)
for disk in disks:
- self.instance.updateDeviceFlags(
- """
-
-
-
-
- """.format(disk["driver_name"],
- disk["driver_type"],
- disk["backing_file"],
- disk["target_dev"],
- disk["target_bus"],
- disk["boot_order"]))
+ self.instance.updateDeviceFlags(ElementTree.tostring(disk).decode("UTF-8"))
- self.create_external_snapshot(name, instance, date, desc)
+ self.create_external_snapshot(name, date, desc)
def get_snapshot(self, flag=VIR_DOMAIN_SNAPSHOT_LIST_INTERNAL):
snapshots = []