[Kimchi-devel] [PATCH 06/10] snapshot: Lookup current snapshot on a domain

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


A new command is added to look up the current snapshot on a virtual
machine:

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

It returns a snapshot structure (as returned by 'GET
/vms/<vm-name>/snapshots/<snapshot-name>') of the current snapshot on
the specified virtual machine. If the VM doesn't have a current
snapshot, an exception will be returned.

Signed-off-by: Crístian Viana <vianac at linux.vnet.ibm.com>
---
 docs/API.md                        |  4 ++++
 src/kimchi/control/vm/snapshots.py | 13 +++++++++++++
 src/kimchi/i18n.py                 |  2 ++
 src/kimchi/mockmodel.py            | 21 +++++++++++++++------
 src/kimchi/model/vmsnapshots.py    | 24 ++++++++++++++++++++++++
 tests/test_rest.py                 | 17 +++++++++++++++++
 6 files changed, 75 insertions(+), 6 deletions(-)

diff --git a/docs/API.md b/docs/API.md
index a6ca0c2..f4100c0 100644
--- a/docs/API.md
+++ b/docs/API.md
@@ -210,6 +210,10 @@ Represents a snapshot of the Virtual Machine's primary monitor.
                 will be deleted; if false, only the snapshot will be deleted
                 (optional, defaults to false).
 
+### Sub-resource: Current snapshot
+**URI:** /vms/*:name*/snapshots/current
+* **GET**: Retrieve current snapshot information for the virtual machine.
+
 ### Collection: Templates
 
 **URI:** /templates
diff --git a/src/kimchi/control/vm/snapshots.py b/src/kimchi/control/vm/snapshots.py
index 5650435..d491015 100644
--- a/src/kimchi/control/vm/snapshots.py
+++ b/src/kimchi/control/vm/snapshots.py
@@ -29,6 +29,7 @@ class VMSnapshots(AsyncCollection):
         self.vm = vm
         self.resource_args = [self.vm, ]
         self.model_args = [self.vm, ]
+        self.current = CurrentVMSnapshot(model, vm)
 
 
 class VMSnapshot(Resource):
@@ -42,3 +43,15 @@ class VMSnapshot(Resource):
     @property
     def data(self):
         return self.info
+
+
+class CurrentVMSnapshot(Resource):
+    def __init__(self, model, vm):
+        super(CurrentVMSnapshot, self).__init__(model)
+        self.vm = vm
+        self.model_args = [self.vm]
+        self.uri_fmt = '/vms/%s/snapshots/current'
+
+    @property
+    def data(self):
+        return self.info
diff --git a/src/kimchi/i18n.py b/src/kimchi/i18n.py
index 6a1e193..b1b8060 100644
--- a/src/kimchi/i18n.py
+++ b/src/kimchi/i18n.py
@@ -317,4 +317,6 @@ messages = {
     "KCHSNAP0004E": _("Unable to retrieve snapshot '%(name)s' on virtual machine '%(vm)s'. Details: %(err)s"),
     "KCHSNAP0005E": _("Unable to list snapshots on virtual machine '%(vm)s'. Details: %(err)s"),
     "KCHSNAP0006E": _("Unable to delete snapshot '%(name)s' on virtual machine '%(vm)s'. Details: %(err)s"),
+    "KCHSNAP0007E": _("Virtual machine '%(vm)s' does not have a current snapshot."),
+    "KCHSNAP0008E": _("Unable to retrieve current snapshot on virtual machine '%(vm)s'. Details: %(err)s"),
 }
diff --git a/src/kimchi/mockmodel.py b/src/kimchi/mockmodel.py
index 50c6e0c..33aaa33 100644
--- a/src/kimchi/mockmodel.py
+++ b/src/kimchi/mockmodel.py
@@ -987,12 +987,12 @@ class MockModel(object):
 
         vm = self._get_vm(vm_name)
 
-        parent = u''
-        for sn, s in vm.snapshots.iteritems():
-            if s.current:
-                s.current = False
-                parent = sn
-                break
+        try:
+            parent = self.currentvmsnapshot_lookup(vm_name)['name']
+        except NotFoundError:
+            parent = u''
+        else:
+            vm.snapshots[parent].current = False
 
         snap_info = {'parent': parent,
                      'state': vm.info['state']}
@@ -1004,6 +1004,15 @@ class MockModel(object):
         vm = self._get_vm(vm_name)
         return sorted(vm.snapshots.keys(), key=unicode.lower)
 
+    def currentvmsnapshot_lookup(self, vm_name):
+        vm = self._get_vm(vm_name)
+
+        for sn, s in vm.snapshots.iteritems():
+            if s.current:
+                return s.info
+
+        raise NotFoundError('KCHSNAP0007E', {'vm': vm_name})
+
     def vmsnapshot_lookup(self, vm_name, name):
         vm = self._get_vm(vm_name)
 
diff --git a/src/kimchi/model/vmsnapshots.py b/src/kimchi/model/vmsnapshots.py
index e02108d..8d6c296 100644
--- a/src/kimchi/model/vmsnapshots.py
+++ b/src/kimchi/model/vmsnapshots.py
@@ -156,3 +156,27 @@ class VMSnapshotModel(object):
                 raise OperationFailed('KCHSNAP0004E', {'name': name,
                                                        'vm': vm_name,
                                                        'err': e.message})
+
+
+class CurrentVMSnapshotModel(object):
+    def __init__(self, **kargs):
+        self.conn = kargs['conn']
+        self.vmsnapshot = VMSnapshotModel(**kargs)
+
+    def lookup(self, vm_name):
+        vir_dom = VMModel.get_vm(vm_name, self.conn)
+
+        try:
+            vir_snap = vir_dom.snapshotCurrent(0)
+            snap_name = vir_snap.getName().decode('utf-8')
+        except libvirt.libvirtError, e:
+            # If there is no current snapshot, "snapshotCurrent" raises an
+            # exception with the error code referenced below. In that case,
+            # return an empty dict.
+            if e.get_error_code() == libvirt.VIR_ERR_NO_DOMAIN_SNAPSHOT:
+                raise NotFoundError('KCHSNAP007E', {'vm': vm_name})
+
+            raise OperationFailed('KCHSNAP0008E',
+                                  {'vm': vm_name, 'err': e.message})
+
+        return self.vmsnapshot.lookup(vm_name, snap_name)
diff --git a/tests/test_rest.py b/tests/test_rest.py
index ef0fbf3..1129aec 100644
--- a/tests/test_rest.py
+++ b/tests/test_rest.py
@@ -386,6 +386,10 @@ class RestTests(unittest.TestCase):
 
         self.assertEquals(original_vm_info, clone_vm_info)
 
+        # Look up current snapshot when there is no snapshot
+        resp = self.request('/vms/test-vm/snapshots/current', '{}', 'GET')
+        self.assertEquals(404, resp.status)
+
         # Create a snapshot on a stopped VM
         params = {'name': 'test-snap'}
         resp = self.request('/vms/test-vm/snapshots', json.dumps(params),
@@ -413,9 +417,16 @@ class RestTests(unittest.TestCase):
         snaps = json.loads(resp.read())
         self.assertEquals(1, len(snaps))
 
+        # Look up current snapshot (the one created above)
+        resp = self.request('/vms/test-vm/snapshots/current', '{}', 'GET')
+        self.assertEquals(200, resp.status)
+        snap = json.loads(resp.read())
+        self.assertEquals(params['name'], snap['name'])
+
         resp = self.request('/vms/test-vm/snapshots', '{}', 'POST')
         self.assertEquals(202, resp.status)
         task = json.loads(resp.read())
+        snap_name = task['target_uri'].split('/')[-1]
         wait_task(self._task_lookup, task['id'])
         resp = self.request('/tasks/%s' % task['id'], '{}', 'GET')
         task = json.loads(resp.read())
@@ -426,6 +437,12 @@ class RestTests(unittest.TestCase):
         snaps = json.loads(resp.read())
         self.assertEquals(2, len(snaps))
 
+        # Look up current snapshot (the one created above)
+        resp = self.request('/vms/test-vm/snapshots/current', '{}', 'GET')
+        self.assertEquals(200, resp.status)
+        snap = json.loads(resp.read())
+        self.assertEquals(snap_name, snap['name'])
+
         # Delete a snapshot
         resp = self.request('/vms/test-vm/snapshots/foobar', '{}', 'DELETE')
         self.assertEquals(404, resp.status)
-- 
1.9.3




More information about the Kimchi-devel mailing list