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