diff --git a/azurelinuxagent/common/version.py b/azurelinuxagent/common/version.py index cee08b7989..512670bd8d 100644 --- a/azurelinuxagent/common/version.py +++ b/azurelinuxagent/common/version.py @@ -119,7 +119,7 @@ def get_distro(): AGENT_NAME = "WALinuxAgent" AGENT_LONG_NAME = "Azure Linux Agent" -AGENT_VERSION = '2.2.41' +AGENT_VERSION = '2.2.42' AGENT_LONG_VERSION = "{0}-{1}".format(AGENT_NAME, AGENT_VERSION) AGENT_DESCRIPTION = """ The Azure Linux Agent supports the provisioning and running of Linux diff --git a/azurelinuxagent/ga/exthandlers.py b/azurelinuxagent/ga/exthandlers.py index 6a1bd697b8..806c232297 100644 --- a/azurelinuxagent/ga/exthandlers.py +++ b/azurelinuxagent/ga/exthandlers.py @@ -246,8 +246,10 @@ def run(self): logger.verbose(msg) # Log status report success on new config self.log_report = True - self.handle_ext_handlers(etag) - self.last_etag = etag + + if self.extension_processing_allowed(): + self.handle_ext_handlers(etag) + self.last_etag = etag self.report_ext_handlers_status() self.cleanup_outdated_handlers() @@ -320,15 +322,10 @@ def cleanup_outdated_handlers(self): except OSError as e: logger.warn("Failed to remove extension package {0}: {1}".format(pkg, e.strerror)) - def handle_ext_handlers(self, etag=None): + def extension_processing_allowed(self): if not conf.get_extensions_enabled(): logger.verbose("Extension handling is disabled") - return - - if self.ext_handlers.extHandlers is None or \ - len(self.ext_handlers.extHandlers) == 0: - logger.verbose("No extension handler config found") - return + return False if conf.get_enable_overprovisioning(): if not self.protocol.supports_overprovisioning(): @@ -337,7 +334,15 @@ def handle_ext_handlers(self, etag=None): artifacts_profile = self.protocol.get_artifacts_profile() if artifacts_profile and artifacts_profile.is_on_hold(): logger.info("Extension handling is on hold") - return + return False + + return True + + def handle_ext_handlers(self, etag=None): + if self.ext_handlers.extHandlers is None or \ + len(self.ext_handlers.extHandlers) == 0: + logger.verbose("No extension handler config found") + return wait_until = datetime.datetime.utcnow() + datetime.timedelta(minutes=DEFAULT_EXT_TIMEOUT_MINUTES) max_dep_level = max([handler.sort_key() for handler in self.ext_handlers.extHandlers]) diff --git a/tests/data/ga/WALinuxAgent-2.2.41.zip b/tests/data/ga/WALinuxAgent-2.2.41.zip deleted file mode 100644 index eb0207adb3..0000000000 Binary files a/tests/data/ga/WALinuxAgent-2.2.41.zip and /dev/null differ diff --git a/tests/data/ga/WALinuxAgent-2.2.42.zip b/tests/data/ga/WALinuxAgent-2.2.42.zip new file mode 100644 index 0000000000..e1b306bf53 Binary files /dev/null and b/tests/data/ga/WALinuxAgent-2.2.42.zip differ diff --git a/tests/ga/test_extension.py b/tests/ga/test_extension.py index 51d25b8033..097bbf44d3 100644 --- a/tests/ga/test_extension.py +++ b/tests/ga/test_extension.py @@ -753,6 +753,39 @@ def test_ext_handler_io_error(self, mock_fileutil, *args): mock_fileutil.write_file.return_value = IOError("Mock IO Error") exthandlers_handler.run() + def test_extension_processing_allowed(self, *args): + exthandlers_handler = get_exthandlers_handler() + exthandlers_handler.protocol = Mock() + + # disable extension handling in configuration + with patch.object(conf, 'get_extensions_enabled', return_value=False): + self.assertFalse(exthandlers_handler.extension_processing_allowed()) + + # enable extension handling in configuration + with patch.object(conf, "get_extensions_enabled", return_value=True): + + # disable overprovisioning in configuration + with patch.object(conf, 'get_enable_overprovisioning', return_value=False): + self.assertTrue(exthandlers_handler.extension_processing_allowed()) + + # enable overprovisioning in configuration + with patch.object(conf, "get_enable_overprovisioning", return_value=True): + + # disable protocol support for over-provisioning + with patch.object(exthandlers_handler.protocol, 'supports_overprovisioning', return_value=False): + self.assertTrue(exthandlers_handler.extension_processing_allowed()) + + # enable protocol support for over-provisioning + with patch.object(exthandlers_handler.protocol, "supports_overprovisioning", return_value=True): + + with patch.object(exthandlers_handler.protocol.get_artifacts_profile(), "is_on_hold", + side_effect=[True, False]): + # Enable on_hold property in artifact_blob + self.assertFalse(exthandlers_handler.extension_processing_allowed()) + + # Disable on_hold property in artifact_blob + self.assertTrue(exthandlers_handler.extension_processing_allowed()) + def test_handle_ext_handlers_on_hold_true(self, *args): test_data = WireProtocolData(DATA_FILE) exthandlers_handler, protocol = self._create_mock(test_data, *args) @@ -761,16 +794,16 @@ def test_handle_ext_handlers_on_hold_true(self, *args): exthandlers_handler.protocol = protocol # Disable extension handling blocking - conf.get_enable_overprovisioning = Mock(return_value=False) - with patch.object(ExtHandlersHandler, 'handle_ext_handler') as patch_handle_ext_handler: - exthandlers_handler.handle_ext_handlers() - self.assertEqual(1, patch_handle_ext_handler.call_count) + exthandlers_handler.extension_processing_allowed = Mock(return_value=False) + with patch.object(ExtHandlersHandler, 'handle_ext_handlers') as patch_handle_ext_handlers: + exthandlers_handler.run() + self.assertEqual(0, patch_handle_ext_handlers.call_count) # enable extension handling blocking - conf.get_enable_overprovisioning = Mock(return_value=True) - with patch.object(ExtHandlersHandler, 'handle_ext_handler') as patch_handle_ext_handler: - exthandlers_handler.handle_ext_handlers() - self.assertEqual(0, patch_handle_ext_handler.call_count) + exthandlers_handler.extension_processing_allowed = Mock(return_value=True) + with patch.object(ExtHandlersHandler, 'handle_ext_handlers') as patch_handle_ext_handlers: + exthandlers_handler.run() + self.assertEqual(1, patch_handle_ext_handlers.call_count) def test_handle_ext_handlers_on_hold_false(self, *args): test_data = WireProtocolData(DATA_FILE) @@ -796,6 +829,25 @@ def test_handle_ext_handlers_on_hold_false(self, *args): exthandlers_handler.handle_ext_handlers() self.assertEqual(1, patch_handle_ext_handler.call_count) + def test_last_etag_on_extension_processing(self, *args): + test_data = WireProtocolData(DATA_FILE) + exthandlers_handler, protocol = self._create_mock(test_data, *args) + exthandlers_handler.ext_handlers, etag = protocol.get_ext_handlers() + exthandlers_handler.protocol = protocol + + # Disable extension handling blocking in the first run and enable in the 2nd run + with patch.object(exthandlers_handler, 'extension_processing_allowed', side_effect=[False, True]): + exthandlers_handler.run() + self.assertIsNone(exthandlers_handler.last_etag, + "The last etag should be None initially as extension_processing is False") + self.assertNotEqual(etag, exthandlers_handler.last_etag, + "Last etag and etag should not be same if extension processing is disabled") + exthandlers_handler.run() + self.assertIsNotNone(exthandlers_handler.last_etag, + "Last etag should not be none if extension processing is allowed") + self.assertEqual(etag, exthandlers_handler.last_etag, + "Last etag and etag should be same if extension processing is enabled") + def _assert_ext_status(self, report_ext_status, expected_status, expected_seq_no): self.assertTrue(report_ext_status.called)