088c30
From f11bbe7f04a48eebcb446e283820d7592f76cf86 Mon Sep 17 00:00:00 2001
088c30
From: Johnson Shi <Johnson.Shi@microsoft.com>
088c30
Date: Thu, 25 Mar 2021 07:20:10 -0700
088c30
Subject: [PATCH 2/7] Azure helper: Ensure Azure http handler sleeps between
088c30
 retries (#842)
088c30
088c30
RH-Author: Eduardo Otubo <otubo@redhat.com>
088c30
RH-MergeRequest: 45: Add support for userdata on Azure from IMDS
088c30
RH-Commit: [2/7] e8f8bb658b629a8444bd2ba19f109952acf33311
088c30
RH-Bugzilla: 2023940
088c30
RH-Acked-by: Emanuele Giuseppe Esposito <eesposit@redhat.com>
088c30
RH-Acked-by: Mohamed Gamal Morsy <mmorsy@redhat.com>
088c30
088c30
Ensure that the Azure helper's http handler sleeps a fixed duration
088c30
between retry failure attempts. The http handler will sleep a fixed
088c30
duration between failed attempts regardless of whether the attempt
088c30
failed due to (1) request timing out or (2) instant failure (no
088c30
timeout).
088c30
088c30
Due to certain platform issues, the http request to the Azure endpoint
088c30
may instantly fail without reaching the http timeout duration. Without
088c30
sleeping a fixed duration in between retry attempts, the http handler
088c30
will loop through the max retry attempts quickly. This causes the
088c30
communication between cloud-init and the Azure platform to be less
088c30
resilient due to the short total duration if there is no sleep in
088c30
between retries.
088c30
---
088c30
 cloudinit/sources/helpers/azure.py                   |  2 ++
088c30
 tests/unittests/test_datasource/test_azure_helper.py | 11 +++++++++--
088c30
 2 files changed, 11 insertions(+), 2 deletions(-)
088c30
088c30
diff --git a/cloudinit/sources/helpers/azure.py b/cloudinit/sources/helpers/azure.py
088c30
index d3055d08..03e7156b 100755
088c30
--- a/cloudinit/sources/helpers/azure.py
088c30
+++ b/cloudinit/sources/helpers/azure.py
088c30
@@ -303,6 +303,7 @@ def http_with_retries(url, **kwargs) -> str:
088c30
 
088c30
     max_readurl_attempts = 240
088c30
     default_readurl_timeout = 5
088c30
+    sleep_duration_between_retries = 5
088c30
     periodic_logging_attempts = 12
088c30
 
088c30
     if 'timeout' not in kwargs:
088c30
@@ -338,6 +339,7 @@ def http_with_retries(url, **kwargs) -> str:
088c30
                     'attempt %d with exception: %s' %
088c30
                     (url, attempt, e),
088c30
                     logger_func=LOG.debug)
088c30
+            time.sleep(sleep_duration_between_retries)
088c30
 
088c30
     raise exc
088c30
 
088c30
diff --git a/tests/unittests/test_datasource/test_azure_helper.py b/tests/unittests/test_datasource/test_azure_helper.py
088c30
index b8899807..63482c6c 100644
088c30
--- a/tests/unittests/test_datasource/test_azure_helper.py
088c30
+++ b/tests/unittests/test_datasource/test_azure_helper.py
088c30
@@ -384,6 +384,7 @@ class TestAzureHelperHttpWithRetries(CiTestCase):
088c30
 
088c30
     max_readurl_attempts = 240
088c30
     default_readurl_timeout = 5
088c30
+    sleep_duration_between_retries = 5
088c30
     periodic_logging_attempts = 12
088c30
 
088c30
     def setUp(self):
088c30
@@ -394,8 +395,8 @@ class TestAzureHelperHttpWithRetries(CiTestCase):
088c30
         self.m_readurl = patches.enter_context(
088c30
             mock.patch.object(
088c30
                 azure_helper.url_helper, 'readurl', mock.MagicMock()))
088c30
-        patches.enter_context(
088c30
-            mock.patch.object(azure_helper.time, 'sleep', mock.MagicMock()))
088c30
+        self.m_sleep = patches.enter_context(
088c30
+            mock.patch.object(azure_helper.time, 'sleep', autospec=True))
088c30
 
088c30
     def test_http_with_retries(self):
088c30
         self.m_readurl.return_value = 'TestResp'
088c30
@@ -438,6 +439,12 @@ class TestAzureHelperHttpWithRetries(CiTestCase):
088c30
             self.m_readurl.call_count,
088c30
             self.periodic_logging_attempts + 1)
088c30
 
088c30
+        # Ensure that cloud-init did sleep between each failed request
088c30
+        self.assertEqual(
088c30
+            self.m_sleep.call_count,
088c30
+            self.periodic_logging_attempts)
088c30
+        self.m_sleep.assert_called_with(self.sleep_duration_between_retries)
088c30
+
088c30
     def test_http_with_retries_long_delay_logs_periodic_failure_msg(self):
088c30
         self.m_readurl.side_effect = \
088c30
             [SentinelException] * self.periodic_logging_attempts + \
088c30
-- 
088c30
2.27.0
088c30