diff --git a/azurelinuxagent/common/exception.py b/azurelinuxagent/common/exception.py index 91972eb..17c6ce0 100644 --- a/azurelinuxagent/common/exception.py +++ b/azurelinuxagent/common/exception.py @@ -149,10 +149,10 @@ class UpdateError(AgentError): super(UpdateError, self).__init__('000012', msg, inner) -class BadRequestError(HttpError): +class ResourceGoneError(HttpError): """ - The server rejected the request (i.e., status code 400) + The requested resource no longer exists (i.e., status code 410) """ def __init__(self, msg=None, inner=None): - super(BadRequestError, self).__init__(msg, inner) + super(ResourceGoneError, self).__init__(msg, inner) diff --git a/azurelinuxagent/common/protocol/hostplugin.py b/azurelinuxagent/common/protocol/hostplugin.py index 56bb984..729d8fb 100644 --- a/azurelinuxagent/common/protocol/hostplugin.py +++ b/azurelinuxagent/common/protocol/hostplugin.py @@ -22,8 +22,8 @@ import json import traceback from azurelinuxagent.common import logger -from azurelinuxagent.common.exception import BadRequestError, \ - HttpError, ProtocolError +from azurelinuxagent.common.exception import HttpError, ProtocolError, \ + ResourceGoneError from azurelinuxagent.common.future import ustr, httpclient from azurelinuxagent.common.utils import restutil from azurelinuxagent.common.utils import textutil @@ -146,7 +146,7 @@ class HostPluginProtocol(object): except Exception as e: # If the HostPlugin rejects the request, # let the error continue, but set to use the HostPlugin - if isinstance(e, BadRequestError): + if isinstance(e, ResourceGoneError): logger.verbose("HostGAPlugin: Setting host plugin as default channel") HostPluginProtocol.set_default_channel(True) diff --git a/azurelinuxagent/common/protocol/wire.py b/azurelinuxagent/common/protocol/wire.py index 0794f82..4f3b7e0 100644 --- a/azurelinuxagent/common/protocol/wire.py +++ b/azurelinuxagent/common/protocol/wire.py @@ -26,8 +26,8 @@ import azurelinuxagent.common.conf as conf import azurelinuxagent.common.utils.fileutil as fileutil import azurelinuxagent.common.utils.textutil as textutil -from azurelinuxagent.common.exception import BadRequestError, \ - ProtocolNotFoundError +from azurelinuxagent.common.exception import ProtocolNotFoundError, \ + ResourceGoneError from azurelinuxagent.common.future import httpclient, bytebuffer from azurelinuxagent.common.protocol.hostplugin import HostPluginProtocol from azurelinuxagent.common.protocol.restapi import * @@ -617,7 +617,7 @@ class WireClient(object): # If the HostPlugin rejects the request, # let the error continue, but set to use the HostPlugin - except BadRequestError: + except ResourceGoneError: HostPluginProtocol.set_default_channel(True) raise @@ -653,7 +653,7 @@ class WireClient(object): except (HttpError, ProtocolError) as e: logger.verbose("Fetch failed from [{0}]: {1}", uri, e) - if isinstance(e, BadRequestError): + if isinstance(e, ResourceGoneError): raise return None @@ -808,7 +808,7 @@ class WireClient(object): self.save_cache(local_file, xml_text) return ExtensionManifest(xml_text) - except BadRequestError: + except ResourceGoneError: continue raise ProtocolError("Failed to retrieve extension manifest") @@ -829,7 +829,7 @@ class WireClient(object): fileutil.write_file(local_file, xml_text) return ExtensionManifest(xml_text) - except BadRequestError: + except ResourceGoneError: continue raise ProtocolError("Failed to retrieve GAFamily manifest") @@ -892,7 +892,7 @@ class WireClient(object): except Exception as e: # If the HostPlugin rejects the request, # let the error continue, but set to use the HostPlugin - if isinstance(e, BadRequestError): + if isinstance(e, ResourceGoneError): HostPluginProtocol.set_default_channel(True) continue @@ -1069,7 +1069,7 @@ class WireClient(object): return artifacts_profile - except BadRequestError: + except ResourceGoneError: HostPluginProtocol.set_default_channel(True) continue diff --git a/azurelinuxagent/common/utils/restutil.py b/azurelinuxagent/common/utils/restutil.py index 5e6c9d1..6ad2479 100644 --- a/azurelinuxagent/common/utils/restutil.py +++ b/azurelinuxagent/common/utils/restutil.py @@ -25,7 +25,7 @@ import azurelinuxagent.common.conf as conf import azurelinuxagent.common.logger as logger import azurelinuxagent.common.utils.textutil as textutil -from azurelinuxagent.common.exception import BadRequestError, HttpError +from azurelinuxagent.common.exception import HttpError, ResourceGoneError from azurelinuxagent.common.future import httpclient, urlparse, ustr from azurelinuxagent.common.version import PY_VERSION_MAJOR @@ -43,9 +43,16 @@ RETRY_CODES = [ httpclient.FORBIDDEN, httpclient.INTERNAL_SERVER_ERROR, httpclient.NOT_IMPLEMENTED, + httpclient.BAD_GATEWAY, httpclient.SERVICE_UNAVAILABLE, httpclient.GATEWAY_TIMEOUT, - httpclient.INSUFFICIENT_STORAGE + httpclient.INSUFFICIENT_STORAGE, + 429, # Request Rate Limit Exceeded +] + +RESOURCE_GONE_CODES = [ + httpclient.BAD_REQUEST, + httpclient.GONE ] OK_CODES = [ @@ -258,8 +265,8 @@ def http_request(method, delay, resp.status)) continue - if resp.status == httpclient.BAD_REQUEST: - raise BadRequestError() + if resp.status in RESOURCE_GONE_CODES: + raise ResourceGoneError() return resp diff --git a/azurelinuxagent/ga/update.py b/azurelinuxagent/ga/update.py index 13ec99c..b7ee96a 100644 --- a/azurelinuxagent/ga/update.py +++ b/azurelinuxagent/ga/update.py @@ -41,8 +41,9 @@ import azurelinuxagent.common.utils.textutil as textutil from azurelinuxagent.common.event import add_event, add_periodic, \ elapsed_milliseconds, \ WALAEventOperation -from azurelinuxagent.common.exception import BadRequestError, \ - ProtocolError, UpdateError +from azurelinuxagent.common.exception import ProtocolError, \ + ResourceGoneError, \ + UpdateError from azurelinuxagent.common.future import ustr from azurelinuxagent.common.osutil import get_osutil from azurelinuxagent.common.protocol import get_protocol_util @@ -603,7 +604,7 @@ class UpdateHandler(object): self.agents[0].version > base_version except Exception as e: - if isinstance(e, BadRequestError): + if isinstance(e, ResourceGoneError): continue msg = u"Exception retrieving agent manifests: {0}".format( @@ -673,7 +674,7 @@ class GuestAgent(object): self._ensure_downloaded() self._ensure_loaded() except Exception as e: - if isinstance(e, BadRequestError): + if isinstance(e, ResourceGoneError): raise # Note the failure, blacklist the agent if the package downloaded @@ -820,7 +821,7 @@ class GuestAgent(object): # If the HostPlugin rejects the request, # let the error continue, but set to use the HostPlugin - except BadRequestError: + except ResourceGoneError: HostPluginProtocol.set_default_channel(True) raise @@ -853,7 +854,7 @@ class GuestAgent(object): logger.verbose("Fetch was unsuccessful [{0}]", restutil.read_response_error(resp)) except restutil.HttpError as http_error: - if isinstance(http_error, BadRequestError): + if isinstance(http_error, ResourceGoneError): raise logger.verbose(u"Agent {0} download from {1} failed [{2}]", diff --git a/tests/ga/test_update.py b/tests/ga/test_update.py index a9701d4..59251cb 100644 --- a/tests/ga/test_update.py +++ b/tests/ga/test_update.py @@ -1611,14 +1611,14 @@ class ProtocolMock(object): self.call_counts["get_vmagent_manifests"] += 1 if self.goal_state_is_stale: self.goal_state_is_stale = False - raise BadRequestError() + raise ResourceGoneError() return self.agent_manifests, self.etag def get_vmagent_pkgs(self, manifest): self.call_counts["get_vmagent_pkgs"] += 1 if self.goal_state_is_stale: self.goal_state_is_stale = False - raise BadRequestError() + raise ResourceGoneError() return self.agent_packages def update_goal_state(self, forced=False, max_retry=3): diff --git a/tests/protocol/mockwiredata.py b/tests/protocol/mockwiredata.py index 6a70a90..5924719 100644 --- a/tests/protocol/mockwiredata.py +++ b/tests/protocol/mockwiredata.py @@ -16,7 +16,7 @@ # from tests.tools import * -from azurelinuxagent.common.exception import BadRequestError, HttpError +from azurelinuxagent.common.exception import HttpError, ResourceGoneError from azurelinuxagent.common.future import httpclient from azurelinuxagent.common.utils.cryptutil import CryptUtil @@ -113,12 +113,12 @@ class WireProtocolData(object): else: # A stale GoalState results in a 400 from the HostPlugin - # for which the HTTP handler in restutil raises BadRequestError + # for which the HTTP handler in restutil raises ResourceGoneError if self.emulate_stale_goal_state: if "extensionArtifact" in url: self.emulate_stale_goal_state = False self.call_counts["extensionArtifact"] += 1 - raise BadRequestError() + raise ResourceGoneError() else: raise HttpError() diff --git a/tests/utils/test_rest_util.py b/tests/utils/test_rest_util.py index 75c75f8..6dfeea2 100644 --- a/tests/utils/test_rest_util.py +++ b/tests/utils/test_rest_util.py @@ -18,8 +18,9 @@ import os import unittest -from azurelinuxagent.common.exception import BadRequestError, \ - HttpError, ProtocolError +from azurelinuxagent.common.exception import HttpError, \ + ProtocolError, \ + ResourceGoneError import azurelinuxagent.common.utils.restutil as restutil from azurelinuxagent.common.future import httpclient, ustr @@ -272,7 +273,17 @@ class TestHttpOperations(AgentTestCase): Mock(status=httpclient.BAD_REQUEST) ] - self.assertRaises(BadRequestError, restutil.http_get, "https://foo.bar") + self.assertRaises(ResourceGoneError, restutil.http_get, "https://foo.bar") + self.assertEqual(1, _http_request.call_count) + + @patch("time.sleep") + @patch("azurelinuxagent.common.utils.restutil._http_request") + def test_http_request_raises_for_resource_gone(self, _http_request, _sleep): + _http_request.side_effect = [ + Mock(status=httpclient.GONE) + ] + + self.assertRaises(ResourceGoneError, restutil.http_get, "https://foo.bar") self.assertEqual(1, _http_request.call_count) @patch("time.sleep")