aws_acm Add additional AWSRetry error codes (#67671)

* Cleanup tests

* Auto-Retry on ResourceNotFound and RequestInProgress exceptions

* Use AnsibleModule options for required_if logic

* changelog

* Remove (now) duplicate RequestInProgressException catching

* Allow a single retry when attempting to fetch the information about a cert directly after deleting it.

There is a small chance that it goes away while we pull the details.
This commit is contained in:
Mark Chappell 2020-02-25 21:48:26 +01:00 committed by GitHub
parent 99f6f0c832
commit 9d455bed7b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 104 additions and 126 deletions

View file

@ -0,0 +1,3 @@
minor_changes:
- 'aws_acm: Add the module to group/aws for module_defaults.'
- 'aws_acm: Update automatic retries to stabilize the integration tests.'

View file

@ -13,6 +13,8 @@ groupings:
- acme - acme
acme_inspect: acme_inspect:
- acme - acme
aws_acm:
- aws
aws_acm_facts: aws_acm_facts:
- aws - aws
aws_acm_info: aws_acm_info:

View file

@ -51,7 +51,7 @@ class ACMServiceManager(object):
region, ec2_url, aws_connect_kwargs = get_aws_connection_info(module, boto3=True) region, ec2_url, aws_connect_kwargs = get_aws_connection_info(module, boto3=True)
self.client = module.client('acm') self.client = module.client('acm')
@AWSRetry.backoff(tries=5, delay=5, backoff=2.0) @AWSRetry.backoff(tries=5, delay=5, backoff=2.0, catch_extra_error_codes=['RequestInProgressException'])
def delete_certificate_with_backoff(self, client, arn): def delete_certificate_with_backoff(self, client, arn):
client.delete_certificate(CertificateArn=arn) client.delete_certificate(CertificateArn=arn)
@ -63,7 +63,7 @@ class ACMServiceManager(object):
module.fail_json_aws(e, msg="Couldn't delete certificate %s" % arn) module.fail_json_aws(e, msg="Couldn't delete certificate %s" % arn)
module.debug("Successfully deleted certificate %s" % arn) module.debug("Successfully deleted certificate %s" % arn)
@AWSRetry.backoff(tries=5, delay=5, backoff=2.0) @AWSRetry.backoff(tries=5, delay=5, backoff=2.0, catch_extra_error_codes=['RequestInProgressException'])
def list_certificates_with_backoff(self, client, statuses=None): def list_certificates_with_backoff(self, client, statuses=None):
paginator = client.get_paginator('list_certificates') paginator = client.get_paginator('list_certificates')
kwargs = dict() kwargs = dict()
@ -71,18 +71,18 @@ class ACMServiceManager(object):
kwargs['CertificateStatuses'] = statuses kwargs['CertificateStatuses'] = statuses
return paginator.paginate(**kwargs).build_full_result()['CertificateSummaryList'] return paginator.paginate(**kwargs).build_full_result()['CertificateSummaryList']
@AWSRetry.backoff(tries=5, delay=5, backoff=2.0, catch_extra_error_codes=['ResourceNotFoundException']) @AWSRetry.backoff(tries=5, delay=5, backoff=2.0, catch_extra_error_codes=['ResourceNotFoundException', 'RequestInProgressException'])
def get_certificate_with_backoff(self, client, certificate_arn): def get_certificate_with_backoff(self, client, certificate_arn):
response = client.get_certificate(CertificateArn=certificate_arn) response = client.get_certificate(CertificateArn=certificate_arn)
# strip out response metadata # strip out response metadata
return {'Certificate': response['Certificate'], return {'Certificate': response['Certificate'],
'CertificateChain': response['CertificateChain']} 'CertificateChain': response['CertificateChain']}
@AWSRetry.backoff(tries=5, delay=5, backoff=2.0, catch_extra_error_codes=['ResourceNotFoundException']) @AWSRetry.backoff(tries=5, delay=5, backoff=2.0, catch_extra_error_codes=['ResourceNotFoundException', 'RequestInProgressException'])
def describe_certificate_with_backoff(self, client, certificate_arn): def describe_certificate_with_backoff(self, client, certificate_arn):
return client.describe_certificate(CertificateArn=certificate_arn)['Certificate'] return client.describe_certificate(CertificateArn=certificate_arn)['Certificate']
@AWSRetry.backoff(tries=5, delay=5, backoff=2.0, catch_extra_error_codes=['ResourceNotFoundException']) @AWSRetry.backoff(tries=5, delay=5, backoff=2.0, catch_extra_error_codes=['ResourceNotFoundException', 'RequestInProgressException'])
def list_certificate_tags_with_backoff(self, client, certificate_arn): def list_certificate_tags_with_backoff(self, client, certificate_arn):
return client.list_tags_for_certificate(CertificateArn=certificate_arn)['Tags'] return client.list_tags_for_certificate(CertificateArn=certificate_arn)['Tags']
@ -118,8 +118,7 @@ class ACMServiceManager(object):
try: try:
cert_data.update(self.get_certificate_with_backoff(client, certificate['CertificateArn'])) cert_data.update(self.get_certificate_with_backoff(client, certificate['CertificateArn']))
except (BotoCoreError, ClientError, KeyError) as e: except (BotoCoreError, ClientError, KeyError) as e:
if e.response['Error']['Code'] != "RequestInProgressException": module.fail_json_aws(e, msg="Couldn't obtain certificate data for domain %s" % certificate['DomainName'])
module.fail_json_aws(e, msg="Couldn't obtain certificate data for domain %s" % certificate['DomainName'])
cert_data = camel_dict_to_snake_dict(cert_data) cert_data = camel_dict_to_snake_dict(cert_data)
try: try:
tags = self.list_certificate_tags_with_backoff(client, certificate['CertificateArn']) tags = self.list_certificate_tags_with_backoff(client, certificate['CertificateArn'])
@ -177,7 +176,7 @@ class ACMServiceManager(object):
# Tags are a normal Ansible style dict # Tags are a normal Ansible style dict
# {'Key':'Value'} # {'Key':'Value'}
@AWSRetry.backoff(tries=5, delay=5, backoff=2.0) @AWSRetry.backoff(tries=5, delay=5, backoff=2.0, catch_extra_error_codes=['ResourceNotFoundException', 'RequestInProgressException'])
def tag_certificate_with_backoff(self, client, arn, tags): def tag_certificate_with_backoff(self, client, arn, tags):
aws_tags = ansible_dict_to_boto3_tag_list(tags) aws_tags = ansible_dict_to_boto3_tag_list(tags)
client.add_tags_to_certificate(CertificateArn=arn, Tags=aws_tags) client.add_tags_to_certificate(CertificateArn=arn, Tags=aws_tags)

View file

@ -295,21 +295,17 @@ def main():
private_key=dict(no_log=True), private_key=dict(no_log=True),
state=dict(default='present', choices=['present', 'absent']) state=dict(default='present', choices=['present', 'absent'])
) )
module = AnsibleAWSModule(argument_spec=argument_spec, supports_check_mode=True) required_if = [
['state', 'present', ['certificate', 'name_tag', 'private_key']],
]
module = AnsibleAWSModule(argument_spec=argument_spec, supports_check_mode=True, required_if=required_if)
acm = ACMServiceManager(module) acm = ACMServiceManager(module)
# Check argument requirements # Check argument requirements
if module.params['state'] == 'present': if module.params['state'] == 'present':
if not module.params['certificate']: if module.params['certificate_arn']:
module.fail_json(msg="Parameter 'certificate' must be specified if 'state' is specified as 'present'")
elif module.params['certificate_arn']:
module.fail_json(msg="Parameter 'certificate_arn' is only valid if parameter 'state' is specified as 'absent'") module.fail_json(msg="Parameter 'certificate_arn' is only valid if parameter 'state' is specified as 'absent'")
elif not module.params['name_tag']:
module.fail_json(msg="Parameter 'name_tag' must be specified if parameter 'state' is specified as 'present'")
elif not module.params['private_key']:
module.fail_json(msg="Parameter 'private_key' must be specified if 'state' is specified as 'present'")
else: # absent else: # absent
# exactly one of these should be specified # exactly one of these should be specified
absent_args = ['certificate_arn', 'domain_name', 'name_tag'] absent_args = ['certificate_arn', 'domain_name', 'name_tag']
if sum([(module.params[a] is not None) for a in absent_args]) != 1: if sum([(module.params[a] is not None) for a in absent_args]) != 1:

View file

@ -1,54 +1,47 @@
- name: AWS ACM integration test - name: AWS ACM integration test
module_defaults:
group/aws:
aws_region: "{{ aws_region }}"
aws_access_key: "{{ aws_access_key }}"
aws_secret_key: "{{ aws_secret_key }}"
security_token: "{{ security_token | default(omit) }}"
block: block:
- set_fact:
aws_connection_info: &aws_connection_info
aws_region: "{{ aws_region }}"
aws_access_key: "{{ aws_access_key }}"
aws_secret_key: "{{ aws_secret_key }}"
security_token: "{{ security_token }}"
no_log: True
# just check this task doesn't fail # just check this task doesn't fail
# I'm not sure if I can assume there aren't already other certs in this account # I'm not sure if I can assume there aren't already other certs in this account
- name: list certs - name: list certs
aws_acm_info: aws_acm_info:
<<: *aws_connection_info
register: list_all register: list_all
failed_when: list_all.certificates is not defined failed_when: list_all.certificates is not defined
- name: ensure absent cert which doesn't exist - first time - name: ensure absent cert which doesn't exist - first time
aws_acm: aws_acm:
<<: *aws_connection_info
name_tag: "{{ item.name }}" name_tag: "{{ item.name }}"
state: absent state: absent
with_items: "{{ local_certs }}" with_items: "{{ local_certs }}"
# just in case it actually existed and was deleted last task # just in case it actually existed and was deleted last task
# check we don't fail when deleting nothing # check we don't fail when deleting nothing
- name: ensure absent cert which doesn't exist - second time - name: ensure absent cert which doesn't exist - second time
aws_acm: aws_acm:
<<: *aws_connection_info
name_tag: "{{ item.name }}" name_tag: "{{ item.name }}"
state: absent state: absent
with_items: "{{ local_certs }}" with_items: "{{ local_certs }}"
register: absent_start_two register: absent_start_two
failed_when: absent_start_two.changed failed_when: absent_start_two.changed
- name: list cert which shouldn't exist - name: list cert which shouldn't exist
aws_acm_info: aws_acm_info:
<<: *aws_connection_info
tags: tags:
Name: "{{ item.name }}" Name: "{{ item.name }}"
register: list_tag register: list_tag
with_items: "{{ local_certs }}" with_items: "{{ local_certs }}"
failed_when: list_tag.certificates | length > 0 failed_when: list_tag.certificates | length > 0
- name: check directory was made - name: check directory was made
assert: assert:
that: that:
- remote_tmp_dir is defined - remote_tmp_dir is defined
# https://github.com/vbotka/ansible-certificate/blob/master/tasks/cert-self-signed.yml # https://github.com/vbotka/ansible-certificate/blob/master/tasks/cert-self-signed.yml
- name: Generate private key for local certs - name: Generate private key for local certs
openssl_privatekey: openssl_privatekey:
@ -79,16 +72,15 @@
- name: upload certificates first time - name: upload certificates first time
aws_acm: aws_acm:
name_tag: "{{ item.name }}" name_tag: "{{ item.name }}"
<<: *aws_connection_info
certificate: "{{ lookup('file', item.cert ) }}" certificate: "{{ lookup('file', item.cert ) }}"
private_key: "{{ lookup('file', item.priv_key ) }}" private_key: "{{ lookup('file', item.priv_key ) }}"
state: present state: present
register: upload register: upload
with_items: "{{ local_certs }}" with_items: "{{ local_certs }}"
until: upload is succeeded until: upload is succeeded
retries: 5 retries: 5
delay: 10 delay: 10
- assert: - assert:
that: that:
- prev_task.certificate.arn is defined - prev_task.certificate.arn is defined
@ -100,20 +92,19 @@
vars: vars:
original_cert: "{{ item.item }}" original_cert: "{{ item.item }}"
prev_task: "{{ item }}" prev_task: "{{ item }}"
- name: fetch data about cert just uploaded, by ARN - name: fetch data about cert just uploaded, by ARN
aws_acm_info: aws_acm_info:
certificate_arn: "{{ item.certificate.arn }}" certificate_arn: "{{ item.certificate.arn }}"
<<: *aws_connection_info
register: fetch_after_up register: fetch_after_up
with_items: "{{ upload.results }}" with_items: "{{ upload.results }}"
- name: check output of prior task (fetch data about cert just uploaded, by ARN) - name: check output of prior task (fetch data about cert just uploaded, by ARN)
assert: assert:
that: that:
- fetch_after_up_result.certificates | length == 1 - fetch_after_up_result.certificates | length == 1
- fetch_after_up_result.certificates[0].certificate_arn == upload_result.certificate.arn - fetch_after_up_result.certificates[0].certificate_arn == upload_result.certificate.arn
- fetch_after_up_result.certificates[0].domain_name == original_cert.domain - fetch_after_up_result.certificates[0].domain_name == original_cert.domain
- (fetch_after_up_result.certificates[0].certificate | replace( ' ', '' ) | replace( '\n', '')) - (fetch_after_up_result.certificates[0].certificate | replace( ' ', '' ) | replace( '\n', ''))
== ==
(lookup( 'file', original_cert.cert ) | replace( ' ', '' ) | replace( '\n', '' )) (lookup( 'file', original_cert.cert ) | replace( ' ', '' ) | replace( '\n', '' ))
@ -129,22 +120,21 @@
aws_acm_info: aws_acm_info:
tags: tags:
Name: "{{ original_cert.name }}" Name: "{{ original_cert.name }}"
<<: *aws_connection_info
register: fetch_after_up_name register: fetch_after_up_name
with_items: "{{ upload.results }}" with_items: "{{ upload.results }}"
vars: vars:
upload_result: "{{ item }}" upload_result: "{{ item }}"
original_cert: "{{ item.item }}" original_cert: "{{ item.item }}"
- name: check fetched data of cert we just uploaded - name: check fetched data of cert we just uploaded
assert: assert:
that: that:
- fetch_after_up_name_result.certificates | length == 1 - fetch_after_up_name_result.certificates | length == 1
- fetch_after_up_name_result.certificates[0].certificate_arn == upload_result.certificate.arn - fetch_after_up_name_result.certificates[0].certificate_arn == upload_result.certificate.arn
- fetch_after_up_name_result.certificates[0].domain_name == original_cert.domain - fetch_after_up_name_result.certificates[0].domain_name == original_cert.domain
- (fetch_after_up_name_result.certificates[0].certificate | replace( ' ', '' ) | replace( '\n', '')) - (fetch_after_up_name_result.certificates[0].certificate | replace( ' ', '' ) | replace( '\n', ''))
== ==
(lookup('file', original_cert.cert ) | replace( ' ', '' ) | replace( '\n', '')) (lookup('file', original_cert.cert ) | replace( ' ', '' ) | replace( '\n', ''))
- "'Name' in fetch_after_up_name_result.certificates[0].tags" - "'Name' in fetch_after_up_name_result.certificates[0].tags"
- fetch_after_up_name_result.certificates[0].tags['Name'] == original_cert.name - fetch_after_up_name_result.certificates[0].tags['Name'] == original_cert.name
with_items: "{{ fetch_after_up_name.results }}" with_items: "{{ fetch_after_up_name.results }}"
@ -157,7 +147,6 @@
- name: fetch data about cert just uploaded, by domain name - name: fetch data about cert just uploaded, by domain name
aws_acm_info: aws_acm_info:
domain_name: "{{ original_cert.domain }}" domain_name: "{{ original_cert.domain }}"
<<: *aws_connection_info
register: fetch_after_up_domain register: fetch_after_up_domain
with_items: "{{ upload.results }}" with_items: "{{ upload.results }}"
vars: vars:
@ -169,7 +158,7 @@
- fetch_after_up_domain_result.certificates | length == 1 - fetch_after_up_domain_result.certificates | length == 1
- fetch_after_up_domain_result.certificates[0].certificate_arn == upload_result.certificate.arn - fetch_after_up_domain_result.certificates[0].certificate_arn == upload_result.certificate.arn
- fetch_after_up_domain_result.certificates[0].domain_name == original_cert.domain - fetch_after_up_domain_result.certificates[0].domain_name == original_cert.domain
- (fetch_after_up_domain_result.certificates[0].certificate | replace( ' ', '' ) | replace( '\n', '')) - (fetch_after_up_domain_result.certificates[0].certificate | replace( ' ', '' ) | replace( '\n', ''))
== ==
(lookup('file', original_cert.cert ) | replace( ' ', '' ) | replace( '\n', '')) (lookup('file', original_cert.cert ) | replace( ' ', '' ) | replace( '\n', ''))
- "'Name' in fetch_after_up_domain_result.certificates[0].tags" - "'Name' in fetch_after_up_domain_result.certificates[0].tags"
@ -179,30 +168,28 @@
fetch_after_up_domain_result: "{{ item }}" fetch_after_up_domain_result: "{{ item }}"
upload_result: "{{ item.item }}" upload_result: "{{ item.item }}"
original_cert: "{{ item.item.item }}" original_cert: "{{ item.item.item }}"
# now upload that certificate # now upload that certificate
- name: upload certificates again, check not changed - name: upload certificates again, check not changed
aws_acm: aws_acm:
name_tag: "{{ item.name }}" name_tag: "{{ item.name }}"
<<: *aws_connection_info
certificate: "{{ lookup('file', item.cert ) }}" certificate: "{{ lookup('file', item.cert ) }}"
private_key: "{{ lookup('file', item.priv_key ) }}" private_key: "{{ lookup('file', item.priv_key ) }}"
state: present state: present
register: upload2 register: upload2
with_items: "{{ local_certs }}" with_items: "{{ local_certs }}"
failed_when: upload2.changed failed_when: upload2.changed
- name: update first cert with body of the second, first time - name: update first cert with body of the second, first time
aws_acm: aws_acm:
state: present state: present
<<: *aws_connection_info
name_tag: "{{ local_certs[0].name }}" name_tag: "{{ local_certs[0].name }}"
certificate: "{{ lookup('file', local_certs[1].cert ) }}" certificate: "{{ lookup('file', local_certs[1].cert ) }}"
private_key: "{{ lookup('file', local_certs[1].priv_key ) }}" private_key: "{{ lookup('file', local_certs[1].priv_key ) }}"
register: overwrite register: overwrite
- name: check output of previous task (update first cert with body of the second, first time) - name: check output of previous task (update first cert with body of the second, first time)
assert: assert:
that: that:
@ -211,15 +198,14 @@
- overwrite.certificate.arn == upload.results[0].certificate.arn - overwrite.certificate.arn == upload.results[0].certificate.arn
- overwrite.certificate.domain_name == local_certs[1].domain - overwrite.certificate.domain_name == local_certs[1].domain
- overwrite.changed - overwrite.changed
- name: check update was sucessfull - name: check update was sucessfull
aws_acm_info: aws_acm_info:
tags: tags:
Name: "{{ local_certs[0].name }}" Name: "{{ local_certs[0].name }}"
<<: *aws_connection_info
register: fetch_after_overwrite register: fetch_after_overwrite
- name: check output of update fetch - name: check output of update fetch
assert: assert:
that: that:
- fetch_after_overwrite.certificates | length == 1 - fetch_after_overwrite.certificates | length == 1
@ -233,15 +219,14 @@
aws_acm_info: aws_acm_info:
tags: tags:
Name: "{{ local_certs[1].name }}" Name: "{{ local_certs[1].name }}"
<<: *aws_connection_info
register: check_after_overwrite register: check_after_overwrite
- name: check other cert unaffected - name: check other cert unaffected
assert: assert:
that: that:
- check_after_overwrite.certificates | length == 1 - check_after_overwrite.certificates | length == 1
- check_after_overwrite.certificates[0].certificate_arn == fetch_after_up.results[1].certificates[0].certificate_arn - check_after_overwrite.certificates[0].certificate_arn == fetch_after_up.results[1].certificates[0].certificate_arn
- check_after_overwrite.certificates[0].domain_name == local_certs[1].domain - check_after_overwrite.certificates[0].domain_name == local_certs[1].domain
- (check_after_overwrite.certificates[0].certificate | replace( ' ', '' ) | replace( '\n', '')) == (lookup('file', local_certs[1].cert ) | replace( ' ', '' ) | replace( '\n', '')) - (check_after_overwrite.certificates[0].certificate | replace( ' ', '' ) | replace( '\n', '')) == (lookup('file', local_certs[1].cert ) | replace( ' ', '' ) | replace( '\n', ''))
- "'Name' in check_after_overwrite.certificates[0].tags" - "'Name' in check_after_overwrite.certificates[0].tags"
- check_after_overwrite.certificates[0].tags['Name'] == local_certs[1].name - check_after_overwrite.certificates[0].tags['Name'] == local_certs[1].name
@ -249,12 +234,11 @@
- name: update first cert with body of the second again - name: update first cert with body of the second again
aws_acm: aws_acm:
state: present state: present
<<: *aws_connection_info
name_tag: "{{ local_certs[0].name }}" name_tag: "{{ local_certs[0].name }}"
certificate: "{{ lookup('file', local_certs[1].cert ) }}" certificate: "{{ lookup('file', local_certs[1].cert ) }}"
private_key: "{{ lookup('file', local_certs[1].priv_key ) }}" private_key: "{{ lookup('file', local_certs[1].priv_key ) }}"
register: overwrite2 register: overwrite2
- name: check output of previous task (update first cert with body of the second again) - name: check output of previous task (update first cert with body of the second again)
assert: assert:
that: that:
@ -263,14 +247,13 @@
- overwrite2.certificate.arn == upload.results[0].certificate.arn - overwrite2.certificate.arn == upload.results[0].certificate.arn
- overwrite2.certificate.domain_name == local_certs[1].domain - overwrite2.certificate.domain_name == local_certs[1].domain
- not overwrite2.changed - not overwrite2.changed
- name: delete certs 1 and 2 - name: delete certs 1 and 2
aws_acm: aws_acm:
<<: *aws_connection_info
state: absent state: absent
domain_name: "{{ local_certs[1].domain }}" domain_name: "{{ local_certs[1].domain }}"
register: delete_both register: delete_both
- name: test prev task - name: test prev task
assert: assert:
that: that:
@ -278,25 +261,31 @@
- check_after_overwrite.certificates[0].certificate_arn in delete_both.arns - check_after_overwrite.certificates[0].certificate_arn in delete_both.arns
- upload.results[0].certificate.arn in delete_both.arns - upload.results[0].certificate.arn in delete_both.arns
- delete_both.changed - delete_both.changed
- name: fetch info for certs 1 and 2 - name: fetch info for certs 1 and 2
aws_acm_info: aws_acm_info:
<<: *aws_connection_info
tags: tags:
Name: "{{ local_certs[item].name }}" Name: "{{ local_certs[item].name }}"
register: check_del_one register: check_del_one
with_items: with_items:
- 0 - 0
- 1 - 1
# There is the chance that we're running as the deletion is in progress,
# this could trigger ResourceNotFoundException allow a single retry to cope
# with this.
retries: 2
until:
- check_del_one is not failed
- check_del_one.certificates | length == 0
delay: 10
- name: check certs 1 and 2 were already deleted - name: check certs 1 and 2 were already deleted
with_items: "{{ check_del_one.results }}" with_items: "{{ check_del_one.results }}"
assert: assert:
that: item.certificates | length == 0 that: item.certificates | length == 0
- name: check cert 3 not deleted - name: check cert 3 not deleted
aws_acm_info: aws_acm_info:
<<: *aws_connection_info
tags: tags:
Name: "{{ local_certs[2].name }}" Name: "{{ local_certs[2].name }}"
register: check_del_one_remain register: check_del_one_remain
@ -304,11 +293,10 @@
- name: delete cert 3 - name: delete cert 3
aws_acm: aws_acm:
<<: *aws_connection_info
state: absent state: absent
domain_name: "{{ local_certs[2].domain }}" domain_name: "{{ local_certs[2].domain }}"
register: delete_third register: delete_third
- name: check cert 3 deletion went as expected - name: check cert 3 deletion went as expected
assert: assert:
that: that:
@ -316,22 +304,20 @@
- delete_third.arns | length == 1 - delete_third.arns | length == 1
- delete_third.arns[0] == upload.results[2].certificate.arn - delete_third.arns[0] == upload.results[2].certificate.arn
- delete_third.changed - delete_third.changed
- name: check cert 3 was deleted - name: check cert 3 was deleted
aws_acm_info: aws_acm_info:
<<: *aws_connection_info
tags: tags:
Name: "{{ local_certs[2].name }}" Name: "{{ local_certs[2].name }}"
register: check_del_three register: check_del_three
failed_when: check_del_three.certificates | length != 0 failed_when: check_del_three.certificates | length != 0
- name: delete cert 3 again - name: delete cert 3 again
aws_acm: aws_acm:
<<: *aws_connection_info
state: absent state: absent
domain_name: "{{ local_certs[2].domain }}" domain_name: "{{ local_certs[2].domain }}"
register: delete_third register: delete_third
- name: check deletion of cert 3 not changed, because already deleted - name: check deletion of cert 3 not changed, because already deleted
assert: assert:
that: that:
@ -341,7 +327,7 @@
- name: check directory was made - name: check directory was made
assert: assert:
that: that:
- remote_tmp_dir is defined - remote_tmp_dir is defined
- name: Generate private key for cert to be chained - name: Generate private key for cert to be chained
@ -356,7 +342,7 @@
privatekey_path: "{{ chained_cert.priv_key }}" privatekey_path: "{{ chained_cert.priv_key }}"
common_name: "{{ chained_cert.domain }}" common_name: "{{ chained_cert.domain }}"
with_items: "{{ chained_cert.chains }}" with_items: "{{ chained_cert.chains }}"
- name: Sign new certs with cert 0 and 1 - name: Sign new certs with cert 0 and 1
openssl_certificate: openssl_certificate:
@ -369,7 +355,7 @@
- 'sha256WithRSAEncryption' - 'sha256WithRSAEncryption'
# - 'sha512WithRSAEncryption' # - 'sha512WithRSAEncryption'
with_items: "{{ chained_cert.chains }}" with_items: "{{ chained_cert.chains }}"
- name: check files exist (for next task) - name: check files exist (for next task)
file: file:
path: "{{ item }}" path: "{{ item }}"
@ -379,7 +365,7 @@
- "{{ local_certs[chained_cert.chains[1].ca].cert }}" - "{{ local_certs[chained_cert.chains[1].ca].cert }}"
- "{{ chained_cert.chains[0].cert }}" - "{{ chained_cert.chains[0].cert }}"
- "{{ chained_cert.chains[1].cert }}" - "{{ chained_cert.chains[1].cert }}"
- name: Find chains - name: Find chains
certificate_complete_chain: certificate_complete_chain:
input_chain: "{{ lookup('file', item.cert ) }}" input_chain: "{{ lookup('file', item.cert ) }}"
@ -391,57 +377,53 @@
- name: upload chained cert, first chain, first time - name: upload chained cert, first chain, first time
aws_acm: aws_acm:
name_tag: "{{ chained_cert.name }}" name_tag: "{{ chained_cert.name }}"
<<: *aws_connection_info
certificate: "{{ lookup('file', chained_cert.chains[0].cert ) }}" certificate: "{{ lookup('file', chained_cert.chains[0].cert ) }}"
certificate_chain: "{{ chains.results[0].complete_chain | join('\n') }}" certificate_chain: "{{ chains.results[0].complete_chain | join('\n') }}"
private_key: "{{ lookup('file', chained_cert.priv_key ) }}" private_key: "{{ lookup('file', chained_cert.priv_key ) }}"
state: present state: present
register: upload_chain register: upload_chain
failed_when: not upload_chain.changed failed_when: not upload_chain.changed
- name: fetch chain of cert we just uploaded - name: fetch chain of cert we just uploaded
aws_acm_info: aws_acm_info:
<<: *aws_connection_info
tags: tags:
Name: "{{ chained_cert.name }}" Name: "{{ chained_cert.name }}"
register: check_chain register: check_chain
- name: check chain of cert we just uploaded - name: check chain of cert we just uploaded
assert: assert:
that: that:
- (check_chain.certificates[0].certificate_chain | replace( ' ', '' ) | replace( '\n', '')) - (check_chain.certificates[0].certificate_chain | replace( ' ', '' ) | replace( '\n', ''))
== ==
( chains.results[0].complete_chain | join( '\n' ) | replace( ' ', '' ) | replace( '\n', '') ) ( chains.results[0].complete_chain | join( '\n' ) | replace( ' ', '' ) | replace( '\n', '') )
- (check_chain.certificates[0].certificate | replace( ' ', '' ) | replace( '\n', '')) - (check_chain.certificates[0].certificate | replace( ' ', '' ) | replace( '\n', ''))
== ==
( lookup('file', chained_cert.chains[0].cert ) | replace( ' ', '' ) | replace( '\n', '') ) ( lookup('file', chained_cert.chains[0].cert ) | replace( ' ', '' ) | replace( '\n', '') )
- name: upload chained cert again, check not changed - name: upload chained cert again, check not changed
aws_acm: aws_acm:
name_tag: "{{ chained_cert.name }}" name_tag: "{{ chained_cert.name }}"
<<: *aws_connection_info
certificate: "{{ lookup('file', chained_cert.chains[0].cert ) }}" certificate: "{{ lookup('file', chained_cert.chains[0].cert ) }}"
certificate_chain: "{{ chains.results[0].complete_chain | join('\n') }}" certificate_chain: "{{ chains.results[0].complete_chain | join('\n') }}"
private_key: "{{ lookup('file', chained_cert.priv_key ) }}" private_key: "{{ lookup('file', chained_cert.priv_key ) }}"
state: present state: present
register: upload_chain_2 register: upload_chain_2
- name: check previous task not changed - name: check previous task not changed
assert: assert:
that: that:
- upload_chain_2.certificate.arn == upload_chain.certificate.arn - upload_chain_2.certificate.arn == upload_chain.certificate.arn
- not upload_chain_2.changed - not upload_chain_2.changed
- name: upload chained cert, different chain - name: upload chained cert, different chain
aws_acm: aws_acm:
name_tag: "{{ chained_cert.name }}" name_tag: "{{ chained_cert.name }}"
<<: *aws_connection_info
certificate: "{{ lookup('file', chained_cert.chains[1].cert ) }}" certificate: "{{ lookup('file', chained_cert.chains[1].cert ) }}"
certificate_chain: "{{ chains.results[1].complete_chain | join('\n') }}" certificate_chain: "{{ chains.results[1].complete_chain | join('\n') }}"
private_key: "{{ lookup('file', chained_cert.priv_key ) }}" private_key: "{{ lookup('file', chained_cert.priv_key ) }}"
state: present state: present
register: upload_chain_3 register: upload_chain_3
- name: check uploading with different chain is changed - name: check uploading with different chain is changed
assert: assert:
that: that:
@ -450,41 +432,38 @@
- name: fetch info about chain of cert we just updated - name: fetch info about chain of cert we just updated
aws_acm_info: aws_acm_info:
<<: *aws_connection_info
tags: tags:
Name: "{{ chained_cert.name }}" Name: "{{ chained_cert.name }}"
register: check_chain_2 register: check_chain_2
- name: check chain of cert we just uploaded - name: check chain of cert we just uploaded
assert: assert:
that: that:
- (check_chain_2.certificates[0].certificate_chain | replace( ' ', '' ) | replace( '\n', '')) - (check_chain_2.certificates[0].certificate_chain | replace( ' ', '' ) | replace( '\n', ''))
== ==
( chains.results[1].complete_chain | join( '\n' ) | replace( ' ', '' ) | replace( '\n', '') ) ( chains.results[1].complete_chain | join( '\n' ) | replace( ' ', '' ) | replace( '\n', '') )
- (check_chain_2.certificates[0].certificate | replace( ' ', '' ) | replace( '\n', '')) - (check_chain_2.certificates[0].certificate | replace( ' ', '' ) | replace( '\n', ''))
== ==
( lookup('file', chained_cert.chains[1].cert ) | replace( ' ', '' ) | replace( '\n', '') ) ( lookup('file', chained_cert.chains[1].cert ) | replace( ' ', '' ) | replace( '\n', '') )
- name: delete chained cert - name: delete chained cert
aws_acm: aws_acm:
name_tag: "{{ chained_cert.name }}" name_tag: "{{ chained_cert.name }}"
<<: *aws_connection_info
state: absent state: absent
register: delete_chain_3 register: delete_chain_3
- name: check deletion of chained cert 3 is changed - name: check deletion of chained cert 3 is changed
assert: assert:
that: that:
- delete_chain_3.changed - delete_chain_3.changed
- upload_chain.certificate.arn in delete_chain_3.arns - upload_chain.certificate.arn in delete_chain_3.arns
always: always:
- name: delete first bunch of certificates - name: delete first bunch of certificates
aws_acm: aws_acm:
name_tag: "{{ item.name }}" name_tag: "{{ item.name }}"
<<: *aws_connection_info
state: absent state: absent
with_items: "{{ local_certs }}" with_items: "{{ local_certs }}"
ignore_errors: yes ignore_errors: yes
@ -493,7 +472,6 @@
aws_acm: aws_acm:
state: absent state: absent
name_tag: "{{ chained_cert.name }}" name_tag: "{{ chained_cert.name }}"
<<: *aws_connection_info
ignore_errors: yes ignore_errors: yes
@ -501,4 +479,4 @@
file: file:
path: "{{ remote_tmp_dir }}" path: "{{ remote_tmp_dir }}"
state: directory state: directory
ignore_errors: yes ignore_errors: yes

View file

@ -3,19 +3,19 @@
- set_fact: - set_fact:
virtualenv: "{{ remote_tmp_dir }}/virtualenv" virtualenv: "{{ remote_tmp_dir }}/virtualenv"
virtualenv_command: "{{ ansible_python_interpreter }} -m virtualenv" virtualenv_command: "{{ ansible_python_interpreter }} -m virtualenv"
- set_fact: - set_fact:
virtualenv_interpreter: "{{ virtualenv }}/bin/python" virtualenv_interpreter: "{{ virtualenv }}/bin/python"
# The CI runs many of these tests in parallel # The CI runs many of these tests in parallel
# Use this random ID to differentiate which resources # Use this random ID to differentiate which resources
# are from which test # are from which test
- set_fact: - set_fact:
aws_acm_test_uuid: "{{ (10**9) | random }}" aws_acm_test_uuid: "{{ (10**9) | random }}"
- pip: - pip:
name: virtualenv name: virtualenv
- pip: - pip:
name: name:
- 'botocore<1.13.0,>=1.12.211' - 'botocore<1.13.0,>=1.12.211'
@ -28,12 +28,12 @@
virtualenv: "{{ virtualenv }}" virtualenv: "{{ virtualenv }}"
virtualenv_command: "{{ virtualenv_command }}" virtualenv_command: "{{ virtualenv_command }}"
virtualenv_site_packages: no virtualenv_site_packages: no
- include_tasks: full_acm_test.yml - include_tasks: full_acm_test.yml
vars: vars:
ansible_python_interpreter: "{{ virtualenv_interpreter }}" ansible_python_interpreter: "{{ virtualenv_interpreter }}"
always: always:
- file: - file:
path: "{{ virtualenv }}" path: "{{ virtualenv }}"
state: absent state: absent