From 32338f14e57f2368f91b77b6df9be08ba4d38008 Mon Sep 17 00:00:00 2001 From: "patchback[bot]" <45432694+patchback[bot]@users.noreply.github.com> Date: Sun, 21 Apr 2024 15:09:57 +0200 Subject: [PATCH] [PR #8238/a05a5982 backport][stable-7] bitwarden_secrets_manager: implement rate limit retry with backoff (#8260) * bitwarden_secrets_manager: implement rate limit retry with backoff (#8238) * bitwarden_secrets_manager: implement rate limit retry with backoff (#8230) * bitwarden_secrets_manager: add changelog fragment for 90cd2d61 (#8238) * bitwarden_secrets_manager: clarify "Too many requests" is an error condition (#8238) * bitwarden_secrets_manager: avoid an extra _run_with_retry execution after the last (very long) delay * bitwarden_secrets_manager: changelog fragment key and reference issue url (cherry picked from commit a05a5982a66e1c2cc37046ef97c637c782d1fcdd) * Make Python 2 compatible. --------- Co-authored-by: Matt Adams Co-authored-by: Felix Fontein --- ...-manager-rate-limit-retry-with-backoff.yml | 2 ++ plugins/lookup/bitwarden_secrets_manager.py | 21 ++++++++++++++++++- 2 files changed, 22 insertions(+), 1 deletion(-) create mode 100644 changelogs/fragments/8238-bitwarden-secrets-manager-rate-limit-retry-with-backoff.yml 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))