From 3e595d8026f088694a402b7898e4f986911e0fce Mon Sep 17 00:00:00 2001 From: Dao Cong Tien Date: Thu, 31 Oct 2019 15:48:32 +0700 Subject: [PATCH] Adds a sleep(3s) after performing power on/off/reset In async mode, performing power on/off/reset will return immediately. However, if we perform multiple power actions in parallel or in a tight sequence, an Error 5 (Input/Output error) will happen. This bug can be reproduced by doing RAID config from Ironic CLI. This patch adds a sleep of 3 seconds to make sure calling code can't perform some power actions too quickly. Change-Id: Iacf43a2ca34822b2b59683f4c5b08b78074e5b5f --- scciclient/irmc/scci.py | 10 ++++++++++ scciclient/tests/irmc/test_scci.py | 12 +++++++++--- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/scciclient/irmc/scci.py b/scciclient/irmc/scci.py index 6dc6d30..9965c83 100755 --- a/scciclient/irmc/scci.py +++ b/scciclient/irmc/scci.py @@ -301,6 +301,16 @@ def scci_cmd(host, userid, password, cmd, port=443, auth_method='basic', if not do_async: time.sleep(5) + else: + # Async mode + # Even in async mode, return immediately may cause error 5 + # (Input/Output error) for some commands such as POWER_ON, + # POWER_OFF, POWER_RESET if we perform multiple calls of them + # in a tight sequence or in parallel. + # So, we sleep some time for such commands. + if cmd in (POWER_ON, POWER_OFF, POWER_RESET): + time.sleep(3) + if DEBUG: print(cmd) print(r.text) diff --git a/scciclient/tests/irmc/test_scci.py b/scciclient/tests/irmc/test_scci.py index 2573e15..300045a 100644 --- a/scciclient/tests/irmc/test_scci.py +++ b/scciclient/tests/irmc/test_scci.py @@ -270,7 +270,8 @@ class SCCITestCase(testtools.TestCase): 'HTTP PROTOCOL ERROR, STATUS CODE = 302', str(e)) - def test_power_on_ok(self): + @mock.patch.object(time, 'sleep') + def test_power_on_ok(self, mock_sleep): self.requests_mock.post("http://" + self.irmc_address + "/config", text=""" @@ -287,8 +288,10 @@ class SCCITestCase(testtools.TestCase): client_timeout=self.irmc_client_timeout) r = client(scci.POWER_ON) self.assertEqual(r.status_code, 200) + mock_sleep.assert_called_once_with(3) - def test_power_off_ok(self): + @mock.patch.object(time, 'sleep') + def test_power_off_ok(self, mock_sleep): self.requests_mock.post("http://" + self.irmc_address + "/config", text=""" @@ -305,6 +308,7 @@ class SCCITestCase(testtools.TestCase): client_timeout=self.irmc_client_timeout) r = client(scci.POWER_OFF) self.assertEqual(r.status_code, 200) + mock_sleep.assert_called_once_with(3) def test_power_cycle_ok(self): self.requests_mock.post("http://" + self.irmc_address + "/config", @@ -324,7 +328,8 @@ class SCCITestCase(testtools.TestCase): r = client(scci.POWER_CYCLE) self.assertEqual(r.status_code, 200) - def test_power_reset_ok(self): + @mock.patch.object(time, 'sleep') + def test_power_reset_ok(self, mock_sleep): self.requests_mock.post("http://" + self.irmc_address + "/config", text=""" @@ -341,6 +346,7 @@ class SCCITestCase(testtools.TestCase): client_timeout=self.irmc_client_timeout) r = client(scci.POWER_RESET) self.assertEqual(r.status_code, 200) + mock_sleep.assert_called_once_with(3) def test_power_raise_nmi_ok(self): self.requests_mock.post("http://" + self.irmc_address + "/config",