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(a)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