galaxy: make retryable HTTP status codes configurable

pull/82246/head
Nejc Habjan 5 months ago
parent 8641144375
commit c8a5d4d311
No known key found for this signature in database

@ -0,0 +1,3 @@
---
minor_changes:
- Make HTTP status codes to retry during galaxy API calls configurable (https://github.com/ansible/ansible/pull/82246).

@ -1510,6 +1510,18 @@ GALAXY_REQUIRED_VALID_SIGNATURE_COUNT:
- The number of signatures that must be successful during GPG signature verification while installing or verifying collections. - The number of signatures that must be successful during GPG signature verification while installing or verifying collections.
- This should be a positive integer or all to indicate all signatures must successfully validate the collection. - This should be a positive integer or all to indicate all signatures must successfully validate the collection.
- Prepend + to the value to fail if no valid signatures are found for the collection. - Prepend + to the value to fail if no valid signatures are found for the collection.
GALAXY_RETRY_HTTP_ERROR_CODES:
type: list
default:
- "429" # Too many requests
- "520" # Galaxy rate limit error code (Cloudflare unknown error)
- "502" # Common error from galaxy that may represent any number of transient backend issues
env:
- name: ANSIBLE_GALAXY_RETRY_HTTP_ERROR_CODES
ini:
- section: galaxy
key: retry_http_error_codes
description: List of HTTP Status error codes to retry on.
HOST_KEY_CHECKING: HOST_KEY_CHECKING:
# NOTE: constant not in use by ssh/paramiko plugins anymore, but they do support the same configuration sources # NOTE: constant not in use by ssh/paramiko plugins anymore, but they do support the same configuration sources
# TODO: check non ssh connection plugins for use/migration # TODO: check non ssh connection plugins for use/migration

@ -15,7 +15,6 @@ import tarfile
import time import time
import threading import threading
from http import HTTPStatus
from http.client import BadStatusLine, IncompleteRead from http.client import BadStatusLine, IncompleteRead
from urllib.error import HTTPError, URLError from urllib.error import HTTPError, URLError
from urllib.parse import quote as urlquote, urlencode, urlparse, parse_qs, urljoin from urllib.parse import quote as urlquote, urlencode, urlparse, parse_qs, urljoin
@ -35,11 +34,6 @@ from ansible.utils.path import makedirs_safe
display = Display() display = Display()
_CACHE_LOCK = threading.Lock() _CACHE_LOCK = threading.Lock()
COLLECTION_PAGE_SIZE = 100 COLLECTION_PAGE_SIZE = 100
RETRY_HTTP_ERROR_CODES = { # TODO: Allow user-configuration
HTTPStatus.TOO_MANY_REQUESTS,
520, # Galaxy rate limit error code (Cloudflare unknown error)
HTTPStatus.BAD_GATEWAY, # Common error from galaxy that may represent any number of transient backend issues
}
def cache_lock(func): def cache_lock(func):
@ -54,7 +48,12 @@ def should_retry_error(exception):
# Note: cloud.redhat.com masks rate limit errors with 403 (Forbidden) error codes. # Note: cloud.redhat.com masks rate limit errors with 403 (Forbidden) error codes.
# Since 403 could reflect the actual problem (such as an expired token), we should # Since 403 could reflect the actual problem (such as an expired token), we should
# not retry by default. # not retry by default.
if isinstance(exception, GalaxyError) and exception.http_code in RETRY_HTTP_ERROR_CODES: try:
retry_codes = [int(code) for code in C.GALAXY_RETRY_HTTP_ERROR_CODES]
except ValueError as e:
raise AnsibleError("Invalid value for HTTP retry code: %s. Only integer values are supported." % e)
if isinstance(exception, GalaxyError) and exception.http_code in retry_codes:
return True return True
if isinstance(exception, AnsibleError) and (orig_exc := getattr(exception, 'orig_exc', None)): if isinstance(exception, AnsibleError) and (orig_exc := getattr(exception, 'orig_exc', None)):

@ -20,7 +20,7 @@ import ansible.constants as C
from ansible import context from ansible import context
from ansible.errors import AnsibleError from ansible.errors import AnsibleError
from ansible.galaxy import api as galaxy_api from ansible.galaxy import api as galaxy_api
from ansible.galaxy.api import CollectionVersionMetadata, GalaxyAPI, GalaxyError from ansible.galaxy.api import CollectionVersionMetadata, GalaxyAPI, GalaxyError, should_retry_error
from ansible.galaxy.token import BasicAuthToken, GalaxyToken, KeycloakToken from ansible.galaxy.token import BasicAuthToken, GalaxyToken, KeycloakToken
from ansible.module_utils.common.text.converters import to_native, to_text from ansible.module_utils.common.text.converters import to_native, to_text
import urllib.error import urllib.error
@ -1353,3 +1353,11 @@ def test_clear_cache(cache_dir):
def test_cache_id(url, expected): def test_cache_id(url, expected):
actual = galaxy_api.get_cache_id(url) actual = galaxy_api.get_cache_id(url)
assert actual == expected assert actual == expected
def test_should_retry_error_with_invalid_code(monkeypatch):
expected = "Invalid value for HTTP retry code"
monkeypatch.setattr(C, 'GALAXY_RETRY_HTTP_ERROR_CODES', ["429", "invalid"])
with pytest.raises(AnsibleError, match=expected):
should_retry_error(Exception())

Loading…
Cancel
Save