Explorar o código

Fix a flaky issue with task percentage not being properly send to Conductor

Fabian Fulga hai 2 semanas
pai
achega
d131231d17

+ 14 - 4
coriolis/conductor/rpc/client.py

@@ -323,8 +323,17 @@ class ConductorClient(rpc.BaseRPCClient):
 
     def update_task_progress_update(
             self, ctxt, task_id, progress_update_index, new_current_step,
-            new_total_steps=None, new_message=None):
-        self._cast(
+            new_total_steps=None, new_message=None, sync=False):
+        # Use _call on the last step to make sure the DB is updated
+        # and the UI is showing the correct progress.
+        # Intermediate steps use cast to avoid blocking on every tick.
+        if sync:
+            return self._call(
+                ctxt, 'update_task_progress_update', task_id=task_id,
+                progress_update_index=progress_update_index,
+                new_current_step=new_current_step,
+                new_total_steps=new_total_steps, new_message=new_message)
+        return self._cast(
             ctxt, 'update_task_progress_update', task_id=task_id,
             progress_update_index=progress_update_index,
             new_current_step=new_current_step,
@@ -498,13 +507,14 @@ class ConductorTaskRpcEventHandler(events.BaseEventHandler):
 
     def update_progress_update(
             self, update_identifier, new_current_step,
-            new_total_steps=None, new_message=None):
+            new_total_steps=None, new_message=None, sync=False):
         LOG.info(
             "Updating progress update '%s' for task '%s' with new step %s",
             update_identifier, self._task_id, new_current_step)
         self._rpc_conductor_client.update_task_progress_update(
             self._ctxt, self._task_id, update_identifier, new_current_step,
-            new_total_steps=new_total_steps, new_message=new_message)
+            new_total_steps=new_total_steps, new_message=new_message,
+            sync=sync)
 
     def add_event(self, message, level=constants.TASK_EVENT_INFO):
         self._rpc_conductor_client.add_task_event(

+ 5 - 2
coriolis/events.py

@@ -76,9 +76,12 @@ class EventManager(object, with_metaclass(abc.ABCMeta)):
             perc = int(new_current_step * 100 // perc_step.total_steps)
 
         if self._call_event_handler and perc > perc_step.last_perc:
+            sync_final = (
+                perc_step.total_steps > 0 and
+                new_current_step >= perc_step.total_steps)
             self._call_event_handler(
                 'update_progress_update', step.progress_update_id,
-                new_current_step)
+                new_current_step, sync=sync_final)
             perc_id = copy.copy(step.progress_update_id)
             total_steps = perc_step.total_steps
             del self._perc_steps[step.progress_update_id]
@@ -114,7 +117,7 @@ class BaseEventHandler(object, with_metaclass(abc.ABCMeta)):
     @abc.abstractmethod
     def update_progress_update(
             self, update_identifier, new_current_step,
-            new_total_steps=None, new_message=None):
+            new_total_steps=None, new_message=None, sync=False):
         pass
 
     @classmethod

+ 1 - 1
coriolis/minion_manager/rpc/client.py

@@ -205,7 +205,7 @@ class MinionManagerPoolRpcEventHandler(events.BaseEventHandler):
 
     def update_progress_update(
             self, update_identifier, new_current_step,
-            new_total_steps=None, new_message=None):
+            new_total_steps=None, new_message=None, sync=False):
         LOG.info(
             "Updating progress update '%s' for pool '%s' with new step %s",
             update_identifier, self._pool_id, new_current_step)

+ 19 - 3
coriolis/tests/conductor/rpc/test_client.py

@@ -297,8 +297,23 @@ class ConductorClientTestCase(test_base.CoriolisRPCClientTestCase):
             "new_total_steps": None,
             "new_message": None
         }
-        self._test(self.client.update_task_progress_update, args,
-                   rpc_op='_cast')
+        self._test(
+            self.client.update_task_progress_update, args, rpc_op='_cast')
+
+    def test_update_task_progress_update_sync_final(self):
+        args = {
+            "task_id": "mock_task_id",
+            "progress_update_index": "mock_progress_update_index",
+            "new_current_step": "mock_new_current_step",
+            "new_total_steps": None,
+            "new_message": None,
+        }
+        with mock.patch.object(self.client, '_call') as op_mock:
+            ctxt = mock.sentinel.ctxt
+            self.client.update_task_progress_update(
+                ctxt, sync=True, **args)
+            op_mock.assert_called_once_with(
+                ctxt, 'update_task_progress_update', **args)
 
     def test_create_transfer_schedule(self):
         args = {
@@ -539,7 +554,8 @@ class ConductorTaskRpcEventHandlerTestCase(test_base.CoriolisBaseTestCase):
             update_identifier,
             new_current_step,
             new_total_steps=new_total_steps,
-            new_message=new_message
+            new_message=new_message,
+            sync=False,
         )
 
     @mock.patch.object(client.ConductorClient, 'add_task_event')

+ 13 - 0
coriolis/tests/test_events.py

@@ -110,6 +110,19 @@ class EventManagerTestCase(test_base.CoriolisBaseTestCase):
             mock.sentinel.progress_update_id: events._PercStepData(
                 mock.sentinel.progress_update_id, 60, 0, 100)}
         self.assertEqual(self.event_manager._perc_steps, expected_perc_steps)
+        self.mock_event_handler.update_progress_update.assert_called_once_with(
+            mock.sentinel.progress_update_id, 60, sync=False)
+
+    def test_set_percentage_step_sync_final_update(self):
+        perc_step_data = events._PercStepData(
+            mock.sentinel.progress_update_id, 90, 0, 100)
+        self.event_manager._perc_steps[
+            mock.sentinel.progress_update_id] = perc_step_data
+
+        self.event_manager.set_percentage_step(perc_step_data, 100)
+
+        self.mock_event_handler.update_progress_update.assert_called_once_with(
+            mock.sentinel.progress_update_id, 100, sync=True)
 
     def test_set_percentage_step_no_perc_step(self):
         self.event_manager.set_percentage_step(