diff --git a/_lastrevision b/_lastrevision index 1d70143..7b5d4c0 100644 --- a/_lastrevision +++ b/_lastrevision @@ -1 +1 @@ -9cbb16539a0cce2bd2d423ca440ea8b142cc13ea \ No newline at end of file +8fe9649055af571bfa44483318fa5a8476035001 \ No newline at end of file diff --git a/fix-async-batch-multiple-done-events.patch b/fix-async-batch-multiple-done-events.patch new file mode 100644 index 0000000..f399bff --- /dev/null +++ b/fix-async-batch-multiple-done-events.patch @@ -0,0 +1,138 @@ +From 2dcee9c2773f588cc5ca040b1d22c1e8036dcbf7 Mon Sep 17 00:00:00 2001 +From: Mihai Dinca +Date: Tue, 7 May 2019 12:24:35 +0200 +Subject: [PATCH] Fix async-batch multiple done events + +--- + salt/cli/batch_async.py | 17 ++++++++++++----- + tests/unit/cli/test_batch_async.py | 20 +++++++++++++------- + 2 files changed, 25 insertions(+), 12 deletions(-) + +diff --git a/salt/cli/batch_async.py b/salt/cli/batch_async.py +index 9c20b2fc6e..8c8f481e34 100644 +--- a/salt/cli/batch_async.py ++++ b/salt/cli/batch_async.py +@@ -84,6 +84,7 @@ class BatchAsync(object): + listen=True, + io_loop=ioloop, + keep_loop=True) ++ self.scheduled = False + + def __set_event_handler(self): + ping_return_pattern = 'salt/job/{0}/ret/*'.format(self.ping_jid) +@@ -116,8 +117,7 @@ class BatchAsync(object): + if minion in self.active: + self.active.remove(minion) + self.done_minions.add(minion) +- # call later so that we maybe gather more returns +- self.event.io_loop.call_later(self.batch_delay, self.schedule_next) ++ self.schedule_next() + + def _get_next(self): + to_run = self.minions.difference( +@@ -137,7 +137,7 @@ class BatchAsync(object): + self.active = self.active.difference(self.timedout_minions) + running = batch_minions.difference(self.done_minions).difference(self.timedout_minions) + if timedout_minions: +- self.event.io_loop.call_later(self.batch_delay, self.schedule_next) ++ self.schedule_next() + if running: + self.event.io_loop.add_callback(self.find_job, running) + +@@ -189,7 +189,7 @@ class BatchAsync(object): + "metadata": self.metadata + } + self.event.fire_event(data, "salt/batch/{0}/start".format(self.batch_jid)) +- yield self.schedule_next() ++ yield self.run_next() + + def end_batch(self): + left = self.minions.symmetric_difference(self.done_minions.union(self.timedout_minions)) +@@ -204,8 +204,14 @@ class BatchAsync(object): + self.event.fire_event(data, "salt/batch/{0}/done".format(self.batch_jid)) + self.event.remove_event_handler(self.__event_handler) + +- @tornado.gen.coroutine + def schedule_next(self): ++ if not self.scheduled: ++ self.scheduled = True ++ # call later so that we maybe gather more returns ++ self.event.io_loop.call_later(self.batch_delay, self.run_next) ++ ++ @tornado.gen.coroutine ++ def run_next(self): + next_batch = self._get_next() + if next_batch: + self.active = self.active.union(next_batch) +@@ -225,3 +231,4 @@ class BatchAsync(object): + self.active = self.active.difference(next_batch) + else: + self.end_batch() ++ self.scheduled = False +diff --git a/tests/unit/cli/test_batch_async.py b/tests/unit/cli/test_batch_async.py +index d519157d92..441f9c58b9 100644 +--- a/tests/unit/cli/test_batch_async.py ++++ b/tests/unit/cli/test_batch_async.py +@@ -111,14 +111,14 @@ class AsyncBatchTestCase(AsyncTestCase, TestCase): + + @tornado.testing.gen_test + def test_start_batch_calls_next(self): +- self.batch.schedule_next = MagicMock(return_value=MagicMock()) ++ self.batch.run_next = MagicMock(return_value=MagicMock()) + self.batch.event = MagicMock() + future = tornado.gen.Future() + future.set_result(None) +- self.batch.schedule_next = MagicMock(return_value=future) ++ self.batch.run_next = MagicMock(return_value=future) + self.batch.start_batch() + self.assertEqual(self.batch.initialized, True) +- self.assertEqual(len(self.batch.schedule_next.mock_calls), 1) ++ self.assertEqual(len(self.batch.run_next.mock_calls), 1) + + def test_batch_fire_done_event(self): + self.batch.targeted_minions = {'foo', 'baz', 'bar'} +@@ -154,7 +154,7 @@ class AsyncBatchTestCase(AsyncTestCase, TestCase): + future = tornado.gen.Future() + future.set_result({'minions': ['foo', 'bar']}) + self.batch.local.run_job_async.return_value = future +- ret = self.batch.schedule_next().result() ++ ret = self.batch.run_next().result() + self.assertEqual( + self.batch.local.run_job_async.call_args[0], + ({'foo', 'bar'}, 'my.fun', [], 'list') +@@ -253,7 +253,7 @@ class AsyncBatchTestCase(AsyncTestCase, TestCase): + self.assertEqual(self.batch.done_minions, {'foo'}) + self.assertEqual( + self.batch.event.io_loop.call_later.call_args[0], +- (self.batch.batch_delay, self.batch.schedule_next)) ++ (self.batch.batch_delay, self.batch.run_next)) + + def test_batch__event_handler_find_job_return(self): + self.batch.event = MagicMock( +@@ -263,10 +263,10 @@ class AsyncBatchTestCase(AsyncTestCase, TestCase): + self.assertEqual(self.batch.find_job_returned, {'foo'}) + + @tornado.testing.gen_test +- def test_batch_schedule_next_end_batch_when_no_next(self): ++ def test_batch_run_next_end_batch_when_no_next(self): + self.batch.end_batch = MagicMock() + self.batch._get_next = MagicMock(return_value={}) +- self.batch.schedule_next() ++ self.batch.run_next() + self.assertEqual(len(self.batch.end_batch.mock_calls), 1) + + @tornado.testing.gen_test +@@ -342,3 +342,9 @@ class AsyncBatchTestCase(AsyncTestCase, TestCase): + self.batch.event.io_loop.add_callback.call_args[0], + (self.batch.find_job, {'foo'}) + ) ++ ++ def test_only_on_run_next_is_scheduled(self): ++ self.batch.event = MagicMock() ++ self.batch.scheduled = True ++ self.batch.schedule_next() ++ self.assertEqual(len(self.batch.event.io_loop.call_later.mock_calls), 0) +-- +2.21.0 + + diff --git a/salt.changes b/salt.changes index db4764e..270d245 100644 --- a/salt.changes +++ b/salt.changes @@ -1,3 +1,11 @@ +------------------------------------------------------------------- +Wed May 8 08:48:49 UTC 2019 - Mihai Dincă + +- Fix async-batch to fire a single done event + +- Added: + * fix-async-batch-multiple-done-events.patch + ------------------------------------------------------------------- Tue May 7 15:37:39 UTC 2019 - psuarezhernandez@suse.com diff --git a/salt.spec b/salt.spec index bd6107a..2e96e7b 100644 --- a/salt.spec +++ b/salt.spec @@ -171,6 +171,9 @@ Patch51: use-threadpool-from-multiprocessing.pool-to-avoid-le.patch Patch52: fix-syndic-start-issue.patch # PATCH-FIX_UPSTREAM https://github.com/saltstack/salt/pull/52888 Patch53: do-not-crash-when-there-are-ipv6-established-connect.patch +# PATCH-FIX_OPENSUSE: https://github.com/openSUSE/salt/pull/144 +# PATCH-FIX_UPSTREAM: https://github.com/saltstack/salt/pull/52855 +Patch54: fix-async-batch-multiple-done-events.patch # BuildRoot: %{_tmppath}/%{name}-%{version}-build BuildRoot: %{_tmppath}/%{name}-%{version}-build @@ -682,6 +685,7 @@ cp %{S:5} ./.travis.yml %patch51 -p1 %patch52 -p1 %patch53 -p1 +%patch54 -p1 %build %if 0%{?build_py2}