mirror of
https://github.com/virt-manager/virt-manager.git
synced 2025-01-08 21:18:04 +03:00
snapshots: Add some specific UI for external snapshots
We sort them separately in the snapshot list, explicitly mention that they are 'external', and add a UI field listing the memory/disk details. In general mixing internal and external snapshots is a recipe for confusion and disaster, so I think the best thing to do is at least acknowledge their presence in the UI but not make any attempt to predict what will or will not work.
This commit is contained in:
parent
6f469d7947
commit
6043a88a0c
@ -593,7 +593,7 @@ test-many-devices, like an alternate RNG.
|
||||
|
||||
|
||||
<domain type='test' xmlns:test='http://libvirt.org/schemas/domain/test/1.0'>
|
||||
<name>test-internal-snapshots</name>
|
||||
<name>test-snapshots</name>
|
||||
<memory>409600</memory>
|
||||
<uuid>12345678-1234-FDDF-1234-12345678FFFF</uuid>
|
||||
<bootloader>/tmp/bootfoo</bootloader>
|
||||
@ -612,6 +612,9 @@ test-many-devices, like an alternate RNG.
|
||||
<disks>
|
||||
<disk name='hda' snapshot='internal'/>
|
||||
</disks>
|
||||
<description>FOO
|
||||
desc line #2
|
||||
ba</description>
|
||||
<domain type='test'>
|
||||
<name>test-internal-snapshots</name>
|
||||
<uuid>12345678-1234-fddf-1234-12345678ffff</uuid>
|
||||
@ -851,6 +854,77 @@ test-many-devices, like an alternate RNG.
|
||||
<active>0</active>
|
||||
</test:domainsnapshot>
|
||||
|
||||
<test:domainsnapshot>
|
||||
<name>aaa-external-mem</name>
|
||||
<state>running</state>
|
||||
<creationTime>1365903080</creationTime>
|
||||
<memory snapshot='external' file='/path/to/memory/state'/>
|
||||
<disks>
|
||||
<disk name='hda' snapshot='external'>
|
||||
<source file='/path/to/new'/>
|
||||
</disk>
|
||||
</disks>
|
||||
<domain type='test'>
|
||||
<name>test-internal-snapshots</name>
|
||||
<uuid>12345678-1234-fddf-1234-12345678ffff</uuid>
|
||||
<memory unit='KiB'>409600</memory>
|
||||
<currentMemory unit='KiB'>409600</currentMemory>
|
||||
<vcpu placement='static'>1</vcpu>
|
||||
<bootloader>/tmp/bootfoo</bootloader>
|
||||
<os>
|
||||
<type arch='i686'>xen</type>
|
||||
</os>
|
||||
<clock offset='utc'/>
|
||||
<on_poweroff>destroy</on_poweroff>
|
||||
<on_reboot>restart</on_reboot>
|
||||
<on_crash>destroy</on_crash>
|
||||
<devices>
|
||||
<disk type='file' device='disk'>
|
||||
<source file='/dev/default-pool/test-clone-simple.img'/>
|
||||
<target dev='hda' bus='ide'/>
|
||||
<address type='drive' controller='0' bus='0' target='0' unit='0'/>
|
||||
</disk>
|
||||
<controller type='ide' index='0'/>
|
||||
</devices>
|
||||
</domain>
|
||||
<active>0</active>
|
||||
</test:domainsnapshot>
|
||||
|
||||
<test:domainsnapshot>
|
||||
<name>zzz-external-diskonly</name>
|
||||
<state>shutoff</state>
|
||||
<creationTime>1365903080</creationTime>
|
||||
<disks>
|
||||
<disk name='hda' snapshot='external'>
|
||||
<source file='/path/to/diskonly'/>
|
||||
</disk>
|
||||
</disks>
|
||||
<domain type='test'>
|
||||
<name>test-internal-snapshots</name>
|
||||
<uuid>12345678-1234-fddf-1234-12345678ffff</uuid>
|
||||
<memory unit='KiB'>409600</memory>
|
||||
<currentMemory unit='KiB'>409600</currentMemory>
|
||||
<vcpu placement='static'>1</vcpu>
|
||||
<bootloader>/tmp/bootfoo</bootloader>
|
||||
<os>
|
||||
<type arch='i686'>xen</type>
|
||||
</os>
|
||||
<clock offset='utc'/>
|
||||
<on_poweroff>destroy</on_poweroff>
|
||||
<on_reboot>restart</on_reboot>
|
||||
<on_crash>destroy</on_crash>
|
||||
<devices>
|
||||
<disk type='file' device='disk'>
|
||||
<source file='/dev/default-pool/test-clone-simple.img'/>
|
||||
<target dev='hda' bus='ide'/>
|
||||
<address type='drive' controller='0' bus='0' target='0' unit='0'/>
|
||||
</disk>
|
||||
<controller type='ide' index='0'/>
|
||||
</devices>
|
||||
</domain>
|
||||
<active>0</active>
|
||||
</test:domainsnapshot>
|
||||
|
||||
</domain>
|
||||
|
||||
|
||||
|
@ -8,9 +8,9 @@ newline
|
||||
<name>newparent</name>
|
||||
</parent>
|
||||
<creationTime>1234</creationTime>
|
||||
<memory snapshot="no"/>
|
||||
<memory snapshot="internal"/>
|
||||
<disks>
|
||||
<disk name="hda" snapshot="internal"/>
|
||||
<disk name="hdb" snapshot="no"/>
|
||||
</disks>
|
||||
<domain type="test">
|
||||
<name>test-internal-snapshots</name>
|
||||
|
@ -833,6 +833,11 @@ class XMLParseTest(unittest.TestCase):
|
||||
check("description", "offline desk", "foo\nnewline\n indent")
|
||||
check("parent", "offline-root", "newparent")
|
||||
check("creationTime", 1375905916, 1234)
|
||||
check("memory_type", "no", "internal")
|
||||
|
||||
check = self._make_checker(snap.disks[0])
|
||||
check("name", "hda", "hdb")
|
||||
check("snapshot", "internal", "no")
|
||||
|
||||
utils.diff_compare(snap.get_xml_config(), outfile)
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- Generated with glade 3.16.0 on Mon Sep 30 17:38:02 2013 -->
|
||||
<!-- Generated with glade 3.16.0 on Mon Sep 30 18:13:03 2013 -->
|
||||
<interface>
|
||||
<!-- interface-requires gtk+ 3.6 -->
|
||||
<object class="GtkImage" id="image3">
|
||||
@ -343,7 +343,7 @@
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">0</property>
|
||||
<property name="top_attach">3</property>
|
||||
<property name="top_attach">4</property>
|
||||
<property name="width">1</property>
|
||||
<property name="height">1</property>
|
||||
</packing>
|
||||
@ -364,7 +364,7 @@
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">1</property>
|
||||
<property name="top_attach">3</property>
|
||||
<property name="top_attach">4</property>
|
||||
<property name="width">1</property>
|
||||
<property name="height">1</property>
|
||||
</packing>
|
||||
@ -464,6 +464,34 @@
|
||||
<property name="height">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="label5">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="xalign">0</property>
|
||||
<property name="label" translatable="yes">Snapshot Mode:</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">0</property>
|
||||
<property name="top_attach">3</property>
|
||||
<property name="width">1</property>
|
||||
<property name="height">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="snapshot-mode">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="xalign">0</property>
|
||||
<property name="label" translatable="yes">label</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">1</property>
|
||||
<property name="top_attach">3</property>
|
||||
<property name="width">1</property>
|
||||
<property name="height">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
|
@ -159,8 +159,6 @@ class vmmDomainSnapshot(vmmLibvirtObject):
|
||||
def _XMLDesc(self, flags):
|
||||
return self._backend.getXMLDesc(flags=flags)
|
||||
|
||||
def is_current(self):
|
||||
return self._backend.isCurrent()
|
||||
def delete(self, force=True):
|
||||
ignore = force
|
||||
self._backend.delete()
|
||||
@ -175,6 +173,14 @@ class vmmDomainSnapshot(vmmLibvirtObject):
|
||||
status = libvirt.VIR_DOMAIN_NOSTATE
|
||||
return uihelpers.vm_status_icons[status]
|
||||
|
||||
def is_external(self):
|
||||
if self.get_xmlobj().memory_type == "external":
|
||||
return True
|
||||
for disk in self.get_xmlobj().disks:
|
||||
if disk.snapshot == "external":
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
class vmmDomain(vmmLibvirtObject):
|
||||
"""
|
||||
|
@ -92,9 +92,9 @@ class vmmSnapshotPage(vmmGObjectUI):
|
||||
buf = Gtk.TextBuffer()
|
||||
self.widget("snapshot-new-description").set_buffer(buf)
|
||||
|
||||
# [snap object, row label, tooltip, icon name]
|
||||
model = Gtk.ListStore(object, str, str, str)
|
||||
model.set_sort_column_id(1, Gtk.SortType.ASCENDING)
|
||||
# [snap object, row label, tooltip, icon name, sortname]
|
||||
model = Gtk.ListStore(object, str, str, str, str)
|
||||
model.set_sort_column_id(4, Gtk.SortType.ASCENDING)
|
||||
|
||||
col = Gtk.TreeViewColumn("")
|
||||
col.set_min_width(150)
|
||||
@ -108,10 +108,14 @@ class vmmSnapshotPage(vmmGObjectUI):
|
||||
col.add_attribute(txt, 'markup', 1)
|
||||
col.add_attribute(img, 'icon-name', 3)
|
||||
|
||||
def _sep_cb(_model, _iter, ignore):
|
||||
return not bool(_model[_iter][0])
|
||||
|
||||
slist = self.widget("snapshot-list")
|
||||
slist.set_model(model)
|
||||
slist.set_tooltip_column(2)
|
||||
slist.append_column(col)
|
||||
slist.set_row_separator_func(_sep_cb, None)
|
||||
|
||||
|
||||
###################
|
||||
@ -156,6 +160,8 @@ class vmmSnapshotPage(vmmGObjectUI):
|
||||
str(e))
|
||||
return
|
||||
|
||||
has_external = False
|
||||
has_internal = False
|
||||
for snap in snapshots:
|
||||
desc = snap.get_xmlobj().description
|
||||
if not uihelpers.can_set_row_none:
|
||||
@ -163,9 +169,22 @@ class vmmSnapshotPage(vmmGObjectUI):
|
||||
|
||||
name = snap.get_name()
|
||||
state = util.xml_escape(snap.run_status())
|
||||
label = "%s\n<span size='small'>%s: %s</span>" % (
|
||||
(name, _("State"), state))
|
||||
model.append([snap, label, desc, snap.run_status_icon_name()])
|
||||
if snap.is_external():
|
||||
has_external = True
|
||||
sortname = "3%s" % name
|
||||
external = " (%s)" % _("External")
|
||||
else:
|
||||
has_internal = True
|
||||
external = ""
|
||||
sortname = "1%s" % name
|
||||
|
||||
label = "%s\n<span size='small'>%s: %s%s</span>" % (
|
||||
(name, _("State"), state, external))
|
||||
model.append([snap, label, desc, snap.run_status_icon_name(),
|
||||
sortname])
|
||||
|
||||
if has_internal and has_external:
|
||||
model.append([None, None, None, None, "2"])
|
||||
|
||||
if len(model):
|
||||
self.widget("snapshot-list").get_selection().select_iter(
|
||||
@ -180,6 +199,8 @@ class vmmSnapshotPage(vmmGObjectUI):
|
||||
desc = snap and xmlobj.description or ""
|
||||
state = snap and snap.run_status() or ""
|
||||
icon = snap and snap.run_status_icon_name() or None
|
||||
is_external = snap and snap.is_external() or False
|
||||
|
||||
timestamp = ""
|
||||
if snap:
|
||||
timestamp = str(datetime.datetime.fromtimestamp(
|
||||
@ -198,6 +219,19 @@ class vmmSnapshotPage(vmmGObjectUI):
|
||||
self.widget("snapshot-status-icon").set_from_icon_name(
|
||||
icon, Gtk.IconSize.MENU)
|
||||
|
||||
uihelpers.set_grid_row_visible(self.widget("snapshot-mode"),
|
||||
is_external)
|
||||
if is_external:
|
||||
is_mem = xmlobj.memory_type == "external"
|
||||
is_disk = [d.snapshot == "external" for d in xmlobj.disks]
|
||||
if is_mem and is_disk:
|
||||
mode = _("External disk and memory")
|
||||
elif is_mem:
|
||||
mode = _("External memory only")
|
||||
else:
|
||||
mode = _("External disk only")
|
||||
self.widget("snapshot-mode").set_text(mode)
|
||||
|
||||
self.widget("snapshot-add").set_sensitive(True)
|
||||
self.widget("snapshot-delete").set_sensitive(bool(snap))
|
||||
self.widget("snapshot-start").set_sensitive(bool(snap))
|
||||
@ -314,12 +348,12 @@ class vmmSnapshotPage(vmmGObjectUI):
|
||||
snap = self._get_selected_snapshot()
|
||||
result = self.err.yes_no(_("Are you sure you want to revert to "
|
||||
"snapshot '%s'? All disk changes since "
|
||||
"the last snapshot will be discarded.") %
|
||||
snap.get_name())
|
||||
"the last snapshot was created will be "
|
||||
"discarded.") % snap.get_name())
|
||||
if not result:
|
||||
return
|
||||
|
||||
logging.debug("Revertin to snapshot '%s'", snap.get_name())
|
||||
logging.debug("Reverting to snapshot '%s'", snap.get_name())
|
||||
vmmAsyncJob.simple_async_noshow(self.vm.revert_to_snapshot,
|
||||
[snap], self,
|
||||
_("Error reverting to snapshot '%s'") %
|
||||
|
@ -20,7 +20,13 @@
|
||||
import libvirt
|
||||
|
||||
from virtinst import util
|
||||
from virtinst.xmlbuilder import XMLBuilder, XMLProperty
|
||||
from virtinst.xmlbuilder import XMLBuilder, XMLChildProperty, XMLProperty
|
||||
|
||||
|
||||
class _SnapshotDisk(XMLBuilder):
|
||||
_XML_ROOT_NAME = "disk"
|
||||
name = XMLProperty("./@name")
|
||||
snapshot = XMLProperty("./@snapshot")
|
||||
|
||||
|
||||
class DomainSnapshot(XMLBuilder):
|
||||
@ -57,11 +63,9 @@ class DomainSnapshot(XMLBuilder):
|
||||
creationTime = XMLProperty("./creationTime", is_int=True)
|
||||
parent = XMLProperty("./parent/name")
|
||||
|
||||
# Missing bits:
|
||||
# <memory> @type and @file
|
||||
# <disks> block which has a psuedo VM disk device
|
||||
# <domain> block which tracks the snapshot guest XML
|
||||
# <active> which should list active status for an internal snapshot
|
||||
memory_type = XMLProperty("./memory/@snapshot")
|
||||
|
||||
disks = XMLChildProperty(_SnapshotDisk, relative_xpath="./disks")
|
||||
|
||||
|
||||
##################
|
||||
|
Loading…
Reference in New Issue
Block a user