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;
* parent: The name of the parent snapshot;
* state: The corresponding VM state when the snapshot was created
(currently, it can only be 'shutoff');
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 | 8 ++++++++
src/kimchi/model/vmsnapshots.py | 43 +++++++++++++++++++++++++++++++++++++++++
tests/test_rest.py | 12 ++++++++++++
5 files changed, 75 insertions(+)
diff --git a/docs/API.md b/docs/API.md
index fe1c3cf..44cc825 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.
+ * created: The time when the snapshot was created
+ (in seconds, since the epoch).
+ * name: The snapshot name.
+ * parent: The name of the parent snapshot, or an empty string if there is
+ no parent.
+ * state: The corresponding domain's state when the snapshot was created.
+
### 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 211ae66..b6fb531 100644
--- a/src/kimchi/mockmodel.py
+++ b/src/kimchi/mockmodel.py
@@ -996,6 +996,14 @@ class MockModel(object):
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')
diff --git a/src/kimchi/model/vmsnapshots.py b/src/kimchi/model/vmsnapshots.py
index 1512d9e..1ce6e9f 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
@@ -89,3 +90,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 {'created': unicode(snap_xml.creationTime),
+ 'name': unicode(snap_xml.name),
+ 'parent': parent,
+ 'state': unicode(snap_xml.state)}
+
+ 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