From 1bdfbaa65a60eaa26df4d3f98e29a3de1b238177 Mon Sep 17 00:00:00 2001 From: Felix Fontein Date: Mon, 13 Apr 2020 13:48:53 +0200 Subject: [PATCH] Move generic I/O functions to plugins/module_utils/io.py. --- plugins/module_utils/crypto/basic.py | 74 ------------------- plugins/module_utils/io.py | 101 ++++++++++++++++++++++++++ plugins/modules/ecs_certificate.py | 4 +- plugins/modules/openssl_csr.py | 7 +- plugins/modules/openssl_dhparam.py | 2 +- plugins/modules/openssl_pkcs12.py | 7 +- plugins/modules/openssl_privatekey.py | 7 +- plugins/modules/openssl_publickey.py | 7 +- plugins/modules/x509_certificate.py | 7 +- plugins/modules/x509_crl.py | 5 +- 10 files changed, 133 insertions(+), 88 deletions(-) create mode 100644 plugins/module_utils/io.py diff --git a/plugins/module_utils/crypto/basic.py b/plugins/module_utils/crypto/basic.py index e87dc0f1a..f91ec90a8 100644 --- a/plugins/module_utils/crypto/basic.py +++ b/plugins/module_utils/crypto/basic.py @@ -20,10 +20,6 @@ __metaclass__ = type -import errno -import os -import tempfile - from distutils.version import LooseVersion try: @@ -114,73 +110,3 @@ class OpenSSLObjectError(Exception): class OpenSSLBadPassphraseError(OpenSSLObjectError): pass - - -def load_file_if_exists(path, module=None, ignore_errors=False): - try: - with open(path, 'rb') as f: - return f.read() - except EnvironmentError as exc: - if exc.errno == errno.ENOENT: - return None - if ignore_errors: - return None - if module is None: - raise - module.fail_json('Error while loading {0} - {1}'.format(path, str(exc))) - except Exception as exc: - if ignore_errors: - return None - if module is None: - raise - module.fail_json('Error while loading {0} - {1}'.format(path, str(exc))) - - -def write_file(module, content, default_mode=None, path=None): - ''' - Writes content into destination file as securely as possible. - Uses file arguments from module. - ''' - # Find out parameters for file - try: - file_args = module.load_file_common_arguments(module.params, path=path) - except TypeError: - # The path argument is only supported in Ansible 2.10+. Fall back to - # pre-2.10 behavior of module_utils/crypto.py for older Ansible versions. - file_args = module.load_file_common_arguments(module.params) - if path is not None: - file_args['path'] = path - if file_args['mode'] is None: - file_args['mode'] = default_mode - # Create tempfile name - tmp_fd, tmp_name = tempfile.mkstemp(prefix=b'.ansible_tmp') - try: - os.close(tmp_fd) - except Exception: - pass - module.add_cleanup_file(tmp_name) # if we fail, let Ansible try to remove the file - try: - try: - # Create tempfile - file = os.open(tmp_name, os.O_WRONLY | os.O_CREAT | os.O_TRUNC, 0o600) - os.write(file, content) - os.close(file) - except Exception as e: - try: - os.remove(tmp_name) - except Exception: - pass - module.fail_json(msg='Error while writing result into temporary file: {0}'.format(e)) - # Update destination to wanted permissions - if os.path.exists(file_args['path']): - module.set_fs_attributes_if_different(file_args, False) - # Move tempfile to final destination - module.atomic_move(tmp_name, file_args['path']) - # Try to update permissions again - module.set_fs_attributes_if_different(file_args, False) - except Exception as e: - try: - os.remove(tmp_name) - except Exception: - pass - module.fail_json(msg='Error while writing result: {0}'.format(e)) diff --git a/plugins/module_utils/io.py b/plugins/module_utils/io.py new file mode 100644 index 000000000..debc499a2 --- /dev/null +++ b/plugins/module_utils/io.py @@ -0,0 +1,101 @@ +# -*- coding: utf-8 -*- +# +# (c) 2016, Yanis Guenane +# +# Ansible is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Ansible is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Ansible. If not, see . + +from __future__ import absolute_import, division, print_function +__metaclass__ = type + + +import errno +import os +import tempfile + + +def load_file_if_exists(path, module=None, ignore_errors=False): + ''' + Load the file as a bytes string. If the file does not exist, ``None`` is returned. + + If ``ignore_errors`` is ``True``, will ignore errors. Otherwise, errors are + raised as exceptions if ``module`` is not specified, and result in ``module.fail_json`` + being called when ``module`` is specified. + ''' + try: + with open(path, 'rb') as f: + return f.read() + except EnvironmentError as exc: + if exc.errno == errno.ENOENT: + return None + if ignore_errors: + return None + if module is None: + raise + module.fail_json('Error while loading {0} - {1}'.format(path, str(exc))) + except Exception as exc: + if ignore_errors: + return None + if module is None: + raise + module.fail_json('Error while loading {0} - {1}'.format(path, str(exc))) + + +def write_file(module, content, default_mode=None, path=None): + ''' + Writes content into destination file as securely as possible. + Uses file arguments from module. + ''' + # Find out parameters for file + try: + file_args = module.load_file_common_arguments(module.params, path=path) + except TypeError: + # The path argument is only supported in Ansible 2.10+. Fall back to + # pre-2.10 behavior of module_utils/crypto.py for older Ansible versions. + file_args = module.load_file_common_arguments(module.params) + if path is not None: + file_args['path'] = path + if file_args['mode'] is None: + file_args['mode'] = default_mode + # Create tempfile name + tmp_fd, tmp_name = tempfile.mkstemp(prefix=b'.ansible_tmp') + try: + os.close(tmp_fd) + except Exception: + pass + module.add_cleanup_file(tmp_name) # if we fail, let Ansible try to remove the file + try: + try: + # Create tempfile + file = os.open(tmp_name, os.O_WRONLY | os.O_CREAT | os.O_TRUNC, 0o600) + os.write(file, content) + os.close(file) + except Exception as e: + try: + os.remove(tmp_name) + except Exception: + pass + module.fail_json(msg='Error while writing result into temporary file: {0}'.format(e)) + # Update destination to wanted permissions + if os.path.exists(file_args['path']): + module.set_fs_attributes_if_different(file_args, False) + # Move tempfile to final destination + module.atomic_move(tmp_name, file_args['path']) + # Try to update permissions again + module.set_fs_attributes_if_different(file_args, False) + except Exception as e: + try: + os.remove(tmp_name) + except Exception: + pass + module.fail_json(msg='Error while writing result: {0}'.format(e)) diff --git a/plugins/modules/ecs_certificate.py b/plugins/modules/ecs_certificate.py index 08fb5833f..7fe9cc315 100644 --- a/plugins/modules/ecs_certificate.py +++ b/plugins/modules/ecs_certificate.py @@ -528,8 +528,8 @@ from ansible.module_utils.basic import AnsibleModule, missing_required_lib from ansible.module_utils._text import to_native, to_bytes -from ansible_collections.community.crypto.plugins.module_utils.crypto.basic import ( - write_file +from ansible_collections.community.crypto.plugins.module_utils.io import ( + write_file, ) from ansible_collections.community.crypto.plugins.module_utils.crypto.support import ( diff --git a/plugins/modules/openssl_csr.py b/plugins/modules/openssl_csr.py index 69a237da6..9de67d783 100644 --- a/plugins/modules/openssl_csr.py +++ b/plugins/modules/openssl_csr.py @@ -428,11 +428,14 @@ from ansible_collections.community.crypto.plugins.module_utils.compat import ipaddress as compat_ipaddress +from ansible_collections.community.crypto.plugins.module_utils.io import ( + load_file_if_exists, + write_file, +) + from ansible_collections.community.crypto.plugins.module_utils.crypto.basic import ( OpenSSLObjectError, OpenSSLBadPassphraseError, - write_file, - load_file_if_exists, ) from ansible_collections.community.crypto.plugins.module_utils.crypto.support import ( diff --git a/plugins/modules/openssl_dhparam.py b/plugins/modules/openssl_dhparam.py index 23f516d75..566cc880f 100644 --- a/plugins/modules/openssl_dhparam.py +++ b/plugins/modules/openssl_dhparam.py @@ -132,7 +132,7 @@ from ansible.module_utils.basic import AnsibleModule, missing_required_lib from ansible.module_utils._text import to_native -from ansible_collections.community.crypto.plugins.module_utils.crypto.basic import ( +from ansible_collections.community.crypto.plugins.module_utils.io import ( load_file_if_exists, write_file, ) diff --git a/plugins/modules/openssl_pkcs12.py b/plugins/modules/openssl_pkcs12.py index 4a4cce899..7c6d69d2d 100644 --- a/plugins/modules/openssl_pkcs12.py +++ b/plugins/modules/openssl_pkcs12.py @@ -187,11 +187,14 @@ from ansible.module_utils.basic import AnsibleModule, missing_required_lib from ansible.module_utils._text import to_bytes, to_native +from ansible_collections.community.crypto.plugins.module_utils.io import ( + load_file_if_exists, + write_file, +) + from ansible_collections.community.crypto.plugins.module_utils.crypto.basic import ( OpenSSLObjectError, OpenSSLBadPassphraseError, - load_file_if_exists, - write_file, ) from ansible_collections.community.crypto.plugins.module_utils.crypto.support import ( diff --git a/plugins/modules/openssl_privatekey.py b/plugins/modules/openssl_privatekey.py index 6dc6bfbc0..4a361326c 100644 --- a/plugins/modules/openssl_privatekey.py +++ b/plugins/modules/openssl_privatekey.py @@ -282,6 +282,11 @@ from ansible.module_utils.basic import AnsibleModule, missing_required_lib from ansible.module_utils._text import to_native, to_bytes +from ansible_collections.community.crypto.plugins.module_utils.io import ( + load_file_if_exists, + write_file, +) + from ansible_collections.community.crypto.plugins.module_utils.crypto.basic import ( CRYPTOGRAPHY_HAS_X25519, CRYPTOGRAPHY_HAS_X25519_FULL, @@ -290,8 +295,6 @@ CRYPTOGRAPHY_HAS_ED448, OpenSSLObjectError, OpenSSLBadPassphraseError, - write_file, - load_file_if_exists, ) from ansible_collections.community.crypto.plugins.module_utils.crypto.support import ( diff --git a/plugins/modules/openssl_publickey.py b/plugins/modules/openssl_publickey.py index c478c240f..d4766a258 100644 --- a/plugins/modules/openssl_publickey.py +++ b/plugins/modules/openssl_publickey.py @@ -185,11 +185,14 @@ from ansible.module_utils.basic import AnsibleModule, missing_required_lib from ansible.module_utils._text import to_native +from ansible_collections.community.crypto.plugins.module_utils.io import ( + load_file_if_exists, + write_file, +) + from ansible_collections.community.crypto.plugins.module_utils.crypto.basic import ( OpenSSLObjectError, OpenSSLBadPassphraseError, - write_file, - load_file_if_exists, ) from ansible_collections.community.crypto.plugins.module_utils.crypto.support import ( diff --git a/plugins/modules/x509_certificate.py b/plugins/modules/x509_certificate.py index 822235285..e91791cb1 100644 --- a/plugins/modules/x509_certificate.py +++ b/plugins/modules/x509_certificate.py @@ -864,11 +864,14 @@ from ansible_collections.community.crypto.plugins.module_utils.compat import ipaddress as compat_ipaddress from ansible_collections.community.crypto.plugins.module_utils.ecs.api import ECSClient, RestOperationException, SessionConfigurationException +from ansible_collections.community.crypto.plugins.module_utils.io import ( + load_file_if_exists, + write_file, +) + from ansible_collections.community.crypto.plugins.module_utils.crypto.basic import ( OpenSSLObjectError, OpenSSLBadPassphraseError, - write_file, - load_file_if_exists, ) from ansible_collections.community.crypto.plugins.module_utils.crypto.support import ( diff --git a/plugins/modules/x509_crl.py b/plugins/modules/x509_crl.py index dd0cd1254..a08c030fb 100644 --- a/plugins/modules/x509_crl.py +++ b/plugins/modules/x509_crl.py @@ -354,10 +354,13 @@ from ansible.module_utils.basic import AnsibleModule, missing_required_lib from ansible.module_utils._text import to_native, to_text +from ansible_collections.community.crypto.plugins.module_utils.io import ( + write_file, +) + from ansible_collections.community.crypto.plugins.module_utils.crypto.basic import ( OpenSSLObjectError, OpenSSLBadPassphraseError, - write_file, ) from ansible_collections.community.crypto.plugins.module_utils.crypto.support import (