<div dir="ltr">Right. We should only apply this patch when the UI gets updated accordingly.<br></div><br><div class="gmail_quote">On Mon, Apr 27, 2015 at 12:37 PM Aline Manera &lt;<a href="mailto:alinefm@linux.vnet.ibm.com">alinefm@linux.vnet.ibm.com</a>&gt; wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><br>
<br>
The UI needs to be changed accordingly, right?<br>
Otherwise, the user will get an unstable behaviour while reverting a<br>
snapshot with the current upstream UI<br>
<br>
On 20/04/2015 15:58, Crístian Deives wrote:<br>
&gt; The action &#39;revert&#39; is currently synchronous; that means that there&#39;s no<br>
&gt; way for the user to run it in background and check its status<br>
&gt; periodically. In some cases, reverting a snapshot can take a a few<br>
&gt; seconds/minutes to finish, so the best option is to change it to an<br>
&gt; asynchronous call.<br>
&gt;<br>
&gt; Change the implementation of the action &#39;revert&#39; so it returns an<br>
&gt; asynchronous Task.<br>
&gt;<br>
&gt; Signed-off-by: Crístian Deives &lt;<a href="mailto:cristiandeives@gmail.com" target="_blank">cristiandeives@gmail.com</a>&gt;<br>
&gt; ---<br>
&gt;   src/kimchi/control/vm/snapshots.py |  2 +-<br>
&gt;   src/kimchi/mockmodel.py            | 11 +++++++++++<br>
&gt;   src/kimchi/model/vmsnapshots.py    | 28 ++++++++++++++++++++--------<br>
&gt;   tests/test_model.py                |  6 ++++--<br>
&gt;   tests/test_rest.py                 |  9 +++++++++<br>
&gt;   5 files changed, 45 insertions(+), 11 deletions(-)<br>
&gt;<br>
&gt; diff --git a/src/kimchi/control/vm/snapshots.py b/src/kimchi/control/vm/snapshots.py<br>
&gt; index bbebc9a..4847d59 100644<br>
&gt; --- a/src/kimchi/control/vm/snapshots.py<br>
&gt; +++ b/src/kimchi/control/vm/snapshots.py<br>
&gt; @@ -39,7 +39,7 @@ class VMSnapshot(Resource):<br>
&gt;           self.ident = ident<br>
&gt;           self.model_args = [self.vm, self.ident]<br>
&gt;           self.uri_fmt = &#39;/vms/%s/snapshots/%s&#39;<br>
&gt; -        self.revert = self.generate_action_handler(&#39;revert&#39;)<br>
&gt; +        self.revert = self.generate_action_handler_task(&#39;revert&#39;)<br>
&gt;<br>
&gt;       @property<br>
&gt;       def data(self):<br>
&gt; diff --git a/src/kimchi/mockmodel.py b/src/kimchi/mockmodel.py<br>
&gt; index dcb8bc1..286f903 100644<br>
&gt; --- a/src/kimchi/mockmodel.py<br>
&gt; +++ b/src/kimchi/mockmodel.py<br>
&gt; @@ -431,6 +431,15 @@ class MockModel(Model):<br>
&gt;           MockModel._mock_snapshots[vm_name] = snapshots<br>
&gt;<br>
&gt;       def _mock_vmsnapshot_revert(self, vm_name, name):<br>
&gt; +        params = {&#39;vm_name&#39;: vm_name, &#39;name&#39;: name}<br>
&gt; +        taskid = add_task(u&#39;/vms/%s/snapshots/%s/revert&#39; % (vm_name, name),<br>
&gt; +                          self._vmsnapshot_revert_task, self.objstore, params)<br>
&gt; +        return self.task_lookup(taskid)<br>
&gt; +<br>
&gt; +    def _vmsnapshot_revert_task(self, cb, params):<br>
&gt; +        vm_name = params[&#39;vm_name&#39;]<br>
&gt; +        name = params[&#39;name&#39;]<br>
&gt; +<br>
&gt;           snapshots = MockModel._mock_snapshots.get(vm_name, [])<br>
&gt;           for sn in snapshots:<br>
&gt;               if sn.current:<br>
&gt; @@ -440,6 +449,8 @@ class MockModel(Model):<br>
&gt;               if <a href="http://sn.name" target="_blank">sn.name</a> == name:<br>
&gt;                   sn.current = True<br>
&gt;<br>
&gt; +        cb(&#39;OK&#39;, True)<br>
&gt; +<br>
&gt;<br>
&gt;   class MockStorageVolumes(object):<br>
&gt;       def __init__(self):<br>
&gt; diff --git a/src/kimchi/model/vmsnapshots.py b/src/kimchi/model/vmsnapshots.py<br>
&gt; index 3a92cdc..331f532 100644<br>
&gt; --- a/src/kimchi/model/vmsnapshots.py<br>
&gt; +++ b/src/kimchi/model/vmsnapshots.py<br>
&gt; @@ -29,7 +29,6 @@ from kimchi.model.tasks import TaskModel<br>
&gt;   from kimchi.model.vms import DOM_STATE_MAP, VMModel<br>
&gt;   from kimchi.model.vmstorages import VMStorageModel, VMStoragesModel<br>
&gt;   from kimchi.utils import add_task<br>
&gt; -from kimchi.xmlutils.utils import xpath_get_text<br>
&gt;<br>
&gt;<br>
&gt;   class VMSnapshotsModel(object):<br>
&gt; @@ -120,6 +119,8 @@ class VMSnapshotsModel(object):<br>
&gt;   class VMSnapshotModel(object):<br>
&gt;       def __init__(self, **kargs):<br>
&gt;           self.conn = kargs[&#39;conn&#39;]<br>
&gt; +        self.objstore = kargs[&#39;objstore&#39;]<br>
&gt; +        self.task = TaskModel(**kargs)<br>
&gt;<br>
&gt;       def lookup(self, vm_name, name):<br>
&gt;           vir_snap = self.get_vmsnapshot(vm_name, name)<br>
&gt; @@ -153,19 +154,30 @@ class VMSnapshotModel(object):<br>
&gt;                                                      &#39;err&#39;: e.message})<br>
&gt;<br>
&gt;       def revert(self, vm_name, name):<br>
&gt; +        vir_dom = VMModel.get_vm(vm_name, self.conn)<br>
&gt; +        vir_snap = self.get_vmsnapshot(vm_name, name)<br>
&gt; +<br>
&gt; +        task_params = {&#39;name&#39;: name, &#39;vm_name&#39;: vm_name,<br>
&gt; +                       &#39;dom&#39;: vir_dom, &#39;snap&#39;: vir_snap}<br>
&gt; +        taskid = add_task(u&#39;/vms/%s/snapshots/%s/revert&#39; % (vm_name, name),<br>
&gt; +                          self._revert_task, self.objstore, task_params)<br>
&gt; +        return self.task.lookup(taskid)<br>
&gt; +<br>
&gt; +    def _revert_task(self, cb, params):<br>
&gt; +        vir_dom = params[&#39;dom&#39;]<br>
&gt; +        vir_snap = params[&#39;snap&#39;]<br>
&gt; +<br>
&gt;           try:<br>
&gt; -            vir_dom = VMModel.get_vm(vm_name, self.conn)<br>
&gt; -            vir_snap = self.get_vmsnapshot(vm_name, name)<br>
&gt; +            cb(&#39;reverting to snapshot&#39;)<br>
&gt;               vir_dom.revertToSnapshot(vir_snap, 0)<br>
&gt; -<br>
&gt; -            # get vm name recorded in the snapshot and return new uri params<br>
&gt; -            vm_new_name = xpath_get_text(vir_snap.getXMLDesc(0),<br>
&gt; -                                         &#39;domain/name&#39;)[0]<br>
&gt; -            return [vm_new_name, name]<br>
&gt;           except libvirt.libvirtError, e:<br>
&gt; +            name = params[&#39;name&#39;]<br>
&gt; +            vm_name = params[&#39;vm_name&#39;]<br>
&gt; +<br>
&gt;               raise OperationFailed(&#39;KCHSNAP0009E&#39;, {&#39;name&#39;: name,<br>
&gt;                                                      &#39;vm&#39;: vm_name,<br>
&gt;                                                      &#39;err&#39;: e.message})<br>
&gt; +        cb(&#39;OK&#39;, True)<br>
&gt;<br>
&gt;       def get_vmsnapshot(self, vm_name, name):<br>
&gt;           vir_dom = VMModel.get_vm(vm_name, self.conn)<br>
&gt; diff --git a/tests/test_model.py b/tests/test_model.py<br>
&gt; index c25929f..b53822a 100644<br>
&gt; --- a/tests/test_model.py<br>
&gt; +++ b/tests/test_model.py<br>
&gt; @@ -198,8 +198,10 @@ class ModelTests(unittest.TestCase):<br>
&gt;               snap = inst.vmsnapshot_lookup(u&#39;kimchi-vm-new&#39;, params[&#39;name&#39;])<br>
&gt;<br>
&gt;               # snapshot revert to the first created vm<br>
&gt; -            result = inst.vmsnapshot_revert(u&#39;kimchi-vm-new&#39;, params[&#39;name&#39;])<br>
&gt; -            self.assertEquals(result, [u&#39;kimchi-vm&#39;, snap[&#39;name&#39;]])<br>
&gt; +            task = inst.vmsnapshot_revert(u&#39;kimchi-vm-new&#39;, params[&#39;name&#39;])<br>
&gt; +            inst.task_wait(task[&#39;id&#39;])<br>
&gt; +            task = inst.task_lookup(task[&#39;id&#39;])<br>
&gt; +            self.assertEquals(&#39;finished&#39;, task[&#39;status&#39;])<br>
&gt;<br>
&gt;               vm = inst.vm_lookup(u&#39;kimchi-vm&#39;)<br>
&gt;               self.assertEquals(vm[&#39;state&#39;], snap[&#39;state&#39;])<br>
&gt; diff --git a/tests/test_rest.py b/tests/test_rest.py<br>
&gt; index c1b81e8..3b592d6 100644<br>
&gt; --- a/tests/test_rest.py<br>
&gt; +++ b/tests/test_rest.py<br>
&gt; @@ -382,6 +382,15 @@ class RestTests(unittest.TestCase):<br>
&gt;           # Revert to snapshot<br>
&gt;           resp = self.request(&#39;/vms/test-vm/snapshots/%s/revert&#39; %<br>
&gt;                               params[&#39;name&#39;], &#39;{}&#39;, &#39;POST&#39;)<br>
&gt; +        self.assertEquals(202, resp.status)<br>
&gt; +        task = json.loads(resp.read())<br>
&gt; +        wait_task(self._task_lookup, task[&#39;id&#39;])<br>
&gt; +        resp = self.request(&#39;/tasks/%s&#39; % task[&#39;id&#39;], &#39;{}&#39;, &#39;GET&#39;)<br>
&gt; +        task = json.loads(resp.read())<br>
&gt; +        self.assertEquals(&#39;finished&#39;, task[&#39;status&#39;])<br>
&gt; +<br>
&gt; +        resp = self.request(&#39;/vms/test-vm/snapshots/%s&#39; % params[&#39;name&#39;],<br>
&gt; +                            &#39;{}&#39;, &#39;GET&#39;)<br>
&gt;           self.assertEquals(200, resp.status)<br>
&gt;           snap = json.loads(resp.read())<br>
&gt;           resp = self.request(&#39;/vms/test-vm&#39;, &#39;{}&#39;, &#39;GET&#39;)<br>
<br>
</blockquote></div>