diff --git a/plugins/inventory/aws_ec2.py b/plugins/inventory/aws_ec2.py index 6f3d1d5ef14..927014f1c76 100644 --- a/plugins/inventory/aws_ec2.py +++ b/plugins/inventory/aws_ec2.py @@ -5,134 +5,134 @@ __metaclass__ = type DOCUMENTATION = ''' - name: aws_ec2 - short_description: EC2 inventory source - extends_documentation_fragment: - - inventory_cache - - constructed - - amazon.aws.aws_boto3 - - amazon.aws.aws_credentials - +name: aws_ec2 +short_description: EC2 inventory source +extends_documentation_fragment: + - inventory_cache + - constructed + - amazon.aws.aws_boto3 + - amazon.aws.aws_credentials +description: + - Get inventory hosts from Amazon Web Services EC2. + - Uses a YAML configuration file that ends with C(aws_ec2.{yml|yaml}). +notes: + - If no credentials are provided and the control node has an associated IAM instance profile then the + role will be used for authentication. +author: + - Sloane Hertel (@s-hertel) +options: + plugin: + description: Token that ensures this is a source file for the plugin. + required: True + choices: ['aws_ec2', 'amazon.aws.aws_ec2'] + iam_role_arn: + description: + - The ARN of the IAM role to assume to perform the inventory lookup. You should still provide AWS + credentials with enough privilege to perform the AssumeRole action. + regions: + description: + - A list of regions in which to describe EC2 instances. + - If empty (the default) default this will include all regions, except possibly restricted ones like us-gov-west-1 and cn-north-1. + type: list + elements: str + default: [] + hostnames: + description: + - A list in order of precedence for hostname variables. + type: list + elements: dict + default: [] + suboptions: + name: + description: + - Name of the host. + - Can be one of the options specified in U(http://docs.aws.amazon.com/cli/latest/reference/ec2/describe-instances.html#options). + - To use tags as hostnames use the syntax tag:Name=Value to use the hostname Name_Value, or tag:Name to use the value of the Name tag. + - If value provided does not exist in the above options, it will be used as a literal string. + type: str + required: True + prefix: + description: + - Prefix to prepend to I(name). Same options as I(name). + - If I(prefix) is specified, final hostname will be I(prefix) + I(separator) + I(name). + type: str + default: '' + required: False + separator: + description: + - Value to separate I(prefix) and I(name) when I(prefix) is specified. + type: str + default: '_' + required: False + filters: + description: + - A dictionary of filter value pairs. + - Available filters are listed here U(http://docs.aws.amazon.com/cli/latest/reference/ec2/describe-instances.html#options). + type: dict + default: {} + include_filters: + description: + - A list of filters. Any instances matching at least one of the filters are included in the result. + - Available filters are listed here U(http://docs.aws.amazon.com/cli/latest/reference/ec2/describe-instances.html#options). + - Every entry in this list triggers a search query. As such, from a performance point of view, it's better to + keep the list as short as possible. + type: list + elements: dict + default: [] + version_added: 1.5.0 + exclude_filters: + description: + - A list of filters. Any instances matching one of the filters are excluded from the result. + - The filters from C(exclude_filters) take priority over the C(include_filters) and C(filters) keys + - Available filters are listed here U(http://docs.aws.amazon.com/cli/latest/reference/ec2/describe-instances.html#options). + - Every entry in this list triggers a search query. As such, from a performance point of view, it's better to + keep the list as short as possible. + type: list + elements: dict + default: [] + version_added: 1.5.0 + include_extra_api_calls: + description: + - Add two additional API calls for every instance to include 'persistent' and 'events' host variables. + - Spot instances may be persistent and instances may have associated events. + type: bool + default: False + strict_permissions: + description: + - By default if a 403 (Forbidden) error code is encountered this plugin will fail. + - You can set this option to False in the inventory config file which will allow 403 errors to be gracefully skipped. + type: bool + default: True + use_contrib_script_compatible_sanitization: + description: + - By default this plugin is using a general group name sanitization to create safe and usable group names for use in Ansible. + This option allows you to override that, in efforts to allow migration from the old inventory script and + matches the sanitization of groups when the script's ``replace_dash_in_groups`` option is set to ``False``. + To replicate behavior of ``replace_dash_in_groups = True`` with constructed groups, + you will need to replace hyphens with underscores via the regex_replace filter for those entries. + - For this to work you should also turn off the TRANSFORM_INVALID_GROUP_CHARS setting, + otherwise the core engine will just use the standard sanitization on top. + - This is not the default as such names break certain functionality as not all characters are valid Python identifiers + which group names end up being used as. + type: bool + default: False + use_contrib_script_compatible_ec2_tag_keys: + description: + - Expose the host tags with ec2_tag_TAGNAME keys like the old ec2.py inventory script. + - The use of this feature is discouraged and we advise to migrate to the new ``tags`` structure. + type: bool + default: False + version_added: 1.5.0 + hostvars_prefix: + description: + - The prefix for host variables names coming from AWS. + type: str + version_added: 3.1.0 + hostvars_suffix: description: - - Get inventory hosts from Amazon Web Services EC2. - - Uses a YAML configuration file that ends with C(aws_ec2.{yml|yaml}). - notes: - - If no credentials are provided and the control node has an associated IAM instance profile then the - role will be used for authentication. - author: - - Sloane Hertel (@s-hertel) - options: - plugin: - description: Token that ensures this is a source file for the plugin. - required: True - choices: ['aws_ec2', 'amazon.aws.aws_ec2'] - iam_role_arn: - description: The ARN of the IAM role to assume to perform the inventory lookup. You should still provide AWS - credentials with enough privilege to perform the AssumeRole action. - regions: - description: - - A list of regions in which to describe EC2 instances. - - If empty (the default) default this will include all regions, except possibly restricted ones like us-gov-west-1 and cn-north-1. - type: list - elements: str - default: [] - hostnames: - description: - - A list in order of precedence for hostname variables. - type: list - elements: dict - default: [] - suboptions: - name: - description: - - Name of the host. - - Can be one of the options specified in U(http://docs.aws.amazon.com/cli/latest/reference/ec2/describe-instances.html#options). - - To use tags as hostnames use the syntax tag:Name=Value to use the hostname Name_Value, or tag:Name to use the value of the Name tag. - - If value provided does not exist in the above options, it will be used as a literal string. - type: str - required: True - prefix: - description: - - Prefix to prepend to I(name). Same options as I(name). - - If I(prefix) is specified, final hostname will be I(prefix) + I(separator) + I(name). - type: str - default: '' - required: False - separator: - description: - - Value to separate I(prefix) and I(name) when I(prefix) is specified. - type: str - default: '_' - required: False - filters: - description: - - A dictionary of filter value pairs. - - Available filters are listed here U(http://docs.aws.amazon.com/cli/latest/reference/ec2/describe-instances.html#options). - type: dict - default: {} - include_filters: - description: - - A list of filters. Any instances matching at least one of the filters are included in the result. - - Available filters are listed here U(http://docs.aws.amazon.com/cli/latest/reference/ec2/describe-instances.html#options). - - Every entry in this list triggers a search query. As such, from a performance point of view, it's better to - keep the list as short as possible. - type: list - elements: dict - default: [] - version_added: 1.5.0 - exclude_filters: - description: - - A list of filters. Any instances matching one of the filters are excluded from the result. - - The filters from C(exclude_filters) take priority over the C(include_filters) and C(filters) keys - - Available filters are listed here U(http://docs.aws.amazon.com/cli/latest/reference/ec2/describe-instances.html#options). - - Every entry in this list triggers a search query. As such, from a performance point of view, it's better to - keep the list as short as possible. - type: list - elements: dict - default: [] - version_added: 1.5.0 - include_extra_api_calls: - description: - - Add two additional API calls for every instance to include 'persistent' and 'events' host variables. - - Spot instances may be persistent and instances may have associated events. - type: bool - default: False - strict_permissions: - description: - - By default if a 403 (Forbidden) error code is encountered this plugin will fail. - - You can set this option to False in the inventory config file which will allow 403 errors to be gracefully skipped. - type: bool - default: True - use_contrib_script_compatible_sanitization: - description: - - By default this plugin is using a general group name sanitization to create safe and usable group names for use in Ansible. - This option allows you to override that, in efforts to allow migration from the old inventory script and - matches the sanitization of groups when the script's ``replace_dash_in_groups`` option is set to ``False``. - To replicate behavior of ``replace_dash_in_groups = True`` with constructed groups, - you will need to replace hyphens with underscores via the regex_replace filter for those entries. - - For this to work you should also turn off the TRANSFORM_INVALID_GROUP_CHARS setting, - otherwise the core engine will just use the standard sanitization on top. - - This is not the default as such names break certain functionality as not all characters are valid Python identifiers - which group names end up being used as. - type: bool - default: False - use_contrib_script_compatible_ec2_tag_keys: - description: - - Expose the host tags with ec2_tag_TAGNAME keys like the old ec2.py inventory script. - - The use of this feature is discouraged and we advise to migrate to the new ``tags`` structure. - type: bool - default: False - version_added: 1.5.0 - hostvars_prefix: - description: - - The prefix for host variables names coming from AWS. - type: str - version_added: 3.1.0 - hostvars_suffix: - description: - - The suffix for host variables names coming from AWS. - type: str - version_added: 3.1.0 + - The suffix for host variables names coming from AWS. + type: str + version_added: 3.1.0 ''' EXAMPLES = ''' @@ -543,7 +543,7 @@ def _get_instances_by_region(self, regions, filters, strict_permissions): ''' all_instances = [] - for connection, region in self._boto3_conn(regions): + for connection, _region in self._boto3_conn(regions): try: # By default find non-terminated/terminating instances if not any(f['Name'] == 'instance-state-name' for f in filters): diff --git a/plugins/inventory/aws_rds.py b/plugins/inventory/aws_rds.py index 1e2683630b7..2c19dfa0ff0 100644 --- a/plugins/inventory/aws_rds.py +++ b/plugins/inventory/aws_rds.py @@ -5,59 +5,63 @@ __metaclass__ = type DOCUMENTATION = ''' - name: aws_rds - short_description: rds instance source +name: aws_rds +short_description: RDS instance inventory source +description: + - Get instances and clusters from Amazon Web Services RDS. + - Uses a YAML configuration file that ends with aws_rds.(yml|yaml). +options: + regions: description: - - Get instances and clusters from Amazon Web Services RDS. - - Uses a YAML configuration file that ends with aws_rds.(yml|yaml). - options: - regions: - description: A list of regions in which to describe RDS instances and clusters. Available regions are listed here - U(https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/Concepts.RegionsAndAvailabilityZones.html) - default: [] - filters: - description: A dictionary of filter value pairs. Available filters are listed here - U(https://docs.aws.amazon.com/cli/latest/reference/rds/describe-db-instances.html#options). If you filter by - db-cluster-id and I(include_clusters) is True it will apply to clusters as well. - default: {} - strict_permissions: - description: By default if an AccessDenied exception is encountered this plugin will fail. You can set strict_permissions to - False in the inventory config file which will allow the restrictions to be gracefully skipped. - type: bool - default: True - include_clusters: - description: Whether or not to query for Aurora clusters as well as instances - type: bool - default: False - statuses: - description: A list of desired states for instances/clusters to be added to inventory. Set to ['all'] as a shorthand to find everything. - type: list - elements: str - default: - - creating - - available - iam_role_arn: - description: The ARN of the IAM role to assume to perform the inventory lookup. You should still provide - AWS credentials with enough privilege to perform the AssumeRole action. - hostvars_prefix: - description: - - The prefix for host variables names coming from AWS. - type: str - version_added: 3.1.0 - hostvars_suffix: - description: - - The suffix for host variables names coming from AWS. - type: str - version_added: 3.1.0 - notes: - - Ansible versions prior to 2.10 should use the fully qualified plugin name 'amazon.aws.aws_rds'. - extends_documentation_fragment: - - inventory_cache - - constructed - - amazon.aws.aws_boto3 - - amazon.aws.aws_credentials - - author: Sloane Hertel (@s-hertel) + - A list of regions in which to describe RDS instances and clusters. Available regions are listed here + U(https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/Concepts.RegionsAndAvailabilityZones.html). + default: [] + filters: + description: + - A dictionary of filter value pairs. Available filters are listed here + U(https://docs.aws.amazon.com/cli/latest/reference/rds/describe-db-instances.html#options). If you filter by + db-cluster-id and I(include_clusters) is True it will apply to clusters as well. + default: {} + strict_permissions: + description: + - By default if an AccessDenied exception is encountered this plugin will fail. You can set strict_permissions to + False in the inventory config file which will allow the restrictions to be gracefully skipped. + type: bool + default: True + include_clusters: + description: Whether or not to query for Aurora clusters as well as instances. + type: bool + default: False + statuses: + description: A list of desired states for instances/clusters to be added to inventory. Set to ['all'] as a shorthand to find everything. + type: list + elements: str + default: + - creating + - available + iam_role_arn: + description: + - The ARN of the IAM role to assume to perform the inventory lookup. You should still provide + AWS credentials with enough privilege to perform the AssumeRole action. + hostvars_prefix: + description: + - The prefix for host variables names coming from AWS. + type: str + version_added: 3.1.0 + hostvars_suffix: + description: + - The suffix for host variables names coming from AWS. + type: str + version_added: 3.1.0 +notes: + - Ansible versions prior to 2.10 should use the fully qualified plugin name 'amazon.aws.aws_rds'. +extends_documentation_fragment: + - inventory_cache + - constructed + - amazon.aws.aws_boto3 + - amazon.aws.aws_credentials +author: + - Sloane Hertel (@s-hertel) ''' EXAMPLES = ''' @@ -209,7 +213,7 @@ def _get_all_hosts(self, regions, instance_filters, cluster_filters, strict, sta ''' all_instances = [] all_clusters = [] - for connection, region in self._boto3_conn(regions): + for connection, _region in self._boto3_conn(regions): paginator = connection.get_paginator('describe_db_instances') all_instances.extend( self._get_hosts_by_region(connection, instance_filters, strict) @@ -313,7 +317,6 @@ def _add_hosts(self, hosts, group): def _set_credentials(self): ''' - :param config_data: contents of the inventory config file ''' self.boto_profile = self.get_option('aws_profile') aws_access_key_id = self.get_option('aws_access_key') @@ -356,7 +359,6 @@ def parse(self, inventory, loader, path, cache=True): if not HAS_BOTO3: raise AnsibleError('The RDS dynamic inventory plugin requires boto3 and botocore.') - config_data = self._read_config_data(path) self._set_credentials() # get user specifications diff --git a/plugins/lookup/aws_account_attribute.py b/plugins/lookup/aws_account_attribute.py index 525938d285c..18dc69b5eae 100644 --- a/plugins/lookup/aws_account_attribute.py +++ b/plugins/lookup/aws_account_attribute.py @@ -8,11 +8,10 @@ author: - Sloane Hertel (@s-hertel) extends_documentation_fragment: -- amazon.aws.aws_boto3 -- amazon.aws.aws_credentials -- amazon.aws.aws_region - -short_description: Look up AWS account attributes. + - amazon.aws.aws_boto3 + - amazon.aws.aws_credentials + - amazon.aws.aws_region +short_description: Look up AWS account attributes description: - Describes attributes of your AWS account. You can specify one of the listed attribute choices or omit it to see all attributes. @@ -69,11 +68,11 @@ def _boto3_conn(region, credentials): try: connection = boto3.session.Session(profile_name=boto_profile).client('ec2', region, **credentials) - except (botocore.exceptions.ProfileNotFound, botocore.exceptions.PartialCredentialsError) as e: + except (botocore.exceptions.ProfileNotFound, botocore.exceptions.PartialCredentialsError): if boto_profile: try: connection = boto3.session.Session(profile_name=boto_profile).client('ec2', region) - except (botocore.exceptions.ProfileNotFound, botocore.exceptions.PartialCredentialsError) as e: + except (botocore.exceptions.ProfileNotFound, botocore.exceptions.PartialCredentialsError): raise AnsibleError("Insufficient credentials found.") else: raise AnsibleError("Insufficient credentials found.") diff --git a/plugins/lookup/aws_secret.py b/plugins/lookup/aws_secret.py index e5e51706787..f861076e2ad 100644 --- a/plugins/lookup/aws_secret.py +++ b/plugins/lookup/aws_secret.py @@ -9,11 +9,11 @@ author: - Aaron Smith (!UNKNOWN) extends_documentation_fragment: -- amazon.aws.aws_boto3 -- amazon.aws.aws_credentials -- amazon.aws.aws_region + - amazon.aws.aws_boto3 + - amazon.aws.aws_credentials + - amazon.aws.aws_region -short_description: Look up secrets stored in AWS Secrets Manager. +short_description: Look up secrets stored in AWS Secrets Manager description: - Look up secrets stored in AWS Secrets Manager provided the caller has the appropriate permissions to read the secret. @@ -41,36 +41,36 @@ required: False join: description: - - Join two or more entries to form an extended secret. - - This is useful for overcoming the 4096 character limit imposed by AWS. - - No effect when used with I(bypath). + - Join two or more entries to form an extended secret. + - This is useful for overcoming the 4096 character limit imposed by AWS. + - No effect when used with I(bypath). type: boolean default: false on_deleted: description: - - Action to take if the secret has been marked for deletion. - - C(error) will raise a fatal error when the secret has been marked for deletion. - - C(skip) will silently ignore the deleted secret. - - C(warn) will skip over the deleted secret but issue a warning. + - Action to take if the secret has been marked for deletion. + - C(error) will raise a fatal error when the secret has been marked for deletion. + - C(skip) will silently ignore the deleted secret. + - C(warn) will skip over the deleted secret but issue a warning. default: error type: string choices: ['error', 'skip', 'warn'] version_added: 2.0.0 on_missing: description: - - Action to take if the secret is missing. - - C(error) will raise a fatal error when the secret is missing. - - C(skip) will silently ignore the missing secret. - - C(warn) will skip over the missing secret but issue a warning. + - Action to take if the secret is missing. + - C(error) will raise a fatal error when the secret is missing. + - C(skip) will silently ignore the missing secret. + - C(warn) will skip over the missing secret but issue a warning. default: error type: string choices: ['error', 'skip', 'warn'] on_denied: description: - - Action to take if access to the secret is denied. - - C(error) will raise a fatal error when access to the secret is denied. - - C(skip) will silently ignore the denied secret. - - C(warn) will skip over the denied secret but issue a warning. + - Action to take if access to the secret is denied. + - C(error) will raise a fatal error when access to the secret is denied. + - C(skip) will silently ignore the denied secret. + - C(warn) will skip over the denied secret but issue a warning. default: error type: string choices: ['error', 'skip', 'warn'] @@ -141,11 +141,11 @@ def _boto3_conn(region, credentials): try: connection = boto3.session.Session(profile_name=boto_profile).client('secretsmanager', region, **credentials) - except (botocore.exceptions.ProfileNotFound, botocore.exceptions.PartialCredentialsError) as e: + except (botocore.exceptions.ProfileNotFound, botocore.exceptions.PartialCredentialsError): if boto_profile: try: connection = boto3.session.Session(profile_name=boto_profile).client('secretsmanager', region) - except (botocore.exceptions.ProfileNotFound, botocore.exceptions.PartialCredentialsError) as e: + except (botocore.exceptions.ProfileNotFound, botocore.exceptions.PartialCredentialsError): raise AnsibleError("Insufficient credentials found.") else: raise AnsibleError("Insufficient credentials found.") @@ -262,7 +262,6 @@ def get_secret_value(self, term, client, version_stage=None, version_id=None, on return response['SecretBinary'] if 'SecretString' in response: if nested: - secrets = [] query = term.split('.')[1:] secret_string = json.loads(response['SecretString']) ret_val = secret_string diff --git a/plugins/lookup/aws_ssm.py b/plugins/lookup/aws_ssm.py index 1c380636e7b..a52528eccd4 100644 --- a/plugins/lookup/aws_ssm.py +++ b/plugins/lookup/aws_ssm.py @@ -13,7 +13,7 @@ - Bill Wang (!UNKNOWN) - Marat Bakeev (!UNKNOWN) - Michael De La Rue (!UNKNOWN) -short_description: Get the value for a SSM parameter or all parameters under a path. +short_description: Get the value for a SSM parameter or all parameters under a path description: - Get the value for an Amazon Simple Systems Manager parameter or a hierarchy of parameters. The first argument you pass the lookup can either be a parameter name or a hierarchy of @@ -72,7 +72,7 @@ type: string version_added: 3.3.0 extends_documentation_fragment: -- amazon.aws.aws_boto3 + - amazon.aws.aws_boto3 ''' EXAMPLES = ''' @@ -129,7 +129,6 @@ try: import botocore - import boto3 except ImportError: pass # will be captured by imported HAS_BOTO3 diff --git a/plugins/module_utils/acm.py b/plugins/module_utils/acm.py index 9e384115d5e..fbfec720cee 100644 --- a/plugins/module_utils/acm.py +++ b/plugins/module_utils/acm.py @@ -21,7 +21,8 @@ # on behalf of Telstra Corporation Limited # # Common functionality to be used by the modules: -# - acm +# - acm_certificate +# - acm_certificate_info from __future__ import (absolute_import, division, print_function) __metaclass__ = type @@ -213,7 +214,7 @@ def import_certificate(self, client, module, certificate, private_key, arn=None, module.debug("Attempting to delete the cert we just created, arn=%s" % arn) try: self.delete_certificate_with_backoff(client, arn) - except Exception as f: + except Exception: module.warn("Certificate %s exists, and is not tagged. So Ansible will not see it on the next run.") module.fail_json_aws(e, msg="Couldn't tag certificate %s, couldn't delete it either" % arn) module.fail_json_aws(e, msg="Couldn't tag certificate %s" % arn) diff --git a/plugins/module_utils/botocore.py b/plugins/module_utils/botocore.py index 33e79420848..791cac60333 100644 --- a/plugins/module_utils/botocore.py +++ b/plugins/module_utils/botocore.py @@ -72,7 +72,7 @@ def boto3_conn(module, conn_type=None, resource=None, region=None, endpoint=None except (botocore.exceptions.ProfileNotFound, botocore.exceptions.PartialCredentialsError, botocore.exceptions.NoCredentialsError, botocore.exceptions.ConfigParseError) as e: module.fail_json(msg=to_native(e)) - except botocore.exceptions.NoRegionError as e: + except botocore.exceptions.NoRegionError: module.fail_json(msg="The %s module requires a region and none was found in configuration, " "environment variables or module parameters" % module._name) @@ -155,7 +155,7 @@ def get_aws_region(module, boto3=None): try: profile_name = module.params.get('profile') return botocore.session.Session(profile=profile_name).get_config_variable('region') - except botocore.exceptions.ProfileNotFound as e: + except botocore.exceptions.ProfileNotFound: return None diff --git a/plugins/module_utils/cloud.py b/plugins/module_utils/cloud.py index 600a7ed158b..ba2fac74c4d 100644 --- a/plugins/module_utils/cloud.py +++ b/plugins/module_utils/cloud.py @@ -32,6 +32,7 @@ import time import functools import random +import ansible.module_utils.common.warnings as ansible_warnings class BackoffIterator: @@ -100,7 +101,7 @@ def status_code_from_exception(error): def found(response_code, catch_extra_error_codes=None): def _is_iterable(): try: - it = iter(catch_extra_error_codes) + iter(catch_extra_error_codes) except TypeError: # not iterable return False @@ -184,7 +185,7 @@ def backoff(cls, tries=10, delay=3, backoff=1.1, catch_extra_error_codes=None): """ Wrap a callable with retry behavior. Developers should use CloudRetry.exponential_backoff instead. - This method has been deprecated and will be removed in release 4.0.0, consider using exponential_backoff method instead. + This method has been deprecated and will be removed in release 6.0.0, consider using exponential_backoff method instead. Args: retries (int): Number of times to retry a failed request before giving up default=10 @@ -197,6 +198,12 @@ def backoff(cls, tries=10, delay=3, backoff=1.1, catch_extra_error_codes=None): Returns: Callable: A generator that calls the decorated function using an exponential backoff. """ + # This won't emit a warning (we don't have the context available to us), but will trigger + # sanity failures as we prepare for 6.0.0 + ansible_warnings.deprecate( + 'CloudRetry.backoff has been deprecated, please use CloudRetry.exponential_backoff instead', + version='6.0.0', collection_name='amazon.aws') + return cls.exponential_backoff( retries=tries, delay=delay, diff --git a/plugins/module_utils/iam.py b/plugins/module_utils/iam.py index 760c15f8e65..6ebed23baca 100644 --- a/plugins/module_utils/iam.py +++ b/plugins/module_utils/iam.py @@ -47,7 +47,7 @@ def get_aws_account_info(module): except (botocore.exceptions.BotoCoreError, botocore.exceptions.ClientError): try: iam_client = module.client('iam', retry_decorator=AWSRetry.jittered_backoff()) - arn, partition, service, reg, account_id, resource = iam_client.get_user(aws_retry=True)['User']['Arn'].split(':') + _arn, partition, _service, _reg, account_id, _resource = iam_client.get_user(aws_retry=True)['User']['Arn'].split(':') except is_boto3_error_code('AccessDenied') as e: try: except_msg = to_native(e.message) diff --git a/plugins/module_utils/modules.py b/plugins/module_utils/modules.py index 53555d7ae28..6c1cc4c86a1 100644 --- a/plugins/module_utils/modules.py +++ b/plugins/module_utils/modules.py @@ -124,7 +124,6 @@ def __init__(self, **kwargs): if not HAS_BOTO3: self._module.fail_json( msg=missing_required_lib('botocore or boto3')) - current_versions = self._gather_versions() if not self.botocore_at_least('1.21.0'): self.warn('botocore < 1.21.0 is not supported or tested.' ' Some features may not work.') diff --git a/plugins/module_utils/rds.py b/plugins/module_utils/rds.py index a2a87227d2a..71981464bfa 100644 --- a/plugins/module_utils/rds.py +++ b/plugins/module_utils/rds.py @@ -227,7 +227,7 @@ def wait(client, db_instance_id, waiter_name): 'db_instance_stopped': 'stopped', } expected_status = waiter_expected_status.get(waiter_name, 'available') - for attempt_to_wait in range(0, 10): + for _wait_attempts in range(0, 10): try: wait(client, db_instance_id, waiter_name) break @@ -378,10 +378,10 @@ def update_iam_roles(client, module, instance_id, roles_to_add, roles_to_remove) params = {'DBInstanceIdentifier': instance_id, 'RoleArn': role['role_arn'], 'FeatureName': role['feature_name']} - result, changed = call_method(client, module, method_name='remove_role_from_db_instance', parameters=params) + _result, changed = call_method(client, module, method_name='remove_role_from_db_instance', parameters=params) for role in roles_to_add: params = {'DBInstanceIdentifier': instance_id, 'RoleArn': role['role_arn'], 'FeatureName': role['feature_name']} - result, changed = call_method(client, module, method_name='add_role_to_db_instance', parameters=params) + _result, changed = call_method(client, module, method_name='add_role_to_db_instance', parameters=params) return changed diff --git a/tests/unit/module_utils/core/ansible_aws_module/test_fail_json_aws.py b/tests/unit/module_utils/core/ansible_aws_module/test_fail_json_aws.py index c7e53afca02..737d93fece6 100644 --- a/tests/unit/module_utils/core/ansible_aws_module/test_fail_json_aws.py +++ b/tests/unit/module_utils/core/ansible_aws_module/test_fail_json_aws.py @@ -61,7 +61,7 @@ def test_fail_client_minimal(self, monkeypatch, stdin, capfd): with pytest.raises(SystemExit) as ctx: module.fail_json_aws(e) assert ctx.value.code == 1 - out, err = capfd.readouterr() + out, _err = capfd.readouterr() return_val = json.loads(out) assert return_val.get("msg") == self.EXAMPLE_MSG @@ -88,7 +88,7 @@ def test_fail_client_msg(self, monkeypatch, stdin, capfd): with pytest.raises(SystemExit) as ctx: module.fail_json_aws(e, msg=self.FAIL_MSG) assert ctx.value.code == 1 - out, err = capfd.readouterr() + out, _err = capfd.readouterr() return_val = json.loads(out) assert return_val.get("msg") == self.FAIL_MSG + ": " + self.EXAMPLE_MSG @@ -115,7 +115,7 @@ def test_fail_client_positional_msg(self, monkeypatch, stdin, capfd): with pytest.raises(SystemExit) as ctx: module.fail_json_aws(e, self.FAIL_MSG) assert ctx.value.code == 1 - out, err = capfd.readouterr() + out, _err = capfd.readouterr() return_val = json.loads(out) assert return_val.get("msg") == self.FAIL_MSG + ": " + self.EXAMPLE_MSG @@ -142,7 +142,7 @@ def test_fail_client_key(self, monkeypatch, stdin, capfd): with pytest.raises(SystemExit) as ctx: module.fail_json_aws(e, extra_key="Some Value") assert ctx.value.code == 1 - out, err = capfd.readouterr() + out, _err = capfd.readouterr() return_val = json.loads(out) assert return_val.get("msg") == self.EXAMPLE_MSG @@ -170,7 +170,7 @@ def test_fail_client_msg_and_key(self, monkeypatch, stdin, capfd): with pytest.raises(SystemExit) as ctx: module.fail_json_aws(e, extra_key="Some Value", msg=self.FAIL_MSG) assert ctx.value.code == 1 - out, err = capfd.readouterr() + out, _err = capfd.readouterr() return_val = json.loads(out) assert return_val.get("msg") == self.FAIL_MSG + ": " + self.EXAMPLE_MSG @@ -198,7 +198,7 @@ def test_fail_botocore_minimal(self, monkeypatch, stdin, capfd): with pytest.raises(SystemExit) as ctx: module.fail_json_aws(e) assert ctx.value.code == 1 - out, err = capfd.readouterr() + out, _err = capfd.readouterr() return_val = json.loads(out) assert return_val.get("msg") == self.DEFAULT_CORE_MSG @@ -225,7 +225,7 @@ def test_fail_botocore_msg(self, monkeypatch, stdin, capfd): with pytest.raises(SystemExit) as ctx: module.fail_json_aws(e, msg=self.FAIL_MSG) assert ctx.value.code == 1 - out, err = capfd.readouterr() + out, _err = capfd.readouterr() return_val = json.loads(out) assert return_val.get("msg") == self.FAIL_MSG + ": " + self.DEFAULT_CORE_MSG @@ -253,7 +253,7 @@ def test_fail_botocore_positional_msg(self, monkeypatch, stdin, capfd): with pytest.raises(SystemExit) as ctx: module.fail_json_aws(e, self.FAIL_MSG) assert ctx.value.code == 1 - out, err = capfd.readouterr() + out, _err = capfd.readouterr() return_val = json.loads(out) assert return_val.get("msg") == self.FAIL_MSG + ": " + self.DEFAULT_CORE_MSG @@ -280,7 +280,7 @@ def test_fail_botocore_key(self, monkeypatch, stdin, capfd): with pytest.raises(SystemExit) as ctx: module.fail_json_aws(e, extra_key="Some Value") assert ctx.value.code == 1 - out, err = capfd.readouterr() + out, _err = capfd.readouterr() return_val = json.loads(out) assert return_val.get("msg") == self.DEFAULT_CORE_MSG @@ -308,7 +308,7 @@ def test_fail_botocore_msg_and_key(self, monkeypatch, stdin, capfd): with pytest.raises(SystemExit) as ctx: module.fail_json_aws(e, extra_key="Some Value", msg=self.FAIL_MSG) assert ctx.value.code == 1 - out, err = capfd.readouterr() + out, _err = capfd.readouterr() return_val = json.loads(out) assert return_val.get("msg") == self.FAIL_MSG + ": " + self.DEFAULT_CORE_MSG diff --git a/tests/unit/module_utils/core/ansible_aws_module/test_minimal_versions.py b/tests/unit/module_utils/core/ansible_aws_module/test_minimal_versions.py index 6dbf3e06411..7a07beafc4a 100644 --- a/tests/unit/module_utils/core/ansible_aws_module/test_minimal_versions.py +++ b/tests/unit/module_utils/core/ansible_aws_module/test_minimal_versions.py @@ -36,10 +36,10 @@ def test_no_warn(self, monkeypatch, stdin, capfd): # Create a minimal module that we can call module = AnsibleAWSModule(argument_spec=dict()) - with pytest.raises(SystemExit) as e: + with pytest.raises(SystemExit): module.exit_json() - out, err = capfd.readouterr() + out, _err = capfd.readouterr() return_val = json.loads(out) assert return_val.get("exception") is None @@ -59,10 +59,10 @@ def test_no_check(self, monkeypatch, stdin, capfd): # Create a minimal module that we can call module = AnsibleAWSModule(argument_spec=dict(), check_boto3=False) - with pytest.raises(SystemExit) as e: + with pytest.raises(SystemExit): module.exit_json() - out, err = capfd.readouterr() + out, _err = capfd.readouterr() return_val = json.loads(out) assert return_val.get("exception") is None @@ -82,7 +82,7 @@ def test_warn_boto3(self, monkeypatch, stdin, capfd): # Create a minimal module that we can call module = AnsibleAWSModule(argument_spec=dict()) - with pytest.raises(SystemExit) as e: + with pytest.raises(SystemExit): module.exit_json() out, err = capfd.readouterr() @@ -115,7 +115,7 @@ def test_warn_botocore(self, monkeypatch, stdin, capfd): # Create a minimal module that we can call module = AnsibleAWSModule(argument_spec=dict()) - with pytest.raises(SystemExit) as e: + with pytest.raises(SystemExit): module.exit_json() out, err = capfd.readouterr() @@ -148,7 +148,7 @@ def test_warn_boto3_and_botocore(self, monkeypatch, stdin, capfd): # Create a minimal module that we can call module = AnsibleAWSModule(argument_spec=dict()) - with pytest.raises(SystemExit) as e: + with pytest.raises(SystemExit): module.exit_json() out, err = capfd.readouterr() diff --git a/tests/unit/module_utils/core/ansible_aws_module/test_require_at_least.py b/tests/unit/module_utils/core/ansible_aws_module/test_require_at_least.py index c0e0e5b6c00..cd532cb7da3 100644 --- a/tests/unit/module_utils/core/ansible_aws_module/test_require_at_least.py +++ b/tests/unit/module_utils/core/ansible_aws_module/test_require_at_least.py @@ -85,11 +85,11 @@ def test_require_botocore_at_least(self, monkeypatch, stdin, desired_version, co # Create a minimal module that we can call module = AnsibleAWSModule(argument_spec=dict()) - with pytest.raises(SystemExit) as e: + with pytest.raises(SystemExit): module.require_botocore_at_least(desired_version) module.exit_json() - out, err = capfd.readouterr() + out, _err = capfd.readouterr() return_val = json.loads(out) assert return_val.get("exception") is None @@ -118,11 +118,11 @@ def test_require_boto3_at_least(self, monkeypatch, stdin, desired_version, compa # Create a minimal module that we can call module = AnsibleAWSModule(argument_spec=dict()) - with pytest.raises(SystemExit) as e: + with pytest.raises(SystemExit): module.require_boto3_at_least(desired_version) module.exit_json() - out, err = capfd.readouterr() + out, _err = capfd.readouterr() return_val = json.loads(out) assert return_val.get("exception") is None @@ -153,11 +153,11 @@ def test_require_botocore_at_least_with_reason(self, monkeypatch, stdin, desired # Create a minimal module that we can call module = AnsibleAWSModule(argument_spec=dict()) - with pytest.raises(SystemExit) as e: + with pytest.raises(SystemExit): module.require_botocore_at_least(desired_version, reason=reason) module.exit_json() - out, err = capfd.readouterr() + out, _err = capfd.readouterr() return_val = json.loads(out) assert return_val.get("exception") is None @@ -189,11 +189,11 @@ def test_require_boto3_at_least_with_reason(self, monkeypatch, stdin, desired_ve # Create a minimal module that we can call module = AnsibleAWSModule(argument_spec=dict()) - with pytest.raises(SystemExit) as e: + with pytest.raises(SystemExit): module.require_boto3_at_least(desired_version, reason=reason) module.exit_json() - out, err = capfd.readouterr() + out, _err = capfd.readouterr() return_val = json.loads(out) assert return_val.get("exception") is None diff --git a/tests/unit/module_utils/test_cloud.py b/tests/unit/module_utils/test_cloud.py index f54dc2dc66e..a473023c99f 100644 --- a/tests/unit/module_utils/test_cloud.py +++ b/tests/unit/module_utils/test_cloud.py @@ -113,6 +113,23 @@ def setUp(self): # nothing to do on setup stage pass + # ======================================================== + # retry original backoff + # ======================================================== + def test_retry_backoff(self): + + @CloudRetryUtils.UnitTestsRetry.backoff(tries=3, delay=1, backoff=1.1, catch_extra_error_codes=CloudRetryUtils.error_codes) + def test_retry_func(): + if test_retry_func.counter < 2: + test_retry_func.counter += 1 + raise self.TestException(status=random.choice(CloudRetryUtils.error_codes)) + else: + return True + + test_retry_func.counter = 0 + ret = test_retry_func() + assert ret is True + # ======================================================== # retry exponential backoff # ======================================================== @@ -143,7 +160,9 @@ def test_retry_func(): test_retry_func.counter = 0 try: - ret = test_retry_func() + test_retry_func() + # We expect the Exception to be thrown... + assert False except self.TestException as exc: assert exc.status == unexpected_except.status @@ -176,7 +195,9 @@ def test_retry_func(): test_retry_func.counter = 0 try: - ret = test_retry_func() + test_retry_func() + # We expect the Exception to be thrown... + assert False except self.TestException as exc: assert exc.status == unexpected_except.status @@ -210,7 +231,7 @@ def _fail(): # run the method 3 times and assert that each it is retrying after 2secs # the elapsed execution time should be closed to 2sec - for u in range(3): + for _i in range(3): start = datetime.now() raised = False try: diff --git a/tests/unit/module_utils/test_elbv2.py b/tests/unit/module_utils/test_elbv2.py index 7fe70b1b2a7..b38f529c97f 100644 --- a/tests/unit/module_utils/test_elbv2.py +++ b/tests/unit/module_utils/test_elbv2.py @@ -178,7 +178,7 @@ def test_get_elb_ip_address_type(self): # Test modify_ip_address_type idempotency def test_modify_ip_address_type_idempotency(self): # Run module - return_value = self.elbv2obj.modify_ip_address_type("ipv4") + self.elbv2obj.modify_ip_address_type("ipv4") # check that no method was called and this has been retrieved from elb attributes self.connection.set_ip_address_type.assert_not_called() # assert we got the expected value @@ -187,7 +187,7 @@ def test_modify_ip_address_type_idempotency(self): # Test modify_ip_address_type def test_modify_ip_address_type_update(self): # Run module - return_value = self.elbv2obj.modify_ip_address_type("dualstack") + self.elbv2obj.modify_ip_address_type("dualstack") # check that no method was called and this has been retrieved from elb attributes self.connection.set_ip_address_type.assert_called_once() # assert we got the expected value diff --git a/tests/unit/module_utils/test_retries.py b/tests/unit/module_utils/test_retries.py index 2655bcd0692..39ae40ec519 100644 --- a/tests/unit/module_utils/test_retries.py +++ b/tests/unit/module_utils/test_retries.py @@ -34,7 +34,7 @@ def test_no_failures(self): def no_failures(): self.counter += 1 - r = no_failures() + no_failures() self.assertEqual(self.counter, 1) def test_extend_boto3_failures(self): diff --git a/tests/unit/plugins/inventory/test_aws_ec2.py b/tests/unit/plugins/inventory/test_aws_ec2.py index c27e84ccdcf..b69b5e3d802 100644 --- a/tests/unit/plugins/inventory/test_aws_ec2.py +++ b/tests/unit/plugins/inventory/test_aws_ec2.py @@ -139,7 +139,7 @@ def test_boto3_conn(inventory): loader = DataLoader() inventory._set_credentials(loader) with pytest.raises(AnsibleError) as error_message: - for connection, region in inventory._boto3_conn(regions=['us-east-1']): + for _connection, _region in inventory._boto3_conn(regions=['us-east-1']): assert "Insufficient credentials found" in error_message