diff --git a/changelogs/fragments/8238-bitwarden-secrets-manager-rate-limit-retry-with-backoff.yml b/changelogs/fragments/8238-bitwarden-secrets-manager-rate-limit-retry-with-backoff.yml new file mode 100644 index 0000000000..b9d80a7cba --- /dev/null +++ b/changelogs/fragments/8238-bitwarden-secrets-manager-rate-limit-retry-with-backoff.yml @@ -0,0 +1,2 @@ +bugfixes: + - "bitwarden_secrets_manager lookup plugin - implements retry with exponential backoff to avoid lookup errors when Bitwardn's API rate limiting is encountered (https://github.com/ansible-collections/community.general/issues/8230, https://github.com/ansible-collections/community.general/pull/8238)." diff --git a/plugins/lookup/bitwarden_secrets_manager.py b/plugins/lookup/bitwarden_secrets_manager.py index 2d6706bee1..3a5f1574a8 100644 --- a/plugins/lookup/bitwarden_secrets_manager.py +++ b/plugins/lookup/bitwarden_secrets_manager.py @@ -70,6 +70,7 @@ RETURN = """ """ from subprocess import Popen, PIPE +from time import sleep from ansible.errors import AnsibleLookupError from ansible.module_utils.common.text.converters import to_text @@ -84,11 +85,29 @@ class BitwardenSecretsManagerException(AnsibleLookupError): class BitwardenSecretsManager(object): def __init__(self, path='bws'): self._cli_path = path + self._max_retries = 3 + self._retry_delay = 1 @property def cli_path(self): return self._cli_path + def _run_with_retry(self, args, stdin=None, retries=0): + out, err, rc = self._run(args, stdin) + + if rc != 0: + if retries >= self._max_retries: + raise BitwardenSecretsManagerException("Max retries exceeded. Unable to retrieve secret.") + + if "Too many requests" in err: + delay = self._retry_delay * (2 ** retries) + sleep(delay) + return self._run_with_retry(args, stdin, retries + 1) + else: + raise BitwardenSecretsManagerException("Command failed with return code {rc}: {err}".format(rc=rc, err=err)) + + return out, err, rc + def _run(self, args, stdin=None): p = Popen([self.cli_path] + args, stdout=PIPE, stderr=PIPE, stdin=PIPE) out, err = p.communicate(stdin) @@ -107,7 +126,7 @@ class BitwardenSecretsManager(object): 'get', 'secret', secret_id ] - out, err, rc = self._run(params) + out, err, rc = self._run_with_retry(params) if rc != 0: raise BitwardenSecretsManagerException(to_text(err))