From d82338273280fd379990894074e8fc0822eccabc Mon Sep 17 00:00:00 2001 From: Felix Fontein Date: Fri, 9 Jun 2023 06:04:34 +0200 Subject: [PATCH] Validate challenges in parallel instead of serially. (#617) --- .../617-acme_certificate-parallel.yml | 2 ++ plugins/module_utils/acme/challenges.py | 18 ++++++++++++++++++ plugins/modules/acme_certificate.py | 9 +++++++-- 3 files changed, 27 insertions(+), 2 deletions(-) create mode 100644 changelogs/fragments/617-acme_certificate-parallel.yml diff --git a/changelogs/fragments/617-acme_certificate-parallel.yml b/changelogs/fragments/617-acme_certificate-parallel.yml new file mode 100644 index 00000000..a8104e8f --- /dev/null +++ b/changelogs/fragments/617-acme_certificate-parallel.yml @@ -0,0 +1,2 @@ +minor_changes: + - "acme_certificate - validate and wait for challenges in parallel instead handling them one after another (https://github.com/ansible-collections/community.crypto/pull/617)." diff --git a/plugins/module_utils/acme/challenges.py b/plugins/module_utils/acme/challenges.py index 366fde54..3a87ffec 100644 --- a/plugins/module_utils/acme/challenges.py +++ b/plugins/module_utils/acme/challenges.py @@ -301,3 +301,21 @@ class Authorization(object): self.status = 'deactivated' return True return False + + +def wait_for_validation(authzs, client): + ''' + Wait until a list of authz is valid. Fail if at least one of them is invalid or revoked. + ''' + while authzs: + authzs_next = [] + for authz in authzs: + authz.refresh(client) + if authz.status in ['valid', 'invalid', 'revoked']: + if authz.status != 'valid': + authz.raise_error('Status is not "valid"', module=client.module) + else: + authzs_next.append(authz) + if authzs_next: + time.sleep(2) + authzs = authzs_next diff --git a/plugins/modules/acme_certificate.py b/plugins/modules/acme_certificate.py index 10f0cdef..6aec44e0 100644 --- a/plugins/modules/acme_certificate.py +++ b/plugins/modules/acme_certificate.py @@ -561,6 +561,7 @@ from ansible_collections.community.crypto.plugins.module_utils.acme.account impo from ansible_collections.community.crypto.plugins.module_utils.acme.challenges import ( combine_identifier, split_identifier, + wait_for_validation, Authorization, ) @@ -747,11 +748,12 @@ class ACMECertificateClient(object): self.authorizations.update(self.order.authorizations) # Step 2: validate pending challenges + authzs_to_wait_for = [] for type_identifier, authz in self.authorizations.items(): if authz.status == 'pending': - identifier_type, identifier = split_identifier(type_identifier) if self.challenge is not None: - authz.call_validate(self.client, self.challenge) + authz.call_validate(self.client, self.challenge, wait=False) + authzs_to_wait_for.append(authz) # If there is no challenge, we must check whether the authz is valid elif authz.status != 'valid': authz.raise_error( @@ -760,6 +762,9 @@ class ACMECertificateClient(object): ) self.changed = True + # Step 3: wait for authzs to validate + wait_for_validation(authzs_to_wait_for, self.client) + def download_alternate_chains(self, cert): alternate_chains = [] for alternate in cert.alternates: