diff --git a/lib/ansible/module_utils/ansible_tower.py b/lib/ansible/module_utils/ansible_tower.py index 0e3d1301c0..9caf3e3e65 100644 --- a/lib/ansible/module_utils/ansible_tower.py +++ b/lib/ansible/module_utils/ansible_tower.py @@ -27,7 +27,9 @@ # USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. import os +import traceback +TOWER_CLI_IMP_ERR = None try: import tower_cli.utils.exceptions as exc from tower_cli.utils import parser @@ -35,9 +37,10 @@ try: HAS_TOWER_CLI = True except ImportError: + TOWER_CLI_IMP_ERR = traceback.format_exc() HAS_TOWER_CLI = False -from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.basic import AnsibleModule, missing_required_lib def tower_auth_config(module): @@ -105,4 +108,5 @@ class TowerModule(AnsibleModule): super(TowerModule, self).__init__(argument_spec=args, **kwargs) if not HAS_TOWER_CLI: - self.fail_json(msg='ansible-tower-cli required for this module') + self.fail_json(msg=missing_required_lib('ansible-tower-cli'), + exception=TOWER_CLI_IMP_ERR) diff --git a/lib/ansible/module_utils/aws/core.py b/lib/ansible/module_utils/aws/core.py index 963bdf8049..289c64dd0a 100644 --- a/lib/ansible/module_utils/aws/core.py +++ b/lib/ansible/module_utils/aws/core.py @@ -64,7 +64,7 @@ import traceback from functools import wraps from distutils.version import LooseVersion -from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.basic import AnsibleModule, missing_required_lib from ansible.module_utils._text import to_native from ansible.module_utils.ec2 import HAS_BOTO3, camel_dict_to_snake_dict, ec2_argument_spec, boto3_conn, get_aws_connection_info @@ -114,7 +114,7 @@ class AnsibleAWSModule(object): if local_settings["check_boto3"] and not HAS_BOTO3: self._module.fail_json( - msg='Python modules "botocore" or "boto3" are missing, please install both') + msg=missing_required_lib('botocore or boto3')) self.check_mode = self._module.check_mode self._diff = self._module._diff diff --git a/lib/ansible/module_utils/azure_rm_common.py b/lib/ansible/module_utils/azure_rm_common.py index f9761f307b..c0200252b7 100644 --- a/lib/ansible/module_utils/azure_rm_common.py +++ b/lib/ansible/module_utils/azure_rm_common.py @@ -13,7 +13,7 @@ import json from os.path import expanduser -from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.basic import AnsibleModule, missing_required_lib from ansible.module_utils.ansible_release import __version__ as ANSIBLE_VERSION from ansible.module_utils.six.moves import configparser import ansible.module_utils.six.moves.urllib.parse as urlparse @@ -99,6 +99,7 @@ AZURE_FAILED_STATE = "Failed" HAS_AZURE = True HAS_AZURE_EXC = None HAS_AZURE_CLI_CORE = True +HAS_AZURE_CLI_CORE_EXC = None HAS_MSRESTAZURE = True HAS_MSRESTAZURE_EXC = None @@ -114,16 +115,16 @@ try: from packaging.version import Version HAS_PACKAGING_VERSION = True HAS_PACKAGING_VERSION_EXC = None -except ImportError as exc: +except ImportError: Version = None HAS_PACKAGING_VERSION = False - HAS_PACKAGING_VERSION_EXC = exc + HAS_PACKAGING_VERSION_EXC = traceback.format_exc() # NB: packaging issue sometimes cause msrestazure not to be installed, check it separately try: from msrest.serialization import Serializer -except ImportError as exc: - HAS_MSRESTAZURE_EXC = exc +except ImportError: + HAS_MSRESTAZURE_EXC = traceback.format_exc() HAS_MSRESTAZURE = False try: @@ -161,7 +162,7 @@ try: from azure.mgmt.containerregistry import ContainerRegistryManagementClient from azure.mgmt.containerinstance import ContainerInstanceManagementClient except ImportError as exc: - HAS_AZURE_EXC = exc + HAS_AZURE_EXC = traceback.format_exc() HAS_AZURE = False try: @@ -170,6 +171,7 @@ try: from azure.common.cloud import get_cli_active_cloud except ImportError: HAS_AZURE_CLI_CORE = False + HAS_AZURE_CLI_CORE_EXC = None CLIError = Exception @@ -266,16 +268,16 @@ class AzureRMModuleBase(object): required_if=merged_required_if) if not HAS_PACKAGING_VERSION: - self.fail("Do you have packaging installed? Try `pip install packaging`" - "- {0}".format(HAS_PACKAGING_VERSION_EXC)) + self.fail(msg=missing_required_lib('packaging'), + exception=HAS_PACKAGING_VERSION_EXC) if not HAS_MSRESTAZURE: - self.fail("Do you have msrestazure installed? Try `pip install msrestazure`" - "- {0}".format(HAS_MSRESTAZURE_EXC)) + self.fail(msg=missing_required_lib('msrestazure'), + exception=HAS_MSRESTAZURE_EXC) if not HAS_AZURE: - self.fail("Do you have azure>={1} installed? Try `pip install ansible[azure]`" - "- {0}".format(HAS_AZURE_EXC, AZURE_MIN_RELEASE)) + self.fail(msg=missing_required_lib('ansible[azure] (azure >= {0})'.format(AZURE_MIN_RELEASE)), + exception=HAS_AZURE_EXC) self._network_client = None self._storage_client = None @@ -1146,7 +1148,8 @@ class AzureRMAuth(object): if auth_source == 'cli': if not HAS_AZURE_CLI_CORE: - self.fail("Azure auth_source is `cli`, but azure-cli package is not available. Try `pip install azure-cli --upgrade`") + self.fail(msg=missing_required_lib('azure-cli', reason='for `cli` auth_source'), + exception=HAS_AZURE_CLI_CORE_EXC) try: self.log('Retrieving credentials from Azure CLI profile') cli_credentials = self._get_azure_cli_credentials() diff --git a/lib/ansible/module_utils/basic.py b/lib/ansible/module_utils/basic.py index d1856afc6d..b74cd28d5a 100644 --- a/lib/ansible/module_utils/basic.py +++ b/lib/ansible/module_utils/basic.py @@ -729,11 +729,13 @@ def jsonify(data, **kwargs): raise UnicodeError('Invalid unicode encoding encountered') -def missing_required_lib(library, reason=None): +def missing_required_lib(library, reason=None, url=None): hostname = platform.node() msg = "Failed to import the required Python library (%s) on %s's Python %s." % (library, hostname, sys.executable) if reason: msg += " This is required %s." % reason + if url: + msg += " See %s for more info." % url return msg + " Please read module documentation and install in the appropriate location" diff --git a/lib/ansible/module_utils/cloudstack.py b/lib/ansible/module_utils/cloudstack.py index 4ef5487453..40c6e3334e 100644 --- a/lib/ansible/module_utils/cloudstack.py +++ b/lib/ansible/module_utils/cloudstack.py @@ -9,13 +9,17 @@ __metaclass__ = type import os import sys import time +import traceback from ansible.module_utils._text import to_text, to_native +from ansible.module_utils.basic import missing_required_lib +CS_IMP_ERR = None try: from cs import CloudStack, CloudStackException, read_config HAS_LIB_CS = True except ImportError: + CS_IMP_ERR = traceback.format_exc() HAS_LIB_CS = False CS_HYPERVISORS = [ @@ -53,7 +57,7 @@ class AnsibleCloudStack: def __init__(self, module): if not HAS_LIB_CS: - module.fail_json(msg="python library cs required: pip install cs") + module.fail_json(msg=missing_required_lib('cs'), exception=CS_IMP_ERR) self.result = { 'changed': False, diff --git a/lib/ansible/module_utils/dimensiondata.py b/lib/ansible/module_utils/dimensiondata.py index 0bc2e8c197..179c3eff9c 100644 --- a/lib/ansible/module_utils/dimensiondata.py +++ b/lib/ansible/module_utils/dimensiondata.py @@ -24,12 +24,14 @@ import os import re +import traceback -from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.basic import AnsibleModule, missing_required_lib from ansible.module_utils.six.moves import configparser from os.path import expanduser from uuid import UUID +LIBCLOUD_IMP_ERR = None try: from libcloud.common.dimensiondata import API_ENDPOINTS, DimensionDataAPIException, DimensionDataStatus from libcloud.compute.base import Node, NodeLocation @@ -40,6 +42,7 @@ try: HAS_LIBCLOUD = True except ImportError: + LIBCLOUD_IMP_ERR = traceback.format_exc() HAS_LIBCLOUD = False # MCP 2.x version patten for location (datacenter) names. @@ -69,7 +72,7 @@ class DimensionDataModule(object): self.module = module if not HAS_LIBCLOUD: - self.module.fail_json(msg='libcloud is required for this module.') + self.module.fail_json(msg=missing_required_lib('libcloud'), exception=LIBCLOUD_IMP_ERR) # Credentials are common to all Dimension Data modules. credentials = self.get_credentials() diff --git a/lib/ansible/module_utils/ec2.py b/lib/ansible/module_utils/ec2.py index e328930779..d2ad715bef 100644 --- a/lib/ansible/module_utils/ec2.py +++ b/lib/ansible/module_utils/ec2.py @@ -28,8 +28,10 @@ import os import re +import traceback from ansible.module_utils.ansible_release import __version__ +from ansible.module_utils.basic import missing_required_lib from ansible.module_utils._text import to_native, to_text from ansible.module_utils.cloud import CloudRetry from ansible.module_utils.six import string_types, binary_type, text_type @@ -38,18 +40,22 @@ from ansible.module_utils.common.dict_transformations import ( _camel_to_snake, _snake_to_camel, ) +BOTO_IMP_ERR = None try: import boto import boto.ec2 # boto does weird import stuff HAS_BOTO = True except ImportError: + BOTO_IMP_ERR = traceback.format_exc() HAS_BOTO = False +BOTO3_IMP_ERR = None try: import boto3 import botocore HAS_BOTO3 = True except Exception: + BOTO3_IMP_ERR = traceback.format_exc() HAS_BOTO3 = False try: @@ -253,7 +259,7 @@ def get_aws_connection_info(module, boto3=False): if not region: region = boto.config.get('Boto', 'ec2_region') else: - module.fail_json(msg="boto is required for this module. Please install boto and try again") + module.fail_json(msg=missing_required_lib('boto'), exception=BOTO_IMP_ERR) elif HAS_BOTO3: # here we don't need to make an additional call, will default to 'us-east-1' if the below evaluates to None. try: @@ -261,7 +267,7 @@ def get_aws_connection_info(module, boto3=False): except botocore.exceptions.ProfileNotFound as e: pass else: - module.fail_json(msg="Boto3 is required for this module. Please install boto3 and try again") + module.fail_json(msg=missing_required_lib('boto3'), exception=BOTO3_IMP_ERR) if not security_token: if os.environ.get('AWS_SECURITY_TOKEN'): diff --git a/lib/ansible/module_utils/heroku.py b/lib/ansible/module_utils/heroku.py index 2d3a28945d..b6e89614f1 100644 --- a/lib/ansible/module_utils/heroku.py +++ b/lib/ansible/module_utils/heroku.py @@ -4,14 +4,17 @@ from __future__ import absolute_import, division, print_function __metaclass__ = type -from ansible.module_utils.basic import env_fallback +import traceback + +from ansible.module_utils.basic import env_fallback, missing_required_lib HAS_HEROKU = False +HEROKU_IMP_ERR = None try: import heroku3 HAS_HEROKU = True except ImportError: - pass + HEROKU_IMP_ERR = traceback.format_exc() class HerokuHelper(): @@ -22,7 +25,7 @@ class HerokuHelper(): def check_lib(self): if not HAS_HEROKU: - self.module.fail_json(msg='heroku3 library required for this module (pip install heroku3)') + self.module.fail_json(msg=missing_required_lib('heroku3'), exception=HEROKU_IMP_ERR) @staticmethod def heroku_argument_spec(): diff --git a/lib/ansible/module_utils/ibm_sa_utils.py b/lib/ansible/module_utils/ibm_sa_utils.py index 7c9539c1ba..db02edb2e8 100644 --- a/lib/ansible/module_utils/ibm_sa_utils.py +++ b/lib/ansible/module_utils/ibm_sa_utils.py @@ -6,13 +6,18 @@ from __future__ import absolute_import, division, print_function __metaclass__ = type +import traceback + from functools import wraps from ansible.module_utils._text import to_native +from ansible.module_utils.basic import missing_required_lib PYXCLI_INSTALLED = True +PYXCLI_IMP_ERR = None try: from pyxcli import client, errors except ImportError: + PYXCLI_IMP_ERR = traceback.format_exc() PYXCLI_INSTALLED = False AVAILABLE_PYXCLI_FIELDS = ['pool', 'size', 'snapshot_size', @@ -83,6 +88,5 @@ def build_pyxcli_command(fields): def is_pyxcli_installed(module): if not PYXCLI_INSTALLED: - module.fail_json( - msg='pyxcli is required, use \'pip install pyxcli\' ' - 'in order to install it.') + module.fail_json(msg=missing_required_lib('pyxcli'), + exception=PYXCLI_IMP_ERR) diff --git a/lib/ansible/module_utils/vca.py b/lib/ansible/module_utils/vca.py index 29805f99f6..daafe4fb8e 100644 --- a/lib/ansible/module_utils/vca.py +++ b/lib/ansible/module_utils/vca.py @@ -15,14 +15,17 @@ # along with Ansible. If not, see . import os +import traceback +PYVCLOUD_IMP_ERR = None try: from pyvcloud.vcloudair import VCA HAS_PYVCLOUD = True except ImportError: + PYVCLOUD_IMP_ERR = traceback.format_exc() HAS_PYVCLOUD = False -from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.basic import AnsibleModule, missing_required_lib SERVICE_MAP = {'vca': 'ondemand', 'vchs': 'subscription', 'vcd': 'vcd'} LOGIN_HOST = {'vca': 'vca.vmware.com', 'vchs': 'vchs.vmware.com'} @@ -64,7 +67,8 @@ class VcaAnsibleModule(AnsibleModule): super(VcaAnsibleModule, self).__init__(*args, **kwargs) if not HAS_PYVCLOUD: - self.fail("python module pyvcloud is required for this module") + self.fail(missing_required_lib('pyvcloud'), + exception=PYVCLOUD_IMP_ERR) self._vca = self.create_instance() self.login() @@ -212,7 +216,8 @@ VCD_REQ_ARGS = [] def _validate_module(module): if not HAS_PYVCLOUD: - module.fail_json(msg="python module pyvcloud is needed for this module") + module.fail_json(msg=missing_required_lib("pyvcloud"), + exception=PYVCLOUD_IMP_ERR) service_type = module.params.get('service_type', DEFAULT_SERVICE_TYPE) diff --git a/lib/ansible/module_utils/vmware.py b/lib/ansible/module_utils/vmware.py index 22d4767002..7dd64c98ad 100644 --- a/lib/ansible/module_utils/vmware.py +++ b/lib/ansible/module_utils/vmware.py @@ -11,25 +11,30 @@ import os import re import ssl import time +import traceback from random import randint +REQUESTS_IMP_ERR = None try: # requests is required for exception handling of the ConnectionError import requests HAS_REQUESTS = True except ImportError: + REQUESTS_IMP_ERR = traceback.format_exc() HAS_REQUESTS = False +PYVMOMI_IMP_ERR = None try: from pyVim import connect from pyVmomi import vim, vmodl HAS_PYVMOMI = True except ImportError: + PYVMOMI_IMP_ERR = traceback.format_exc() HAS_PYVMOMI = False from ansible.module_utils._text import to_text, to_native from ansible.module_utils.six import integer_types, iteritems, string_types, raise_from -from ansible.module_utils.basic import env_fallback +from ansible.module_utils.basic import env_fallback, missing_required_lib class TaskError(Exception): @@ -776,11 +781,12 @@ class PyVmomi(object): Constructor """ if not HAS_REQUESTS: - module.fail_json(msg="Unable to find 'requests' Python library which is required." - " Please install using 'pip install requests'") + module.fail_json(msg=missing_required_lib('requests'), + exception=REQUESTS_IMP_ERR) if not HAS_PYVMOMI: - module.fail_json(msg='PyVmomi Python module required. Install using "pip install PyVmomi"') + module.fail_json(msg=missing_required_lib('PyVmomi'), + exception=PYVMOMI_IMP_ERR) self.module = module self.params = module.params diff --git a/lib/ansible/module_utils/vmware_rest_client.py b/lib/ansible/module_utils/vmware_rest_client.py index cff97203ce..34ce5b2536 100644 --- a/lib/ansible/module_utils/vmware_rest_client.py +++ b/lib/ansible/module_utils/vmware_rest_client.py @@ -6,19 +6,26 @@ from __future__ import absolute_import, division, print_function __metaclass__ = type +import traceback + +REQUESTS_IMP_ERR = None try: import requests HAS_REQUESTS = True except ImportError: + REQUESTS_IMP_ERR = traceback.format_exc() HAS_REQUESTS = False +PYVMOMI_IMP_ERR = None try: from pyVim import connect from pyVmomi import vim, vmodl HAS_PYVMOMI = True except ImportError: + PYVMOMI_IMP_ERR = traceback.format_exc() HAS_PYVMOMI = False +VCLOUD_IMP_ERR = None try: from vmware.vapi.lib.connect import get_requests_connector from vmware.vapi.security.session import create_session_security_context @@ -27,16 +34,19 @@ try: from com.vmware.vapi.std_client import DynamicID HAS_VCLOUD = True except ImportError: + VCLOUD_IMP_ERR = traceback.format_exc() HAS_VCLOUD = False +VSPHERE_IMP_ERR = None try: from vmware.vapi.stdlib.client.factories import StubConfigurationFactory HAS_VSPHERE = True except ImportError: + VSPHERE_IMP_ERR = traceback.format_exc() HAS_VSPHERE = False from ansible.module_utils._text import to_native -from ansible.module_utils.basic import env_fallback +from ansible.module_utils.basic import env_fallback, missing_required_lib class VmwareRestClient(object): @@ -56,18 +66,21 @@ class VmwareRestClient(object): """ if not HAS_REQUESTS: - self.module.fail_json(msg="Unable to find 'requests' Python library which is required." - " Please install using 'pip install requests'") + self.module.fail_json(msg=missing_required_lib('requests'), + exception=REQUESTS_IMP_ERR) if not HAS_PYVMOMI: - self.module.fail_json(msg="PyVmomi Python module required. Install using 'pip install PyVmomi'") + self.module.fail_json(msg=missing_required_lib('PyVmomi'), + exception=PYVMOMI_IMP_ERR) if not HAS_VSPHERE: - self.module.fail_json(msg="Unable to find 'vSphere Automation SDK' Python library which is required." - " Please refer this URL for installation steps" - " - https://code.vmware.com/web/sdk/65/vsphere-automation-python") + self.module.fail_json( + msg=missing_required_lib('vSphere Automation SDK', + url='https://code.vmware.com/web/sdk/65/vsphere-automation-python'), + exception=VSPHERE_IMP_ERR) if not HAS_VCLOUD: - self.module.fail_json(msg="Unable to find 'vCloud Suite SDK' Python library which is required." - " Please refer this URL for installation steps" - " - https://code.vmware.com/web/sdk/60/vcloudsuite-python") + self.module.fail_json( + msg=missing_required_lib('vCloud Suite SDK', + url='https://code.vmware.com/web/sdk/60/vcloudsuite-python'), + exception=VCLOUD_IMP_ERR) def connect_to_rest(self): """ diff --git a/lib/ansible/modules/cloud/alicloud/ali_instance.py b/lib/ansible/modules/cloud/alicloud/ali_instance.py index 6a6505c059..edc2609ed8 100644 --- a/lib/ansible/modules/cloud/alicloud/ali_instance.py +++ b/lib/ansible/modules/cloud/alicloud/ali_instance.py @@ -508,15 +508,17 @@ ids: ''' import time -from ansible.module_utils.basic import AnsibleModule +import traceback +from ansible.module_utils.basic import AnsibleModule, missing_required_lib from ansible.module_utils.alicloud_ecs import ecs_argument_spec, ecs_connect HAS_FOOTMARK = False - +FOOTMARK_IMP_ERR = None try: from footmark.exception import ECSResponseError HAS_FOOTMARK = True except ImportError: + FOOTMARK_IMP_ERR = traceback.format_exc() HAS_FOOTMARK = False @@ -626,7 +628,7 @@ def main(): module = AnsibleModule(argument_spec=argument_spec) if HAS_FOOTMARK is False: - module.fail_json(msg="Package 'footmark' required for the module ali_instance.") + module.fail_json(msg=missing_required_lib('footmark'), exception=FOOTMARK_IMP_ERR) ecs = ecs_connect(module) state = module.params['state'] diff --git a/lib/ansible/modules/cloud/alicloud/ali_instance_facts.py b/lib/ansible/modules/cloud/alicloud/ali_instance_facts.py index f1e3d83b3b..8636622c51 100644 --- a/lib/ansible/modules/cloud/alicloud/ali_instance_facts.py +++ b/lib/ansible/modules/cloud/alicloud/ali_instance_facts.py @@ -338,15 +338,17 @@ ids: # import time # import sys -from ansible.module_utils.basic import AnsibleModule +import traceback +from ansible.module_utils.basic import AnsibleModule, missing_required_lib from ansible.module_utils.alicloud_ecs import get_acs_connection_info, ecs_argument_spec, ecs_connect HAS_FOOTMARK = False - +FOOTMARK_IMP_ERR = None try: from footmark.exception import ECSResponseError HAS_FOOTMARK = True except ImportError: + FOOTMARK_IMP_ERR = traceback.format_exc() HAS_FOOTMARK = False @@ -362,7 +364,7 @@ def main(): module = AnsibleModule(argument_spec=argument_spec) if HAS_FOOTMARK is False: - module.fail_json(msg='footmark required for the module ali_instance_facts') + module.fail_json(msg=missing_required_lib('footmark'), exception=FOOTMARK_IMP_ERR) ecs = ecs_connect(module) diff --git a/lib/ansible/modules/cloud/centurylink/clc_aa_policy.py b/lib/ansible/modules/cloud/centurylink/clc_aa_policy.py index 63232872e8..e7c8b5e106 100644 --- a/lib/ansible/modules/cloud/centurylink/clc_aa_policy.py +++ b/lib/ansible/modules/cloud/centurylink/clc_aa_policy.py @@ -127,12 +127,15 @@ policy: __version__ = '${version}' import os +import traceback from distutils.version import LooseVersion +REQUESTS_IMP_ERR = None try: import requests except ImportError: + REQUESTS_IMP_ERR = traceback.format_exc() REQUESTS_FOUND = False else: REQUESTS_FOUND = True @@ -141,16 +144,18 @@ else: # Requires the clc-python-sdk: # sudo pip install clc-sdk # +CLC_IMP_ERR = None try: import clc as clc_sdk from clc import CLCException except ImportError: + CLC_IMP_ERR = traceback.format_exc() CLC_FOUND = False clc_sdk = None else: CLC_FOUND = True -from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.basic import AnsibleModule, missing_required_lib class ClcAntiAffinityPolicy: @@ -166,11 +171,11 @@ class ClcAntiAffinityPolicy: self.policy_dict = {} if not CLC_FOUND: - self.module.fail_json( - msg='clc-python-sdk required for this module') + self.module.fail_json(msg=missing_required_lib('clc-sdk'), + exception=CLC_IMP_ERR) if not REQUESTS_FOUND: - self.module.fail_json( - msg='requests library is required for this module') + self.module.fail_json(msg=missing_required_lib('requests'), + exception=REQUESTS_IMP_ERR) if requests.__version__ and LooseVersion(requests.__version__) < LooseVersion('2.5.0'): self.module.fail_json( msg='requests library version should be >= 2.5.0') diff --git a/lib/ansible/modules/cloud/centurylink/clc_alert_policy.py b/lib/ansible/modules/cloud/centurylink/clc_alert_policy.py index caf57b9295..81375a5d05 100644 --- a/lib/ansible/modules/cloud/centurylink/clc_alert_policy.py +++ b/lib/ansible/modules/cloud/centurylink/clc_alert_policy.py @@ -157,11 +157,14 @@ __version__ = '${version}' import json import os +import traceback from distutils.version import LooseVersion +REQUESTS_IMP_ERR = None try: import requests except ImportError: + REQUESTS_IMP_ERR = traceback.format_exc() REQUESTS_FOUND = False else: REQUESTS_FOUND = True @@ -170,16 +173,18 @@ else: # Requires the clc-python-sdk. # sudo pip install clc-sdk # +CLC_IMP_ERR = None try: import clc as clc_sdk from clc import APIFailedResponse except ImportError: + CLC_IMP_ERR = traceback.format_exc() CLC_FOUND = False clc_sdk = None else: CLC_FOUND = True -from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.basic import AnsibleModule, missing_required_lib class ClcAlertPolicy: @@ -195,11 +200,9 @@ class ClcAlertPolicy: self.policy_dict = {} if not CLC_FOUND: - self.module.fail_json( - msg='clc-python-sdk required for this module') + self.module.fail_json(msg=missing_required_lib('clc-sdk'), exception=CLC_IMP_ERR) if not REQUESTS_FOUND: - self.module.fail_json( - msg='requests library is required for this module') + self.module.fail_json(msg=missing_required_lib('requests'), exception=REQUESTS_IMP_ERR) if requests.__version__ and LooseVersion(requests.__version__) < LooseVersion('2.5.0'): self.module.fail_json( msg='requests library version should be >= 2.5.0') diff --git a/lib/ansible/modules/cloud/centurylink/clc_blueprint_package.py b/lib/ansible/modules/cloud/centurylink/clc_blueprint_package.py index 3f009e3e8e..dba425faf7 100644 --- a/lib/ansible/modules/cloud/centurylink/clc_blueprint_package.py +++ b/lib/ansible/modules/cloud/centurylink/clc_blueprint_package.py @@ -88,11 +88,14 @@ server_ids: __version__ = '${version}' import os +import traceback from distutils.version import LooseVersion +REQUESTS_IMP_ERR = None try: import requests except ImportError: + REQUESTS_IMP_ERR = traceback.format_exc() REQUESTS_FOUND = False else: REQUESTS_FOUND = True @@ -101,16 +104,18 @@ else: # Requires the clc-python-sdk. # sudo pip install clc-sdk # +CLC_IMP_ERR = None try: import clc as clc_sdk from clc import CLCException except ImportError: + CLC_IMP_ERR = traceback.format_exc() CLC_FOUND = False clc_sdk = None else: CLC_FOUND = True -from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.basic import AnsibleModule, missing_required_lib class ClcBlueprintPackage: @@ -124,11 +129,9 @@ class ClcBlueprintPackage: """ self.module = module if not CLC_FOUND: - self.module.fail_json( - msg='clc-python-sdk required for this module') + self.module.fail_json(msg=missing_required_lib('clc-sdk'), exception=CLC_IMP_ERR) if not REQUESTS_FOUND: - self.module.fail_json( - msg='requests library is required for this module') + self.module.fail_json(msg=missing_required_lib('requests'), exception=REQUESTS_IMP_ERR) if requests.__version__ and LooseVersion( requests.__version__) < LooseVersion('2.5.0'): self.module.fail_json( diff --git a/lib/ansible/modules/cloud/centurylink/clc_firewall_policy.py b/lib/ansible/modules/cloud/centurylink/clc_firewall_policy.py index b0da24af71..bec4663bfc 100644 --- a/lib/ansible/modules/cloud/centurylink/clc_firewall_policy.py +++ b/lib/ansible/modules/cloud/centurylink/clc_firewall_policy.py @@ -153,27 +153,32 @@ firewall_policy: __version__ = '${version}' import os +import traceback from ansible.module_utils.six.moves.urllib.parse import urlparse from time import sleep from distutils.version import LooseVersion +REQUESTS_IMP_ERR = None try: import requests except ImportError: + REQUESTS_IMP_ERR = traceback.format_exc() REQUESTS_FOUND = False else: REQUESTS_FOUND = True +CLC_IMP_ERR = None try: import clc as clc_sdk from clc import APIFailedResponse except ImportError: + CLC_IMP_ERR = traceback.format_exc() CLC_FOUND = False clc_sdk = None else: CLC_FOUND = True -from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.basic import AnsibleModule, missing_required_lib class ClcFirewallPolicy: @@ -189,11 +194,9 @@ class ClcFirewallPolicy: self.firewall_dict = {} if not CLC_FOUND: - self.module.fail_json( - msg='clc-python-sdk required for this module') + self.module.fail_json(msg=missing_required_lib('clc-sdk'), exception=CLC_IMP_ERR) if not REQUESTS_FOUND: - self.module.fail_json( - msg='requests library is required for this module') + self.module.fail_json(msg=missing_required_lib('requests'), exception=REQUESTS_IMP_ERR) if requests.__version__ and LooseVersion( requests.__version__) < LooseVersion('2.5.0'): self.module.fail_json( diff --git a/lib/ansible/modules/cloud/centurylink/clc_group.py b/lib/ansible/modules/cloud/centurylink/clc_group.py index 50b8aff3da..23dcdb04e6 100644 --- a/lib/ansible/modules/cloud/centurylink/clc_group.py +++ b/lib/ansible/modules/cloud/centurylink/clc_group.py @@ -208,11 +208,14 @@ group: __version__ = '${version}' import os +import traceback from distutils.version import LooseVersion +REQUESTS_IMP_ERR = None try: import requests except ImportError: + REQUESTS_IMP_ERR = traceback.format_exc() REQUESTS_FOUND = False else: REQUESTS_FOUND = True @@ -221,16 +224,18 @@ else: # Requires the clc-python-sdk. # sudo pip install clc-sdk # +CLC_IMP_ERR = None try: import clc as clc_sdk from clc import CLCException except ImportError: + CLC_IMP_ERR = traceback.format_exc() CLC_FOUND = False clc_sdk = None else: CLC_FOUND = True -from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.basic import AnsibleModule, missing_required_lib class ClcGroup(object): @@ -247,11 +252,9 @@ class ClcGroup(object): self.group_dict = {} if not CLC_FOUND: - self.module.fail_json( - msg='clc-python-sdk required for this module') + self.module.fail_json(msg=missing_required_lib('clc-sdk'), exception=CLC_IMP_ERR) if not REQUESTS_FOUND: - self.module.fail_json( - msg='requests library is required for this module') + self.module.fail_json(msg=missing_required_lib('requests'), exception=REQUESTS_IMP_ERR) if requests.__version__ and LooseVersion(requests.__version__) < LooseVersion('2.5.0'): self.module.fail_json( msg='requests library version should be >= 2.5.0') diff --git a/lib/ansible/modules/cloud/centurylink/clc_loadbalancer.py b/lib/ansible/modules/cloud/centurylink/clc_loadbalancer.py index ee2f9f2655..6a0cba46a3 100644 --- a/lib/ansible/modules/cloud/centurylink/clc_loadbalancer.py +++ b/lib/ansible/modules/cloud/centurylink/clc_loadbalancer.py @@ -202,12 +202,15 @@ __version__ = '${version}' import json import os +import traceback from time import sleep from distutils.version import LooseVersion +REQUESTS_IMP_ERR = None try: import requests except ImportError: + REQUESTS_IMP_ERR = traceback.format_exc() REQUESTS_FOUND = False else: REQUESTS_FOUND = True @@ -216,16 +219,18 @@ else: # Requires the clc-python-sdk. # sudo pip install clc-sdk # +CLC_IMP_ERR = None try: import clc as clc_sdk from clc import APIFailedResponse except ImportError: + CLC_IMP_ERR = traceback.format_exc() CLC_FOUND = False clc_sdk = None else: CLC_FOUND = True -from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.basic import AnsibleModule, missing_required_lib class ClcLoadBalancer: @@ -241,11 +246,9 @@ class ClcLoadBalancer: self.lb_dict = {} if not CLC_FOUND: - self.module.fail_json( - msg='clc-python-sdk required for this module') + self.module.fail_json(msg=missing_required_lib('clc-sdk'), exception=CLC_IMP_ERR) if not REQUESTS_FOUND: - self.module.fail_json( - msg='requests library is required for this module') + self.module.fail_json(msg=missing_required_lib('requests'), exception=REQUESTS_IMP_ERR) if requests.__version__ and LooseVersion( requests.__version__) < LooseVersion('2.5.0'): self.module.fail_json( diff --git a/lib/ansible/modules/cloud/centurylink/clc_modify_server.py b/lib/ansible/modules/cloud/centurylink/clc_modify_server.py index 8c23d5ce9e..d7a4e07a23 100644 --- a/lib/ansible/modules/cloud/centurylink/clc_modify_server.py +++ b/lib/ansible/modules/cloud/centurylink/clc_modify_server.py @@ -306,11 +306,14 @@ __version__ = '${version}' import json import os +import traceback from distutils.version import LooseVersion +REQUESTS_IMP_ERR = None try: import requests except ImportError: + REQUESTS_IMP_ERR = traceback.format_exc() REQUESTS_FOUND = False else: REQUESTS_FOUND = True @@ -319,17 +322,19 @@ else: # Requires the clc-python-sdk. # sudo pip install clc-sdk # +CLC_IMP_ERR = None try: import clc as clc_sdk from clc import CLCException from clc import APIFailedResponse except ImportError: + CLC_IMP_ERR = traceback.format_exc() CLC_FOUND = False clc_sdk = None else: CLC_FOUND = True -from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.basic import AnsibleModule, missing_required_lib class ClcModifyServer: @@ -343,11 +348,9 @@ class ClcModifyServer: self.module = module if not CLC_FOUND: - self.module.fail_json( - msg='clc-python-sdk required for this module') + self.module.fail_json(msg=missing_required_lib('clc-sdk'), exception=CLC_IMP_ERR) if not REQUESTS_FOUND: - self.module.fail_json( - msg='requests library is required for this module') + self.module.fail_json(msg=missing_required_lib('requests'), exception=REQUESTS_IMP_ERR) if requests.__version__ and LooseVersion( requests.__version__) < LooseVersion('2.5.0'): self.module.fail_json( diff --git a/lib/ansible/modules/cloud/centurylink/clc_publicip.py b/lib/ansible/modules/cloud/centurylink/clc_publicip.py index 5165f84596..bedfdee68d 100644 --- a/lib/ansible/modules/cloud/centurylink/clc_publicip.py +++ b/lib/ansible/modules/cloud/centurylink/clc_publicip.py @@ -115,11 +115,14 @@ server_ids: __version__ = '${version}' import os +import traceback from distutils.version import LooseVersion +REQUESTS_IMP_ERR = None try: import requests except ImportError: + REQUESTS_IMP_ERR = traceback.format_exc() REQUESTS_FOUND = False else: REQUESTS_FOUND = True @@ -128,16 +131,18 @@ else: # Requires the clc-python-sdk. # sudo pip install clc-sdk # +CLC_IMP_ERR = None try: import clc as clc_sdk from clc import CLCException except ImportError: + CLC_IMP_ERR = traceback.format_exc() CLC_FOUND = False clc_sdk = None else: CLC_FOUND = True -from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.basic import AnsibleModule, missing_required_lib class ClcPublicIp(object): @@ -150,11 +155,9 @@ class ClcPublicIp(object): """ self.module = module if not CLC_FOUND: - self.module.fail_json( - msg='clc-python-sdk required for this module') + self.module.fail_json(msg=missing_required_lib('clc-sdk'), exception=CLC_IMP_ERR) if not REQUESTS_FOUND: - self.module.fail_json( - msg='requests library is required for this module') + self.module.fail_json(msg=missing_required_lib('requests'), exception=REQUESTS_IMP_ERR) if requests.__version__ and LooseVersion(requests.__version__) < LooseVersion('2.5.0'): self.module.fail_json( msg='requests library version should be >= 2.5.0') diff --git a/lib/ansible/modules/cloud/centurylink/clc_server.py b/lib/ansible/modules/cloud/centurylink/clc_server.py index 222c92e9c6..4d75d204aa 100644 --- a/lib/ansible/modules/cloud/centurylink/clc_server.py +++ b/lib/ansible/modules/cloud/centurylink/clc_server.py @@ -398,11 +398,14 @@ __version__ = '${version}' import json import os import time +import traceback from distutils.version import LooseVersion +REQUESTS_IMP_ERR = None try: import requests except ImportError: + REQUESTS_IMP_ERR = traceback.format_exc() REQUESTS_FOUND = False else: REQUESTS_FOUND = True @@ -411,17 +414,19 @@ else: # Requires the clc-python-sdk. # sudo pip install clc-sdk # +CLC_IMP_ERR = None try: import clc as clc_sdk from clc import CLCException from clc import APIFailedResponse except ImportError: + CLC_IMP_ERR = traceback.format_exc() CLC_FOUND = False clc_sdk = None else: CLC_FOUND = True -from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.basic import AnsibleModule, missing_required_lib class ClcServer: @@ -436,11 +441,9 @@ class ClcServer: self.group_dict = {} if not CLC_FOUND: - self.module.fail_json( - msg='clc-python-sdk required for this module') + self.module.fail_json(msg=missing_required_lib('clc-sdk'), exception=CLC_IMP_ERR) if not REQUESTS_FOUND: - self.module.fail_json( - msg='requests library is required for this module') + self.module.fail_json(msg=missing_required_lib('requests'), exception=REQUESTS_IMP_ERR) if requests.__version__ and LooseVersion( requests.__version__) < LooseVersion('2.5.0'): self.module.fail_json( diff --git a/lib/ansible/modules/cloud/centurylink/clc_server_snapshot.py b/lib/ansible/modules/cloud/centurylink/clc_server_snapshot.py index dc2a544e4e..80353219fb 100644 --- a/lib/ansible/modules/cloud/centurylink/clc_server_snapshot.py +++ b/lib/ansible/modules/cloud/centurylink/clc_server_snapshot.py @@ -101,11 +101,14 @@ server_ids: __version__ = '${version}' import os +import traceback from distutils.version import LooseVersion +REQUESTS_IMP_ERR = None try: import requests except ImportError: + REQUESTS_IMP_ERR = traceback.format_exc() REQUESTS_FOUND = False else: REQUESTS_FOUND = True @@ -114,16 +117,18 @@ else: # Requires the clc-python-sdk. # sudo pip install clc-sdk # +CLC_IMP_ERR = None try: import clc as clc_sdk from clc import CLCException except ImportError: + CLC_IMP_ERR = traceback.format_exc() CLC_FOUND = False clc_sdk = None else: CLC_FOUND = True -from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.basic import AnsibleModule, missing_required_lib class ClcSnapshot: @@ -138,11 +143,9 @@ class ClcSnapshot: self.module = module if not CLC_FOUND: - self.module.fail_json( - msg='clc-python-sdk required for this module') + self.module.fail_json(msg=missing_required_lib('clc-sdk'), exception=CLC_IMP_ERR) if not REQUESTS_FOUND: - self.module.fail_json( - msg='requests library is required for this module') + self.module.fail_json(msg=missing_required_lib('requests'), exception=REQUESTS_IMP_ERR) if requests.__version__ and LooseVersion( requests.__version__) < LooseVersion('2.5.0'): self.module.fail_json( diff --git a/lib/ansible/modules/cloud/cloudscale/cloudscale_floating_ip.py b/lib/ansible/modules/cloud/cloudscale/cloudscale_floating_ip.py index f50b614314..244641fce1 100644 --- a/lib/ansible/modules/cloud/cloudscale/cloudscale_floating_ip.py +++ b/lib/ansible/modules/cloud/cloudscale/cloudscale_floating_ip.py @@ -151,14 +151,17 @@ state: ''' import os +import traceback +IPADDRESS_IMP_ERR = None try: from ipaddress import ip_network HAS_IPADDRESS = True except ImportError: + IPADDRESS_IMP_ERR = traceback.format_exc() HAS_IPADDRESS = False -from ansible.module_utils.basic import AnsibleModule, env_fallback +from ansible.module_utils.basic import AnsibleModule, env_fallback, missing_required_lib from ansible.module_utils.cloudscale import AnsibleCloudscaleBase, cloudscale_argument_spec @@ -249,7 +252,7 @@ def main(): ) if not HAS_IPADDRESS: - module.fail_json(msg='Could not import the python library ipaddress required by this module') + module.fail_json(msg=missing_required_lib('ipaddress'), exception=IPADDRESS_IMP_ERR) target_state = module.params['state'] target_server = module.params['server'] diff --git a/lib/ansible/modules/cloud/cloudstack/cs_facts.py b/lib/ansible/modules/cloud/cloudstack/cs_facts.py index fe3d1a11f3..331e410a46 100644 --- a/lib/ansible/modules/cloud/cloudstack/cs_facts.py +++ b/lib/ansible/modules/cloud/cloudstack/cs_facts.py @@ -113,14 +113,17 @@ cloudstack_user_data: ''' import os -from ansible.module_utils.basic import AnsibleModule +import traceback +from ansible.module_utils.basic import AnsibleModule, missing_required_lib from ansible.module_utils.urls import fetch_url from ansible.module_utils.facts import ansible_collector, default_collectors +YAML_IMP_ERR = None try: import yaml HAS_LIB_YAML = True except ImportError: + YAML_IMP_ERR = traceback.format_exc() HAS_LIB_YAML = False CS_METADATA_BASE_URL = "http://%s/latest/meta-data" @@ -231,7 +234,7 @@ def main(): ) if not HAS_LIB_YAML: - module.fail_json(msg="missing python library: yaml") + module.fail_json(msg=missing_required_lib("PyYAML"), exception=YAML_IMP_ERR) cs_facts = CloudStackFacts().run() cs_facts_result = dict(changed=False, ansible_facts=cs_facts) diff --git a/lib/ansible/modules/cloud/cloudstack/cs_sshkeypair.py b/lib/ansible/modules/cloud/cloudstack/cs_sshkeypair.py index 8c163a9ec1..03d8b4d0ee 100644 --- a/lib/ansible/modules/cloud/cloudstack/cs_sshkeypair.py +++ b/lib/ansible/modules/cloud/cloudstack/cs_sshkeypair.py @@ -104,13 +104,17 @@ private_key: sample: "-----BEGIN RSA PRIVATE KEY-----\nMII...8tO\n-----END RSA PRIVATE KEY-----\n" ''' +import traceback + +SSHPUBKEYS_IMP_ERR = None try: import sshpubkeys HAS_LIB_SSHPUBKEYS = True except ImportError: + SSHPUBKEYS_IMP_ERR = traceback.format_exc() HAS_LIB_SSHPUBKEYS = False -from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.basic import AnsibleModule, missing_required_lib from ansible.module_utils._text import to_native from ansible.module_utils.cloudstack import ( AnsibleCloudStack, @@ -246,7 +250,7 @@ def main(): ) if not HAS_LIB_SSHPUBKEYS: - module.fail_json(msg="python library sshpubkeys required: pip install sshpubkeys") + module.fail_json(msg=missing_required_lib("sshpubkeys"), exception=SSHPUBKEYS_IMP_ERR) acs_sshkey = AnsibleCloudStackSshKey(module) state = module.params.get('state') diff --git a/lib/ansible/modules/cloud/linode/linode.py b/lib/ansible/modules/cloud/linode/linode.py index 59773bee8c..d13c7a435a 100644 --- a/lib/ansible/modules/cloud/linode/linode.py +++ b/lib/ansible/modules/cloud/linode/linode.py @@ -264,14 +264,17 @@ EXAMPLES = ''' import os import time +import traceback +LINODE_IMP_ERR = None try: from linode import api as linode_api HAS_LINODE = True except ImportError: + LINODE_IMP_ERR = traceback.format_exc() HAS_LINODE = False -from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.basic import AnsibleModule, missing_required_lib def randompass(): @@ -608,7 +611,7 @@ def main(): ) if not HAS_LINODE: - module.fail_json(msg='linode-python required for this module') + module.fail_json(msg=missing_required_lib('linode-python'), exception=LINODE_IMP_ERR) state = module.params.get('state') api_key = module.params.get('api_key') diff --git a/lib/ansible/modules/cloud/linode/linode_v4.py b/lib/ansible/modules/cloud/linode/linode_v4.py index 4bf2aaa03d..5f7418795e 100644 --- a/lib/ansible/modules/cloud/linode/linode_v4.py +++ b/lib/ansible/modules/cloud/linode/linode_v4.py @@ -162,14 +162,17 @@ instance: } """ +import traceback -from ansible.module_utils.basic import AnsibleModule, env_fallback +from ansible.module_utils.basic import AnsibleModule, env_fallback, missing_required_lib from ansible.module_utils.linode import get_user_agent +LINODE_IMP_ERR = None try: from linode_api4 import Instance, LinodeClient HAS_LINODE_DEPENDENCY = True except ImportError: + LINODE_IMP_ERR = traceback.format_exc() HAS_LINODE_DEPENDENCY = False @@ -257,7 +260,7 @@ def main(): module = initialise_module() if not HAS_LINODE_DEPENDENCY: - module.fail_json(msg='The linode_v4 module requires the linode_api4 package') + module.fail_json(msg=missing_required_lib('linode-api4'), exception=LINODE_IMP_ERR) client = build_client(module) instance = maybe_instance_from_label(module, client) diff --git a/lib/ansible/modules/storage/emc/emc_vnx_sg_member.py b/lib/ansible/modules/storage/emc/emc_vnx_sg_member.py index a0a748f9c5..8418c0c221 100644 --- a/lib/ansible/modules/storage/emc/emc_vnx_sg_member.py +++ b/lib/ansible/modules/storage/emc/emc_vnx_sg_member.py @@ -79,16 +79,20 @@ hluid: returned: success ''' -from ansible.module_utils.basic import AnsibleModule +import traceback + +from ansible.module_utils.basic import AnsibleModule, missing_required_lib from ansible.module_utils._text import to_native from ansible.module_utils.storage.emc.emc_vnx import emc_vnx_argument_spec +LIB_IMP_ERR = None try: from storops import VNXSystem from storops.exception import VNXCredentialError, VNXStorageGroupError, \ VNXAluAlreadyAttachedError, VNXAttachAluError, VNXDetachAluNotFoundError HAS_LIB = True except Exception: + LIB_IMP_ERR = traceback.format_exc() HAS_LIB = False @@ -112,9 +116,8 @@ def run_module(): ) if not HAS_LIB: - module.fail_json(msg='storops library (0.5.10 or greater) is missing.' - 'Install with pip install storops' - ) + module.fail_json(msg=missing_required_lib('storops >= 0.5.10'), + exception=LIB_IMP_ERR) sp_user = module.params['sp_user'] sp_address = module.params['sp_address'] diff --git a/lib/ansible/modules/storage/infinidat/infini_export.py b/lib/ansible/modules/storage/infinidat/infini_export.py index 5ad35f6ae3..ffc02e5f6d 100644 --- a/lib/ansible/modules/storage/infinidat/infini_export.py +++ b/lib/ansible/modules/storage/infinidat/infini_export.py @@ -83,13 +83,17 @@ EXAMPLES = ''' RETURN = ''' ''' +import traceback + +MUNCH_IMP_ERR = None try: from munch import unmunchify HAS_MUNCH = True except ImportError: + MUNCH_IMP_ERR = traceback.format_exc() HAS_MUNCH = False -from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.basic import AnsibleModule, missing_required_lib from ansible.module_utils.infinibox import HAS_INFINISDK, api_wrapper, get_system, infinibox_argument_spec @@ -168,9 +172,9 @@ def main(): module = AnsibleModule(argument_spec, supports_check_mode=True) if not HAS_INFINISDK: - module.fail_json(msg='infinisdk is required for this module') + module.fail_json(msg=missing_required_lib('infinisdk')) if not HAS_MUNCH: - module.fail_json(msg='the python munch library is required for this module') + module.fail_json(msg=missing_required_lib('munch'), exception=MUNCH_IMP_ERR) state = module.params['state'] system = get_system(module) diff --git a/lib/ansible/modules/storage/infinidat/infini_export_client.py b/lib/ansible/modules/storage/infinidat/infini_export_client.py index 68292427b8..93db60aa8c 100644 --- a/lib/ansible/modules/storage/infinidat/infini_export_client.py +++ b/lib/ansible/modules/storage/infinidat/infini_export_client.py @@ -83,14 +83,17 @@ EXAMPLES = ''' RETURN = ''' ''' +import traceback +MUNCH_IMP_ERR = None try: from munch import Munch, unmunchify HAS_MUNCH = True except ImportError: + MUNCH_IMP_ERR = traceback.format_exc() HAS_MUNCH = False -from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.basic import AnsibleModule, missing_required_lib from ansible.module_utils.infinibox import HAS_INFINISDK, api_wrapper, get_system, infinibox_argument_spec @@ -186,9 +189,9 @@ def main(): module = AnsibleModule(argument_spec, supports_check_mode=True) if not HAS_INFINISDK: - module.fail_json(msg='infinisdk is required for this module') + module.fail_json(msg=missing_required_lib('infinisdk')) if not HAS_MUNCH: - module.fail_json(msg='the python munch library is required for this module') + module.fail_json(msg=missing_required_lib('munch'), exception=MUNCH_IMP_ERR) system = get_system(module) export = get_export(module, system) diff --git a/lib/ansible/modules/storage/infinidat/infini_fs.py b/lib/ansible/modules/storage/infinidat/infini_fs.py index 421421cd52..3e57313cfb 100644 --- a/lib/ansible/modules/storage/infinidat/infini_fs.py +++ b/lib/ansible/modules/storage/infinidat/infini_fs.py @@ -60,14 +60,17 @@ EXAMPLES = ''' RETURN = ''' ''' +import traceback +CAPACITY_IMP_ERR = None try: from capacity import KiB, Capacity HAS_CAPACITY = True except ImportError: + CAPACITY_IMP_ERR = traceback.format_exc() HAS_CAPACITY = False -from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.basic import AnsibleModule, missing_required_lib from ansible.module_utils.infinibox import HAS_INFINISDK, api_wrapper, get_system, infinibox_argument_spec @@ -136,9 +139,9 @@ def main(): module = AnsibleModule(argument_spec, supports_check_mode=True) if not HAS_INFINISDK: - module.fail_json(msg='infinisdk is required for this module') + module.fail_json(msg=missing_required_lib('infinisdk')) if not HAS_CAPACITY: - module.fail_json(msg='The capacity python library is required for this module') + module.fail_json(msg=missing_required_lib('capacity'), exception=CAPACITY_IMP_ERR) if module.params['size']: try: diff --git a/lib/ansible/modules/storage/infinidat/infini_host.py b/lib/ansible/modules/storage/infinidat/infini_host.py index 6ab09839bf..47633e3cd3 100644 --- a/lib/ansible/modules/storage/infinidat/infini_host.py +++ b/lib/ansible/modules/storage/infinidat/infini_host.py @@ -74,7 +74,7 @@ EXAMPLES = ''' RETURN = ''' ''' -from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.basic import AnsibleModule, missing_required_lib from ansible.module_utils.infinibox import HAS_INFINISDK, api_wrapper, get_system, infinibox_argument_spec @@ -134,7 +134,7 @@ def main(): module = AnsibleModule(argument_spec, supports_check_mode=True) if not HAS_INFINISDK: - module.fail_json(msg='infinisdk is required for this module') + module.fail_json(msg=missing_required_lib('infinisdk')) state = module.params['state'] system = get_system(module) diff --git a/lib/ansible/modules/storage/infinidat/infini_pool.py b/lib/ansible/modules/storage/infinidat/infini_pool.py index 2fdbfa34d9..4bfb915a0b 100644 --- a/lib/ansible/modules/storage/infinidat/infini_pool.py +++ b/lib/ansible/modules/storage/infinidat/infini_pool.py @@ -79,14 +79,17 @@ EXAMPLES = ''' RETURN = ''' ''' +import traceback +CAPACITY_IMP_ERR = None try: from capacity import KiB, Capacity HAS_CAPACITY = True except ImportError: + CAPACITY_IMP_ERR = traceback.format_exc() HAS_CAPACITY = False -from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.basic import AnsibleModule, missing_required_lib from ansible.module_utils.infinibox import HAS_INFINISDK, api_wrapper, get_system, infinibox_argument_spec @@ -178,9 +181,9 @@ def main(): module = AnsibleModule(argument_spec, supports_check_mode=True) if not HAS_INFINISDK: - module.fail_json(msg='infinisdk is required for this module') + module.fail_json(msg=missing_required_lib('infinisdk')) if not HAS_CAPACITY: - module.fail_json(msg='The capacity python library is required for this module') + module.fail_json(msg=missing_required_lib('capacity'), exception=CAPACITY_IMP_ERR) if module.params['size']: try: diff --git a/lib/ansible/modules/storage/infinidat/infini_vol.py b/lib/ansible/modules/storage/infinidat/infini_vol.py index b4ef41e3aa..e4bfb16a85 100644 --- a/lib/ansible/modules/storage/infinidat/infini_vol.py +++ b/lib/ansible/modules/storage/infinidat/infini_vol.py @@ -67,7 +67,7 @@ try: except ImportError: HAS_CAPACITY = False -from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.basic import AnsibleModule, missing_required_lib from ansible.module_utils.infinibox import HAS_INFINISDK, api_wrapper, get_system, infinibox_argument_spec @@ -136,7 +136,7 @@ def main(): module = AnsibleModule(argument_spec, supports_check_mode=True) if not HAS_INFINISDK: - module.fail_json(msg='infinisdk is required for this module') + module.fail_json(msg=missing_required_lib('infinisdk')) if module.params['size']: try: diff --git a/lib/ansible/modules/web_infrastructure/apache2_mod_proxy.py b/lib/ansible/modules/web_infrastructure/apache2_mod_proxy.py index e427daa5da..07d1d2add0 100644 --- a/lib/ansible/modules/web_infrastructure/apache2_mod_proxy.py +++ b/lib/ansible/modules/web_infrastructure/apache2_mod_proxy.py @@ -190,10 +190,13 @@ members: ''' import re +import traceback +BEAUTIFUL_SOUP_IMP_ERR = None try: from BeautifulSoup import BeautifulSoup except ImportError: + BEAUTIFUL_SOUP_IMP_ERR = traceback.format_exc() HAS_BEAUTIFULSOUP = False else: HAS_BEAUTIFULSOUP = True @@ -357,7 +360,7 @@ def main(): ) if HAS_BEAUTIFULSOUP is False: - module.fail_json(msg="python module 'BeautifulSoup' is required!") + module.fail_json(msg=missing_required_lib('BeautifulSoup'), exception=BEAUTIFUL_SOUP_IMP_ERR) if module.params['state'] is not None: states = module.params['state'].split(',') @@ -435,7 +438,7 @@ def main(): module.fail_json(msg=str(module.params['member_host']) + ' is not a member of the balancer ' + str(module.params['balancer_vhost']) + '!') -from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.basic import AnsibleModule, missing_required_lib from ansible.module_utils.urls import fetch_url if __name__ == '__main__': main() diff --git a/lib/ansible/modules/web_infrastructure/htpasswd.py b/lib/ansible/modules/web_infrastructure/htpasswd.py index 984e1b1e35..ad12b0c02d 100644 --- a/lib/ansible/modules/web_infrastructure/htpasswd.py +++ b/lib/ansible/modules/web_infrastructure/htpasswd.py @@ -95,14 +95,18 @@ EXAMPLES = """ import os import tempfile +import traceback from distutils.version import LooseVersion -from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.basic import AnsibleModule, missing_required_lib from ansible.module_utils._text import to_native + +PASSLIB_IMP_ERR = None try: from passlib.apache import HtpasswdFile, htpasswd_context from passlib.context import CryptContext import passlib except ImportError: + PASSLIB_IMP_ERR = traceback.format_exc() passlib_installed = False else: passlib_installed = True @@ -218,7 +222,7 @@ def main(): check_mode = module.check_mode if not passlib_installed: - module.fail_json(msg="This module requires the passlib Python library") + module.fail_json(msg=missing_required_lib("passlib"), exception=PASSLIB_IMP_ERR) # Check file for blank lines in effort to avoid "need more than 1 value to unpack" error. try: diff --git a/lib/ansible/modules/web_infrastructure/jenkins_job.py b/lib/ansible/modules/web_infrastructure/jenkins_job.py index 1bd7f3106c..08dff1d432 100644 --- a/lib/ansible/modules/web_infrastructure/jenkins_job.py +++ b/lib/ansible/modules/web_infrastructure/jenkins_job.py @@ -148,19 +148,23 @@ url: import traceback +JENKINS_IMP_ERR = None try: import jenkins python_jenkins_installed = True except ImportError: + JENKINS_IMP_ERR = traceback.format_exc() python_jenkins_installed = False +LXML_IMP_ERR = None try: from lxml import etree as ET python_lxml_installed = True except ImportError: + LXML_IMP_ERR = traceback.format_exc() python_lxml_installed = False -from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.basic import AnsibleModule, missing_required_lib from ansible.module_utils._text import to_native @@ -325,12 +329,15 @@ class JenkinsJob: def test_dependencies(module): if not python_jenkins_installed: - module.fail_json(msg="python-jenkins required for this module. " - "see http://python-jenkins.readthedocs.io/en/latest/install.html") + module.fail_json( + msg=missing_required_lib("python-jenkins", + url="https://python-jenkins.readthedocs.io/en/latest/install.html"), + exception=JENKINS_IMP_ERR) if not python_lxml_installed: - module.fail_json(msg="lxml required for this module. " - "see http://lxml.de/installation.html") + module.fail_json( + msg=missing_required_lib("lxml", url="https://lxml.de/installation.html"), + exception=LXML_IMP_ERR) def job_config_to_string(xml_str): diff --git a/lib/ansible/modules/web_infrastructure/jenkins_job_facts.py b/lib/ansible/modules/web_infrastructure/jenkins_job_facts.py index f31b822203..390709582b 100644 --- a/lib/ansible/modules/web_infrastructure/jenkins_job_facts.py +++ b/lib/ansible/modules/web_infrastructure/jenkins_job_facts.py @@ -137,13 +137,15 @@ import ssl import fnmatch import traceback +JENKINS_IMP_ERR = None try: import jenkins HAS_JENKINS = True except ImportError: + JENKINS_IMP_ERR = traceback.format_exc() HAS_JENKINS = False -from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.basic import AnsibleModule, missing_required_lib from ansible.module_utils._text import to_native @@ -171,8 +173,9 @@ def get_jenkins_connection(module): def test_dependencies(module): if not HAS_JENKINS: module.fail_json( - msg="python-jenkins required for this module. " - "see http://python-jenkins.readthedocs.io/en/latest/install.html") + msg=missing_required_lib("python-jenkins", + url="https://python-jenkins.readthedocs.io/en/latest/install.html"), + exception=JENKINS_IMP_ERR) def get_jobs(module): diff --git a/lib/ansible/modules/web_infrastructure/taiga_issue.py b/lib/ansible/modules/web_infrastructure/taiga_issue.py index 872a0a63d3..8c061c397a 100644 --- a/lib/ansible/modules/web_infrastructure/taiga_issue.py +++ b/lib/ansible/modules/web_infrastructure/taiga_issue.py @@ -105,15 +105,20 @@ EXAMPLES = ''' ''' RETURN = '''# ''' +import traceback + from os import getenv from os.path import isfile -from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.basic import AnsibleModule, missing_required_lib from ansible.module_utils._text import to_native + +TAIGA_IMP_ERR = None try: from taiga import TaigaAPI from taiga.exceptions import TaigaException TAIGA_MODULE_IMPORTED = True except ImportError: + TAIGA_IMP_ERR = traceback.format_exc() TAIGA_MODULE_IMPORTED = False @@ -252,8 +257,8 @@ def main(): ) if not TAIGA_MODULE_IMPORTED: - msg = "This module needs python-taiga module" - module.fail_json(msg=msg) + module.fail_json(msg=missing_required_lib("python-taiga"), + exception=TAIGA_IMP_ERR) taiga_host = module.params['taiga_host'] project_name = module.params['project'] diff --git a/test/units/module_utils/test_vmware.py b/test/units/module_utils/test_vmware.py index 98d3f7610a..e3905e40a3 100644 --- a/test/units/module_utils/test_vmware.py +++ b/test/units/module_utils/test_vmware.py @@ -98,7 +98,7 @@ def test_pyvmomi_lib_exists(mocker, fake_ansible_module): with pytest.raises(FailJson) as exec_info: PyVmomi(fake_ansible_module) - assert 'PyVmomi Python module required. Install using "pip install PyVmomi"' == exec_info.value.kwargs['msg'] + assert 'Failed to import the required Python library (PyVmomi) on' in exec_info.value.kwargs['msg'] def test_requests_lib_exists(mocker, fake_ansible_module): @@ -107,8 +107,7 @@ def test_requests_lib_exists(mocker, fake_ansible_module): with pytest.raises(FailJson) as exec_info: PyVmomi(fake_ansible_module) - msg = "Unable to find 'requests' Python library which is required. Please install using 'pip install requests'" - assert msg == exec_info.value.kwargs['msg'] + assert 'Failed to import the required Python library (requests) on' in exec_info.value.kwargs['msg'] @pytest.mark.skipif(sys.version_info < (2, 7), reason="requires python2.7 and greater")