[Kimchi-devel] [PATCH 03/10] snapshot: Lookup a domain snapshot

Crístian Viana vianac at linux.vnet.ibm.com
Wed Nov 12 13:08:41 UTC 2014


A new command is added to look up an existing snapshot:

GET /vms/<vm-name>/snapshots/<snapshot-name>

It returns the following values:

* created: The time when the snapshot was created (in seconds, since the
    Unix Epoch);
* name: The snapshot name;
* state: The corresponding VM state when the snapshot was created
    (currently, it can only be 'shutoff');
* parent: The name of the parent snapshot;

Signed-off-by: Crístian Viana <vianac at linux.vnet.ibm.com>
---
 docs/API.md                     | 10 ++++++++++
 src/kimchi/i18n.py              |  2 ++
 src/kimchi/mockmodel.py         | 18 ++++++++++++-----
 src/kimchi/model/vmsnapshots.py | 43 +++++++++++++++++++++++++++++++++++++++++
 tests/test_rest.py              | 12 ++++++++++++
 5 files changed, 80 insertions(+), 5 deletions(-)

diff --git a/docs/API.md b/docs/API.md
index fe1c3cf..616958a 100644
--- a/docs/API.md
+++ b/docs/API.md
@@ -194,6 +194,16 @@ Represents a snapshot of the Virtual Machine's primary monitor.
     * name: The snapshot name (optional, defaults to a value based on the
             current time).
 
+### Sub-resource: Snapshot
+**URI:** /vms/*:name*/snapshots/*:snapshot*
+* **GET**: Retrieve snapshot information.
+    * name: The snapshot name.
+    * state: The corresponding domain's state when the snapshot was created.
+    * created: The time when the snapshot was created
+               (in seconds, since the epoch).
+    * parent: The name of the parent snapshot, or an empty string if there is
+              no parent.
+
 ### Collection: Templates
 
 **URI:** /templates
diff --git a/src/kimchi/i18n.py b/src/kimchi/i18n.py
index 9c37931..159a2d2 100644
--- a/src/kimchi/i18n.py
+++ b/src/kimchi/i18n.py
@@ -313,4 +313,6 @@ messages = {
 
     "KCHSNAP0001E": _("Virtual machine '%(vm)s' must be stopped before creating a snapshot on it."),
     "KCHSNAP0002E": _("Unable to create snapshot '%(name)s' on virtual machine '%(vm)s'. Details: %(err)s"),
+    "KCHSNAP0003E": _("Snapshot '%(name)s' does not exist on virtual machine '%(vm)s'."),
+    "KCHSNAP0004E": _("Unable to retrieve snapshot '%(name)s' on virtual machine '%(vm)s'. Details: %(err)s"),
 }
diff --git a/src/kimchi/mockmodel.py b/src/kimchi/mockmodel.py
index e06b01f..cb52750 100644
--- a/src/kimchi/mockmodel.py
+++ b/src/kimchi/mockmodel.py
@@ -989,18 +989,25 @@ class MockModel(object):
 
         parent = u''
         for sn, s in vm.snapshots.iteritems():
-            if s.info['current']:
-                s.info['current'] = False
+            if s.current:
+                s.current = False
                 parent = sn
                 break
 
-        snap_info = {'name': name,
-                     'parent': parent,
+        snap_info = {'parent': parent,
                      'state': vm.info['state']}
         vm.snapshots[name] = MockVMSnapshot(vm_name, name, snap_info)
 
         cb('OK', True)
 
+    def vmsnapshot_lookup(self, vm_name, name):
+        vm = self._get_vm(vm_name)
+
+        try:
+            return vm.snapshots[name].info
+        except KeyError:
+            raise NotFoundError('KCHSNAP0003E', {'vm': vm_name, 'name': name})
+
     def tasks_get_list(self):
         with self.objstore as session:
             return session.get_list('task')
@@ -1622,10 +1629,11 @@ class MockVMSnapshot(object):
     def __init__(self, vm_name, name, params={}):
         self.vm = vm_name
         self.name = name
+        self.current = True
 
         self.info = {'created': params.get('created',
                                            unicode(int(time.time()))),
-                     'current': params.get('current', True),
+                     'name': name,
                      'parent': params.get('parent', u''),
                      'state': params.get('state', u'shutoff')}
 
diff --git a/src/kimchi/model/vmsnapshots.py b/src/kimchi/model/vmsnapshots.py
index 8701c03..27fd052 100644
--- a/src/kimchi/model/vmsnapshots.py
+++ b/src/kimchi/model/vmsnapshots.py
@@ -21,6 +21,7 @@ import time
 
 import libvirt
 import lxml.etree as ET
+from lxml import objectify
 from lxml.builder import E
 
 from kimchi.exception import InvalidOperation, NotFoundError, OperationFailed
@@ -93,3 +94,45 @@ class VMSnapshotsModel(object):
                                    'err': e.message})
 
         cb('OK', True)
+
+
+class VMSnapshotModel(object):
+    def __init__(self, **kargs):
+        self.conn = kargs['conn']
+
+    def lookup(self, vm_name, name):
+        vir_snap = self.get_vmsnapshot(vm_name, name)
+
+        try:
+            snap_xml_str = vir_snap.getXMLDesc(0).decode('utf-8')
+        except libvirt.libvirtError, e:
+            raise OperationFailed('KCHSNAP0004E', {'name': name,
+                                                   'vm': vm_name,
+                                                   'err': e.message})
+
+        snap_xml = objectify.fromstring(snap_xml_str)
+
+        try:
+            parent = unicode(snap_xml.parent.name)
+        except AttributeError:
+            parent = u''
+
+        return {'name': unicode(snap_xml.name),
+                'state': unicode(snap_xml.state),
+                'created': unicode(snap_xml.creationTime),
+                'parent': parent}
+
+    def get_vmsnapshot(self, vm_name, name):
+        vir_dom = VMModel.get_vm(vm_name, self.conn)
+
+        try:
+            return vir_dom.snapshotLookupByName(name)
+        except libvirt.libvirtError, e:
+            code = e.get_error_code()
+            if code == libvirt.VIR_ERR_NO_DOMAIN_SNAPSHOT:
+                raise NotFoundError('KCHSNAP0003E', {'name': name,
+                                                     'vm': vm_name})
+            else:
+                raise OperationFailed('KCHSNAP0004E', {'name': name,
+                                                       'vm': vm_name,
+                                                       'err': e.message})
diff --git a/tests/test_rest.py b/tests/test_rest.py
index 7e6d684..e6ce715 100644
--- a/tests/test_rest.py
+++ b/tests/test_rest.py
@@ -396,6 +396,18 @@ class RestTests(unittest.TestCase):
         task = json.loads(self.request('/tasks/%s' % task['id']).read())
         self.assertEquals('finished', task['status'])
 
+        # Look up a snapshot
+        resp = self.request('/vms/test-vm/snapshots/foobar', '{}', 'GET')
+        self.assertEquals(404, resp.status)
+        resp = self.request('/vms/test-vm/snapshots/%s' % params['name'], '{}',
+                            'GET')
+        self.assertEquals(200, resp.status)
+        snap = json.loads(resp.read())
+        self.assertTrue(int(time.time()) >= int(snap['created']))
+        self.assertEquals(params['name'], snap['name'])
+        self.assertEquals(u'', snap['parent'])
+        self.assertEquals(u'shutoff', snap['state'])
+
         # Delete the VM
         resp = self.request('/vms/test-vm', '{}', 'DELETE')
         self.assertEquals(204, resp.status)
-- 
1.9.3




More information about the Kimchi-devel mailing list