
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@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 | 21 +++++++++++++++++++++ tests/test_rest.py | 17 +++++++++++++++++ 6 files changed, 72 insertions(+), 6 deletions(-) diff --git a/docs/API.md b/docs/API.md index 9e7365a..23c787b 100644 --- a/docs/API.md +++ b/docs/API.md @@ -207,6 +207,10 @@ Represents a snapshot of the Virtual Machine's primary monitor. * **DELETE**: Delete snapshot. If the snapshot has any children, they will be merged automatically with the snapshot's parent. +### 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 480cb8e..75855f6 100644 --- a/src/kimchi/mockmodel.py +++ b/src/kimchi/mockmodel.py @@ -983,12 +983,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']} @@ -1000,6 +1000,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 b66cd99..b6702b9 100644 --- a/src/kimchi/model/vmsnapshots.py +++ b/src/kimchi/model/vmsnapshots.py @@ -152,3 +152,24 @@ 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 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