diff --git a/changelogs/fragments/54298-openssl_certificate-remove.yaml b/changelogs/fragments/54298-openssl_certificate-remove.yaml new file mode 100644 index 0000000000..9ccfd52e7e --- /dev/null +++ b/changelogs/fragments/54298-openssl_certificate-remove.yaml @@ -0,0 +1,2 @@ +bugfixes: +- "openssl_certificate - fix ``state=absent``." diff --git a/lib/ansible/modules/crypto/openssl_certificate.py b/lib/ansible/modules/crypto/openssl_certificate.py index 4bf6a1af6e..490a873978 100644 --- a/lib/ansible/modules/crypto/openssl_certificate.py +++ b/lib/ansible/modules/crypto/openssl_certificate.py @@ -530,6 +530,26 @@ class Certificate(crypto_utils.OpenSSLObject): return True +class CertificateAbsent(Certificate): + def __init__(self, module): + super(CertificateAbsent, self).__init__(module) + + def generate(self, module): + pass + + def dump(self, check_mode=False): + # Use only for absent + + result = { + 'changed': self.changed, + 'filename': self.path, + 'privatekey': self.privatekey_path, + 'csr': self.csr_path + } + + return result + + class SelfSignedCertificate(Certificate): """Generate the self-signed certificate.""" @@ -1088,9 +1108,6 @@ def main(): except AttributeError: module.fail_json(msg='You need to have PyOpenSSL>=0.15') - if module.params['provider'] != 'assertonly' and module.params['csr_path'] is None: - module.fail_json(msg='csr_path is required when provider is not assertonly') - base_dir = os.path.dirname(module.params['path']) or '.' if not os.path.isdir(base_dir): module.fail_json( @@ -1098,16 +1115,23 @@ def main(): msg='The directory %s does not exist or the file is not a directory' % base_dir ) - provider = module.params['provider'] + if module.params['state'] == 'absent': + certificate = CertificateAbsent(module) - if provider == 'selfsigned': - certificate = SelfSignedCertificate(module) - elif provider == 'acme': - certificate = AcmeCertificate(module) - elif provider == 'ownca': - certificate = OwnCACertificate(module) else: - certificate = AssertOnlyCertificate(module) + if module.params['provider'] != 'assertonly' and module.params['csr_path'] is None: + module.fail_json(msg='csr_path is required when provider is not assertonly') + + provider = module.params['provider'] + + if provider == 'selfsigned': + certificate = SelfSignedCertificate(module) + elif provider == 'acme': + certificate = AcmeCertificate(module) + elif provider == 'ownca': + certificate = OwnCACertificate(module) + else: + certificate = AssertOnlyCertificate(module) if module.params['state'] == 'present': diff --git a/test/integration/targets/openssl_certificate/tasks/main.yml b/test/integration/targets/openssl_certificate/tasks/main.yml index b70dd8b3e8..23bee89640 100644 --- a/test/integration/targets/openssl_certificate/tasks/main.yml +++ b/test/integration/targets/openssl_certificate/tasks/main.yml @@ -8,4 +8,6 @@ - import_tasks: ownca.yml + - import_tasks: removal.yml + when: pyopenssl_version.stdout is version('0.15', '>=') diff --git a/test/integration/targets/openssl_certificate/tasks/removal.yml b/test/integration/targets/openssl_certificate/tasks/removal.yml new file mode 100644 index 0000000000..bb65d24747 --- /dev/null +++ b/test/integration/targets/openssl_certificate/tasks/removal.yml @@ -0,0 +1,47 @@ +--- +- name: (Removal) Generate privatekey + openssl_privatekey: + path: '{{ output_dir }}/removal_privatekey.pem' + +- name: (Removal) Generate CSR + openssl_csr: + path: '{{ output_dir }}/removal_csr.csr' + privatekey_path: '{{ output_dir }}/removal_privatekey.pem' + +- name: (Removal) Generate selfsigned certificate + openssl_certificate: + path: '{{ output_dir }}/removal_cert.pem' + csr_path: '{{ output_dir }}/removal_csr.csr' + privatekey_path: '{{ output_dir }}/removal_privatekey.pem' + provider: selfsigned + selfsigned_digest: sha256 + +- name: "(Removal) Check that file is not gone" + stat: + path: "{{ output_dir }}/removal_cert.pem" + register: removal_1_prestat + +- name: "(Removal) Remove certificate" + openssl_certificate: + path: "{{ output_dir }}/removal_cert.pem" + state: absent + register: removal_1 + +- name: "(Removal) Check that file is gone" + stat: + path: "{{ output_dir }}/removal_cert.pem" + register: removal_1_poststat + +- name: "(Removal) Remove certificate (idempotent)" + openssl_certificate: + path: "{{ output_dir }}/removal_cert.pem" + state: absent + register: removal_2 + +- name: (Removal) Ensure removal worked + assert: + that: + - removal_1_prestat.stat.exists + - removal_1 is changed + - not removal_1_poststat.stat.exists + - removal_2 is not changed