` modules.
+
+
Synopsis
--------
@@ -25,8 +32,10 @@ Requirements
------------
The below requirements are needed on the host that executes this module.
-- python >= 2.6
-- boto
+- boto >= 2.49.0
+- boto3 >= 1.15.0
+- botocore >= 1.18.0
+- python >= 3.6
Parameters
@@ -93,7 +102,7 @@ Parameters
|
- AWS access key. If not set then the value of the AWS_ACCESS_KEY_ID, AWS_ACCESS_KEY or EC2_ACCESS_KEY environment variable is used.
+ AWS access key . If not set then the value of the AWS_ACCESS_KEY_ID , AWS_ACCESS_KEY or EC2_ACCESS_KEY environment variable is used.
If profile is set this parameter is ignored.
Passing the aws_access_key and profile options at the same time has been deprecated and the options will be made mutually exclusive after 2022-06-01.
aliases: ec2_access_key, access_key
@@ -112,7 +121,7 @@ Parameters
|
The location of a CA Bundle to use when validating SSL certificates.
- Only used for boto3 based modules.
+ Not used by boto 2 based modules.
Note: The CA Bundle is read 'module' side and may need to be explicitly copied from the controller if not run locally.
|
@@ -145,7 +154,7 @@ Parameters
|
- AWS secret key. If not set then the value of the AWS_SECRET_ACCESS_KEY, AWS_SECRET_KEY, or EC2_SECRET_KEY environment variable is used.
+ AWS secret key . If not set then the value of the AWS_SECRET_ACCESS_KEY , AWS_SECRET_KEY , or EC2_SECRET_KEY environment variable is used.
If profile is set this parameter is ignored.
Passing the aws_secret_key and profile options at the same time has been deprecated and the options will be made mutually exclusive after 2022-06-01.
aliases: ec2_secret_key, secret_key
@@ -182,7 +191,7 @@ Parameters
|
|
- Url to use to connect to EC2 or your Eucalyptus cloud (by default the module will use EC2 endpoints). Ignored for modules where region is required. Must be specified for all other modules if region is not used. If not set then the value of the EC2_URL environment variable, if any, is used.
+ URL to use to connect to EC2 or your Eucalyptus cloud (by default the module will use EC2 endpoints). Ignored for modules where region is required. Must be specified for all other modules if region is not used. If not set then the value of the EC2_URL environment variable, if any, is used.
aliases: aws_endpoint_url, endpoint_url
|
@@ -330,7 +339,6 @@ Parameters
|
- Uses a boto profile. Only works with boto >= 2.24.0.
Using profile will override aws_access_key, aws_secret_key and security_token and support for passing them at the same time as profile has been deprecated.
aws_access_key, aws_secret_key and security_token will be made mutually exclusive with profile after 2022-06-01.
aliases: aws_profile
@@ -364,7 +372,7 @@ Parameters
|
|
- AWS STS security token. If not set then the value of the AWS_SECURITY_TOKEN or EC2_SECURITY_TOKEN environment variable is used.
+ AWS STS security token . If not set then the value of the AWS_SECURITY_TOKEN or EC2_SECURITY_TOKEN environment variable is used.
If profile is set this parameter is ignored.
Passing the security_token and profile options at the same time has been deprecated and the options will be made mutually exclusive after 2022-06-01.
aliases: aws_security_token, access_token
@@ -460,7 +468,7 @@ Parameters
|
- When set to "no", SSL certificates will not be validated for boto versions >= 2.6.0.
+ When set to "no", SSL certificates will not be validated for communication with the AWS APIs.
|
@@ -473,8 +481,9 @@ Notes
.. note::
- Currently boto does not support the removal of Managed Policies, the module will error out if your user/group/role has managed policies when you try to do state=absent. They will need to be removed manually.
- If parameters are not set within the module, the following environment variables can be used in decreasing order of precedence ``AWS_URL`` or ``EC2_URL``, ``AWS_PROFILE`` or ``AWS_DEFAULT_PROFILE``, ``AWS_ACCESS_KEY_ID`` or ``AWS_ACCESS_KEY`` or ``EC2_ACCESS_KEY``, ``AWS_SECRET_ACCESS_KEY`` or ``AWS_SECRET_KEY`` or ``EC2_SECRET_KEY``, ``AWS_SECURITY_TOKEN`` or ``EC2_SECURITY_TOKEN``, ``AWS_REGION`` or ``EC2_REGION``, ``AWS_CA_BUNDLE``
- - Ansible uses the boto configuration file (typically ~/.boto) if no credentials are provided. See https://boto.readthedocs.io/en/latest/boto_config_tut.html
- - ``AWS_REGION`` or ``EC2_REGION`` can be typically be used to specify the AWS region, when required, but this can also be configured in the boto config file
+ - When no credentials are explicitly provided the AWS SDK (boto3) that Ansible uses will fall back to its configuration files (typically ``~/.aws/credentials``). See https://boto3.amazonaws.com/v1/documentation/api/latest/guide/credentials.html for more information.
+ - Modules based on the original AWS SDK (boto) may read their default configuration from different files. See https://boto.readthedocs.io/en/latest/boto_config_tut.html for more information.
+ - ``AWS_REGION`` or ``EC2_REGION`` can be typically be used to specify the AWS region, when required, but this can also be defined in the configuration files.
@@ -585,6 +594,10 @@ Status
------
+- This module will be removed in version 3.0.0. *[deprecated]*
+- For more information see `DEPRECATED`_.
+
+
Authors
~~~~~~~
diff --git a/docs/community.aws.iam_password_policy_module.rst b/docs/community.aws.iam_password_policy_module.rst
index e1bdb8ce9fe..593be87d97f 100644
--- a/docs/community.aws.iam_password_policy_module.rst
+++ b/docs/community.aws.iam_password_policy_module.rst
@@ -25,10 +25,9 @@ Requirements
------------
The below requirements are needed on the host that executes this module.
-- boto
-- boto3
-- botocore
-- python >= 2.6
+- python >= 3.6
+- boto3 >= 1.15.0
+- botocore >= 1.18.0
Parameters
@@ -74,7 +73,7 @@ Parameters
|
- AWS access key. If not set then the value of the AWS_ACCESS_KEY_ID, AWS_ACCESS_KEY or EC2_ACCESS_KEY environment variable is used.
+ AWS access key . If not set then the value of the AWS_ACCESS_KEY_ID , AWS_ACCESS_KEY or EC2_ACCESS_KEY environment variable is used.
If profile is set this parameter is ignored.
Passing the aws_access_key and profile options at the same time has been deprecated and the options will be made mutually exclusive after 2022-06-01.
aliases: ec2_access_key, access_key
@@ -93,7 +92,7 @@ Parameters
|
The location of a CA Bundle to use when validating SSL certificates.
- Only used for boto3 based modules.
+ Not used by boto 2 based modules.
Note: The CA Bundle is read 'module' side and may need to be explicitly copied from the controller if not run locally.
|
@@ -126,7 +125,7 @@ Parameters
|
- AWS secret key. If not set then the value of the AWS_SECRET_ACCESS_KEY, AWS_SECRET_KEY, or EC2_SECRET_KEY environment variable is used.
+ AWS secret key . If not set then the value of the AWS_SECRET_ACCESS_KEY , AWS_SECRET_KEY , or EC2_SECRET_KEY environment variable is used.
If profile is set this parameter is ignored.
Passing the aws_secret_key and profile options at the same time has been deprecated and the options will be made mutually exclusive after 2022-06-01.
aliases: ec2_secret_key, secret_key
@@ -163,7 +162,7 @@ Parameters
|
|
- Url to use to connect to EC2 or your Eucalyptus cloud (by default the module will use EC2 endpoints). Ignored for modules where region is required. Must be specified for all other modules if region is not used. If not set then the value of the EC2_URL environment variable, if any, is used.
+ URL to use to connect to EC2 or your Eucalyptus cloud (by default the module will use EC2 endpoints). Ignored for modules where region is required. Must be specified for all other modules if region is not used. If not set then the value of the EC2_URL environment variable, if any, is used.
aliases: aws_endpoint_url, endpoint_url
|
@@ -196,7 +195,6 @@ Parameters
|
- Uses a boto profile. Only works with boto >= 2.24.0.
Using profile will override aws_access_key, aws_secret_key and security_token and support for passing them at the same time as profile has been deprecated.
aws_access_key, aws_secret_key and security_token will be made mutually exclusive with profile after 2022-06-01.
aliases: aws_profile
@@ -360,7 +358,7 @@ Parameters
|
|
- AWS STS security token. If not set then the value of the AWS_SECURITY_TOKEN or EC2_SECURITY_TOKEN environment variable is used.
+ AWS STS security token . If not set then the value of the AWS_SECURITY_TOKEN or EC2_SECURITY_TOKEN environment variable is used.
If profile is set this parameter is ignored.
Passing the security_token and profile options at the same time has been deprecated and the options will be made mutually exclusive after 2022-06-01.
aliases: aws_security_token, access_token
@@ -402,7 +400,7 @@ Parameters
|
- When set to "no", SSL certificates will not be validated for boto versions >= 2.6.0.
+ When set to "no", SSL certificates will not be validated for communication with the AWS APIs.
|
@@ -414,8 +412,9 @@ Notes
.. note::
- If parameters are not set within the module, the following environment variables can be used in decreasing order of precedence ``AWS_URL`` or ``EC2_URL``, ``AWS_PROFILE`` or ``AWS_DEFAULT_PROFILE``, ``AWS_ACCESS_KEY_ID`` or ``AWS_ACCESS_KEY`` or ``EC2_ACCESS_KEY``, ``AWS_SECRET_ACCESS_KEY`` or ``AWS_SECRET_KEY`` or ``EC2_SECRET_KEY``, ``AWS_SECURITY_TOKEN`` or ``EC2_SECURITY_TOKEN``, ``AWS_REGION`` or ``EC2_REGION``, ``AWS_CA_BUNDLE``
- - Ansible uses the boto configuration file (typically ~/.boto) if no credentials are provided. See https://boto.readthedocs.io/en/latest/boto_config_tut.html
- - ``AWS_REGION`` or ``EC2_REGION`` can be typically be used to specify the AWS region, when required, but this can also be configured in the boto config file
+ - When no credentials are explicitly provided the AWS SDK (boto3) that Ansible uses will fall back to its configuration files (typically ``~/.aws/credentials``). See https://boto3.amazonaws.com/v1/documentation/api/latest/guide/credentials.html for more information.
+ - Modules based on the original AWS SDK (boto) may read their default configuration from different files. See https://boto.readthedocs.io/en/latest/boto_config_tut.html for more information.
+ - ``AWS_REGION`` or ``EC2_REGION`` can be typically be used to specify the AWS region, when required, but this can also be defined in the configuration files.
diff --git a/docs/community.aws.iam_policy_info_module.rst b/docs/community.aws.iam_policy_info_module.rst
index 6d06db1d93f..1c3361febd1 100644
--- a/docs/community.aws.iam_policy_info_module.rst
+++ b/docs/community.aws.iam_policy_info_module.rst
@@ -25,8 +25,9 @@ Requirements
------------
The below requirements are needed on the host that executes this module.
-- python >= 2.6
-- boto
+- python >= 3.6
+- boto3 >= 1.15.0
+- botocore >= 1.18.0
Parameters
@@ -52,7 +53,7 @@ Parameters
|
- AWS access key. If not set then the value of the AWS_ACCESS_KEY_ID, AWS_ACCESS_KEY or EC2_ACCESS_KEY environment variable is used.
+ AWS access key . If not set then the value of the AWS_ACCESS_KEY_ID , AWS_ACCESS_KEY or EC2_ACCESS_KEY environment variable is used.
If profile is set this parameter is ignored.
Passing the aws_access_key and profile options at the same time has been deprecated and the options will be made mutually exclusive after 2022-06-01.
aliases: ec2_access_key, access_key
@@ -71,7 +72,7 @@ Parameters
|
The location of a CA Bundle to use when validating SSL certificates.
- Only used for boto3 based modules.
+ Not used by boto 2 based modules.
Note: The CA Bundle is read 'module' side and may need to be explicitly copied from the controller if not run locally.
|
@@ -104,7 +105,7 @@ Parameters
|
- AWS secret key. If not set then the value of the AWS_SECRET_ACCESS_KEY, AWS_SECRET_KEY, or EC2_SECRET_KEY environment variable is used.
+ AWS secret key . If not set then the value of the AWS_SECRET_ACCESS_KEY , AWS_SECRET_KEY , or EC2_SECRET_KEY environment variable is used.
If profile is set this parameter is ignored.
Passing the aws_secret_key and profile options at the same time has been deprecated and the options will be made mutually exclusive after 2022-06-01.
aliases: ec2_secret_key, secret_key
@@ -141,7 +142,7 @@ Parameters
|
|
- Url to use to connect to EC2 or your Eucalyptus cloud (by default the module will use EC2 endpoints). Ignored for modules where region is required. Must be specified for all other modules if region is not used. If not set then the value of the EC2_URL environment variable, if any, is used.
+ URL to use to connect to EC2 or your Eucalyptus cloud (by default the module will use EC2 endpoints). Ignored for modules where region is required. Must be specified for all other modules if region is not used. If not set then the value of the EC2_URL environment variable, if any, is used.
aliases: aws_endpoint_url, endpoint_url
|
@@ -209,7 +210,6 @@ Parameters
|
- Uses a boto profile. Only works with boto >= 2.24.0.
Using profile will override aws_access_key, aws_secret_key and security_token and support for passing them at the same time as profile has been deprecated.
aws_access_key, aws_secret_key and security_token will be made mutually exclusive with profile after 2022-06-01.
aliases: aws_profile
@@ -243,7 +243,7 @@ Parameters
|
|
- AWS STS security token. If not set then the value of the AWS_SECURITY_TOKEN or EC2_SECURITY_TOKEN environment variable is used.
+ AWS STS security token . If not set then the value of the AWS_SECURITY_TOKEN or EC2_SECURITY_TOKEN environment variable is used.
If profile is set this parameter is ignored.
Passing the security_token and profile options at the same time has been deprecated and the options will be made mutually exclusive after 2022-06-01.
aliases: aws_security_token, access_token
@@ -265,7 +265,7 @@ Parameters
|
- When set to "no", SSL certificates will not be validated for boto versions >= 2.6.0.
+ When set to "no", SSL certificates will not be validated for communication with the AWS APIs.
|
@@ -277,8 +277,9 @@ Notes
.. note::
- If parameters are not set within the module, the following environment variables can be used in decreasing order of precedence ``AWS_URL`` or ``EC2_URL``, ``AWS_PROFILE`` or ``AWS_DEFAULT_PROFILE``, ``AWS_ACCESS_KEY_ID`` or ``AWS_ACCESS_KEY`` or ``EC2_ACCESS_KEY``, ``AWS_SECRET_ACCESS_KEY`` or ``AWS_SECRET_KEY`` or ``EC2_SECRET_KEY``, ``AWS_SECURITY_TOKEN`` or ``EC2_SECURITY_TOKEN``, ``AWS_REGION`` or ``EC2_REGION``, ``AWS_CA_BUNDLE``
- - Ansible uses the boto configuration file (typically ~/.boto) if no credentials are provided. See https://boto.readthedocs.io/en/latest/boto_config_tut.html
- - ``AWS_REGION`` or ``EC2_REGION`` can be typically be used to specify the AWS region, when required, but this can also be configured in the boto config file
+ - When no credentials are explicitly provided the AWS SDK (boto3) that Ansible uses will fall back to its configuration files (typically ``~/.aws/credentials``). See https://boto3.amazonaws.com/v1/documentation/api/latest/guide/credentials.html for more information.
+ - Modules based on the original AWS SDK (boto) may read their default configuration from different files. See https://boto.readthedocs.io/en/latest/boto_config_tut.html for more information.
+ - ``AWS_REGION`` or ``EC2_REGION`` can be typically be used to specify the AWS region, when required, but this can also be defined in the configuration files.
diff --git a/docs/community.aws.iam_policy_module.rst b/docs/community.aws.iam_policy_module.rst
index f976ac1a4d0..e5fc98f019e 100644
--- a/docs/community.aws.iam_policy_module.rst
+++ b/docs/community.aws.iam_policy_module.rst
@@ -26,8 +26,9 @@ Requirements
------------
The below requirements are needed on the host that executes this module.
-- python >= 2.6
-- boto
+- python >= 3.6
+- boto3 >= 1.15.0
+- botocore >= 1.18.0
Parameters
@@ -53,7 +54,7 @@ Parameters
|
- AWS access key. If not set then the value of the AWS_ACCESS_KEY_ID, AWS_ACCESS_KEY or EC2_ACCESS_KEY environment variable is used.
+ AWS access key . If not set then the value of the AWS_ACCESS_KEY_ID , AWS_ACCESS_KEY or EC2_ACCESS_KEY environment variable is used.
If profile is set this parameter is ignored.
Passing the aws_access_key and profile options at the same time has been deprecated and the options will be made mutually exclusive after 2022-06-01.
aliases: ec2_access_key, access_key
@@ -72,7 +73,7 @@ Parameters
|
The location of a CA Bundle to use when validating SSL certificates.
- Only used for boto3 based modules.
+ Not used by boto 2 based modules.
Note: The CA Bundle is read 'module' side and may need to be explicitly copied from the controller if not run locally.
|
@@ -105,7 +106,7 @@ Parameters
|
- AWS secret key. If not set then the value of the AWS_SECRET_ACCESS_KEY, AWS_SECRET_KEY, or EC2_SECRET_KEY environment variable is used.
+ AWS secret key . If not set then the value of the AWS_SECRET_ACCESS_KEY , AWS_SECRET_KEY , or EC2_SECRET_KEY environment variable is used.
If profile is set this parameter is ignored.
Passing the aws_secret_key and profile options at the same time has been deprecated and the options will be made mutually exclusive after 2022-06-01.
aliases: ec2_secret_key, secret_key
@@ -142,7 +143,7 @@ Parameters
|
|
- Url to use to connect to EC2 or your Eucalyptus cloud (by default the module will use EC2 endpoints). Ignored for modules where region is required. Must be specified for all other modules if region is not used. If not set then the value of the EC2_URL environment variable, if any, is used.
+ URL to use to connect to EC2 or your Eucalyptus cloud (by default the module will use EC2 endpoints). Ignored for modules where region is required. Must be specified for all other modules if region is not used. If not set then the value of the EC2_URL environment variable, if any, is used.
aliases: aws_endpoint_url, endpoint_url
|
@@ -245,7 +246,6 @@ Parameters
|
- Uses a boto profile. Only works with boto >= 2.24.0.
Using profile will override aws_access_key, aws_secret_key and security_token and support for passing them at the same time as profile has been deprecated.
aws_access_key, aws_secret_key and security_token will be made mutually exclusive with profile after 2022-06-01.
aliases: aws_profile
@@ -279,7 +279,7 @@ Parameters
|
|
- AWS STS security token. If not set then the value of the AWS_SECURITY_TOKEN or EC2_SECURITY_TOKEN environment variable is used.
+ AWS STS security token . If not set then the value of the AWS_SECURITY_TOKEN or EC2_SECURITY_TOKEN environment variable is used.
If profile is set this parameter is ignored.
Passing the security_token and profile options at the same time has been deprecated and the options will be made mutually exclusive after 2022-06-01.
aliases: aws_security_token, access_token
@@ -340,7 +340,7 @@ Parameters
|
- When set to "no", SSL certificates will not be validated for boto versions >= 2.6.0.
+ When set to "no", SSL certificates will not be validated for communication with the AWS APIs.
|
@@ -352,8 +352,9 @@ Notes
.. note::
- If parameters are not set within the module, the following environment variables can be used in decreasing order of precedence ``AWS_URL`` or ``EC2_URL``, ``AWS_PROFILE`` or ``AWS_DEFAULT_PROFILE``, ``AWS_ACCESS_KEY_ID`` or ``AWS_ACCESS_KEY`` or ``EC2_ACCESS_KEY``, ``AWS_SECRET_ACCESS_KEY`` or ``AWS_SECRET_KEY`` or ``EC2_SECRET_KEY``, ``AWS_SECURITY_TOKEN`` or ``EC2_SECURITY_TOKEN``, ``AWS_REGION`` or ``EC2_REGION``, ``AWS_CA_BUNDLE``
- - Ansible uses the boto configuration file (typically ~/.boto) if no credentials are provided. See https://boto.readthedocs.io/en/latest/boto_config_tut.html
- - ``AWS_REGION`` or ``EC2_REGION`` can be typically be used to specify the AWS region, when required, but this can also be configured in the boto config file
+ - When no credentials are explicitly provided the AWS SDK (boto3) that Ansible uses will fall back to its configuration files (typically ``~/.aws/credentials``). See https://boto3.amazonaws.com/v1/documentation/api/latest/guide/credentials.html for more information.
+ - Modules based on the original AWS SDK (boto) may read their default configuration from different files. See https://boto.readthedocs.io/en/latest/boto_config_tut.html for more information.
+ - ``AWS_REGION`` or ``EC2_REGION`` can be typically be used to specify the AWS region, when required, but this can also be defined in the configuration files.
diff --git a/docs/community.aws.iam_role_info_module.rst b/docs/community.aws.iam_role_info_module.rst
index 2e3abc9fe1e..d7de4a0837d 100644
--- a/docs/community.aws.iam_role_info_module.rst
+++ b/docs/community.aws.iam_role_info_module.rst
@@ -26,9 +26,9 @@ Requirements
------------
The below requirements are needed on the host that executes this module.
-- boto
-- boto3
-- python >= 2.6
+- python >= 3.6
+- boto3 >= 1.15.0
+- botocore >= 1.18.0
Parameters
@@ -54,7 +54,7 @@ Parameters
|
- AWS access key. If not set then the value of the AWS_ACCESS_KEY_ID, AWS_ACCESS_KEY or EC2_ACCESS_KEY environment variable is used.
+ AWS access key . If not set then the value of the AWS_ACCESS_KEY_ID , AWS_ACCESS_KEY or EC2_ACCESS_KEY environment variable is used.
If profile is set this parameter is ignored.
Passing the aws_access_key and profile options at the same time has been deprecated and the options will be made mutually exclusive after 2022-06-01.
aliases: ec2_access_key, access_key
@@ -73,7 +73,7 @@ Parameters
|
The location of a CA Bundle to use when validating SSL certificates.
- Only used for boto3 based modules.
+ Not used by boto 2 based modules.
Note: The CA Bundle is read 'module' side and may need to be explicitly copied from the controller if not run locally.
|
@@ -106,7 +106,7 @@ Parameters
|
- AWS secret key. If not set then the value of the AWS_SECRET_ACCESS_KEY, AWS_SECRET_KEY, or EC2_SECRET_KEY environment variable is used.
+ AWS secret key . If not set then the value of the AWS_SECRET_ACCESS_KEY , AWS_SECRET_KEY , or EC2_SECRET_KEY environment variable is used.
If profile is set this parameter is ignored.
Passing the aws_secret_key and profile options at the same time has been deprecated and the options will be made mutually exclusive after 2022-06-01.
aliases: ec2_secret_key, secret_key
@@ -143,7 +143,7 @@ Parameters
|
|
- Url to use to connect to EC2 or your Eucalyptus cloud (by default the module will use EC2 endpoints). Ignored for modules where region is required. Must be specified for all other modules if region is not used. If not set then the value of the EC2_URL environment variable, if any, is used.
+ URL to use to connect to EC2 or your Eucalyptus cloud (by default the module will use EC2 endpoints). Ignored for modules where region is required. Must be specified for all other modules if region is not used. If not set then the value of the EC2_URL environment variable, if any, is used.
aliases: aws_endpoint_url, endpoint_url
|
@@ -192,7 +192,6 @@ Parameters
|
- Uses a boto profile. Only works with boto >= 2.24.0.
Using profile will override aws_access_key, aws_secret_key and security_token and support for passing them at the same time as profile has been deprecated.
aws_access_key, aws_secret_key and security_token will be made mutually exclusive with profile after 2022-06-01.
aliases: aws_profile
@@ -226,7 +225,7 @@ Parameters
|
|
- AWS STS security token. If not set then the value of the AWS_SECURITY_TOKEN or EC2_SECURITY_TOKEN environment variable is used.
+ AWS STS security token . If not set then the value of the AWS_SECURITY_TOKEN or EC2_SECURITY_TOKEN environment variable is used.
If profile is set this parameter is ignored.
Passing the security_token and profile options at the same time has been deprecated and the options will be made mutually exclusive after 2022-06-01.
aliases: aws_security_token, access_token
@@ -248,7 +247,7 @@ Parameters
|
- When set to "no", SSL certificates will not be validated for boto versions >= 2.6.0.
+ When set to "no", SSL certificates will not be validated for communication with the AWS APIs.
|
@@ -260,8 +259,9 @@ Notes
.. note::
- If parameters are not set within the module, the following environment variables can be used in decreasing order of precedence ``AWS_URL`` or ``EC2_URL``, ``AWS_PROFILE`` or ``AWS_DEFAULT_PROFILE``, ``AWS_ACCESS_KEY_ID`` or ``AWS_ACCESS_KEY`` or ``EC2_ACCESS_KEY``, ``AWS_SECRET_ACCESS_KEY`` or ``AWS_SECRET_KEY`` or ``EC2_SECRET_KEY``, ``AWS_SECURITY_TOKEN`` or ``EC2_SECURITY_TOKEN``, ``AWS_REGION`` or ``EC2_REGION``, ``AWS_CA_BUNDLE``
- - Ansible uses the boto configuration file (typically ~/.boto) if no credentials are provided. See https://boto.readthedocs.io/en/latest/boto_config_tut.html
- - ``AWS_REGION`` or ``EC2_REGION`` can be typically be used to specify the AWS region, when required, but this can also be configured in the boto config file
+ - When no credentials are explicitly provided the AWS SDK (boto3) that Ansible uses will fall back to its configuration files (typically ``~/.aws/credentials``). See https://boto3.amazonaws.com/v1/documentation/api/latest/guide/credentials.html for more information.
+ - Modules based on the original AWS SDK (boto) may read their default configuration from different files. See https://boto.readthedocs.io/en/latest/boto_config_tut.html for more information.
+ - ``AWS_REGION`` or ``EC2_REGION`` can be typically be used to specify the AWS region, when required, but this can also be defined in the configuration files.
diff --git a/docs/community.aws.iam_role_module.rst b/docs/community.aws.iam_role_module.rst
index e81541d815a..b2f8568bf43 100644
--- a/docs/community.aws.iam_role_module.rst
+++ b/docs/community.aws.iam_role_module.rst
@@ -25,10 +25,9 @@ Requirements
------------
The below requirements are needed on the host that executes this module.
-- boto
-- boto3
-- botocore
-- python >= 2.6
+- python >= 3.6
+- boto3 >= 1.15.0
+- botocore >= 1.18.0
Parameters
@@ -70,7 +69,7 @@ Parameters
|
- AWS access key. If not set then the value of the AWS_ACCESS_KEY_ID, AWS_ACCESS_KEY or EC2_ACCESS_KEY environment variable is used.
+ AWS access key . If not set then the value of the AWS_ACCESS_KEY_ID , AWS_ACCESS_KEY or EC2_ACCESS_KEY environment variable is used.
If profile is set this parameter is ignored.
Passing the aws_access_key and profile options at the same time has been deprecated and the options will be made mutually exclusive after 2022-06-01.
aliases: ec2_access_key, access_key
@@ -89,7 +88,7 @@ Parameters
|
The location of a CA Bundle to use when validating SSL certificates.
- Only used for boto3 based modules.
+ Not used by boto 2 based modules.
Note: The CA Bundle is read 'module' side and may need to be explicitly copied from the controller if not run locally.
|
@@ -122,7 +121,7 @@ Parameters
|
- AWS secret key. If not set then the value of the AWS_SECRET_ACCESS_KEY, AWS_SECRET_KEY, or EC2_SECRET_KEY environment variable is used.
+ AWS secret key . If not set then the value of the AWS_SECRET_ACCESS_KEY , AWS_SECRET_KEY , or EC2_SECRET_KEY environment variable is used.
If profile is set this parameter is ignored.
Passing the aws_secret_key and profile options at the same time has been deprecated and the options will be made mutually exclusive after 2022-06-01.
aliases: ec2_secret_key, secret_key
@@ -144,7 +143,6 @@ Parameters
Boundaries cannot be set on Instance Profiles, as such if this option is specified then create_instance_profile must be false .
This is intended for roles/users that have permissions to create new IAM objects.
- Requires botocore 1.10.57 or above.
aliases: boundary_policy_arn
|
@@ -233,7 +231,7 @@ Parameters
|
- Url to use to connect to EC2 or your Eucalyptus cloud (by default the module will use EC2 endpoints). Ignored for modules where region is required. Must be specified for all other modules if region is not used. If not set then the value of the EC2_URL environment variable, if any, is used.
+ URL to use to connect to EC2 or your Eucalyptus cloud (by default the module will use EC2 endpoints). Ignored for modules where region is required. Must be specified for all other modules if region is not used. If not set then the value of the EC2_URL environment variable, if any, is used.
aliases: aws_endpoint_url, endpoint_url
|
@@ -316,7 +314,6 @@ Parameters
|
- Uses a boto profile. Only works with boto >= 2.24.0.
Using profile will override aws_access_key, aws_secret_key and security_token and support for passing them at the same time as profile has been deprecated.
aws_access_key, aws_secret_key and security_token will be made mutually exclusive with profile after 2022-06-01.
aliases: aws_profile
@@ -390,7 +387,7 @@ Parameters
|
|
- AWS STS security token. If not set then the value of the AWS_SECURITY_TOKEN or EC2_SECURITY_TOKEN environment variable is used.
+ AWS STS security token . If not set then the value of the AWS_SECURITY_TOKEN or EC2_SECURITY_TOKEN environment variable is used.
If profile is set this parameter is ignored.
Passing the security_token and profile options at the same time has been deprecated and the options will be made mutually exclusive after 2022-06-01.
aliases: aws_security_token, access_token
@@ -428,7 +425,6 @@ Parameters
|
Tag dict to apply to the queue.
- Requires botocore 1.12.46 or above.
|
@@ -447,7 +443,7 @@ Parameters
- When set to "no", SSL certificates will not be validated for boto versions >= 2.6.0.
+ When set to "no", SSL certificates will not be validated for communication with the AWS APIs.
|
@@ -459,8 +455,9 @@ Notes
.. note::
- If parameters are not set within the module, the following environment variables can be used in decreasing order of precedence ``AWS_URL`` or ``EC2_URL``, ``AWS_PROFILE`` or ``AWS_DEFAULT_PROFILE``, ``AWS_ACCESS_KEY_ID`` or ``AWS_ACCESS_KEY`` or ``EC2_ACCESS_KEY``, ``AWS_SECRET_ACCESS_KEY`` or ``AWS_SECRET_KEY`` or ``EC2_SECRET_KEY``, ``AWS_SECURITY_TOKEN`` or ``EC2_SECURITY_TOKEN``, ``AWS_REGION`` or ``EC2_REGION``, ``AWS_CA_BUNDLE``
- - Ansible uses the boto configuration file (typically ~/.boto) if no credentials are provided. See https://boto.readthedocs.io/en/latest/boto_config_tut.html
- - ``AWS_REGION`` or ``EC2_REGION`` can be typically be used to specify the AWS region, when required, but this can also be configured in the boto config file
+ - When no credentials are explicitly provided the AWS SDK (boto3) that Ansible uses will fall back to its configuration files (typically ``~/.aws/credentials``). See https://boto3.amazonaws.com/v1/documentation/api/latest/guide/credentials.html for more information.
+ - Modules based on the original AWS SDK (boto) may read their default configuration from different files. See https://boto.readthedocs.io/en/latest/boto_config_tut.html for more information.
+ - ``AWS_REGION`` or ``EC2_REGION`` can be typically be used to specify the AWS region, when required, but this can also be defined in the configuration files.
diff --git a/docs/community.aws.iam_saml_federation_module.rst b/docs/community.aws.iam_saml_federation_module.rst
index 3e9ac69b646..785b1509c4b 100644
--- a/docs/community.aws.iam_saml_federation_module.rst
+++ b/docs/community.aws.iam_saml_federation_module.rst
@@ -25,9 +25,9 @@ Requirements
------------
The below requirements are needed on the host that executes this module.
-- boto
-- boto3
-- python >= 2.6
+- python >= 3.6
+- boto3 >= 1.15.0
+- botocore >= 1.18.0
Parameters
@@ -53,7 +53,7 @@ Parameters
|
- AWS access key. If not set then the value of the AWS_ACCESS_KEY_ID, AWS_ACCESS_KEY or EC2_ACCESS_KEY environment variable is used.
+ AWS access key . If not set then the value of the AWS_ACCESS_KEY_ID , AWS_ACCESS_KEY or EC2_ACCESS_KEY environment variable is used.
If profile is set this parameter is ignored.
Passing the aws_access_key and profile options at the same time has been deprecated and the options will be made mutually exclusive after 2022-06-01.
aliases: ec2_access_key, access_key
@@ -72,7 +72,7 @@ Parameters
|
The location of a CA Bundle to use when validating SSL certificates.
- Only used for boto3 based modules.
+ Not used by boto 2 based modules.
Note: The CA Bundle is read 'module' side and may need to be explicitly copied from the controller if not run locally.
|
@@ -105,7 +105,7 @@ Parameters
|
- AWS secret key. If not set then the value of the AWS_SECRET_ACCESS_KEY, AWS_SECRET_KEY, or EC2_SECRET_KEY environment variable is used.
+ AWS secret key . If not set then the value of the AWS_SECRET_ACCESS_KEY , AWS_SECRET_KEY , or EC2_SECRET_KEY environment variable is used.
If profile is set this parameter is ignored.
Passing the aws_secret_key and profile options at the same time has been deprecated and the options will be made mutually exclusive after 2022-06-01.
aliases: ec2_secret_key, secret_key
@@ -142,7 +142,7 @@ Parameters
|
|
- Url to use to connect to EC2 or your Eucalyptus cloud (by default the module will use EC2 endpoints). Ignored for modules where region is required. Must be specified for all other modules if region is not used. If not set then the value of the EC2_URL environment variable, if any, is used.
+ URL to use to connect to EC2 or your Eucalyptus cloud (by default the module will use EC2 endpoints). Ignored for modules where region is required. Must be specified for all other modules if region is not used. If not set then the value of the EC2_URL environment variable, if any, is used.
aliases: aws_endpoint_url, endpoint_url
|
@@ -174,7 +174,6 @@ Parameters
|
- Uses a boto profile. Only works with boto >= 2.24.0.
Using profile will override aws_access_key, aws_secret_key and security_token and support for passing them at the same time as profile has been deprecated.
aws_access_key, aws_secret_key and security_token will be made mutually exclusive with profile after 2022-06-01.
aliases: aws_profile
@@ -223,7 +222,7 @@ Parameters
|
|
- AWS STS security token. If not set then the value of the AWS_SECURITY_TOKEN or EC2_SECURITY_TOKEN environment variable is used.
+ AWS STS security token . If not set then the value of the AWS_SECURITY_TOKEN or EC2_SECURITY_TOKEN environment variable is used.
If profile is set this parameter is ignored.
Passing the security_token and profile options at the same time has been deprecated and the options will be made mutually exclusive after 2022-06-01.
aliases: aws_security_token, access_token
@@ -264,7 +263,7 @@ Parameters
|
- When set to "no", SSL certificates will not be validated for boto versions >= 2.6.0.
+ When set to "no", SSL certificates will not be validated for communication with the AWS APIs.
|
@@ -276,8 +275,9 @@ Notes
.. note::
- If parameters are not set within the module, the following environment variables can be used in decreasing order of precedence ``AWS_URL`` or ``EC2_URL``, ``AWS_PROFILE`` or ``AWS_DEFAULT_PROFILE``, ``AWS_ACCESS_KEY_ID`` or ``AWS_ACCESS_KEY`` or ``EC2_ACCESS_KEY``, ``AWS_SECRET_ACCESS_KEY`` or ``AWS_SECRET_KEY`` or ``EC2_SECRET_KEY``, ``AWS_SECURITY_TOKEN`` or ``EC2_SECURITY_TOKEN``, ``AWS_REGION`` or ``EC2_REGION``, ``AWS_CA_BUNDLE``
- - Ansible uses the boto configuration file (typically ~/.boto) if no credentials are provided. See https://boto.readthedocs.io/en/latest/boto_config_tut.html
- - ``AWS_REGION`` or ``EC2_REGION`` can be typically be used to specify the AWS region, when required, but this can also be configured in the boto config file
+ - When no credentials are explicitly provided the AWS SDK (boto3) that Ansible uses will fall back to its configuration files (typically ``~/.aws/credentials``). See https://boto3.amazonaws.com/v1/documentation/api/latest/guide/credentials.html for more information.
+ - Modules based on the original AWS SDK (boto) may read their default configuration from different files. See https://boto.readthedocs.io/en/latest/boto_config_tut.html for more information.
+ - ``AWS_REGION`` or ``EC2_REGION`` can be typically be used to specify the AWS region, when required, but this can also be defined in the configuration files.
diff --git a/docs/community.aws.iam_server_certificate_info_module.rst b/docs/community.aws.iam_server_certificate_info_module.rst
index c41d2407cb4..1f81ea21f74 100644
--- a/docs/community.aws.iam_server_certificate_info_module.rst
+++ b/docs/community.aws.iam_server_certificate_info_module.rst
@@ -26,10 +26,9 @@ Requirements
------------
The below requirements are needed on the host that executes this module.
-- boto
-- boto3
-- botocore
-- python >= 2.6
+- python >= 3.6
+- boto3 >= 1.15.0
+- botocore >= 1.18.0
Parameters
@@ -55,7 +54,7 @@ Parameters
|
- AWS access key. If not set then the value of the AWS_ACCESS_KEY_ID, AWS_ACCESS_KEY or EC2_ACCESS_KEY environment variable is used.
+ AWS access key . If not set then the value of the AWS_ACCESS_KEY_ID , AWS_ACCESS_KEY or EC2_ACCESS_KEY environment variable is used.
If profile is set this parameter is ignored.
Passing the aws_access_key and profile options at the same time has been deprecated and the options will be made mutually exclusive after 2022-06-01.
aliases: ec2_access_key, access_key
@@ -74,7 +73,7 @@ Parameters
|
The location of a CA Bundle to use when validating SSL certificates.
- Only used for boto3 based modules.
+ Not used by boto 2 based modules.
Note: The CA Bundle is read 'module' side and may need to be explicitly copied from the controller if not run locally.
|
@@ -107,7 +106,7 @@ Parameters
|
- AWS secret key. If not set then the value of the AWS_SECRET_ACCESS_KEY, AWS_SECRET_KEY, or EC2_SECRET_KEY environment variable is used.
+ AWS secret key . If not set then the value of the AWS_SECRET_ACCESS_KEY , AWS_SECRET_KEY , or EC2_SECRET_KEY environment variable is used.
If profile is set this parameter is ignored.
Passing the aws_secret_key and profile options at the same time has been deprecated and the options will be made mutually exclusive after 2022-06-01.
aliases: ec2_secret_key, secret_key
@@ -144,7 +143,7 @@ Parameters
|
|
- Url to use to connect to EC2 or your Eucalyptus cloud (by default the module will use EC2 endpoints). Ignored for modules where region is required. Must be specified for all other modules if region is not used. If not set then the value of the EC2_URL environment variable, if any, is used.
+ URL to use to connect to EC2 or your Eucalyptus cloud (by default the module will use EC2 endpoints). Ignored for modules where region is required. Must be specified for all other modules if region is not used. If not set then the value of the EC2_URL environment variable, if any, is used.
aliases: aws_endpoint_url, endpoint_url
|
@@ -175,7 +174,6 @@ Parameters
|
- Uses a boto profile. Only works with boto >= 2.24.0.
Using profile will override aws_access_key, aws_secret_key and security_token and support for passing them at the same time as profile has been deprecated.
aws_access_key, aws_secret_key and security_token will be made mutually exclusive with profile after 2022-06-01.
aliases: aws_profile
@@ -209,7 +207,7 @@ Parameters
|
|
- AWS STS security token. If not set then the value of the AWS_SECURITY_TOKEN or EC2_SECURITY_TOKEN environment variable is used.
+ AWS STS security token . If not set then the value of the AWS_SECURITY_TOKEN or EC2_SECURITY_TOKEN environment variable is used.
If profile is set this parameter is ignored.
Passing the security_token and profile options at the same time has been deprecated and the options will be made mutually exclusive after 2022-06-01.
aliases: aws_security_token, access_token
@@ -231,7 +229,7 @@ Parameters
|
- When set to "no", SSL certificates will not be validated for boto versions >= 2.6.0.
+ When set to "no", SSL certificates will not be validated for communication with the AWS APIs.
|
@@ -243,8 +241,9 @@ Notes
.. note::
- If parameters are not set within the module, the following environment variables can be used in decreasing order of precedence ``AWS_URL`` or ``EC2_URL``, ``AWS_PROFILE`` or ``AWS_DEFAULT_PROFILE``, ``AWS_ACCESS_KEY_ID`` or ``AWS_ACCESS_KEY`` or ``EC2_ACCESS_KEY``, ``AWS_SECRET_ACCESS_KEY`` or ``AWS_SECRET_KEY`` or ``EC2_SECRET_KEY``, ``AWS_SECURITY_TOKEN`` or ``EC2_SECURITY_TOKEN``, ``AWS_REGION`` or ``EC2_REGION``, ``AWS_CA_BUNDLE``
- - Ansible uses the boto configuration file (typically ~/.boto) if no credentials are provided. See https://boto.readthedocs.io/en/latest/boto_config_tut.html
- - ``AWS_REGION`` or ``EC2_REGION`` can be typically be used to specify the AWS region, when required, but this can also be configured in the boto config file
+ - When no credentials are explicitly provided the AWS SDK (boto3) that Ansible uses will fall back to its configuration files (typically ``~/.aws/credentials``). See https://boto3.amazonaws.com/v1/documentation/api/latest/guide/credentials.html for more information.
+ - Modules based on the original AWS SDK (boto) may read their default configuration from different files. See https://boto.readthedocs.io/en/latest/boto_config_tut.html for more information.
+ - ``AWS_REGION`` or ``EC2_REGION`` can be typically be used to specify the AWS region, when required, but this can also be defined in the configuration files.
diff --git a/docs/community.aws.iam_user_info_module.rst b/docs/community.aws.iam_user_info_module.rst
index f33064c0dd6..1ad22f8cc81 100644
--- a/docs/community.aws.iam_user_info_module.rst
+++ b/docs/community.aws.iam_user_info_module.rst
@@ -25,10 +25,9 @@ Requirements
------------
The below requirements are needed on the host that executes this module.
-- boto
-- boto3
-- botocore
-- python >= 2.6
+- python >= 3.6
+- boto3 >= 1.15.0
+- botocore >= 1.18.0
Parameters
@@ -54,7 +53,7 @@ Parameters
|
- AWS access key. If not set then the value of the AWS_ACCESS_KEY_ID, AWS_ACCESS_KEY or EC2_ACCESS_KEY environment variable is used.
+ AWS access key . If not set then the value of the AWS_ACCESS_KEY_ID , AWS_ACCESS_KEY or EC2_ACCESS_KEY environment variable is used.
If profile is set this parameter is ignored.
Passing the aws_access_key and profile options at the same time has been deprecated and the options will be made mutually exclusive after 2022-06-01.
aliases: ec2_access_key, access_key
@@ -73,7 +72,7 @@ Parameters
|
The location of a CA Bundle to use when validating SSL certificates.
- Only used for boto3 based modules.
+ Not used by boto 2 based modules.
Note: The CA Bundle is read 'module' side and may need to be explicitly copied from the controller if not run locally.
|
@@ -106,7 +105,7 @@ Parameters
|
- AWS secret key. If not set then the value of the AWS_SECRET_ACCESS_KEY, AWS_SECRET_KEY, or EC2_SECRET_KEY environment variable is used.
+ AWS secret key . If not set then the value of the AWS_SECRET_ACCESS_KEY , AWS_SECRET_KEY , or EC2_SECRET_KEY environment variable is used.
If profile is set this parameter is ignored.
Passing the aws_secret_key and profile options at the same time has been deprecated and the options will be made mutually exclusive after 2022-06-01.
aliases: ec2_secret_key, secret_key
@@ -143,7 +142,7 @@ Parameters
|
|
- Url to use to connect to EC2 or your Eucalyptus cloud (by default the module will use EC2 endpoints). Ignored for modules where region is required. Must be specified for all other modules if region is not used. If not set then the value of the EC2_URL environment variable, if any, is used.
+ URL to use to connect to EC2 or your Eucalyptus cloud (by default the module will use EC2 endpoints). Ignored for modules where region is required. Must be specified for all other modules if region is not used. If not set then the value of the EC2_URL environment variable, if any, is used.
aliases: aws_endpoint_url, endpoint_url
|
@@ -206,7 +205,6 @@ Parameters
|
- Uses a boto profile. Only works with boto >= 2.24.0.
Using profile will override aws_access_key, aws_secret_key and security_token and support for passing them at the same time as profile has been deprecated.
aws_access_key, aws_secret_key and security_token will be made mutually exclusive with profile after 2022-06-01.
aliases: aws_profile
@@ -240,7 +238,7 @@ Parameters
|
|
- AWS STS security token. If not set then the value of the AWS_SECURITY_TOKEN or EC2_SECURITY_TOKEN environment variable is used.
+ AWS STS security token . If not set then the value of the AWS_SECURITY_TOKEN or EC2_SECURITY_TOKEN environment variable is used.
If profile is set this parameter is ignored.
Passing the security_token and profile options at the same time has been deprecated and the options will be made mutually exclusive after 2022-06-01.
aliases: aws_security_token, access_token
@@ -262,7 +260,7 @@ Parameters
|
- When set to "no", SSL certificates will not be validated for boto versions >= 2.6.0.
+ When set to "no", SSL certificates will not be validated for communication with the AWS APIs.
|
@@ -274,8 +272,9 @@ Notes
.. note::
- If parameters are not set within the module, the following environment variables can be used in decreasing order of precedence ``AWS_URL`` or ``EC2_URL``, ``AWS_PROFILE`` or ``AWS_DEFAULT_PROFILE``, ``AWS_ACCESS_KEY_ID`` or ``AWS_ACCESS_KEY`` or ``EC2_ACCESS_KEY``, ``AWS_SECRET_ACCESS_KEY`` or ``AWS_SECRET_KEY`` or ``EC2_SECRET_KEY``, ``AWS_SECURITY_TOKEN`` or ``EC2_SECURITY_TOKEN``, ``AWS_REGION`` or ``EC2_REGION``, ``AWS_CA_BUNDLE``
- - Ansible uses the boto configuration file (typically ~/.boto) if no credentials are provided. See https://boto.readthedocs.io/en/latest/boto_config_tut.html
- - ``AWS_REGION`` or ``EC2_REGION`` can be typically be used to specify the AWS region, when required, but this can also be configured in the boto config file
+ - When no credentials are explicitly provided the AWS SDK (boto3) that Ansible uses will fall back to its configuration files (typically ``~/.aws/credentials``). See https://boto3.amazonaws.com/v1/documentation/api/latest/guide/credentials.html for more information.
+ - Modules based on the original AWS SDK (boto) may read their default configuration from different files. See https://boto.readthedocs.io/en/latest/boto_config_tut.html for more information.
+ - ``AWS_REGION`` or ``EC2_REGION`` can be typically be used to specify the AWS region, when required, but this can also be defined in the configuration files.
diff --git a/docs/community.aws.iam_user_module.rst b/docs/community.aws.iam_user_module.rst
index de70f8358d3..806451fa983 100644
--- a/docs/community.aws.iam_user_module.rst
+++ b/docs/community.aws.iam_user_module.rst
@@ -25,10 +25,9 @@ Requirements
------------
The below requirements are needed on the host that executes this module.
-- boto
-- boto3
-- botocore
-- python >= 2.6
+- python >= 3.6
+- boto3 >= 1.15.0
+- botocore >= 1.18.0
Parameters
@@ -54,7 +53,7 @@ Parameters
|
- AWS access key. If not set then the value of the AWS_ACCESS_KEY_ID, AWS_ACCESS_KEY or EC2_ACCESS_KEY environment variable is used.
+ AWS access key . If not set then the value of the AWS_ACCESS_KEY_ID , AWS_ACCESS_KEY or EC2_ACCESS_KEY environment variable is used.
If profile is set this parameter is ignored.
Passing the aws_access_key and profile options at the same time has been deprecated and the options will be made mutually exclusive after 2022-06-01.
aliases: ec2_access_key, access_key
@@ -73,7 +72,7 @@ Parameters
|
The location of a CA Bundle to use when validating SSL certificates.
- Only used for boto3 based modules.
+ Not used by boto 2 based modules.
Note: The CA Bundle is read 'module' side and may need to be explicitly copied from the controller if not run locally.
|
@@ -106,7 +105,7 @@ Parameters
|
- AWS secret key. If not set then the value of the AWS_SECRET_ACCESS_KEY, AWS_SECRET_KEY, or EC2_SECRET_KEY environment variable is used.
+ AWS secret key . If not set then the value of the AWS_SECRET_ACCESS_KEY , AWS_SECRET_KEY , or EC2_SECRET_KEY environment variable is used.
If profile is set this parameter is ignored.
Passing the aws_secret_key and profile options at the same time has been deprecated and the options will be made mutually exclusive after 2022-06-01.
aliases: ec2_secret_key, secret_key
@@ -143,7 +142,7 @@ Parameters
|
|
- Url to use to connect to EC2 or your Eucalyptus cloud (by default the module will use EC2 endpoints). Ignored for modules where region is required. Must be specified for all other modules if region is not used. If not set then the value of the EC2_URL environment variable, if any, is used.
+ URL to use to connect to EC2 or your Eucalyptus cloud (by default the module will use EC2 endpoints). Ignored for modules where region is required. Must be specified for all other modules if region is not used. If not set then the value of the EC2_URL environment variable, if any, is used.
aliases: aws_endpoint_url, endpoint_url
|
@@ -193,7 +192,6 @@ Parameters
|
- Uses a boto profile. Only works with boto >= 2.24.0.
Using profile will override aws_access_key, aws_secret_key and security_token and support for passing them at the same time as profile has been deprecated.
aws_access_key, aws_secret_key and security_token will be made mutually exclusive with profile after 2022-06-01.
aliases: aws_profile
@@ -247,7 +245,7 @@ Parameters
|
|
- AWS STS security token. If not set then the value of the AWS_SECURITY_TOKEN or EC2_SECURITY_TOKEN environment variable is used.
+ AWS STS security token . If not set then the value of the AWS_SECURITY_TOKEN or EC2_SECURITY_TOKEN environment variable is used.
If profile is set this parameter is ignored.
Passing the security_token and profile options at the same time has been deprecated and the options will be made mutually exclusive after 2022-06-01.
aliases: aws_security_token, access_token
@@ -289,7 +287,7 @@ Parameters
|
- When set to "no", SSL certificates will not be validated for boto versions >= 2.6.0.
+ When set to "no", SSL certificates will not be validated for communication with the AWS APIs.
|
@@ -301,8 +299,9 @@ Notes
.. note::
- If parameters are not set within the module, the following environment variables can be used in decreasing order of precedence ``AWS_URL`` or ``EC2_URL``, ``AWS_PROFILE`` or ``AWS_DEFAULT_PROFILE``, ``AWS_ACCESS_KEY_ID`` or ``AWS_ACCESS_KEY`` or ``EC2_ACCESS_KEY``, ``AWS_SECRET_ACCESS_KEY`` or ``AWS_SECRET_KEY`` or ``EC2_SECRET_KEY``, ``AWS_SECURITY_TOKEN`` or ``EC2_SECURITY_TOKEN``, ``AWS_REGION`` or ``EC2_REGION``, ``AWS_CA_BUNDLE``
- - Ansible uses the boto configuration file (typically ~/.boto) if no credentials are provided. See https://boto.readthedocs.io/en/latest/boto_config_tut.html
- - ``AWS_REGION`` or ``EC2_REGION`` can be typically be used to specify the AWS region, when required, but this can also be configured in the boto config file
+ - When no credentials are explicitly provided the AWS SDK (boto3) that Ansible uses will fall back to its configuration files (typically ``~/.aws/credentials``). See https://boto3.amazonaws.com/v1/documentation/api/latest/guide/credentials.html for more information.
+ - Modules based on the original AWS SDK (boto) may read their default configuration from different files. See https://boto.readthedocs.io/en/latest/boto_config_tut.html for more information.
+ - ``AWS_REGION`` or ``EC2_REGION`` can be typically be used to specify the AWS region, when required, but this can also be defined in the configuration files.
diff --git a/docs/community.aws.kinesis_stream_module.rst b/docs/community.aws.kinesis_stream_module.rst
index 27b71b0b487..51ed5640cb0 100644
--- a/docs/community.aws.kinesis_stream_module.rst
+++ b/docs/community.aws.kinesis_stream_module.rst
@@ -28,9 +28,9 @@ Requirements
------------
The below requirements are needed on the host that executes this module.
-- boto
-- boto3
-- python >= 2.6
+- python >= 3.6
+- boto3 >= 1.15.0
+- botocore >= 1.18.0
Parameters
@@ -56,7 +56,7 @@ Parameters
|
- AWS access key. If not set then the value of the AWS_ACCESS_KEY_ID, AWS_ACCESS_KEY or EC2_ACCESS_KEY environment variable is used.
+ AWS access key . If not set then the value of the AWS_ACCESS_KEY_ID , AWS_ACCESS_KEY or EC2_ACCESS_KEY environment variable is used.
If profile is set this parameter is ignored.
Passing the aws_access_key and profile options at the same time has been deprecated and the options will be made mutually exclusive after 2022-06-01.
aliases: ec2_access_key, access_key
@@ -75,7 +75,7 @@ Parameters
|
The location of a CA Bundle to use when validating SSL certificates.
- Only used for boto3 based modules.
+ Not used by boto 2 based modules.
Note: The CA Bundle is read 'module' side and may need to be explicitly copied from the controller if not run locally.
|
@@ -108,7 +108,7 @@ Parameters
|
- AWS secret key. If not set then the value of the AWS_SECRET_ACCESS_KEY, AWS_SECRET_KEY, or EC2_SECRET_KEY environment variable is used.
+ AWS secret key . If not set then the value of the AWS_SECRET_ACCESS_KEY , AWS_SECRET_KEY , or EC2_SECRET_KEY environment variable is used.
If profile is set this parameter is ignored.
Passing the aws_secret_key and profile options at the same time has been deprecated and the options will be made mutually exclusive after 2022-06-01.
aliases: ec2_secret_key, secret_key
@@ -145,7 +145,7 @@ Parameters
|
|
- Url to use to connect to EC2 or your Eucalyptus cloud (by default the module will use EC2 endpoints). Ignored for modules where region is required. Must be specified for all other modules if region is not used. If not set then the value of the EC2_URL environment variable, if any, is used.
+ URL to use to connect to EC2 or your Eucalyptus cloud (by default the module will use EC2 endpoints). Ignored for modules where region is required. Must be specified for all other modules if region is not used. If not set then the value of the EC2_URL environment variable, if any, is used.
aliases: aws_endpoint_url, endpoint_url
|
@@ -231,7 +231,6 @@ Parameters
|
- Uses a boto profile. Only works with boto >= 2.24.0.
Using profile will override aws_access_key, aws_secret_key and security_token and support for passing them at the same time as profile has been deprecated.
aws_access_key, aws_secret_key and security_token will be made mutually exclusive with profile after 2022-06-01.
aliases: aws_profile
@@ -283,7 +282,7 @@ Parameters
|
|
- AWS STS security token. If not set then the value of the AWS_SECURITY_TOKEN or EC2_SECURITY_TOKEN environment variable is used.
+ AWS STS security token . If not set then the value of the AWS_SECURITY_TOKEN or EC2_SECURITY_TOKEN environment variable is used.
If profile is set this parameter is ignored.
Passing the security_token and profile options at the same time has been deprecated and the options will be made mutually exclusive after 2022-06-01.
aliases: aws_security_token, access_token
@@ -356,7 +355,7 @@ Parameters
|
- When set to "no", SSL certificates will not be validated for boto versions >= 2.6.0.
+ When set to "no", SSL certificates will not be validated for communication with the AWS APIs.
|
@@ -403,8 +402,9 @@ Notes
.. note::
- If parameters are not set within the module, the following environment variables can be used in decreasing order of precedence ``AWS_URL`` or ``EC2_URL``, ``AWS_PROFILE`` or ``AWS_DEFAULT_PROFILE``, ``AWS_ACCESS_KEY_ID`` or ``AWS_ACCESS_KEY`` or ``EC2_ACCESS_KEY``, ``AWS_SECRET_ACCESS_KEY`` or ``AWS_SECRET_KEY`` or ``EC2_SECRET_KEY``, ``AWS_SECURITY_TOKEN`` or ``EC2_SECURITY_TOKEN``, ``AWS_REGION`` or ``EC2_REGION``, ``AWS_CA_BUNDLE``
- - Ansible uses the boto configuration file (typically ~/.boto) if no credentials are provided. See https://boto.readthedocs.io/en/latest/boto_config_tut.html
- - ``AWS_REGION`` or ``EC2_REGION`` can be typically be used to specify the AWS region, when required, but this can also be configured in the boto config file
+ - When no credentials are explicitly provided the AWS SDK (boto3) that Ansible uses will fall back to its configuration files (typically ``~/.aws/credentials``). See https://boto3.amazonaws.com/v1/documentation/api/latest/guide/credentials.html for more information.
+ - Modules based on the original AWS SDK (boto) may read their default configuration from different files. See https://boto.readthedocs.io/en/latest/boto_config_tut.html for more information.
+ - ``AWS_REGION`` or ``EC2_REGION`` can be typically be used to specify the AWS region, when required, but this can also be defined in the configuration files.
diff --git a/docs/community.aws.lambda_alias_module.rst b/docs/community.aws.lambda_alias_module.rst
index c50bf63db31..6d0acd53328 100644
--- a/docs/community.aws.lambda_alias_module.rst
+++ b/docs/community.aws.lambda_alias_module.rst
@@ -25,9 +25,9 @@ Requirements
------------
The below requirements are needed on the host that executes this module.
-- boto
-- boto3
-- python >= 2.6
+- python >= 3.6
+- boto3 >= 1.15.0
+- botocore >= 1.18.0
Parameters
@@ -53,7 +53,7 @@ Parameters
|
- AWS access key. If not set then the value of the AWS_ACCESS_KEY_ID, AWS_ACCESS_KEY or EC2_ACCESS_KEY environment variable is used.
+ AWS access key . If not set then the value of the AWS_ACCESS_KEY_ID , AWS_ACCESS_KEY or EC2_ACCESS_KEY environment variable is used.
If profile is set this parameter is ignored.
Passing the aws_access_key and profile options at the same time has been deprecated and the options will be made mutually exclusive after 2022-06-01.
aliases: ec2_access_key, access_key
@@ -72,7 +72,7 @@ Parameters
|
The location of a CA Bundle to use when validating SSL certificates.
- Only used for boto3 based modules.
+ Not used by boto 2 based modules.
Note: The CA Bundle is read 'module' side and may need to be explicitly copied from the controller if not run locally.
|
@@ -105,7 +105,7 @@ Parameters
|
- AWS secret key. If not set then the value of the AWS_SECRET_ACCESS_KEY, AWS_SECRET_KEY, or EC2_SECRET_KEY environment variable is used.
+ AWS secret key . If not set then the value of the AWS_SECRET_ACCESS_KEY , AWS_SECRET_KEY , or EC2_SECRET_KEY environment variable is used.
If profile is set this parameter is ignored.
Passing the aws_secret_key and profile options at the same time has been deprecated and the options will be made mutually exclusive after 2022-06-01.
aliases: ec2_secret_key, secret_key
@@ -157,7 +157,7 @@ Parameters
|
|
- Url to use to connect to EC2 or your Eucalyptus cloud (by default the module will use EC2 endpoints). Ignored for modules where region is required. Must be specified for all other modules if region is not used. If not set then the value of the EC2_URL environment variable, if any, is used.
+ URL to use to connect to EC2 or your Eucalyptus cloud (by default the module will use EC2 endpoints). Ignored for modules where region is required. Must be specified for all other modules if region is not used. If not set then the value of the EC2_URL environment variable, if any, is used.
aliases: aws_endpoint_url, endpoint_url
|
@@ -222,7 +222,6 @@ Parameters
|
- Uses a boto profile. Only works with boto >= 2.24.0.
Using profile will override aws_access_key, aws_secret_key and security_token and support for passing them at the same time as profile has been deprecated.
aws_access_key, aws_secret_key and security_token will be made mutually exclusive with profile after 2022-06-01.
aliases: aws_profile
@@ -256,7 +255,7 @@ Parameters
|
|
- AWS STS security token. If not set then the value of the AWS_SECURITY_TOKEN or EC2_SECURITY_TOKEN environment variable is used.
+ AWS STS security token . If not set then the value of the AWS_SECURITY_TOKEN or EC2_SECURITY_TOKEN environment variable is used.
If profile is set this parameter is ignored.
Passing the security_token and profile options at the same time has been deprecated and the options will be made mutually exclusive after 2022-06-01.
aliases: aws_security_token, access_token
@@ -297,7 +296,7 @@ Parameters
|
- When set to "no", SSL certificates will not be validated for boto versions >= 2.6.0.
+ When set to "no", SSL certificates will not be validated for communication with the AWS APIs.
|
@@ -309,8 +308,9 @@ Notes
.. note::
- If parameters are not set within the module, the following environment variables can be used in decreasing order of precedence ``AWS_URL`` or ``EC2_URL``, ``AWS_PROFILE`` or ``AWS_DEFAULT_PROFILE``, ``AWS_ACCESS_KEY_ID`` or ``AWS_ACCESS_KEY`` or ``EC2_ACCESS_KEY``, ``AWS_SECRET_ACCESS_KEY`` or ``AWS_SECRET_KEY`` or ``EC2_SECRET_KEY``, ``AWS_SECURITY_TOKEN`` or ``EC2_SECURITY_TOKEN``, ``AWS_REGION`` or ``EC2_REGION``, ``AWS_CA_BUNDLE``
- - Ansible uses the boto configuration file (typically ~/.boto) if no credentials are provided. See https://boto.readthedocs.io/en/latest/boto_config_tut.html
- - ``AWS_REGION`` or ``EC2_REGION`` can be typically be used to specify the AWS region, when required, but this can also be configured in the boto config file
+ - When no credentials are explicitly provided the AWS SDK (boto3) that Ansible uses will fall back to its configuration files (typically ``~/.aws/credentials``). See https://boto3.amazonaws.com/v1/documentation/api/latest/guide/credentials.html for more information.
+ - Modules based on the original AWS SDK (boto) may read their default configuration from different files. See https://boto.readthedocs.io/en/latest/boto_config_tut.html for more information.
+ - ``AWS_REGION`` or ``EC2_REGION`` can be typically be used to specify the AWS region, when required, but this can also be defined in the configuration files.
diff --git a/docs/community.aws.lambda_event_module.rst b/docs/community.aws.lambda_event_module.rst
index 9d10ac318e9..14c0f6d008c 100644
--- a/docs/community.aws.lambda_event_module.rst
+++ b/docs/community.aws.lambda_event_module.rst
@@ -25,9 +25,9 @@ Requirements
------------
The below requirements are needed on the host that executes this module.
-- boto
-- boto3
-- python >= 2.6
+- python >= 3.6
+- boto3 >= 1.15.0
+- botocore >= 1.18.0
Parameters
@@ -69,7 +69,7 @@ Parameters
|
- AWS access key. If not set then the value of the AWS_ACCESS_KEY_ID, AWS_ACCESS_KEY or EC2_ACCESS_KEY environment variable is used.
+ AWS access key . If not set then the value of the AWS_ACCESS_KEY_ID , AWS_ACCESS_KEY or EC2_ACCESS_KEY environment variable is used.
If profile is set this parameter is ignored.
Passing the aws_access_key and profile options at the same time has been deprecated and the options will be made mutually exclusive after 2022-06-01.
aliases: ec2_access_key, access_key
@@ -88,7 +88,7 @@ Parameters
|
The location of a CA Bundle to use when validating SSL certificates.
- Only used for boto3 based modules.
+ Not used by boto 2 based modules.
Note: The CA Bundle is read 'module' side and may need to be explicitly copied from the controller if not run locally.
|
@@ -121,7 +121,7 @@ Parameters
|
- AWS secret key. If not set then the value of the AWS_SECRET_ACCESS_KEY, AWS_SECRET_KEY, or EC2_SECRET_KEY environment variable is used.
+ AWS secret key . If not set then the value of the AWS_SECRET_ACCESS_KEY , AWS_SECRET_KEY , or EC2_SECRET_KEY environment variable is used.
If profile is set this parameter is ignored.
Passing the aws_secret_key and profile options at the same time has been deprecated and the options will be made mutually exclusive after 2022-06-01.
aliases: ec2_secret_key, secret_key
@@ -158,7 +158,7 @@ Parameters
|
|
- Url to use to connect to EC2 or your Eucalyptus cloud (by default the module will use EC2 endpoints). Ignored for modules where region is required. Must be specified for all other modules if region is not used. If not set then the value of the EC2_URL environment variable, if any, is used.
+ URL to use to connect to EC2 or your Eucalyptus cloud (by default the module will use EC2 endpoints). Ignored for modules where region is required. Must be specified for all other modules if region is not used. If not set then the value of the EC2_URL environment variable, if any, is used.
aliases: aws_endpoint_url, endpoint_url
|
@@ -212,7 +212,6 @@ Parameters
|
- Uses a boto profile. Only works with boto >= 2.24.0.
Using profile will override aws_access_key, aws_secret_key and security_token and support for passing them at the same time as profile has been deprecated.
aws_access_key, aws_secret_key and security_token will be made mutually exclusive with profile after 2022-06-01.
aliases: aws_profile
@@ -246,7 +245,7 @@ Parameters
|
|
- AWS STS security token. If not set then the value of the AWS_SECURITY_TOKEN or EC2_SECURITY_TOKEN environment variable is used.
+ AWS STS security token . If not set then the value of the AWS_SECURITY_TOKEN or EC2_SECURITY_TOKEN environment variable is used.
If profile is set this parameter is ignored.
Passing the security_token and profile options at the same time has been deprecated and the options will be made mutually exclusive after 2022-06-01.
aliases: aws_security_token, access_token
@@ -380,7 +379,7 @@ Parameters
|
- When set to "no", SSL certificates will not be validated for boto versions >= 2.6.0.
+ When set to "no", SSL certificates will not be validated for communication with the AWS APIs.
|
@@ -408,8 +407,9 @@ Notes
.. note::
- If parameters are not set within the module, the following environment variables can be used in decreasing order of precedence ``AWS_URL`` or ``EC2_URL``, ``AWS_PROFILE`` or ``AWS_DEFAULT_PROFILE``, ``AWS_ACCESS_KEY_ID`` or ``AWS_ACCESS_KEY`` or ``EC2_ACCESS_KEY``, ``AWS_SECRET_ACCESS_KEY`` or ``AWS_SECRET_KEY`` or ``EC2_SECRET_KEY``, ``AWS_SECURITY_TOKEN`` or ``EC2_SECURITY_TOKEN``, ``AWS_REGION`` or ``EC2_REGION``, ``AWS_CA_BUNDLE``
- - Ansible uses the boto configuration file (typically ~/.boto) if no credentials are provided. See https://boto.readthedocs.io/en/latest/boto_config_tut.html
- - ``AWS_REGION`` or ``EC2_REGION`` can be typically be used to specify the AWS region, when required, but this can also be configured in the boto config file
+ - When no credentials are explicitly provided the AWS SDK (boto3) that Ansible uses will fall back to its configuration files (typically ``~/.aws/credentials``). See https://boto3.amazonaws.com/v1/documentation/api/latest/guide/credentials.html for more information.
+ - Modules based on the original AWS SDK (boto) may read their default configuration from different files. See https://boto.readthedocs.io/en/latest/boto_config_tut.html for more information.
+ - ``AWS_REGION`` or ``EC2_REGION`` can be typically be used to specify the AWS region, when required, but this can also be defined in the configuration files.
diff --git a/docs/community.aws.lambda_facts_module.rst b/docs/community.aws.lambda_facts_module.rst
index 369bd9399be..417f3d17179 100644
--- a/docs/community.aws.lambda_facts_module.rst
+++ b/docs/community.aws.lambda_facts_module.rst
@@ -32,9 +32,9 @@ Requirements
------------
The below requirements are needed on the host that executes this module.
-- boto
-- boto3
-- python >= 2.6
+- python >= 3.6
+- boto3 >= 1.15.0
+- botocore >= 1.18.0
Parameters
@@ -60,7 +60,7 @@ Parameters
|
- AWS access key. If not set then the value of the AWS_ACCESS_KEY_ID, AWS_ACCESS_KEY or EC2_ACCESS_KEY environment variable is used.
+ AWS access key . If not set then the value of the AWS_ACCESS_KEY_ID , AWS_ACCESS_KEY or EC2_ACCESS_KEY environment variable is used.
If profile is set this parameter is ignored.
Passing the aws_access_key and profile options at the same time has been deprecated and the options will be made mutually exclusive after 2022-06-01.
aliases: ec2_access_key, access_key
@@ -79,7 +79,7 @@ Parameters
|
The location of a CA Bundle to use when validating SSL certificates.
- Only used for boto3 based modules.
+ Not used by boto 2 based modules.
Note: The CA Bundle is read 'module' side and may need to be explicitly copied from the controller if not run locally.
|
@@ -112,7 +112,7 @@ Parameters
|
- AWS secret key. If not set then the value of the AWS_SECRET_ACCESS_KEY, AWS_SECRET_KEY, or EC2_SECRET_KEY environment variable is used.
+ AWS secret key . If not set then the value of the AWS_SECRET_ACCESS_KEY , AWS_SECRET_KEY , or EC2_SECRET_KEY environment variable is used.
If profile is set this parameter is ignored.
Passing the aws_secret_key and profile options at the same time has been deprecated and the options will be made mutually exclusive after 2022-06-01.
aliases: ec2_secret_key, secret_key
@@ -149,7 +149,7 @@ Parameters
|
|
- Url to use to connect to EC2 or your Eucalyptus cloud (by default the module will use EC2 endpoints). Ignored for modules where region is required. Must be specified for all other modules if region is not used. If not set then the value of the EC2_URL environment variable, if any, is used.
+ URL to use to connect to EC2 or your Eucalyptus cloud (by default the module will use EC2 endpoints). Ignored for modules where region is required. Must be specified for all other modules if region is not used. If not set then the value of the EC2_URL environment variable, if any, is used.
aliases: aws_endpoint_url, endpoint_url
|
@@ -196,7 +196,6 @@ Parameters
|
- Uses a boto profile. Only works with boto >= 2.24.0.
Using profile will override aws_access_key, aws_secret_key and security_token and support for passing them at the same time as profile has been deprecated.
aws_access_key, aws_secret_key and security_token will be made mutually exclusive with profile after 2022-06-01.
aliases: aws_profile
@@ -253,7 +252,7 @@ Parameters
|
|
- AWS STS security token. If not set then the value of the AWS_SECURITY_TOKEN or EC2_SECURITY_TOKEN environment variable is used.
+ AWS STS security token . If not set then the value of the AWS_SECURITY_TOKEN or EC2_SECURITY_TOKEN environment variable is used.
If profile is set this parameter is ignored.
Passing the security_token and profile options at the same time has been deprecated and the options will be made mutually exclusive after 2022-06-01.
aliases: aws_security_token, access_token
@@ -275,7 +274,7 @@ Parameters
|
- When set to "no", SSL certificates will not be validated for boto versions >= 2.6.0.
+ When set to "no", SSL certificates will not be validated for communication with the AWS APIs.
|
@@ -287,8 +286,9 @@ Notes
.. note::
- If parameters are not set within the module, the following environment variables can be used in decreasing order of precedence ``AWS_URL`` or ``EC2_URL``, ``AWS_PROFILE`` or ``AWS_DEFAULT_PROFILE``, ``AWS_ACCESS_KEY_ID`` or ``AWS_ACCESS_KEY`` or ``EC2_ACCESS_KEY``, ``AWS_SECRET_ACCESS_KEY`` or ``AWS_SECRET_KEY`` or ``EC2_SECRET_KEY``, ``AWS_SECURITY_TOKEN`` or ``EC2_SECURITY_TOKEN``, ``AWS_REGION`` or ``EC2_REGION``, ``AWS_CA_BUNDLE``
- - Ansible uses the boto configuration file (typically ~/.boto) if no credentials are provided. See https://boto.readthedocs.io/en/latest/boto_config_tut.html
- - ``AWS_REGION`` or ``EC2_REGION`` can be typically be used to specify the AWS region, when required, but this can also be configured in the boto config file
+ - When no credentials are explicitly provided the AWS SDK (boto3) that Ansible uses will fall back to its configuration files (typically ``~/.aws/credentials``). See https://boto3.amazonaws.com/v1/documentation/api/latest/guide/credentials.html for more information.
+ - Modules based on the original AWS SDK (boto) may read their default configuration from different files. See https://boto.readthedocs.io/en/latest/boto_config_tut.html for more information.
+ - ``AWS_REGION`` or ``EC2_REGION`` can be typically be used to specify the AWS region, when required, but this can also be defined in the configuration files.
diff --git a/docs/community.aws.lambda_info_module.rst b/docs/community.aws.lambda_info_module.rst
index ce265e7087d..2f08ea7159b 100644
--- a/docs/community.aws.lambda_info_module.rst
+++ b/docs/community.aws.lambda_info_module.rst
@@ -26,9 +26,9 @@ Requirements
------------
The below requirements are needed on the host that executes this module.
-- boto
-- boto3
-- python >= 2.6
+- python >= 3.6
+- boto3 >= 1.15.0
+- botocore >= 1.18.0
Parameters
@@ -54,7 +54,7 @@ Parameters
|
- AWS access key. If not set then the value of the AWS_ACCESS_KEY_ID, AWS_ACCESS_KEY or EC2_ACCESS_KEY environment variable is used.
+ AWS access key . If not set then the value of the AWS_ACCESS_KEY_ID , AWS_ACCESS_KEY or EC2_ACCESS_KEY environment variable is used.
If profile is set this parameter is ignored.
Passing the aws_access_key and profile options at the same time has been deprecated and the options will be made mutually exclusive after 2022-06-01.
aliases: ec2_access_key, access_key
@@ -73,7 +73,7 @@ Parameters
|
The location of a CA Bundle to use when validating SSL certificates.
- Only used for boto3 based modules.
+ Not used by boto 2 based modules.
Note: The CA Bundle is read 'module' side and may need to be explicitly copied from the controller if not run locally.
|
@@ -106,7 +106,7 @@ Parameters
|
- AWS secret key. If not set then the value of the AWS_SECRET_ACCESS_KEY, AWS_SECRET_KEY, or EC2_SECRET_KEY environment variable is used.
+ AWS secret key . If not set then the value of the AWS_SECRET_ACCESS_KEY , AWS_SECRET_KEY , or EC2_SECRET_KEY environment variable is used.
If profile is set this parameter is ignored.
Passing the aws_secret_key and profile options at the same time has been deprecated and the options will be made mutually exclusive after 2022-06-01.
aliases: ec2_secret_key, secret_key
@@ -143,7 +143,7 @@ Parameters
|
|
- Url to use to connect to EC2 or your Eucalyptus cloud (by default the module will use EC2 endpoints). Ignored for modules where region is required. Must be specified for all other modules if region is not used. If not set then the value of the EC2_URL environment variable, if any, is used.
+ URL to use to connect to EC2 or your Eucalyptus cloud (by default the module will use EC2 endpoints). Ignored for modules where region is required. Must be specified for all other modules if region is not used. If not set then the value of the EC2_URL environment variable, if any, is used.
aliases: aws_endpoint_url, endpoint_url
|
@@ -190,7 +190,6 @@ Parameters
|
- Uses a boto profile. Only works with boto >= 2.24.0.
Using profile will override aws_access_key, aws_secret_key and security_token and support for passing them at the same time as profile has been deprecated.
aws_access_key, aws_secret_key and security_token will be made mutually exclusive with profile after 2022-06-01.
aliases: aws_profile
@@ -247,7 +246,7 @@ Parameters
|
|
- AWS STS security token. If not set then the value of the AWS_SECURITY_TOKEN or EC2_SECURITY_TOKEN environment variable is used.
+ AWS STS security token . If not set then the value of the AWS_SECURITY_TOKEN or EC2_SECURITY_TOKEN environment variable is used.
If profile is set this parameter is ignored.
Passing the security_token and profile options at the same time has been deprecated and the options will be made mutually exclusive after 2022-06-01.
aliases: aws_security_token, access_token
@@ -269,7 +268,7 @@ Parameters
|
- When set to "no", SSL certificates will not be validated for boto versions >= 2.6.0.
+ When set to "no", SSL certificates will not be validated for communication with the AWS APIs.
|
@@ -281,8 +280,9 @@ Notes
.. note::
- If parameters are not set within the module, the following environment variables can be used in decreasing order of precedence ``AWS_URL`` or ``EC2_URL``, ``AWS_PROFILE`` or ``AWS_DEFAULT_PROFILE``, ``AWS_ACCESS_KEY_ID`` or ``AWS_ACCESS_KEY`` or ``EC2_ACCESS_KEY``, ``AWS_SECRET_ACCESS_KEY`` or ``AWS_SECRET_KEY`` or ``EC2_SECRET_KEY``, ``AWS_SECURITY_TOKEN`` or ``EC2_SECURITY_TOKEN``, ``AWS_REGION`` or ``EC2_REGION``, ``AWS_CA_BUNDLE``
- - Ansible uses the boto configuration file (typically ~/.boto) if no credentials are provided. See https://boto.readthedocs.io/en/latest/boto_config_tut.html
- - ``AWS_REGION`` or ``EC2_REGION`` can be typically be used to specify the AWS region, when required, but this can also be configured in the boto config file
+ - When no credentials are explicitly provided the AWS SDK (boto3) that Ansible uses will fall back to its configuration files (typically ``~/.aws/credentials``). See https://boto3.amazonaws.com/v1/documentation/api/latest/guide/credentials.html for more information.
+ - Modules based on the original AWS SDK (boto) may read their default configuration from different files. See https://boto.readthedocs.io/en/latest/boto_config_tut.html for more information.
+ - ``AWS_REGION`` or ``EC2_REGION`` can be typically be used to specify the AWS region, when required, but this can also be defined in the configuration files.
diff --git a/docs/community.aws.lambda_module.rst b/docs/community.aws.lambda_module.rst
index 7368c05fed4..682891507e9 100644
--- a/docs/community.aws.lambda_module.rst
+++ b/docs/community.aws.lambda_module.rst
@@ -25,9 +25,9 @@ Requirements
------------
The below requirements are needed on the host that executes this module.
-- boto
-- boto3
-- python >= 2.6
+- python >= 3.6
+- boto3 >= 1.15.0
+- botocore >= 1.18.0
Parameters
@@ -53,7 +53,7 @@ Parameters
|
- AWS access key. If not set then the value of the AWS_ACCESS_KEY_ID, AWS_ACCESS_KEY or EC2_ACCESS_KEY environment variable is used.
+ AWS access key . If not set then the value of the AWS_ACCESS_KEY_ID , AWS_ACCESS_KEY or EC2_ACCESS_KEY environment variable is used.
If profile is set this parameter is ignored.
Passing the aws_access_key and profile options at the same time has been deprecated and the options will be made mutually exclusive after 2022-06-01.
aliases: ec2_access_key, access_key
@@ -72,7 +72,7 @@ Parameters
|
The location of a CA Bundle to use when validating SSL certificates.
- Only used for boto3 based modules.
+ Not used by boto 2 based modules.
Note: The CA Bundle is read 'module' side and may need to be explicitly copied from the controller if not run locally.
|
@@ -105,7 +105,7 @@ Parameters
|
- AWS secret key. If not set then the value of the AWS_SECRET_ACCESS_KEY, AWS_SECRET_KEY, or EC2_SECRET_KEY environment variable is used.
+ AWS secret key . If not set then the value of the AWS_SECRET_ACCESS_KEY , AWS_SECRET_KEY , or EC2_SECRET_KEY environment variable is used.
If profile is set this parameter is ignored.
Passing the aws_secret_key and profile options at the same time has been deprecated and the options will be made mutually exclusive after 2022-06-01.
aliases: ec2_secret_key, secret_key
@@ -172,7 +172,7 @@ Parameters
|
|
- Url to use to connect to EC2 or your Eucalyptus cloud (by default the module will use EC2 endpoints). Ignored for modules where region is required. Must be specified for all other modules if region is not used. If not set then the value of the EC2_URL environment variable, if any, is used.
+ URL to use to connect to EC2 or your Eucalyptus cloud (by default the module will use EC2 endpoints). Ignored for modules where region is required. Must be specified for all other modules if region is not used. If not set then the value of the EC2_URL environment variable, if any, is used.
aliases: aws_endpoint_url, endpoint_url
|
@@ -250,7 +250,6 @@ Parameters
|
- Uses a boto profile. Only works with boto >= 2.24.0.
Using profile will override aws_access_key, aws_secret_key and security_token and support for passing them at the same time as profile has been deprecated.
aws_access_key, aws_secret_key and security_token will be made mutually exclusive with profile after 2022-06-01.
aliases: aws_profile
@@ -366,7 +365,7 @@ Parameters
|
|
- AWS STS security token. If not set then the value of the AWS_SECURITY_TOKEN or EC2_SECURITY_TOKEN environment variable is used.
+ AWS STS security token . If not set then the value of the AWS_SECURITY_TOKEN or EC2_SECURITY_TOKEN environment variable is used.
If profile is set this parameter is ignored.
Passing the security_token and profile options at the same time has been deprecated and the options will be made mutually exclusive after 2022-06-01.
aliases: aws_security_token, access_token
@@ -403,7 +402,7 @@ Parameters
|
|
- tag dict to apply to the function (requires botocore 1.5.40 or above).
+ Tag dict to apply to the function.
|
@@ -457,7 +456,7 @@ Parameters
- When set to "no", SSL certificates will not be validated for boto versions >= 2.6.0.
+ When set to "no", SSL certificates will not be validated for communication with the AWS APIs.
|
@@ -521,8 +520,9 @@ Notes
.. note::
- If parameters are not set within the module, the following environment variables can be used in decreasing order of precedence ``AWS_URL`` or ``EC2_URL``, ``AWS_PROFILE`` or ``AWS_DEFAULT_PROFILE``, ``AWS_ACCESS_KEY_ID`` or ``AWS_ACCESS_KEY`` or ``EC2_ACCESS_KEY``, ``AWS_SECRET_ACCESS_KEY`` or ``AWS_SECRET_KEY`` or ``EC2_SECRET_KEY``, ``AWS_SECURITY_TOKEN`` or ``EC2_SECURITY_TOKEN``, ``AWS_REGION`` or ``EC2_REGION``, ``AWS_CA_BUNDLE``
- - Ansible uses the boto configuration file (typically ~/.boto) if no credentials are provided. See https://boto.readthedocs.io/en/latest/boto_config_tut.html
- - ``AWS_REGION`` or ``EC2_REGION`` can be typically be used to specify the AWS region, when required, but this can also be configured in the boto config file
+ - When no credentials are explicitly provided the AWS SDK (boto3) that Ansible uses will fall back to its configuration files (typically ``~/.aws/credentials``). See https://boto3.amazonaws.com/v1/documentation/api/latest/guide/credentials.html for more information.
+ - Modules based on the original AWS SDK (boto) may read their default configuration from different files. See https://boto.readthedocs.io/en/latest/boto_config_tut.html for more information.
+ - ``AWS_REGION`` or ``EC2_REGION`` can be typically be used to specify the AWS region, when required, but this can also be defined in the configuration files.
diff --git a/docs/community.aws.lambda_policy_module.rst b/docs/community.aws.lambda_policy_module.rst
index 6b9fdbf943b..ca1dd8a9309 100644
--- a/docs/community.aws.lambda_policy_module.rst
+++ b/docs/community.aws.lambda_policy_module.rst
@@ -27,9 +27,9 @@ Requirements
------------
The below requirements are needed on the host that executes this module.
-- boto
-- boto3
-- python >= 2.6
+- python >= 3.6
+- boto3 >= 1.15.0
+- botocore >= 1.18.0
Parameters
@@ -86,7 +86,7 @@ Parameters
|
- AWS access key. If not set then the value of the AWS_ACCESS_KEY_ID, AWS_ACCESS_KEY or EC2_ACCESS_KEY environment variable is used.
+ AWS access key . If not set then the value of the AWS_ACCESS_KEY_ID , AWS_ACCESS_KEY or EC2_ACCESS_KEY environment variable is used.
If profile is set this parameter is ignored.
Passing the aws_access_key and profile options at the same time has been deprecated and the options will be made mutually exclusive after 2022-06-01.
aliases: ec2_access_key, access_key
@@ -105,7 +105,7 @@ Parameters
|
The location of a CA Bundle to use when validating SSL certificates.
- Only used for boto3 based modules.
+ Not used by boto 2 based modules.
Note: The CA Bundle is read 'module' side and may need to be explicitly copied from the controller if not run locally.
|
@@ -138,7 +138,7 @@ Parameters
|
- AWS secret key. If not set then the value of the AWS_SECRET_ACCESS_KEY, AWS_SECRET_KEY, or EC2_SECRET_KEY environment variable is used.
+ AWS secret key . If not set then the value of the AWS_SECRET_ACCESS_KEY , AWS_SECRET_KEY , or EC2_SECRET_KEY environment variable is used.
If profile is set this parameter is ignored.
Passing the aws_secret_key and profile options at the same time has been deprecated and the options will be made mutually exclusive after 2022-06-01.
aliases: ec2_secret_key, secret_key
@@ -175,7 +175,7 @@ Parameters
|
|
- Url to use to connect to EC2 or your Eucalyptus cloud (by default the module will use EC2 endpoints). Ignored for modules where region is required. Must be specified for all other modules if region is not used. If not set then the value of the EC2_URL environment variable, if any, is used.
+ URL to use to connect to EC2 or your Eucalyptus cloud (by default the module will use EC2 endpoints). Ignored for modules where region is required. Must be specified for all other modules if region is not used. If not set then the value of the EC2_URL environment variable, if any, is used.
aliases: aws_endpoint_url, endpoint_url
|
@@ -243,7 +243,6 @@ Parameters
|
- Uses a boto profile. Only works with boto >= 2.24.0.
Using profile will override aws_access_key, aws_secret_key and security_token and support for passing them at the same time as profile has been deprecated.
aws_access_key, aws_secret_key and security_token will be made mutually exclusive with profile after 2022-06-01.
aliases: aws_profile
@@ -277,7 +276,7 @@ Parameters
|
|
- AWS STS security token. If not set then the value of the AWS_SECURITY_TOKEN or EC2_SECURITY_TOKEN environment variable is used.
+ AWS STS security token . If not set then the value of the AWS_SECURITY_TOKEN or EC2_SECURITY_TOKEN environment variable is used.
If profile is set this parameter is ignored.
Passing the security_token and profile options at the same time has been deprecated and the options will be made mutually exclusive after 2022-06-01.
aliases: aws_security_token, access_token
@@ -365,7 +364,7 @@ Parameters
|
- When set to "no", SSL certificates will not be validated for boto versions >= 2.6.0.
+ When set to "no", SSL certificates will not be validated for communication with the AWS APIs.
|
@@ -392,8 +391,9 @@ Notes
.. note::
- If parameters are not set within the module, the following environment variables can be used in decreasing order of precedence ``AWS_URL`` or ``EC2_URL``, ``AWS_PROFILE`` or ``AWS_DEFAULT_PROFILE``, ``AWS_ACCESS_KEY_ID`` or ``AWS_ACCESS_KEY`` or ``EC2_ACCESS_KEY``, ``AWS_SECRET_ACCESS_KEY`` or ``AWS_SECRET_KEY`` or ``EC2_SECRET_KEY``, ``AWS_SECURITY_TOKEN`` or ``EC2_SECURITY_TOKEN``, ``AWS_REGION`` or ``EC2_REGION``, ``AWS_CA_BUNDLE``
- - Ansible uses the boto configuration file (typically ~/.boto) if no credentials are provided. See https://boto.readthedocs.io/en/latest/boto_config_tut.html
- - ``AWS_REGION`` or ``EC2_REGION`` can be typically be used to specify the AWS region, when required, but this can also be configured in the boto config file
+ - When no credentials are explicitly provided the AWS SDK (boto3) that Ansible uses will fall back to its configuration files (typically ``~/.aws/credentials``). See https://boto3.amazonaws.com/v1/documentation/api/latest/guide/credentials.html for more information.
+ - Modules based on the original AWS SDK (boto) may read their default configuration from different files. See https://boto.readthedocs.io/en/latest/boto_config_tut.html for more information.
+ - ``AWS_REGION`` or ``EC2_REGION`` can be typically be used to specify the AWS region, when required, but this can also be defined in the configuration files.
diff --git a/docs/community.aws.lightsail_module.rst b/docs/community.aws.lightsail_module.rst
index 5ff6b603b43..441529b5378 100644
--- a/docs/community.aws.lightsail_module.rst
+++ b/docs/community.aws.lightsail_module.rst
@@ -26,9 +26,9 @@ Requirements
------------
The below requirements are needed on the host that executes this module.
-- boto
-- boto3
-- python >= 2.6
+- python >= 3.6
+- boto3 >= 1.15.0
+- botocore >= 1.18.0
Parameters
@@ -54,7 +54,7 @@ Parameters
|
- AWS access key. If not set then the value of the AWS_ACCESS_KEY_ID, AWS_ACCESS_KEY or EC2_ACCESS_KEY environment variable is used.
+ AWS access key . If not set then the value of the AWS_ACCESS_KEY_ID , AWS_ACCESS_KEY or EC2_ACCESS_KEY environment variable is used.
If profile is set this parameter is ignored.
Passing the aws_access_key and profile options at the same time has been deprecated and the options will be made mutually exclusive after 2022-06-01.
aliases: ec2_access_key, access_key
@@ -73,7 +73,7 @@ Parameters
|
The location of a CA Bundle to use when validating SSL certificates.
- Only used for boto3 based modules.
+ Not used by boto 2 based modules.
Note: The CA Bundle is read 'module' side and may need to be explicitly copied from the controller if not run locally.
|
@@ -106,7 +106,7 @@ Parameters
|
- AWS secret key. If not set then the value of the AWS_SECRET_ACCESS_KEY, AWS_SECRET_KEY, or EC2_SECRET_KEY environment variable is used.
+ AWS secret key . If not set then the value of the AWS_SECRET_ACCESS_KEY , AWS_SECRET_KEY , or EC2_SECRET_KEY environment variable is used.
If profile is set this parameter is ignored.
Passing the aws_secret_key and profile options at the same time has been deprecated and the options will be made mutually exclusive after 2022-06-01.
aliases: ec2_secret_key, secret_key
@@ -175,7 +175,7 @@ Parameters
|
|
- Url to use to connect to EC2 or your Eucalyptus cloud (by default the module will use EC2 endpoints). Ignored for modules where region is required. Must be specified for all other modules if region is not used. If not set then the value of the EC2_URL environment variable, if any, is used.
+ URL to use to connect to EC2 or your Eucalyptus cloud (by default the module will use EC2 endpoints). Ignored for modules where region is required. Must be specified for all other modules if region is not used. If not set then the value of the EC2_URL environment variable, if any, is used.
aliases: aws_endpoint_url, endpoint_url
|
@@ -223,7 +223,6 @@ Parameters
|
- Uses a boto profile. Only works with boto >= 2.24.0.
Using profile will override aws_access_key, aws_secret_key and security_token and support for passing them at the same time as profile has been deprecated.
aws_access_key, aws_secret_key and security_token will be made mutually exclusive with profile after 2022-06-01.
aliases: aws_profile
@@ -257,7 +256,7 @@ Parameters
|
|
- AWS STS security token. If not set then the value of the AWS_SECURITY_TOKEN or EC2_SECURITY_TOKEN environment variable is used.
+ AWS STS security token . If not set then the value of the AWS_SECURITY_TOKEN or EC2_SECURITY_TOKEN environment variable is used.
If profile is set this parameter is ignored.
Passing the security_token and profile options at the same time has been deprecated and the options will be made mutually exclusive after 2022-06-01.
aliases: aws_security_token, access_token
@@ -318,7 +317,7 @@ Parameters
|
- When set to "no", SSL certificates will not be validated for boto versions >= 2.6.0.
+ When set to "no", SSL certificates will not be validated for communication with the AWS APIs.
|
@@ -383,8 +382,9 @@ Notes
.. note::
- If parameters are not set within the module, the following environment variables can be used in decreasing order of precedence ``AWS_URL`` or ``EC2_URL``, ``AWS_PROFILE`` or ``AWS_DEFAULT_PROFILE``, ``AWS_ACCESS_KEY_ID`` or ``AWS_ACCESS_KEY`` or ``EC2_ACCESS_KEY``, ``AWS_SECRET_ACCESS_KEY`` or ``AWS_SECRET_KEY`` or ``EC2_SECRET_KEY``, ``AWS_SECURITY_TOKEN`` or ``EC2_SECURITY_TOKEN``, ``AWS_REGION`` or ``EC2_REGION``, ``AWS_CA_BUNDLE``
- - Ansible uses the boto configuration file (typically ~/.boto) if no credentials are provided. See https://boto.readthedocs.io/en/latest/boto_config_tut.html
- - ``AWS_REGION`` or ``EC2_REGION`` can be typically be used to specify the AWS region, when required, but this can also be configured in the boto config file
+ - When no credentials are explicitly provided the AWS SDK (boto3) that Ansible uses will fall back to its configuration files (typically ``~/.aws/credentials``). See https://boto3.amazonaws.com/v1/documentation/api/latest/guide/credentials.html for more information.
+ - Modules based on the original AWS SDK (boto) may read their default configuration from different files. See https://boto.readthedocs.io/en/latest/boto_config_tut.html for more information.
+ - ``AWS_REGION`` or ``EC2_REGION`` can be typically be used to specify the AWS region, when required, but this can also be defined in the configuration files.
diff --git a/docs/community.aws.rds_instance_info_module.rst b/docs/community.aws.rds_instance_info_module.rst
index 3e199320cb1..530ac744f26 100644
--- a/docs/community.aws.rds_instance_info_module.rst
+++ b/docs/community.aws.rds_instance_info_module.rst
@@ -26,10 +26,9 @@ Requirements
------------
The below requirements are needed on the host that executes this module.
-- boto
-- boto3
-- python >= 2.6
-- python >= 2.7
+- python >= 3.6
+- boto3 >= 1.15.0
+- botocore >= 1.18.0
Parameters
@@ -55,7 +54,7 @@ Parameters
|
- AWS access key. If not set then the value of the AWS_ACCESS_KEY_ID, AWS_ACCESS_KEY or EC2_ACCESS_KEY environment variable is used.
+ AWS access key . If not set then the value of the AWS_ACCESS_KEY_ID , AWS_ACCESS_KEY or EC2_ACCESS_KEY environment variable is used.
If profile is set this parameter is ignored.
Passing the aws_access_key and profile options at the same time has been deprecated and the options will be made mutually exclusive after 2022-06-01.
aliases: ec2_access_key, access_key
@@ -74,7 +73,7 @@ Parameters
|
The location of a CA Bundle to use when validating SSL certificates.
- Only used for boto3 based modules.
+ Not used by boto 2 based modules.
Note: The CA Bundle is read 'module' side and may need to be explicitly copied from the controller if not run locally.
|
@@ -107,7 +106,7 @@ Parameters
|
- AWS secret key. If not set then the value of the AWS_SECRET_ACCESS_KEY, AWS_SECRET_KEY, or EC2_SECRET_KEY environment variable is used.
+ AWS secret key . If not set then the value of the AWS_SECRET_ACCESS_KEY , AWS_SECRET_KEY , or EC2_SECRET_KEY environment variable is used.
If profile is set this parameter is ignored.
Passing the aws_secret_key and profile options at the same time has been deprecated and the options will be made mutually exclusive after 2022-06-01.
aliases: ec2_secret_key, secret_key
@@ -160,7 +159,7 @@ Parameters
|
|
- Url to use to connect to EC2 or your Eucalyptus cloud (by default the module will use EC2 endpoints). Ignored for modules where region is required. Must be specified for all other modules if region is not used. If not set then the value of the EC2_URL environment variable, if any, is used.
+ URL to use to connect to EC2 or your Eucalyptus cloud (by default the module will use EC2 endpoints). Ignored for modules where region is required. Must be specified for all other modules if region is not used. If not set then the value of the EC2_URL environment variable, if any, is used.
aliases: aws_endpoint_url, endpoint_url
|
@@ -191,7 +190,6 @@ Parameters
|
- Uses a boto profile. Only works with boto >= 2.24.0.
Using profile will override aws_access_key, aws_secret_key and security_token and support for passing them at the same time as profile has been deprecated.
aws_access_key, aws_secret_key and security_token will be made mutually exclusive with profile after 2022-06-01.
aliases: aws_profile
@@ -225,7 +223,7 @@ Parameters
|
|
- AWS STS security token. If not set then the value of the AWS_SECURITY_TOKEN or EC2_SECURITY_TOKEN environment variable is used.
+ AWS STS security token . If not set then the value of the AWS_SECURITY_TOKEN or EC2_SECURITY_TOKEN environment variable is used.
If profile is set this parameter is ignored.
Passing the security_token and profile options at the same time has been deprecated and the options will be made mutually exclusive after 2022-06-01.
aliases: aws_security_token, access_token
@@ -247,7 +245,7 @@ Parameters
|
- When set to "no", SSL certificates will not be validated for boto versions >= 2.6.0.
+ When set to "no", SSL certificates will not be validated for communication with the AWS APIs.
|
@@ -259,8 +257,9 @@ Notes
.. note::
- If parameters are not set within the module, the following environment variables can be used in decreasing order of precedence ``AWS_URL`` or ``EC2_URL``, ``AWS_PROFILE`` or ``AWS_DEFAULT_PROFILE``, ``AWS_ACCESS_KEY_ID`` or ``AWS_ACCESS_KEY`` or ``EC2_ACCESS_KEY``, ``AWS_SECRET_ACCESS_KEY`` or ``AWS_SECRET_KEY`` or ``EC2_SECRET_KEY``, ``AWS_SECURITY_TOKEN`` or ``EC2_SECURITY_TOKEN``, ``AWS_REGION`` or ``EC2_REGION``, ``AWS_CA_BUNDLE``
- - Ansible uses the boto configuration file (typically ~/.boto) if no credentials are provided. See https://boto.readthedocs.io/en/latest/boto_config_tut.html
- - ``AWS_REGION`` or ``EC2_REGION`` can be typically be used to specify the AWS region, when required, but this can also be configured in the boto config file
+ - When no credentials are explicitly provided the AWS SDK (boto3) that Ansible uses will fall back to its configuration files (typically ``~/.aws/credentials``). See https://boto3.amazonaws.com/v1/documentation/api/latest/guide/credentials.html for more information.
+ - Modules based on the original AWS SDK (boto) may read their default configuration from different files. See https://boto.readthedocs.io/en/latest/boto_config_tut.html for more information.
+ - ``AWS_REGION`` or ``EC2_REGION`` can be typically be used to specify the AWS region, when required, but this can also be defined in the configuration files.
diff --git a/docs/community.aws.rds_instance_module.rst b/docs/community.aws.rds_instance_module.rst
index e679974045b..2bb3a389893 100644
--- a/docs/community.aws.rds_instance_module.rst
+++ b/docs/community.aws.rds_instance_module.rst
@@ -25,10 +25,9 @@ Requirements
------------
The below requirements are needed on the host that executes this module.
-- boto
-- boto3 >= 1.5.0
-- botocore
-- python >= 2.6
+- python >= 3.6
+- boto3 >= 1.15.0
+- botocore >= 1.18.0
Parameters
@@ -142,7 +141,7 @@ Parameters
|
- AWS access key. If not set then the value of the AWS_ACCESS_KEY_ID, AWS_ACCESS_KEY or EC2_ACCESS_KEY environment variable is used.
+ AWS access key . If not set then the value of the AWS_ACCESS_KEY_ID , AWS_ACCESS_KEY or EC2_ACCESS_KEY environment variable is used.
If profile is set this parameter is ignored.
Passing the aws_access_key and profile options at the same time has been deprecated and the options will be made mutually exclusive after 2022-06-01.
aliases: ec2_access_key, access_key
@@ -161,7 +160,7 @@ Parameters
|
The location of a CA Bundle to use when validating SSL certificates.
- Only used for boto3 based modules.
+ Not used by boto 2 based modules.
Note: The CA Bundle is read 'module' side and may need to be explicitly copied from the controller if not run locally.
|
@@ -194,7 +193,7 @@ Parameters
|
- AWS secret key. If not set then the value of the AWS_SECRET_ACCESS_KEY, AWS_SECRET_KEY, or EC2_SECRET_KEY environment variable is used.
+ AWS secret key . If not set then the value of the AWS_SECRET_ACCESS_KEY , AWS_SECRET_KEY , or EC2_SECRET_KEY environment variable is used.
If profile is set this parameter is ignored.
Passing the aws_secret_key and profile options at the same time has been deprecated and the options will be made mutually exclusive after 2022-06-01.
aliases: ec2_secret_key, secret_key
@@ -473,7 +472,7 @@ Parameters
|
|
- Url to use to connect to EC2 or your Eucalyptus cloud (by default the module will use EC2 endpoints). Ignored for modules where region is required. Must be specified for all other modules if region is not used. If not set then the value of the EC2_URL environment variable, if any, is used.
+ URL to use to connect to EC2 or your Eucalyptus cloud (by default the module will use EC2 endpoints). Ignored for modules where region is required. Must be specified for all other modules if region is not used. If not set then the value of the EC2_URL environment variable, if any, is used.
aliases: aws_endpoint_url, endpoint_url
|
@@ -928,7 +927,6 @@ Parameters
|
- Uses a boto profile. Only works with boto >= 2.24.0.
Using profile will override aws_access_key, aws_secret_key and security_token and support for passing them at the same time as profile has been deprecated.
aws_access_key, aws_secret_key and security_token will be made mutually exclusive with profile after 2022-06-01.
aliases: aws_profile
@@ -1136,7 +1134,7 @@ Parameters
|
|
- AWS STS security token. If not set then the value of the AWS_SECURITY_TOKEN or EC2_SECURITY_TOKEN environment variable is used.
+ AWS STS security token . If not set then the value of the AWS_SECURITY_TOKEN or EC2_SECURITY_TOKEN environment variable is used.
If profile is set this parameter is ignored.
Passing the security_token and profile options at the same time has been deprecated and the options will be made mutually exclusive after 2022-06-01.
aliases: aws_security_token, access_token
@@ -1403,7 +1401,7 @@ Parameters
|
- When set to "no", SSL certificates will not be validated for boto versions >= 2.6.0.
+ When set to "no", SSL certificates will not be validated for communication with the AWS APIs.
|
@@ -1450,8 +1448,9 @@ Notes
.. note::
- If parameters are not set within the module, the following environment variables can be used in decreasing order of precedence ``AWS_URL`` or ``EC2_URL``, ``AWS_PROFILE`` or ``AWS_DEFAULT_PROFILE``, ``AWS_ACCESS_KEY_ID`` or ``AWS_ACCESS_KEY`` or ``EC2_ACCESS_KEY``, ``AWS_SECRET_ACCESS_KEY`` or ``AWS_SECRET_KEY`` or ``EC2_SECRET_KEY``, ``AWS_SECURITY_TOKEN`` or ``EC2_SECURITY_TOKEN``, ``AWS_REGION`` or ``EC2_REGION``, ``AWS_CA_BUNDLE``
- - Ansible uses the boto configuration file (typically ~/.boto) if no credentials are provided. See https://boto.readthedocs.io/en/latest/boto_config_tut.html
- - ``AWS_REGION`` or ``EC2_REGION`` can be typically be used to specify the AWS region, when required, but this can also be configured in the boto config file
+ - When no credentials are explicitly provided the AWS SDK (boto3) that Ansible uses will fall back to its configuration files (typically ``~/.aws/credentials``). See https://boto3.amazonaws.com/v1/documentation/api/latest/guide/credentials.html for more information.
+ - Modules based on the original AWS SDK (boto) may read their default configuration from different files. See https://boto.readthedocs.io/en/latest/boto_config_tut.html for more information.
+ - ``AWS_REGION`` or ``EC2_REGION`` can be typically be used to specify the AWS region, when required, but this can also be defined in the configuration files.
diff --git a/docs/community.aws.rds_module.rst b/docs/community.aws.rds_module.rst
index c3391656668..76da476f977 100644
--- a/docs/community.aws.rds_module.rst
+++ b/docs/community.aws.rds_module.rst
@@ -14,14 +14,20 @@ Version added: 1.0.0
:local:
:depth: 1
+DEPRECATED
+----------
+:Removed in collection release after
+:Why: The rds module is based upon a deprecated version of the AWS SDK.
+:Alternative: Use :ref:`rds_instance `, :ref:`rds_instance_info `, and :ref:`rds_snapshot `.
+
+
Synopsis
--------
- Creates, deletes, or modifies rds resources.
- When creating an instance it can be either a new instance or a read-only replica of an existing instance.
-- This module has a dependency on python-boto >= 2.5 and will soon be deprecated.
- The 'promote' command requires boto >= 2.18.0. Certain features such as tags rely on boto.rds2 (boto >= 2.26.0).
-- Please use boto3 based :ref:`community.aws.rds_instance ` instead.
+- Please use the boto3 based :ref:`community.aws.rds_instance ` instead.
@@ -29,8 +35,10 @@ Requirements
------------
The below requirements are needed on the host that executes this module.
-- boto
-- python >= 2.6
+- boto >= 2.49.0
+- boto3 >= 1.15.0
+- botocore >= 1.18.0
+- python >= 3.6
Parameters
@@ -76,7 +84,7 @@ Parameters
|
- AWS access key. If not set then the value of the AWS_ACCESS_KEY_ID, AWS_ACCESS_KEY or EC2_ACCESS_KEY environment variable is used.
+ AWS access key . If not set then the value of the AWS_ACCESS_KEY_ID , AWS_ACCESS_KEY or EC2_ACCESS_KEY environment variable is used.
If profile is set this parameter is ignored.
Passing the aws_access_key and profile options at the same time has been deprecated and the options will be made mutually exclusive after 2022-06-01.
aliases: ec2_access_key, access_key
@@ -95,7 +103,7 @@ Parameters
|
The location of a CA Bundle to use when validating SSL certificates.
- Only used for boto3 based modules.
+ Not used by boto 2 based modules.
Note: The CA Bundle is read 'module' side and may need to be explicitly copied from the controller if not run locally.
|
@@ -128,7 +136,7 @@ Parameters
|
- AWS secret key. If not set then the value of the AWS_SECRET_ACCESS_KEY, AWS_SECRET_KEY, or EC2_SECRET_KEY environment variable is used.
+ AWS secret key . If not set then the value of the AWS_SECRET_ACCESS_KEY , AWS_SECRET_KEY , or EC2_SECRET_KEY environment variable is used.
If profile is set this parameter is ignored.
Passing the aws_secret_key and profile options at the same time has been deprecated and the options will be made mutually exclusive after 2022-06-01.
aliases: ec2_secret_key, secret_key
@@ -293,7 +301,7 @@ Parameters
|
|
- Url to use to connect to EC2 or your Eucalyptus cloud (by default the module will use EC2 endpoints). Ignored for modules where region is required. Must be specified for all other modules if region is not used. If not set then the value of the EC2_URL environment variable, if any, is used.
+ URL to use to connect to EC2 or your Eucalyptus cloud (by default the module will use EC2 endpoints). Ignored for modules where region is required. Must be specified for all other modules if region is not used. If not set then the value of the EC2_URL environment variable, if any, is used.
aliases: aws_endpoint_url, endpoint_url
|
@@ -542,7 +550,6 @@ Parameters
|
- Uses a boto profile. Only works with boto >= 2.24.0.
Using profile will override aws_access_key, aws_secret_key and security_token and support for passing them at the same time as profile has been deprecated.
aws_access_key, aws_secret_key and security_token will be made mutually exclusive with profile after 2022-06-01.
aliases: aws_profile
@@ -609,7 +616,7 @@ Parameters
|
|
- AWS STS security token. If not set then the value of the AWS_SECURITY_TOKEN or EC2_SECURITY_TOKEN environment variable is used.
+ AWS STS security token . If not set then the value of the AWS_SECURITY_TOKEN or EC2_SECURITY_TOKEN environment variable is used.
If profile is set this parameter is ignored.
Passing the security_token and profile options at the same time has been deprecated and the options will be made mutually exclusive after 2022-06-01.
aliases: aws_security_token, access_token
@@ -751,7 +758,7 @@ Parameters
|
- When set to "no", SSL certificates will not be validated for boto versions >= 2.6.0.
+ When set to "no", SSL certificates will not be validated for communication with the AWS APIs.
|
@@ -836,8 +843,9 @@ Notes
.. note::
- If parameters are not set within the module, the following environment variables can be used in decreasing order of precedence ``AWS_URL`` or ``EC2_URL``, ``AWS_PROFILE`` or ``AWS_DEFAULT_PROFILE``, ``AWS_ACCESS_KEY_ID`` or ``AWS_ACCESS_KEY`` or ``EC2_ACCESS_KEY``, ``AWS_SECRET_ACCESS_KEY`` or ``AWS_SECRET_KEY`` or ``EC2_SECRET_KEY``, ``AWS_SECURITY_TOKEN`` or ``EC2_SECURITY_TOKEN``, ``AWS_REGION`` or ``EC2_REGION``, ``AWS_CA_BUNDLE``
- - Ansible uses the boto configuration file (typically ~/.boto) if no credentials are provided. See https://boto.readthedocs.io/en/latest/boto_config_tut.html
- - ``AWS_REGION`` or ``EC2_REGION`` can be typically be used to specify the AWS region, when required, but this can also be configured in the boto config file
+ - When no credentials are explicitly provided the AWS SDK (boto3) that Ansible uses will fall back to its configuration files (typically ``~/.aws/credentials``). See https://boto3.amazonaws.com/v1/documentation/api/latest/guide/credentials.html for more information.
+ - Modules based on the original AWS SDK (boto) may read their default configuration from different files. See https://boto.readthedocs.io/en/latest/boto_config_tut.html for more information.
+ - ``AWS_REGION`` or ``EC2_REGION`` can be typically be used to specify the AWS region, when required, but this can also be defined in the configuration files.
@@ -1699,6 +1707,10 @@ Status
------
+- This module will be removed in version 3.0.0. *[deprecated]*
+- For more information see `DEPRECATED`_.
+
+
Authors
~~~~~~~
diff --git a/docs/community.aws.rds_param_group_module.rst b/docs/community.aws.rds_param_group_module.rst
index 9905c5a88d8..9715206d56c 100644
--- a/docs/community.aws.rds_param_group_module.rst
+++ b/docs/community.aws.rds_param_group_module.rst
@@ -25,9 +25,9 @@ Requirements
------------
The below requirements are needed on the host that executes this module.
-- boto
-- boto3
-- python >= 2.6
+- python >= 3.6
+- boto3 >= 1.15.0
+- botocore >= 1.18.0
Parameters
@@ -53,7 +53,7 @@ Parameters
|
- AWS access key. If not set then the value of the AWS_ACCESS_KEY_ID, AWS_ACCESS_KEY or EC2_ACCESS_KEY environment variable is used.
+ AWS access key . If not set then the value of the AWS_ACCESS_KEY_ID , AWS_ACCESS_KEY or EC2_ACCESS_KEY environment variable is used.
If profile is set this parameter is ignored.
Passing the aws_access_key and profile options at the same time has been deprecated and the options will be made mutually exclusive after 2022-06-01.
aliases: ec2_access_key, access_key
@@ -72,7 +72,7 @@ Parameters
|
The location of a CA Bundle to use when validating SSL certificates.
- Only used for boto3 based modules.
+ Not used by boto 2 based modules.
Note: The CA Bundle is read 'module' side and may need to be explicitly copied from the controller if not run locally.
|
@@ -105,7 +105,7 @@ Parameters
|
- AWS secret key. If not set then the value of the AWS_SECRET_ACCESS_KEY, AWS_SECRET_KEY, or EC2_SECRET_KEY environment variable is used.
+ AWS secret key . If not set then the value of the AWS_SECRET_ACCESS_KEY , AWS_SECRET_KEY , or EC2_SECRET_KEY environment variable is used.
If profile is set this parameter is ignored.
Passing the aws_secret_key and profile options at the same time has been deprecated and the options will be made mutually exclusive after 2022-06-01.
aliases: ec2_secret_key, secret_key
@@ -157,7 +157,7 @@ Parameters
|
|
- Url to use to connect to EC2 or your Eucalyptus cloud (by default the module will use EC2 endpoints). Ignored for modules where region is required. Must be specified for all other modules if region is not used. If not set then the value of the EC2_URL environment variable, if any, is used.
+ URL to use to connect to EC2 or your Eucalyptus cloud (by default the module will use EC2 endpoints). Ignored for modules where region is required. Must be specified for all other modules if region is not used. If not set then the value of the EC2_URL environment variable, if any, is used.
aliases: aws_endpoint_url, endpoint_url
|
@@ -243,7 +243,6 @@ Parameters
|
- Uses a boto profile. Only works with boto >= 2.24.0.
Using profile will override aws_access_key, aws_secret_key and security_token and support for passing them at the same time as profile has been deprecated.
aws_access_key, aws_secret_key and security_token will be made mutually exclusive with profile after 2022-06-01.
aliases: aws_profile
@@ -296,7 +295,7 @@ Parameters
|
|
- AWS STS security token. If not set then the value of the AWS_SECURITY_TOKEN or EC2_SECURITY_TOKEN environment variable is used.
+ AWS STS security token . If not set then the value of the AWS_SECURITY_TOKEN or EC2_SECURITY_TOKEN environment variable is used.
If profile is set this parameter is ignored.
Passing the security_token and profile options at the same time has been deprecated and the options will be made mutually exclusive after 2022-06-01.
aliases: aws_security_token, access_token
@@ -353,7 +352,7 @@ Parameters
|
- When set to "no", SSL certificates will not be validated for boto versions >= 2.6.0.
+ When set to "no", SSL certificates will not be validated for communication with the AWS APIs.
|
@@ -365,8 +364,9 @@ Notes
.. note::
- If parameters are not set within the module, the following environment variables can be used in decreasing order of precedence ``AWS_URL`` or ``EC2_URL``, ``AWS_PROFILE`` or ``AWS_DEFAULT_PROFILE``, ``AWS_ACCESS_KEY_ID`` or ``AWS_ACCESS_KEY`` or ``EC2_ACCESS_KEY``, ``AWS_SECRET_ACCESS_KEY`` or ``AWS_SECRET_KEY`` or ``EC2_SECRET_KEY``, ``AWS_SECURITY_TOKEN`` or ``EC2_SECURITY_TOKEN``, ``AWS_REGION`` or ``EC2_REGION``, ``AWS_CA_BUNDLE``
- - Ansible uses the boto configuration file (typically ~/.boto) if no credentials are provided. See https://boto.readthedocs.io/en/latest/boto_config_tut.html
- - ``AWS_REGION`` or ``EC2_REGION`` can be typically be used to specify the AWS region, when required, but this can also be configured in the boto config file
+ - When no credentials are explicitly provided the AWS SDK (boto3) that Ansible uses will fall back to its configuration files (typically ``~/.aws/credentials``). See https://boto3.amazonaws.com/v1/documentation/api/latest/guide/credentials.html for more information.
+ - Modules based on the original AWS SDK (boto) may read their default configuration from different files. See https://boto.readthedocs.io/en/latest/boto_config_tut.html for more information.
+ - ``AWS_REGION`` or ``EC2_REGION`` can be typically be used to specify the AWS region, when required, but this can also be defined in the configuration files.
diff --git a/docs/community.aws.rds_snapshot_info_module.rst b/docs/community.aws.rds_snapshot_info_module.rst
index 8835ebf4347..7e5c169f9fe 100644
--- a/docs/community.aws.rds_snapshot_info_module.rst
+++ b/docs/community.aws.rds_snapshot_info_module.rst
@@ -27,9 +27,9 @@ Requirements
------------
The below requirements are needed on the host that executes this module.
-- boto
-- boto3
-- python >= 2.6
+- python >= 3.6
+- boto3 >= 1.15.0
+- botocore >= 1.18.0
Parameters
@@ -55,7 +55,7 @@ Parameters
|
- AWS access key. If not set then the value of the AWS_ACCESS_KEY_ID, AWS_ACCESS_KEY or EC2_ACCESS_KEY environment variable is used.
+ AWS access key . If not set then the value of the AWS_ACCESS_KEY_ID , AWS_ACCESS_KEY or EC2_ACCESS_KEY environment variable is used.
If profile is set this parameter is ignored.
Passing the aws_access_key and profile options at the same time has been deprecated and the options will be made mutually exclusive after 2022-06-01.
aliases: ec2_access_key, access_key
@@ -74,7 +74,7 @@ Parameters
|
The location of a CA Bundle to use when validating SSL certificates.
- Only used for boto3 based modules.
+ Not used by boto 2 based modules.
Note: The CA Bundle is read 'module' side and may need to be explicitly copied from the controller if not run locally.
|
@@ -107,7 +107,7 @@ Parameters
|
- AWS secret key. If not set then the value of the AWS_SECRET_ACCESS_KEY, AWS_SECRET_KEY, or EC2_SECRET_KEY environment variable is used.
+ AWS secret key . If not set then the value of the AWS_SECRET_ACCESS_KEY , AWS_SECRET_KEY , or EC2_SECRET_KEY environment variable is used.
If profile is set this parameter is ignored.
Passing the aws_secret_key and profile options at the same time has been deprecated and the options will be made mutually exclusive after 2022-06-01.
aliases: ec2_secret_key, secret_key
@@ -209,7 +209,7 @@ Parameters
|
|
- Url to use to connect to EC2 or your Eucalyptus cloud (by default the module will use EC2 endpoints). Ignored for modules where region is required. Must be specified for all other modules if region is not used. If not set then the value of the EC2_URL environment variable, if any, is used.
+ URL to use to connect to EC2 or your Eucalyptus cloud (by default the module will use EC2 endpoints). Ignored for modules where region is required. Must be specified for all other modules if region is not used. If not set then the value of the EC2_URL environment variable, if any, is used.
aliases: aws_endpoint_url, endpoint_url
|
@@ -225,7 +225,6 @@ Parameters
|
- Uses a boto profile. Only works with boto >= 2.24.0.
Using profile will override aws_access_key, aws_secret_key and security_token and support for passing them at the same time as profile has been deprecated.
aws_access_key, aws_secret_key and security_token will be made mutually exclusive with profile after 2022-06-01.
aliases: aws_profile
@@ -259,7 +258,7 @@ Parameters
|
|
- AWS STS security token. If not set then the value of the AWS_SECURITY_TOKEN or EC2_SECURITY_TOKEN environment variable is used.
+ AWS STS security token . If not set then the value of the AWS_SECURITY_TOKEN or EC2_SECURITY_TOKEN environment variable is used.
If profile is set this parameter is ignored.
Passing the security_token and profile options at the same time has been deprecated and the options will be made mutually exclusive after 2022-06-01.
aliases: aws_security_token, access_token
@@ -303,7 +302,7 @@ Parameters
|
- When set to "no", SSL certificates will not be validated for boto versions >= 2.6.0.
+ When set to "no", SSL certificates will not be validated for communication with the AWS APIs.
|
@@ -315,8 +314,9 @@ Notes
.. note::
- If parameters are not set within the module, the following environment variables can be used in decreasing order of precedence ``AWS_URL`` or ``EC2_URL``, ``AWS_PROFILE`` or ``AWS_DEFAULT_PROFILE``, ``AWS_ACCESS_KEY_ID`` or ``AWS_ACCESS_KEY`` or ``EC2_ACCESS_KEY``, ``AWS_SECRET_ACCESS_KEY`` or ``AWS_SECRET_KEY`` or ``EC2_SECRET_KEY``, ``AWS_SECURITY_TOKEN`` or ``EC2_SECURITY_TOKEN``, ``AWS_REGION`` or ``EC2_REGION``, ``AWS_CA_BUNDLE``
- - Ansible uses the boto configuration file (typically ~/.boto) if no credentials are provided. See https://boto.readthedocs.io/en/latest/boto_config_tut.html
- - ``AWS_REGION`` or ``EC2_REGION`` can be typically be used to specify the AWS region, when required, but this can also be configured in the boto config file
+ - When no credentials are explicitly provided the AWS SDK (boto3) that Ansible uses will fall back to its configuration files (typically ``~/.aws/credentials``). See https://boto3.amazonaws.com/v1/documentation/api/latest/guide/credentials.html for more information.
+ - Modules based on the original AWS SDK (boto) may read their default configuration from different files. See https://boto.readthedocs.io/en/latest/boto_config_tut.html for more information.
+ - ``AWS_REGION`` or ``EC2_REGION`` can be typically be used to specify the AWS region, when required, but this can also be defined in the configuration files.
diff --git a/docs/community.aws.rds_snapshot_module.rst b/docs/community.aws.rds_snapshot_module.rst
index 95ec276a159..657b56b7165 100644
--- a/docs/community.aws.rds_snapshot_module.rst
+++ b/docs/community.aws.rds_snapshot_module.rst
@@ -25,9 +25,9 @@ Requirements
------------
The below requirements are needed on the host that executes this module.
-- boto
-- boto3
-- python >= 2.6
+- python >= 3.6
+- boto3 >= 1.15.0
+- botocore >= 1.18.0
Parameters
@@ -53,7 +53,7 @@ Parameters
|
- AWS access key. If not set then the value of the AWS_ACCESS_KEY_ID, AWS_ACCESS_KEY or EC2_ACCESS_KEY environment variable is used.
+ AWS access key . If not set then the value of the AWS_ACCESS_KEY_ID , AWS_ACCESS_KEY or EC2_ACCESS_KEY environment variable is used.
If profile is set this parameter is ignored.
Passing the aws_access_key and profile options at the same time has been deprecated and the options will be made mutually exclusive after 2022-06-01.
aliases: ec2_access_key, access_key
@@ -72,7 +72,7 @@ Parameters
|
The location of a CA Bundle to use when validating SSL certificates.
- Only used for boto3 based modules.
+ Not used by boto 2 based modules.
Note: The CA Bundle is read 'module' side and may need to be explicitly copied from the controller if not run locally.
|
@@ -105,7 +105,7 @@ Parameters
|
- AWS secret key. If not set then the value of the AWS_SECRET_ACCESS_KEY, AWS_SECRET_KEY, or EC2_SECRET_KEY environment variable is used.
+ AWS secret key . If not set then the value of the AWS_SECRET_ACCESS_KEY , AWS_SECRET_KEY , or EC2_SECRET_KEY environment variable is used.
If profile is set this parameter is ignored.
Passing the aws_secret_key and profile options at the same time has been deprecated and the options will be made mutually exclusive after 2022-06-01.
aliases: ec2_secret_key, secret_key
@@ -175,7 +175,7 @@ Parameters
|
|
- Url to use to connect to EC2 or your Eucalyptus cloud (by default the module will use EC2 endpoints). Ignored for modules where region is required. Must be specified for all other modules if region is not used. If not set then the value of the EC2_URL environment variable, if any, is used.
+ URL to use to connect to EC2 or your Eucalyptus cloud (by default the module will use EC2 endpoints). Ignored for modules where region is required. Must be specified for all other modules if region is not used. If not set then the value of the EC2_URL environment variable, if any, is used.
aliases: aws_endpoint_url, endpoint_url
|
@@ -191,7 +191,6 @@ Parameters
|
- Uses a boto profile. Only works with boto >= 2.24.0.
Using profile will override aws_access_key, aws_secret_key and security_token and support for passing them at the same time as profile has been deprecated.
aws_access_key, aws_secret_key and security_token will be made mutually exclusive with profile after 2022-06-01.
aliases: aws_profile
@@ -244,7 +243,7 @@ Parameters
|
|
- AWS STS security token. If not set then the value of the AWS_SECURITY_TOKEN or EC2_SECURITY_TOKEN environment variable is used.
+ AWS STS security token . If not set then the value of the AWS_SECURITY_TOKEN or EC2_SECURITY_TOKEN environment variable is used.
If profile is set this parameter is ignored.
Passing the security_token and profile options at the same time has been deprecated and the options will be made mutually exclusive after 2022-06-01.
aliases: aws_security_token, access_token
@@ -300,7 +299,7 @@ Parameters
|
- When set to "no", SSL certificates will not be validated for boto versions >= 2.6.0.
+ When set to "no", SSL certificates will not be validated for communication with the AWS APIs.
|
@@ -347,8 +346,9 @@ Notes
.. note::
- If parameters are not set within the module, the following environment variables can be used in decreasing order of precedence ``AWS_URL`` or ``EC2_URL``, ``AWS_PROFILE`` or ``AWS_DEFAULT_PROFILE``, ``AWS_ACCESS_KEY_ID`` or ``AWS_ACCESS_KEY`` or ``EC2_ACCESS_KEY``, ``AWS_SECRET_ACCESS_KEY`` or ``AWS_SECRET_KEY`` or ``EC2_SECRET_KEY``, ``AWS_SECURITY_TOKEN`` or ``EC2_SECURITY_TOKEN``, ``AWS_REGION`` or ``EC2_REGION``, ``AWS_CA_BUNDLE``
- - Ansible uses the boto configuration file (typically ~/.boto) if no credentials are provided. See https://boto.readthedocs.io/en/latest/boto_config_tut.html
- - ``AWS_REGION`` or ``EC2_REGION`` can be typically be used to specify the AWS region, when required, but this can also be configured in the boto config file
+ - When no credentials are explicitly provided the AWS SDK (boto3) that Ansible uses will fall back to its configuration files (typically ``~/.aws/credentials``). See https://boto3.amazonaws.com/v1/documentation/api/latest/guide/credentials.html for more information.
+ - Modules based on the original AWS SDK (boto) may read their default configuration from different files. See https://boto.readthedocs.io/en/latest/boto_config_tut.html for more information.
+ - ``AWS_REGION`` or ``EC2_REGION`` can be typically be used to specify the AWS region, when required, but this can also be defined in the configuration files.
diff --git a/docs/community.aws.rds_subnet_group_module.rst b/docs/community.aws.rds_subnet_group_module.rst
index 3b624ccdb09..2618eb29a14 100644
--- a/docs/community.aws.rds_subnet_group_module.rst
+++ b/docs/community.aws.rds_subnet_group_module.rst
@@ -25,8 +25,9 @@ Requirements
------------
The below requirements are needed on the host that executes this module.
-- python >= 2.6
-- boto
+- python >= 3.6
+- boto3 >= 1.15.0
+- botocore >= 1.18.0
Parameters
@@ -52,7 +53,7 @@ Parameters
|
- AWS access key. If not set then the value of the AWS_ACCESS_KEY_ID, AWS_ACCESS_KEY or EC2_ACCESS_KEY environment variable is used.
+ AWS access key . If not set then the value of the AWS_ACCESS_KEY_ID , AWS_ACCESS_KEY or EC2_ACCESS_KEY environment variable is used.
If profile is set this parameter is ignored.
Passing the aws_access_key and profile options at the same time has been deprecated and the options will be made mutually exclusive after 2022-06-01.
aliases: ec2_access_key, access_key
@@ -71,7 +72,7 @@ Parameters
|
The location of a CA Bundle to use when validating SSL certificates.
- Only used for boto3 based modules.
+ Not used by boto 2 based modules.
Note: The CA Bundle is read 'module' side and may need to be explicitly copied from the controller if not run locally.
|
@@ -104,7 +105,7 @@ Parameters
|
- AWS secret key. If not set then the value of the AWS_SECRET_ACCESS_KEY, AWS_SECRET_KEY, or EC2_SECRET_KEY environment variable is used.
+ AWS secret key . If not set then the value of the AWS_SECRET_ACCESS_KEY , AWS_SECRET_KEY , or EC2_SECRET_KEY environment variable is used.
If profile is set this parameter is ignored.
Passing the aws_secret_key and profile options at the same time has been deprecated and the options will be made mutually exclusive after 2022-06-01.
aliases: ec2_secret_key, secret_key
@@ -157,7 +158,7 @@ Parameters
|
|
- Url to use to connect to EC2 or your Eucalyptus cloud (by default the module will use EC2 endpoints). Ignored for modules where region is required. Must be specified for all other modules if region is not used. If not set then the value of the EC2_URL environment variable, if any, is used.
+ URL to use to connect to EC2 or your Eucalyptus cloud (by default the module will use EC2 endpoints). Ignored for modules where region is required. Must be specified for all other modules if region is not used. If not set then the value of the EC2_URL environment variable, if any, is used.
aliases: aws_endpoint_url, endpoint_url
|
@@ -189,7 +190,6 @@ Parameters
|
- Uses a boto profile. Only works with boto >= 2.24.0.
Using profile will override aws_access_key, aws_secret_key and security_token and support for passing them at the same time as profile has been deprecated.
aws_access_key, aws_secret_key and security_token will be made mutually exclusive with profile after 2022-06-01.
aliases: aws_profile
@@ -223,7 +223,7 @@ Parameters
|
|
- AWS STS security token. If not set then the value of the AWS_SECURITY_TOKEN or EC2_SECURITY_TOKEN environment variable is used.
+ AWS STS security token . If not set then the value of the AWS_SECURITY_TOKEN or EC2_SECURITY_TOKEN environment variable is used.
If profile is set this parameter is ignored.
Passing the security_token and profile options at the same time has been deprecated and the options will be made mutually exclusive after 2022-06-01.
aliases: aws_security_token, access_token
@@ -282,7 +282,7 @@ Parameters
|
- When set to "no", SSL certificates will not be validated for boto versions >= 2.6.0.
+ When set to "no", SSL certificates will not be validated for communication with the AWS APIs.
|
@@ -294,8 +294,9 @@ Notes
.. note::
- If parameters are not set within the module, the following environment variables can be used in decreasing order of precedence ``AWS_URL`` or ``EC2_URL``, ``AWS_PROFILE`` or ``AWS_DEFAULT_PROFILE``, ``AWS_ACCESS_KEY_ID`` or ``AWS_ACCESS_KEY`` or ``EC2_ACCESS_KEY``, ``AWS_SECRET_ACCESS_KEY`` or ``AWS_SECRET_KEY`` or ``EC2_SECRET_KEY``, ``AWS_SECURITY_TOKEN`` or ``EC2_SECURITY_TOKEN``, ``AWS_REGION`` or ``EC2_REGION``, ``AWS_CA_BUNDLE``
- - Ansible uses the boto configuration file (typically ~/.boto) if no credentials are provided. See https://boto.readthedocs.io/en/latest/boto_config_tut.html
- - ``AWS_REGION`` or ``EC2_REGION`` can be typically be used to specify the AWS region, when required, but this can also be configured in the boto config file
+ - When no credentials are explicitly provided the AWS SDK (boto3) that Ansible uses will fall back to its configuration files (typically ``~/.aws/credentials``). See https://boto3.amazonaws.com/v1/documentation/api/latest/guide/credentials.html for more information.
+ - Modules based on the original AWS SDK (boto) may read their default configuration from different files. See https://boto.readthedocs.io/en/latest/boto_config_tut.html for more information.
+ - ``AWS_REGION`` or ``EC2_REGION`` can be typically be used to specify the AWS region, when required, but this can also be defined in the configuration files.
diff --git a/docs/community.aws.redshift_cross_region_snapshots_module.rst b/docs/community.aws.redshift_cross_region_snapshots_module.rst
index f1ad74a43b6..10e633cb2e0 100644
--- a/docs/community.aws.redshift_cross_region_snapshots_module.rst
+++ b/docs/community.aws.redshift_cross_region_snapshots_module.rst
@@ -26,10 +26,9 @@ Requirements
------------
The below requirements are needed on the host that executes this module.
-- boto
-- boto3
-- botocore
-- python >= 2.6
+- python >= 3.6
+- boto3 >= 1.15.0
+- botocore >= 1.18.0
Parameters
@@ -55,7 +54,7 @@ Parameters
|
- AWS access key. If not set then the value of the AWS_ACCESS_KEY_ID, AWS_ACCESS_KEY or EC2_ACCESS_KEY environment variable is used.
+ AWS access key . If not set then the value of the AWS_ACCESS_KEY_ID , AWS_ACCESS_KEY or EC2_ACCESS_KEY environment variable is used.
If profile is set this parameter is ignored.
Passing the aws_access_key and profile options at the same time has been deprecated and the options will be made mutually exclusive after 2022-06-01.
aliases: ec2_access_key, access_key
@@ -74,7 +73,7 @@ Parameters
|
The location of a CA Bundle to use when validating SSL certificates.
- Only used for boto3 based modules.
+ Not used by boto 2 based modules.
Note: The CA Bundle is read 'module' side and may need to be explicitly copied from the controller if not run locally.
|
@@ -107,7 +106,7 @@ Parameters
|
- AWS secret key. If not set then the value of the AWS_SECRET_ACCESS_KEY, AWS_SECRET_KEY, or EC2_SECRET_KEY environment variable is used.
+ AWS secret key . If not set then the value of the AWS_SECRET_ACCESS_KEY , AWS_SECRET_KEY , or EC2_SECRET_KEY environment variable is used.
If profile is set this parameter is ignored.
Passing the aws_secret_key and profile options at the same time has been deprecated and the options will be made mutually exclusive after 2022-06-01.
aliases: ec2_secret_key, secret_key
@@ -178,7 +177,7 @@ Parameters
|
|
- Url to use to connect to EC2 or your Eucalyptus cloud (by default the module will use EC2 endpoints). Ignored for modules where region is required. Must be specified for all other modules if region is not used. If not set then the value of the EC2_URL environment variable, if any, is used.
+ URL to use to connect to EC2 or your Eucalyptus cloud (by default the module will use EC2 endpoints). Ignored for modules where region is required. Must be specified for all other modules if region is not used. If not set then the value of the EC2_URL environment variable, if any, is used.
aliases: aws_endpoint_url, endpoint_url
|
@@ -194,7 +193,6 @@ Parameters
|
- Uses a boto profile. Only works with boto >= 2.24.0.
Using profile will override aws_access_key, aws_secret_key and security_token and support for passing them at the same time as profile has been deprecated.
aws_access_key, aws_secret_key and security_token will be made mutually exclusive with profile after 2022-06-01.
aliases: aws_profile
@@ -229,7 +227,7 @@ Parameters
|
|
- AWS STS security token. If not set then the value of the AWS_SECURITY_TOKEN or EC2_SECURITY_TOKEN environment variable is used.
+ AWS STS security token . If not set then the value of the AWS_SECURITY_TOKEN or EC2_SECURITY_TOKEN environment variable is used.
If profile is set this parameter is ignored.
Passing the security_token and profile options at the same time has been deprecated and the options will be made mutually exclusive after 2022-06-01.
aliases: aws_security_token, access_token
@@ -304,7 +302,7 @@ Parameters
|
- When set to "no", SSL certificates will not be validated for boto versions >= 2.6.0.
+ When set to "no", SSL certificates will not be validated for communication with the AWS APIs.
|
@@ -316,8 +314,9 @@ Notes
.. note::
- If parameters are not set within the module, the following environment variables can be used in decreasing order of precedence ``AWS_URL`` or ``EC2_URL``, ``AWS_PROFILE`` or ``AWS_DEFAULT_PROFILE``, ``AWS_ACCESS_KEY_ID`` or ``AWS_ACCESS_KEY`` or ``EC2_ACCESS_KEY``, ``AWS_SECRET_ACCESS_KEY`` or ``AWS_SECRET_KEY`` or ``EC2_SECRET_KEY``, ``AWS_SECURITY_TOKEN`` or ``EC2_SECURITY_TOKEN``, ``AWS_REGION`` or ``EC2_REGION``, ``AWS_CA_BUNDLE``
- - Ansible uses the boto configuration file (typically ~/.boto) if no credentials are provided. See https://boto.readthedocs.io/en/latest/boto_config_tut.html
- - ``AWS_REGION`` or ``EC2_REGION`` can be typically be used to specify the AWS region, when required, but this can also be configured in the boto config file
+ - When no credentials are explicitly provided the AWS SDK (boto3) that Ansible uses will fall back to its configuration files (typically ``~/.aws/credentials``). See https://boto3.amazonaws.com/v1/documentation/api/latest/guide/credentials.html for more information.
+ - Modules based on the original AWS SDK (boto) may read their default configuration from different files. See https://boto.readthedocs.io/en/latest/boto_config_tut.html for more information.
+ - ``AWS_REGION`` or ``EC2_REGION`` can be typically be used to specify the AWS region, when required, but this can also be defined in the configuration files.
diff --git a/docs/community.aws.redshift_info_module.rst b/docs/community.aws.redshift_info_module.rst
index 4d8230f0ea6..6535817f66c 100644
--- a/docs/community.aws.redshift_info_module.rst
+++ b/docs/community.aws.redshift_info_module.rst
@@ -26,9 +26,9 @@ Requirements
------------
The below requirements are needed on the host that executes this module.
-- boto
-- boto3
-- python >= 2.6
+- python >= 3.6
+- boto3 >= 1.15.0
+- botocore >= 1.18.0
Parameters
@@ -54,7 +54,7 @@ Parameters
|
- AWS access key. If not set then the value of the AWS_ACCESS_KEY_ID, AWS_ACCESS_KEY or EC2_ACCESS_KEY environment variable is used.
+ AWS access key . If not set then the value of the AWS_ACCESS_KEY_ID , AWS_ACCESS_KEY or EC2_ACCESS_KEY environment variable is used.
If profile is set this parameter is ignored.
Passing the aws_access_key and profile options at the same time has been deprecated and the options will be made mutually exclusive after 2022-06-01.
aliases: ec2_access_key, access_key
@@ -73,7 +73,7 @@ Parameters
|
The location of a CA Bundle to use when validating SSL certificates.
- Only used for boto3 based modules.
+ Not used by boto 2 based modules.
Note: The CA Bundle is read 'module' side and may need to be explicitly copied from the controller if not run locally.
|
@@ -106,7 +106,7 @@ Parameters
|
- AWS secret key. If not set then the value of the AWS_SECRET_ACCESS_KEY, AWS_SECRET_KEY, or EC2_SECRET_KEY environment variable is used.
+ AWS secret key . If not set then the value of the AWS_SECRET_ACCESS_KEY , AWS_SECRET_KEY , or EC2_SECRET_KEY environment variable is used.
If profile is set this parameter is ignored.
Passing the aws_secret_key and profile options at the same time has been deprecated and the options will be made mutually exclusive after 2022-06-01.
aliases: ec2_secret_key, secret_key
@@ -160,7 +160,7 @@ Parameters
|
|
- Url to use to connect to EC2 or your Eucalyptus cloud (by default the module will use EC2 endpoints). Ignored for modules where region is required. Must be specified for all other modules if region is not used. If not set then the value of the EC2_URL environment variable, if any, is used.
+ URL to use to connect to EC2 or your Eucalyptus cloud (by default the module will use EC2 endpoints). Ignored for modules where region is required. Must be specified for all other modules if region is not used. If not set then the value of the EC2_URL environment variable, if any, is used.
aliases: aws_endpoint_url, endpoint_url
|
@@ -176,7 +176,6 @@ Parameters
|
- Uses a boto profile. Only works with boto >= 2.24.0.
Using profile will override aws_access_key, aws_secret_key and security_token and support for passing them at the same time as profile has been deprecated.
aws_access_key, aws_secret_key and security_token will be made mutually exclusive with profile after 2022-06-01.
aliases: aws_profile
@@ -210,7 +209,7 @@ Parameters
|
|
- AWS STS security token. If not set then the value of the AWS_SECURITY_TOKEN or EC2_SECURITY_TOKEN environment variable is used.
+ AWS STS security token . If not set then the value of the AWS_SECURITY_TOKEN or EC2_SECURITY_TOKEN environment variable is used.
If profile is set this parameter is ignored.
Passing the security_token and profile options at the same time has been deprecated and the options will be made mutually exclusive after 2022-06-01.
aliases: aws_security_token, access_token
@@ -247,7 +246,7 @@ Parameters
|
- When set to "no", SSL certificates will not be validated for boto versions >= 2.6.0.
+ When set to "no", SSL certificates will not be validated for communication with the AWS APIs.
|
@@ -259,8 +258,9 @@ Notes
.. note::
- If parameters are not set within the module, the following environment variables can be used in decreasing order of precedence ``AWS_URL`` or ``EC2_URL``, ``AWS_PROFILE`` or ``AWS_DEFAULT_PROFILE``, ``AWS_ACCESS_KEY_ID`` or ``AWS_ACCESS_KEY`` or ``EC2_ACCESS_KEY``, ``AWS_SECRET_ACCESS_KEY`` or ``AWS_SECRET_KEY`` or ``EC2_SECRET_KEY``, ``AWS_SECURITY_TOKEN`` or ``EC2_SECURITY_TOKEN``, ``AWS_REGION`` or ``EC2_REGION``, ``AWS_CA_BUNDLE``
- - Ansible uses the boto configuration file (typically ~/.boto) if no credentials are provided. See https://boto.readthedocs.io/en/latest/boto_config_tut.html
- - ``AWS_REGION`` or ``EC2_REGION`` can be typically be used to specify the AWS region, when required, but this can also be configured in the boto config file
+ - When no credentials are explicitly provided the AWS SDK (boto3) that Ansible uses will fall back to its configuration files (typically ``~/.aws/credentials``). See https://boto3.amazonaws.com/v1/documentation/api/latest/guide/credentials.html for more information.
+ - Modules based on the original AWS SDK (boto) may read their default configuration from different files. See https://boto.readthedocs.io/en/latest/boto_config_tut.html for more information.
+ - ``AWS_REGION`` or ``EC2_REGION`` can be typically be used to specify the AWS region, when required, but this can also be defined in the configuration files.
diff --git a/docs/community.aws.redshift_module.rst b/docs/community.aws.redshift_module.rst
index 27742aa8b82..c5bd313bacc 100644
--- a/docs/community.aws.redshift_module.rst
+++ b/docs/community.aws.redshift_module.rst
@@ -25,9 +25,9 @@ Requirements
------------
The below requirements are needed on the host that executes this module.
-- boto
-- boto3
-- python >= 2.6
+- python >= 3.6
+- boto3 >= 1.15.0
+- botocore >= 1.18.0
Parameters
@@ -105,7 +105,7 @@ Parameters
|
- AWS access key. If not set then the value of the AWS_ACCESS_KEY_ID, AWS_ACCESS_KEY or EC2_ACCESS_KEY environment variable is used.
+ AWS access key . If not set then the value of the AWS_ACCESS_KEY_ID , AWS_ACCESS_KEY or EC2_ACCESS_KEY environment variable is used.
If profile is set this parameter is ignored.
Passing the aws_access_key and profile options at the same time has been deprecated and the options will be made mutually exclusive after 2022-06-01.
aliases: ec2_access_key, access_key
@@ -124,7 +124,7 @@ Parameters
|
The location of a CA Bundle to use when validating SSL certificates.
- Only used for boto3 based modules.
+ Not used by boto 2 based modules.
Note: The CA Bundle is read 'module' side and may need to be explicitly copied from the controller if not run locally.
|
@@ -157,7 +157,7 @@ Parameters
|
- AWS secret key. If not set then the value of the AWS_SECRET_ACCESS_KEY, AWS_SECRET_KEY, or EC2_SECRET_KEY environment variable is used.
+ AWS secret key . If not set then the value of the AWS_SECRET_ACCESS_KEY , AWS_SECRET_KEY , or EC2_SECRET_KEY environment variable is used.
If profile is set this parameter is ignored.
Passing the aws_secret_key and profile options at the same time has been deprecated and the options will be made mutually exclusive after 2022-06-01.
aliases: ec2_secret_key, secret_key
@@ -318,7 +318,7 @@ Parameters
|
|
- Url to use to connect to EC2 or your Eucalyptus cloud (by default the module will use EC2 endpoints). Ignored for modules where region is required. Must be specified for all other modules if region is not used. If not set then the value of the EC2_URL environment variable, if any, is used.
+ URL to use to connect to EC2 or your Eucalyptus cloud (by default the module will use EC2 endpoints). Ignored for modules where region is required. Must be specified for all other modules if region is not used. If not set then the value of the EC2_URL environment variable, if any, is used.
aliases: aws_endpoint_url, endpoint_url
|
@@ -531,7 +531,6 @@ Parameters
|
- Uses a boto profile. Only works with boto >= 2.24.0.
Using profile will override aws_access_key, aws_secret_key and security_token and support for passing them at the same time as profile has been deprecated.
aws_access_key, aws_secret_key and security_token will be made mutually exclusive with profile after 2022-06-01.
aliases: aws_profile
@@ -604,7 +603,7 @@ Parameters
|
|
- AWS STS security token. If not set then the value of the AWS_SECURITY_TOKEN or EC2_SECURITY_TOKEN environment variable is used.
+ AWS STS security token . If not set then the value of the AWS_SECURITY_TOKEN or EC2_SECURITY_TOKEN environment variable is used.
If profile is set this parameter is ignored.
Passing the security_token and profile options at the same time has been deprecated and the options will be made mutually exclusive after 2022-06-01.
aliases: aws_security_token, access_token
@@ -680,7 +679,7 @@ Parameters
|
- When set to "no", SSL certificates will not be validated for boto versions >= 2.6.0.
+ When set to "no", SSL certificates will not be validated for communication with the AWS APIs.
|
@@ -745,8 +744,9 @@ Notes
.. note::
- If parameters are not set within the module, the following environment variables can be used in decreasing order of precedence ``AWS_URL`` or ``EC2_URL``, ``AWS_PROFILE`` or ``AWS_DEFAULT_PROFILE``, ``AWS_ACCESS_KEY_ID`` or ``AWS_ACCESS_KEY`` or ``EC2_ACCESS_KEY``, ``AWS_SECRET_ACCESS_KEY`` or ``AWS_SECRET_KEY`` or ``EC2_SECRET_KEY``, ``AWS_SECURITY_TOKEN`` or ``EC2_SECURITY_TOKEN``, ``AWS_REGION`` or ``EC2_REGION``, ``AWS_CA_BUNDLE``
- - Ansible uses the boto configuration file (typically ~/.boto) if no credentials are provided. See https://boto.readthedocs.io/en/latest/boto_config_tut.html
- - ``AWS_REGION`` or ``EC2_REGION`` can be typically be used to specify the AWS region, when required, but this can also be configured in the boto config file
+ - When no credentials are explicitly provided the AWS SDK (boto3) that Ansible uses will fall back to its configuration files (typically ``~/.aws/credentials``). See https://boto3.amazonaws.com/v1/documentation/api/latest/guide/credentials.html for more information.
+ - Modules based on the original AWS SDK (boto) may read their default configuration from different files. See https://boto.readthedocs.io/en/latest/boto_config_tut.html for more information.
+ - ``AWS_REGION`` or ``EC2_REGION`` can be typically be used to specify the AWS region, when required, but this can also be defined in the configuration files.
diff --git a/docs/community.aws.redshift_subnet_group_module.rst b/docs/community.aws.redshift_subnet_group_module.rst
index 7f66c0334a7..b007c1e9934 100644
--- a/docs/community.aws.redshift_subnet_group_module.rst
+++ b/docs/community.aws.redshift_subnet_group_module.rst
@@ -25,8 +25,10 @@ Requirements
------------
The below requirements are needed on the host that executes this module.
-- boto
-- python >= 2.6
+- boto >= 2.49.0
+- boto3 >= 1.15.0
+- botocore >= 1.18.0
+- python >= 3.6
Parameters
@@ -52,7 +54,7 @@ Parameters
|
- AWS access key. If not set then the value of the AWS_ACCESS_KEY_ID, AWS_ACCESS_KEY or EC2_ACCESS_KEY environment variable is used.
+ AWS access key . If not set then the value of the AWS_ACCESS_KEY_ID , AWS_ACCESS_KEY or EC2_ACCESS_KEY environment variable is used.
If profile is set this parameter is ignored.
Passing the aws_access_key and profile options at the same time has been deprecated and the options will be made mutually exclusive after 2022-06-01.
aliases: ec2_access_key, access_key
@@ -71,7 +73,7 @@ Parameters
|
The location of a CA Bundle to use when validating SSL certificates.
- Only used for boto3 based modules.
+ Not used by boto 2 based modules.
Note: The CA Bundle is read 'module' side and may need to be explicitly copied from the controller if not run locally.
|
@@ -104,7 +106,7 @@ Parameters
|
- AWS secret key. If not set then the value of the AWS_SECRET_ACCESS_KEY, AWS_SECRET_KEY, or EC2_SECRET_KEY environment variable is used.
+ AWS secret key . If not set then the value of the AWS_SECRET_ACCESS_KEY , AWS_SECRET_KEY , or EC2_SECRET_KEY environment variable is used.
If profile is set this parameter is ignored.
Passing the aws_secret_key and profile options at the same time has been deprecated and the options will be made mutually exclusive after 2022-06-01.
aliases: ec2_secret_key, secret_key
@@ -141,7 +143,7 @@ Parameters
|
|
- Url to use to connect to EC2 or your Eucalyptus cloud (by default the module will use EC2 endpoints). Ignored for modules where region is required. Must be specified for all other modules if region is not used. If not set then the value of the EC2_URL environment variable, if any, is used.
+ URL to use to connect to EC2 or your Eucalyptus cloud (by default the module will use EC2 endpoints). Ignored for modules where region is required. Must be specified for all other modules if region is not used. If not set then the value of the EC2_URL environment variable, if any, is used.
aliases: aws_endpoint_url, endpoint_url
|
@@ -158,6 +160,7 @@ Parameters
Database subnet group description.
+ Required when state=present.
aliases: description
|
@@ -192,6 +195,7 @@ Parameters
List of subnet IDs that make up the cluster subnet group.
+ Required when state=present.
aliases: subnets
|
@@ -207,7 +211,6 @@ Parameters
|
- Uses a boto profile. Only works with boto >= 2.24.0.
Using profile will override aws_access_key, aws_secret_key and security_token and support for passing them at the same time as profile has been deprecated.
aws_access_key, aws_secret_key and security_token will be made mutually exclusive with profile after 2022-06-01.
aliases: aws_profile
@@ -241,7 +244,7 @@ Parameters
|
|
- AWS STS security token. If not set then the value of the AWS_SECURITY_TOKEN or EC2_SECURITY_TOKEN environment variable is used.
+ AWS STS security token . If not set then the value of the AWS_SECURITY_TOKEN or EC2_SECURITY_TOKEN environment variable is used.
If profile is set this parameter is ignored.
Passing the security_token and profile options at the same time has been deprecated and the options will be made mutually exclusive after 2022-06-01.
aliases: aws_security_token, access_token
@@ -283,7 +286,7 @@ Parameters
|
- When set to "no", SSL certificates will not be validated for boto versions >= 2.6.0.
+ When set to "no", SSL certificates will not be validated for communication with the AWS APIs.
|
@@ -295,8 +298,9 @@ Notes
.. note::
- If parameters are not set within the module, the following environment variables can be used in decreasing order of precedence ``AWS_URL`` or ``EC2_URL``, ``AWS_PROFILE`` or ``AWS_DEFAULT_PROFILE``, ``AWS_ACCESS_KEY_ID`` or ``AWS_ACCESS_KEY`` or ``EC2_ACCESS_KEY``, ``AWS_SECRET_ACCESS_KEY`` or ``AWS_SECRET_KEY`` or ``EC2_SECRET_KEY``, ``AWS_SECURITY_TOKEN`` or ``EC2_SECURITY_TOKEN``, ``AWS_REGION`` or ``EC2_REGION``, ``AWS_CA_BUNDLE``
- - Ansible uses the boto configuration file (typically ~/.boto) if no credentials are provided. See https://boto.readthedocs.io/en/latest/boto_config_tut.html
- - ``AWS_REGION`` or ``EC2_REGION`` can be typically be used to specify the AWS region, when required, but this can also be configured in the boto config file
+ - When no credentials are explicitly provided the AWS SDK (boto3) that Ansible uses will fall back to its configuration files (typically ``~/.aws/credentials``). See https://boto3.amazonaws.com/v1/documentation/api/latest/guide/credentials.html for more information.
+ - Modules based on the original AWS SDK (boto) may read their default configuration from different files. See https://boto.readthedocs.io/en/latest/boto_config_tut.html for more information.
+ - ``AWS_REGION`` or ``EC2_REGION`` can be typically be used to specify the AWS region, when required, but this can also be defined in the configuration files.
diff --git a/docs/community.aws.route53_health_check_module.rst b/docs/community.aws.route53_health_check_module.rst
index b4b25fada6b..3d29ebeb929 100644
--- a/docs/community.aws.route53_health_check_module.rst
+++ b/docs/community.aws.route53_health_check_module.rst
@@ -26,8 +26,10 @@ Requirements
------------
The below requirements are needed on the host that executes this module.
-- python >= 2.6
-- boto
+- boto >= 2.49.0
+- boto3 >= 1.15.0
+- botocore >= 1.18.0
+- python >= 3.6
Parameters
@@ -53,7 +55,7 @@ Parameters
|
- AWS access key. If not set then the value of the AWS_ACCESS_KEY_ID, AWS_ACCESS_KEY or EC2_ACCESS_KEY environment variable is used.
+ AWS access key . If not set then the value of the AWS_ACCESS_KEY_ID , AWS_ACCESS_KEY or EC2_ACCESS_KEY environment variable is used.
If profile is set this parameter is ignored.
Passing the aws_access_key and profile options at the same time has been deprecated and the options will be made mutually exclusive after 2022-06-01.
aliases: ec2_access_key, access_key
@@ -72,7 +74,7 @@ Parameters
|
The location of a CA Bundle to use when validating SSL certificates.
- Only used for boto3 based modules.
+ Not used by boto 2 based modules.
Note: The CA Bundle is read 'module' side and may need to be explicitly copied from the controller if not run locally.
|
@@ -105,7 +107,7 @@ Parameters
|
- AWS secret key. If not set then the value of the AWS_SECRET_ACCESS_KEY, AWS_SECRET_KEY, or EC2_SECRET_KEY environment variable is used.
+ AWS secret key . If not set then the value of the AWS_SECRET_ACCESS_KEY , AWS_SECRET_KEY , or EC2_SECRET_KEY environment variable is used.
If profile is set this parameter is ignored.
Passing the aws_secret_key and profile options at the same time has been deprecated and the options will be made mutually exclusive after 2022-06-01.
aliases: ec2_secret_key, secret_key
@@ -142,7 +144,7 @@ Parameters
|
|
- Url to use to connect to EC2 or your Eucalyptus cloud (by default the module will use EC2 endpoints). Ignored for modules where region is required. Must be specified for all other modules if region is not used. If not set then the value of the EC2_URL environment variable, if any, is used.
+ URL to use to connect to EC2 or your Eucalyptus cloud (by default the module will use EC2 endpoints). Ignored for modules where region is required. Must be specified for all other modules if region is not used. If not set then the value of the EC2_URL environment variable, if any, is used.
aliases: aws_endpoint_url, endpoint_url
|
@@ -230,7 +232,6 @@ Parameters
|
- Uses a boto profile. Only works with boto >= 2.24.0.
Using profile will override aws_access_key, aws_secret_key and security_token and support for passing them at the same time as profile has been deprecated.
aws_access_key, aws_secret_key and security_token will be made mutually exclusive with profile after 2022-06-01.
aliases: aws_profile
@@ -301,7 +302,7 @@ Parameters
|
|
- AWS STS security token. If not set then the value of the AWS_SECURITY_TOKEN or EC2_SECURITY_TOKEN environment variable is used.
+ AWS STS security token . If not set then the value of the AWS_SECURITY_TOKEN or EC2_SECURITY_TOKEN environment variable is used.
If profile is set this parameter is ignored.
Passing the security_token and profile options at the same time has been deprecated and the options will be made mutually exclusive after 2022-06-01.
aliases: aws_security_token, access_token
@@ -380,7 +381,7 @@ Parameters
|
- When set to "no", SSL certificates will not be validated for boto versions >= 2.6.0.
+ When set to "no", SSL certificates will not be validated for communication with the AWS APIs.
|
@@ -392,8 +393,9 @@ Notes
.. note::
- If parameters are not set within the module, the following environment variables can be used in decreasing order of precedence ``AWS_URL`` or ``EC2_URL``, ``AWS_PROFILE`` or ``AWS_DEFAULT_PROFILE``, ``AWS_ACCESS_KEY_ID`` or ``AWS_ACCESS_KEY`` or ``EC2_ACCESS_KEY``, ``AWS_SECRET_ACCESS_KEY`` or ``AWS_SECRET_KEY`` or ``EC2_SECRET_KEY``, ``AWS_SECURITY_TOKEN`` or ``EC2_SECURITY_TOKEN``, ``AWS_REGION`` or ``EC2_REGION``, ``AWS_CA_BUNDLE``
- - Ansible uses the boto configuration file (typically ~/.boto) if no credentials are provided. See https://boto.readthedocs.io/en/latest/boto_config_tut.html
- - ``AWS_REGION`` or ``EC2_REGION`` can be typically be used to specify the AWS region, when required, but this can also be configured in the boto config file
+ - When no credentials are explicitly provided the AWS SDK (boto3) that Ansible uses will fall back to its configuration files (typically ``~/.aws/credentials``). See https://boto3.amazonaws.com/v1/documentation/api/latest/guide/credentials.html for more information.
+ - Modules based on the original AWS SDK (boto) may read their default configuration from different files. See https://boto.readthedocs.io/en/latest/boto_config_tut.html for more information.
+ - ``AWS_REGION`` or ``EC2_REGION`` can be typically be used to specify the AWS region, when required, but this can also be defined in the configuration files.
diff --git a/docs/community.aws.route53_info_module.rst b/docs/community.aws.route53_info_module.rst
index e44d3e25ed0..d81b24597e5 100644
--- a/docs/community.aws.route53_info_module.rst
+++ b/docs/community.aws.route53_info_module.rst
@@ -26,8 +26,9 @@ Requirements
------------
The below requirements are needed on the host that executes this module.
-- python >= 2.6
-- boto
+- python >= 3.6
+- boto3 >= 1.15.0
+- botocore >= 1.18.0
Parameters
@@ -53,7 +54,7 @@ Parameters
|
- AWS access key. If not set then the value of the AWS_ACCESS_KEY_ID, AWS_ACCESS_KEY or EC2_ACCESS_KEY environment variable is used.
+ AWS access key . If not set then the value of the AWS_ACCESS_KEY_ID , AWS_ACCESS_KEY or EC2_ACCESS_KEY environment variable is used.
If profile is set this parameter is ignored.
Passing the aws_access_key and profile options at the same time has been deprecated and the options will be made mutually exclusive after 2022-06-01.
aliases: ec2_access_key, access_key
@@ -72,7 +73,7 @@ Parameters
|
The location of a CA Bundle to use when validating SSL certificates.
- Only used for boto3 based modules.
+ Not used by boto 2 based modules.
Note: The CA Bundle is read 'module' side and may need to be explicitly copied from the controller if not run locally.
|
@@ -105,7 +106,7 @@ Parameters
|
- AWS secret key. If not set then the value of the AWS_SECRET_ACCESS_KEY, AWS_SECRET_KEY, or EC2_SECRET_KEY environment variable is used.
+ AWS secret key . If not set then the value of the AWS_SECRET_ACCESS_KEY , AWS_SECRET_KEY , or EC2_SECRET_KEY environment variable is used.
If profile is set this parameter is ignored.
Passing the aws_secret_key and profile options at the same time has been deprecated and the options will be made mutually exclusive after 2022-06-01.
aliases: ec2_secret_key, secret_key
@@ -189,7 +190,7 @@ Parameters
|
|
- Url to use to connect to EC2 or your Eucalyptus cloud (by default the module will use EC2 endpoints). Ignored for modules where region is required. Must be specified for all other modules if region is not used. If not set then the value of the EC2_URL environment variable, if any, is used.
+ URL to use to connect to EC2 or your Eucalyptus cloud (by default the module will use EC2 endpoints). Ignored for modules where region is required. Must be specified for all other modules if region is not used. If not set then the value of the EC2_URL environment variable, if any, is used.
aliases: aws_endpoint_url, endpoint_url
|
@@ -313,7 +314,6 @@ Parameters
|
- Uses a boto profile. Only works with boto >= 2.24.0.
Using profile will override aws_access_key, aws_secret_key and security_token and support for passing them at the same time as profile has been deprecated.
aws_access_key, aws_secret_key and security_token will be made mutually exclusive with profile after 2022-06-01.
aliases: aws_profile
@@ -390,7 +390,7 @@ Parameters
|
|
- AWS STS security token. If not set then the value of the AWS_SECURITY_TOKEN or EC2_SECURITY_TOKEN environment variable is used.
+ AWS STS security token . If not set then the value of the AWS_SECURITY_TOKEN or EC2_SECURITY_TOKEN environment variable is used.
If profile is set this parameter is ignored.
Passing the security_token and profile options at the same time has been deprecated and the options will be made mutually exclusive after 2022-06-01.
aliases: aws_security_token, access_token
@@ -454,7 +454,7 @@ Parameters
|
- When set to "no", SSL certificates will not be validated for boto versions >= 2.6.0.
+ When set to "no", SSL certificates will not be validated for communication with the AWS APIs.
|
@@ -466,8 +466,9 @@ Notes
.. note::
- If parameters are not set within the module, the following environment variables can be used in decreasing order of precedence ``AWS_URL`` or ``EC2_URL``, ``AWS_PROFILE`` or ``AWS_DEFAULT_PROFILE``, ``AWS_ACCESS_KEY_ID`` or ``AWS_ACCESS_KEY`` or ``EC2_ACCESS_KEY``, ``AWS_SECRET_ACCESS_KEY`` or ``AWS_SECRET_KEY`` or ``EC2_SECRET_KEY``, ``AWS_SECURITY_TOKEN`` or ``EC2_SECURITY_TOKEN``, ``AWS_REGION`` or ``EC2_REGION``, ``AWS_CA_BUNDLE``
- - Ansible uses the boto configuration file (typically ~/.boto) if no credentials are provided. See https://boto.readthedocs.io/en/latest/boto_config_tut.html
- - ``AWS_REGION`` or ``EC2_REGION`` can be typically be used to specify the AWS region, when required, but this can also be configured in the boto config file
+ - When no credentials are explicitly provided the AWS SDK (boto3) that Ansible uses will fall back to its configuration files (typically ``~/.aws/credentials``). See https://boto3.amazonaws.com/v1/documentation/api/latest/guide/credentials.html for more information.
+ - Modules based on the original AWS SDK (boto) may read their default configuration from different files. See https://boto.readthedocs.io/en/latest/boto_config_tut.html for more information.
+ - ``AWS_REGION`` or ``EC2_REGION`` can be typically be used to specify the AWS region, when required, but this can also be defined in the configuration files.
diff --git a/docs/community.aws.route53_module.rst b/docs/community.aws.route53_module.rst
index 8c08e3bff64..47e58e06062 100644
--- a/docs/community.aws.route53_module.rst
+++ b/docs/community.aws.route53_module.rst
@@ -25,10 +25,9 @@ Requirements
------------
The below requirements are needed on the host that executes this module.
-- boto
-- boto3
-- botocore
-- python >= 2.6
+- python >= 3.6
+- boto3 >= 1.15.0
+- botocore >= 1.18.0
Parameters
@@ -109,7 +108,7 @@ Parameters
|
- AWS access key. If not set then the value of the AWS_ACCESS_KEY_ID, AWS_ACCESS_KEY or EC2_ACCESS_KEY environment variable is used.
+ AWS access key . If not set then the value of the AWS_ACCESS_KEY_ID , AWS_ACCESS_KEY or EC2_ACCESS_KEY environment variable is used.
If profile is set this parameter is ignored.
Passing the aws_access_key and profile options at the same time has been deprecated and the options will be made mutually exclusive after 2022-06-01.
aliases: ec2_access_key, access_key
@@ -128,7 +127,7 @@ Parameters
|
The location of a CA Bundle to use when validating SSL certificates.
- Only used for boto3 based modules.
+ Not used by boto 2 based modules.
Note: The CA Bundle is read 'module' side and may need to be explicitly copied from the controller if not run locally.
|
@@ -161,7 +160,7 @@ Parameters
|
- AWS secret key. If not set then the value of the AWS_SECRET_ACCESS_KEY, AWS_SECRET_KEY, or EC2_SECRET_KEY environment variable is used.
+ AWS secret key . If not set then the value of the AWS_SECRET_ACCESS_KEY , AWS_SECRET_KEY , or EC2_SECRET_KEY environment variable is used.
If profile is set this parameter is ignored.
Passing the aws_secret_key and profile options at the same time has been deprecated and the options will be made mutually exclusive after 2022-06-01.
aliases: ec2_secret_key, secret_key
@@ -198,7 +197,7 @@ Parameters
|
|
- Url to use to connect to EC2 or your Eucalyptus cloud (by default the module will use EC2 endpoints). Ignored for modules where region is required. Must be specified for all other modules if region is not used. If not set then the value of the EC2_URL environment variable, if any, is used.
+ URL to use to connect to EC2 or your Eucalyptus cloud (by default the module will use EC2 endpoints). Ignored for modules where region is required. Must be specified for all other modules if region is not used. If not set then the value of the EC2_URL environment variable, if any, is used.
aliases: aws_endpoint_url, endpoint_url
|
@@ -319,7 +318,6 @@ Parameters
|
- Uses a boto profile. Only works with boto >= 2.24.0.
Using profile will override aws_access_key, aws_secret_key and security_token and support for passing them at the same time as profile has been deprecated.
aws_access_key, aws_secret_key and security_token will be made mutually exclusive with profile after 2022-06-01.
aliases: aws_profile
@@ -385,7 +383,7 @@ Parameters
|
|
- AWS STS security token. If not set then the value of the AWS_SECURITY_TOKEN or EC2_SECURITY_TOKEN environment variable is used.
+ AWS STS security token . If not set then the value of the AWS_SECURITY_TOKEN or EC2_SECURITY_TOKEN environment variable is used.
If profile is set this parameter is ignored.
Passing the security_token and profile options at the same time has been deprecated and the options will be made mutually exclusive after 2022-06-01.
aliases: aws_security_token, access_token
@@ -477,7 +475,7 @@ Parameters
|
- When set to "no", SSL certificates will not be validated for boto versions >= 2.6.0.
+ When set to "no", SSL certificates will not be validated for communication with the AWS APIs.
|
@@ -589,8 +587,9 @@ Notes
.. note::
- If parameters are not set within the module, the following environment variables can be used in decreasing order of precedence ``AWS_URL`` or ``EC2_URL``, ``AWS_PROFILE`` or ``AWS_DEFAULT_PROFILE``, ``AWS_ACCESS_KEY_ID`` or ``AWS_ACCESS_KEY`` or ``EC2_ACCESS_KEY``, ``AWS_SECRET_ACCESS_KEY`` or ``AWS_SECRET_KEY`` or ``EC2_SECRET_KEY``, ``AWS_SECURITY_TOKEN`` or ``EC2_SECURITY_TOKEN``, ``AWS_REGION`` or ``EC2_REGION``, ``AWS_CA_BUNDLE``
- - Ansible uses the boto configuration file (typically ~/.boto) if no credentials are provided. See https://boto.readthedocs.io/en/latest/boto_config_tut.html
- - ``AWS_REGION`` or ``EC2_REGION`` can be typically be used to specify the AWS region, when required, but this can also be configured in the boto config file
+ - When no credentials are explicitly provided the AWS SDK (boto3) that Ansible uses will fall back to its configuration files (typically ``~/.aws/credentials``). See https://boto3.amazonaws.com/v1/documentation/api/latest/guide/credentials.html for more information.
+ - Modules based on the original AWS SDK (boto) may read their default configuration from different files. See https://boto.readthedocs.io/en/latest/boto_config_tut.html for more information.
+ - ``AWS_REGION`` or ``EC2_REGION`` can be typically be used to specify the AWS region, when required, but this can also be defined in the configuration files.
diff --git a/docs/community.aws.route53_zone_module.rst b/docs/community.aws.route53_zone_module.rst
index 0af97d45d8f..f80f0e2a9ac 100644
--- a/docs/community.aws.route53_zone_module.rst
+++ b/docs/community.aws.route53_zone_module.rst
@@ -25,9 +25,9 @@ Requirements
------------
The below requirements are needed on the host that executes this module.
-- boto
-- boto3
-- python >= 2.6
+- python >= 3.6
+- boto3 >= 1.15.0
+- botocore >= 1.18.0
Parameters
@@ -53,7 +53,7 @@ Parameters
|
- AWS access key. If not set then the value of the AWS_ACCESS_KEY_ID, AWS_ACCESS_KEY or EC2_ACCESS_KEY environment variable is used.
+ AWS access key . If not set then the value of the AWS_ACCESS_KEY_ID , AWS_ACCESS_KEY or EC2_ACCESS_KEY environment variable is used.
If profile is set this parameter is ignored.
Passing the aws_access_key and profile options at the same time has been deprecated and the options will be made mutually exclusive after 2022-06-01.
aliases: ec2_access_key, access_key
@@ -72,7 +72,7 @@ Parameters
|
The location of a CA Bundle to use when validating SSL certificates.
- Only used for boto3 based modules.
+ Not used by boto 2 based modules.
Note: The CA Bundle is read 'module' side and may need to be explicitly copied from the controller if not run locally.
|
@@ -105,7 +105,7 @@ Parameters
|
- AWS secret key. If not set then the value of the AWS_SECRET_ACCESS_KEY, AWS_SECRET_KEY, or EC2_SECRET_KEY environment variable is used.
+ AWS secret key . If not set then the value of the AWS_SECRET_ACCESS_KEY , AWS_SECRET_KEY , or EC2_SECRET_KEY environment variable is used.
If profile is set this parameter is ignored.
Passing the aws_secret_key and profile options at the same time has been deprecated and the options will be made mutually exclusive after 2022-06-01.
aliases: ec2_secret_key, secret_key
@@ -174,7 +174,7 @@ Parameters
|
|
- Url to use to connect to EC2 or your Eucalyptus cloud (by default the module will use EC2 endpoints). Ignored for modules where region is required. Must be specified for all other modules if region is not used. If not set then the value of the EC2_URL environment variable, if any, is used.
+ URL to use to connect to EC2 or your Eucalyptus cloud (by default the module will use EC2 endpoints). Ignored for modules where region is required. Must be specified for all other modules if region is not used. If not set then the value of the EC2_URL environment variable, if any, is used.
aliases: aws_endpoint_url, endpoint_url
|
@@ -206,7 +206,6 @@ Parameters
|
- Uses a boto profile. Only works with boto >= 2.24.0.
Using profile will override aws_access_key, aws_secret_key and security_token and support for passing them at the same time as profile has been deprecated.
aws_access_key, aws_secret_key and security_token will be made mutually exclusive with profile after 2022-06-01.
aliases: aws_profile
@@ -240,7 +239,7 @@ Parameters
|
|
- AWS STS security token. If not set then the value of the AWS_SECURITY_TOKEN or EC2_SECURITY_TOKEN environment variable is used.
+ AWS STS security token . If not set then the value of the AWS_SECURITY_TOKEN or EC2_SECURITY_TOKEN environment variable is used.
If profile is set this parameter is ignored.
Passing the security_token and profile options at the same time has been deprecated and the options will be made mutually exclusive after 2022-06-01.
aliases: aws_security_token, access_token
@@ -281,7 +280,7 @@ Parameters
|
- When set to "no", SSL certificates will not be validated for boto versions >= 2.6.0.
+ When set to "no", SSL certificates will not be validated for communication with the AWS APIs.
|
@@ -339,8 +338,9 @@ Notes
.. note::
- If parameters are not set within the module, the following environment variables can be used in decreasing order of precedence ``AWS_URL`` or ``EC2_URL``, ``AWS_PROFILE`` or ``AWS_DEFAULT_PROFILE``, ``AWS_ACCESS_KEY_ID`` or ``AWS_ACCESS_KEY`` or ``EC2_ACCESS_KEY``, ``AWS_SECRET_ACCESS_KEY`` or ``AWS_SECRET_KEY`` or ``EC2_SECRET_KEY``, ``AWS_SECURITY_TOKEN`` or ``EC2_SECURITY_TOKEN``, ``AWS_REGION`` or ``EC2_REGION``, ``AWS_CA_BUNDLE``
- - Ansible uses the boto configuration file (typically ~/.boto) if no credentials are provided. See https://boto.readthedocs.io/en/latest/boto_config_tut.html
- - ``AWS_REGION`` or ``EC2_REGION`` can be typically be used to specify the AWS region, when required, but this can also be configured in the boto config file
+ - When no credentials are explicitly provided the AWS SDK (boto3) that Ansible uses will fall back to its configuration files (typically ``~/.aws/credentials``). See https://boto3.amazonaws.com/v1/documentation/api/latest/guide/credentials.html for more information.
+ - Modules based on the original AWS SDK (boto) may read their default configuration from different files. See https://boto.readthedocs.io/en/latest/boto_config_tut.html for more information.
+ - ``AWS_REGION`` or ``EC2_REGION`` can be typically be used to specify the AWS region, when required, but this can also be defined in the configuration files.
diff --git a/docs/community.aws.s3_bucket_notification_module.rst b/docs/community.aws.s3_bucket_notification_module.rst
index a801b0ded68..0f62c6e343b 100644
--- a/docs/community.aws.s3_bucket_notification_module.rst
+++ b/docs/community.aws.s3_bucket_notification_module.rst
@@ -25,9 +25,9 @@ Requirements
------------
The below requirements are needed on the host that executes this module.
-- boto
-- boto3
-- python >= 2.6
+- python >= 3.6
+- boto3 >= 1.15.0
+- botocore >= 1.18.0
Parameters
@@ -53,7 +53,7 @@ Parameters
|
- AWS access key. If not set then the value of the AWS_ACCESS_KEY_ID, AWS_ACCESS_KEY or EC2_ACCESS_KEY environment variable is used.
+ AWS access key . If not set then the value of the AWS_ACCESS_KEY_ID , AWS_ACCESS_KEY or EC2_ACCESS_KEY environment variable is used.
If profile is set this parameter is ignored.
Passing the aws_access_key and profile options at the same time has been deprecated and the options will be made mutually exclusive after 2022-06-01.
aliases: ec2_access_key, access_key
@@ -72,7 +72,7 @@ Parameters
|
The location of a CA Bundle to use when validating SSL certificates.
- Only used for boto3 based modules.
+ Not used by boto 2 based modules.
Note: The CA Bundle is read 'module' side and may need to be explicitly copied from the controller if not run locally.
|
@@ -105,7 +105,7 @@ Parameters
|
- AWS secret key. If not set then the value of the AWS_SECRET_ACCESS_KEY, AWS_SECRET_KEY, or EC2_SECRET_KEY environment variable is used.
+ AWS secret key . If not set then the value of the AWS_SECRET_ACCESS_KEY , AWS_SECRET_KEY , or EC2_SECRET_KEY environment variable is used.
If profile is set this parameter is ignored.
Passing the aws_secret_key and profile options at the same time has been deprecated and the options will be made mutually exclusive after 2022-06-01.
aliases: ec2_secret_key, secret_key
@@ -158,7 +158,7 @@ Parameters
|
|
- Url to use to connect to EC2 or your Eucalyptus cloud (by default the module will use EC2 endpoints). Ignored for modules where region is required. Must be specified for all other modules if region is not used. If not set then the value of the EC2_URL environment variable, if any, is used.
+ URL to use to connect to EC2 or your Eucalyptus cloud (by default the module will use EC2 endpoints). Ignored for modules where region is required. Must be specified for all other modules if region is not used. If not set then the value of the EC2_URL environment variable, if any, is used.
aliases: aws_endpoint_url, endpoint_url
|
@@ -283,7 +283,6 @@ Parameters
|
- Uses a boto profile. Only works with boto >= 2.24.0.
Using profile will override aws_access_key, aws_secret_key and security_token and support for passing them at the same time as profile has been deprecated.
aws_access_key, aws_secret_key and security_token will be made mutually exclusive with profile after 2022-06-01.
aliases: aws_profile
@@ -317,7 +316,7 @@ Parameters
|
|
- AWS STS security token. If not set then the value of the AWS_SECURITY_TOKEN or EC2_SECURITY_TOKEN environment variable is used.
+ AWS STS security token . If not set then the value of the AWS_SECURITY_TOKEN or EC2_SECURITY_TOKEN environment variable is used.
If profile is set this parameter is ignored.
Passing the security_token and profile options at the same time has been deprecated and the options will be made mutually exclusive after 2022-06-01.
aliases: aws_security_token, access_token
@@ -373,7 +372,7 @@ Parameters
|
- When set to "no", SSL certificates will not be validated for boto versions >= 2.6.0.
+ When set to "no", SSL certificates will not be validated for communication with the AWS APIs.
|
@@ -386,8 +385,9 @@ Notes
.. note::
- This module heavily depends on :ref:`community.aws.lambda_policy ` as you need to allow ``lambda:InvokeFunction`` permission for your lambda function.
- If parameters are not set within the module, the following environment variables can be used in decreasing order of precedence ``AWS_URL`` or ``EC2_URL``, ``AWS_PROFILE`` or ``AWS_DEFAULT_PROFILE``, ``AWS_ACCESS_KEY_ID`` or ``AWS_ACCESS_KEY`` or ``EC2_ACCESS_KEY``, ``AWS_SECRET_ACCESS_KEY`` or ``AWS_SECRET_KEY`` or ``EC2_SECRET_KEY``, ``AWS_SECURITY_TOKEN`` or ``EC2_SECURITY_TOKEN``, ``AWS_REGION`` or ``EC2_REGION``, ``AWS_CA_BUNDLE``
- - Ansible uses the boto configuration file (typically ~/.boto) if no credentials are provided. See https://boto.readthedocs.io/en/latest/boto_config_tut.html
- - ``AWS_REGION`` or ``EC2_REGION`` can be typically be used to specify the AWS region, when required, but this can also be configured in the boto config file
+ - When no credentials are explicitly provided the AWS SDK (boto3) that Ansible uses will fall back to its configuration files (typically ``~/.aws/credentials``). See https://boto3.amazonaws.com/v1/documentation/api/latest/guide/credentials.html for more information.
+ - Modules based on the original AWS SDK (boto) may read their default configuration from different files. See https://boto.readthedocs.io/en/latest/boto_config_tut.html for more information.
+ - ``AWS_REGION`` or ``EC2_REGION`` can be typically be used to specify the AWS region, when required, but this can also be defined in the configuration files.
diff --git a/docs/community.aws.s3_lifecycle_module.rst b/docs/community.aws.s3_lifecycle_module.rst
index 6382c26d25c..6a940862780 100644
--- a/docs/community.aws.s3_lifecycle_module.rst
+++ b/docs/community.aws.s3_lifecycle_module.rst
@@ -25,8 +25,9 @@ Requirements
------------
The below requirements are needed on the host that executes this module.
-- python >= 2.6
-- boto
+- python >= 3.6
+- boto3 >= 1.15.0
+- botocore >= 1.18.0
Parameters
@@ -52,7 +53,7 @@ Parameters
|
- AWS access key. If not set then the value of the AWS_ACCESS_KEY_ID, AWS_ACCESS_KEY or EC2_ACCESS_KEY environment variable is used.
+ AWS access key . If not set then the value of the AWS_ACCESS_KEY_ID , AWS_ACCESS_KEY or EC2_ACCESS_KEY environment variable is used.
If profile is set this parameter is ignored.
Passing the aws_access_key and profile options at the same time has been deprecated and the options will be made mutually exclusive after 2022-06-01.
aliases: ec2_access_key, access_key
@@ -71,7 +72,7 @@ Parameters
|
The location of a CA Bundle to use when validating SSL certificates.
- Only used for boto3 based modules.
+ Not used by boto 2 based modules.
Note: The CA Bundle is read 'module' side and may need to be explicitly copied from the controller if not run locally.
|
@@ -104,7 +105,7 @@ Parameters
|
- AWS secret key. If not set then the value of the AWS_SECRET_ACCESS_KEY, AWS_SECRET_KEY, or EC2_SECRET_KEY environment variable is used.
+ AWS secret key . If not set then the value of the AWS_SECRET_ACCESS_KEY , AWS_SECRET_KEY , or EC2_SECRET_KEY environment variable is used.
If profile is set this parameter is ignored.
Passing the aws_secret_key and profile options at the same time has been deprecated and the options will be made mutually exclusive after 2022-06-01.
aliases: ec2_secret_key, secret_key
@@ -141,7 +142,7 @@ Parameters
|
|
- Url to use to connect to EC2 or your Eucalyptus cloud (by default the module will use EC2 endpoints). Ignored for modules where region is required. Must be specified for all other modules if region is not used. If not set then the value of the EC2_URL environment variable, if any, is used.
+ URL to use to connect to EC2 or your Eucalyptus cloud (by default the module will use EC2 endpoints). Ignored for modules where region is required. Must be specified for all other modules if region is not used. If not set then the value of the EC2_URL environment variable, if any, is used.
aliases: aws_endpoint_url, endpoint_url
|
@@ -290,7 +291,6 @@ Parameters
|
- Uses a boto profile. Only works with boto >= 2.24.0.
Using profile will override aws_access_key, aws_secret_key and security_token and support for passing them at the same time as profile has been deprecated.
aws_access_key, aws_secret_key and security_token will be made mutually exclusive with profile after 2022-06-01.
aliases: aws_profile
@@ -380,7 +380,7 @@ Parameters
|
|
- AWS STS security token. If not set then the value of the AWS_SECURITY_TOKEN or EC2_SECURITY_TOKEN environment variable is used.
+ AWS STS security token . If not set then the value of the AWS_SECURITY_TOKEN or EC2_SECURITY_TOKEN environment variable is used.
If profile is set this parameter is ignored.
Passing the security_token and profile options at the same time has been deprecated and the options will be made mutually exclusive after 2022-06-01.
aliases: aws_security_token, access_token
@@ -513,7 +513,7 @@ Parameters
|
- When set to "no", SSL certificates will not be validated for boto versions >= 2.6.0.
+ When set to "no", SSL certificates will not be validated for communication with the AWS APIs.
|
@@ -547,8 +547,9 @@ Notes
- If specifying expiration time as days then transition time must also be specified in days.
- If specifying expiration time as a date then transition time must also be specified as a date.
- If parameters are not set within the module, the following environment variables can be used in decreasing order of precedence ``AWS_URL`` or ``EC2_URL``, ``AWS_PROFILE`` or ``AWS_DEFAULT_PROFILE``, ``AWS_ACCESS_KEY_ID`` or ``AWS_ACCESS_KEY`` or ``EC2_ACCESS_KEY``, ``AWS_SECRET_ACCESS_KEY`` or ``AWS_SECRET_KEY`` or ``EC2_SECRET_KEY``, ``AWS_SECURITY_TOKEN`` or ``EC2_SECURITY_TOKEN``, ``AWS_REGION`` or ``EC2_REGION``, ``AWS_CA_BUNDLE``
- - Ansible uses the boto configuration file (typically ~/.boto) if no credentials are provided. See https://boto.readthedocs.io/en/latest/boto_config_tut.html
- - ``AWS_REGION`` or ``EC2_REGION`` can be typically be used to specify the AWS region, when required, but this can also be configured in the boto config file
+ - When no credentials are explicitly provided the AWS SDK (boto3) that Ansible uses will fall back to its configuration files (typically ``~/.aws/credentials``). See https://boto3.amazonaws.com/v1/documentation/api/latest/guide/credentials.html for more information.
+ - Modules based on the original AWS SDK (boto) may read their default configuration from different files. See https://boto.readthedocs.io/en/latest/boto_config_tut.html for more information.
+ - ``AWS_REGION`` or ``EC2_REGION`` can be typically be used to specify the AWS region, when required, but this can also be defined in the configuration files.
diff --git a/docs/community.aws.s3_logging_module.rst b/docs/community.aws.s3_logging_module.rst
index cba4b51503d..67762810882 100644
--- a/docs/community.aws.s3_logging_module.rst
+++ b/docs/community.aws.s3_logging_module.rst
@@ -25,8 +25,9 @@ Requirements
------------
The below requirements are needed on the host that executes this module.
-- python >= 2.6
-- boto
+- python >= 3.6
+- boto3 >= 1.15.0
+- botocore >= 1.18.0
Parameters
@@ -52,7 +53,7 @@ Parameters
|
- AWS access key. If not set then the value of the AWS_ACCESS_KEY_ID, AWS_ACCESS_KEY or EC2_ACCESS_KEY environment variable is used.
+ AWS access key . If not set then the value of the AWS_ACCESS_KEY_ID , AWS_ACCESS_KEY or EC2_ACCESS_KEY environment variable is used.
If profile is set this parameter is ignored.
Passing the aws_access_key and profile options at the same time has been deprecated and the options will be made mutually exclusive after 2022-06-01.
aliases: ec2_access_key, access_key
@@ -71,7 +72,7 @@ Parameters
|
The location of a CA Bundle to use when validating SSL certificates.
- Only used for boto3 based modules.
+ Not used by boto 2 based modules.
Note: The CA Bundle is read 'module' side and may need to be explicitly copied from the controller if not run locally.
|
@@ -104,7 +105,7 @@ Parameters
|
- AWS secret key. If not set then the value of the AWS_SECRET_ACCESS_KEY, AWS_SECRET_KEY, or EC2_SECRET_KEY environment variable is used.
+ AWS secret key . If not set then the value of the AWS_SECRET_ACCESS_KEY , AWS_SECRET_KEY , or EC2_SECRET_KEY environment variable is used.
If profile is set this parameter is ignored.
Passing the aws_secret_key and profile options at the same time has been deprecated and the options will be made mutually exclusive after 2022-06-01.
aliases: ec2_secret_key, secret_key
@@ -141,7 +142,7 @@ Parameters
|
|
- Url to use to connect to EC2 or your Eucalyptus cloud (by default the module will use EC2 endpoints). Ignored for modules where region is required. Must be specified for all other modules if region is not used. If not set then the value of the EC2_URL environment variable, if any, is used.
+ URL to use to connect to EC2 or your Eucalyptus cloud (by default the module will use EC2 endpoints). Ignored for modules where region is required. Must be specified for all other modules if region is not used. If not set then the value of the EC2_URL environment variable, if any, is used.
aliases: aws_endpoint_url, endpoint_url
|
@@ -173,7 +174,6 @@ Parameters
|
- Uses a boto profile. Only works with boto >= 2.24.0.
Using profile will override aws_access_key, aws_secret_key and security_token and support for passing them at the same time as profile has been deprecated.
aws_access_key, aws_secret_key and security_token will be made mutually exclusive with profile after 2022-06-01.
aliases: aws_profile
@@ -207,7 +207,7 @@ Parameters
|
|
- AWS STS security token. If not set then the value of the AWS_SECURITY_TOKEN or EC2_SECURITY_TOKEN environment variable is used.
+ AWS STS security token . If not set then the value of the AWS_SECURITY_TOKEN or EC2_SECURITY_TOKEN environment variable is used.
If profile is set this parameter is ignored.
Passing the security_token and profile options at the same time has been deprecated and the options will be made mutually exclusive after 2022-06-01.
aliases: aws_security_token, access_token
@@ -279,7 +279,7 @@ Parameters
|
- When set to "no", SSL certificates will not be validated for boto versions >= 2.6.0.
+ When set to "no", SSL certificates will not be validated for communication with the AWS APIs.
|
@@ -291,8 +291,9 @@ Notes
.. note::
- If parameters are not set within the module, the following environment variables can be used in decreasing order of precedence ``AWS_URL`` or ``EC2_URL``, ``AWS_PROFILE`` or ``AWS_DEFAULT_PROFILE``, ``AWS_ACCESS_KEY_ID`` or ``AWS_ACCESS_KEY`` or ``EC2_ACCESS_KEY``, ``AWS_SECRET_ACCESS_KEY`` or ``AWS_SECRET_KEY`` or ``EC2_SECRET_KEY``, ``AWS_SECURITY_TOKEN`` or ``EC2_SECURITY_TOKEN``, ``AWS_REGION`` or ``EC2_REGION``, ``AWS_CA_BUNDLE``
- - Ansible uses the boto configuration file (typically ~/.boto) if no credentials are provided. See https://boto.readthedocs.io/en/latest/boto_config_tut.html
- - ``AWS_REGION`` or ``EC2_REGION`` can be typically be used to specify the AWS region, when required, but this can also be configured in the boto config file
+ - When no credentials are explicitly provided the AWS SDK (boto3) that Ansible uses will fall back to its configuration files (typically ``~/.aws/credentials``). See https://boto3.amazonaws.com/v1/documentation/api/latest/guide/credentials.html for more information.
+ - Modules based on the original AWS SDK (boto) may read their default configuration from different files. See https://boto.readthedocs.io/en/latest/boto_config_tut.html for more information.
+ - ``AWS_REGION`` or ``EC2_REGION`` can be typically be used to specify the AWS region, when required, but this can also be defined in the configuration files.
diff --git a/docs/community.aws.s3_metrics_configuration_module.rst b/docs/community.aws.s3_metrics_configuration_module.rst
index 570d88bd6f3..449fd5d9b1f 100644
--- a/docs/community.aws.s3_metrics_configuration_module.rst
+++ b/docs/community.aws.s3_metrics_configuration_module.rst
@@ -25,8 +25,9 @@ Requirements
------------
The below requirements are needed on the host that executes this module.
-- python >= 2.6
-- boto
+- python >= 3.6
+- boto3 >= 1.15.0
+- botocore >= 1.18.0
Parameters
@@ -52,7 +53,7 @@ Parameters
|
- AWS access key. If not set then the value of the AWS_ACCESS_KEY_ID, AWS_ACCESS_KEY or EC2_ACCESS_KEY environment variable is used.
+ AWS access key . If not set then the value of the AWS_ACCESS_KEY_ID , AWS_ACCESS_KEY or EC2_ACCESS_KEY environment variable is used.
If profile is set this parameter is ignored.
Passing the aws_access_key and profile options at the same time has been deprecated and the options will be made mutually exclusive after 2022-06-01.
aliases: ec2_access_key, access_key
@@ -71,7 +72,7 @@ Parameters
|
The location of a CA Bundle to use when validating SSL certificates.
- Only used for boto3 based modules.
+ Not used by boto 2 based modules.
Note: The CA Bundle is read 'module' side and may need to be explicitly copied from the controller if not run locally.
|
@@ -104,7 +105,7 @@ Parameters
|
- AWS secret key. If not set then the value of the AWS_SECRET_ACCESS_KEY, AWS_SECRET_KEY, or EC2_SECRET_KEY environment variable is used.
+ AWS secret key . If not set then the value of the AWS_SECRET_ACCESS_KEY , AWS_SECRET_KEY , or EC2_SECRET_KEY environment variable is used.
If profile is set this parameter is ignored.
Passing the aws_secret_key and profile options at the same time has been deprecated and the options will be made mutually exclusive after 2022-06-01.
aliases: ec2_secret_key, secret_key
@@ -157,7 +158,7 @@ Parameters
|
|
- Url to use to connect to EC2 or your Eucalyptus cloud (by default the module will use EC2 endpoints). Ignored for modules where region is required. Must be specified for all other modules if region is not used. If not set then the value of the EC2_URL environment variable, if any, is used.
+ URL to use to connect to EC2 or your Eucalyptus cloud (by default the module will use EC2 endpoints). Ignored for modules where region is required. Must be specified for all other modules if region is not used. If not set then the value of the EC2_URL environment variable, if any, is used.
aliases: aws_endpoint_url, endpoint_url
|
@@ -220,7 +221,6 @@ Parameters
|
- Uses a boto profile. Only works with boto >= 2.24.0.
Using profile will override aws_access_key, aws_secret_key and security_token and support for passing them at the same time as profile has been deprecated.
aws_access_key, aws_secret_key and security_token will be made mutually exclusive with profile after 2022-06-01.
aliases: aws_profile
@@ -254,7 +254,7 @@ Parameters
|
|
- AWS STS security token. If not set then the value of the AWS_SECURITY_TOKEN or EC2_SECURITY_TOKEN environment variable is used.
+ AWS STS security token . If not set then the value of the AWS_SECURITY_TOKEN or EC2_SECURITY_TOKEN environment variable is used.
If profile is set this parameter is ignored.
Passing the security_token and profile options at the same time has been deprecated and the options will be made mutually exclusive after 2022-06-01.
aliases: aws_security_token, access_token
@@ -295,7 +295,7 @@ Parameters
|
- When set to "no", SSL certificates will not be validated for boto versions >= 2.6.0.
+ When set to "no", SSL certificates will not be validated for communication with the AWS APIs.
|
@@ -310,8 +310,9 @@ Notes
- To request metrics for the entire bucket, create a metrics configuration without a filter
- Metrics configurations are necessary only to enable request metric, bucket-level daily storage metrics are always turned on
- If parameters are not set within the module, the following environment variables can be used in decreasing order of precedence ``AWS_URL`` or ``EC2_URL``, ``AWS_PROFILE`` or ``AWS_DEFAULT_PROFILE``, ``AWS_ACCESS_KEY_ID`` or ``AWS_ACCESS_KEY`` or ``EC2_ACCESS_KEY``, ``AWS_SECRET_ACCESS_KEY`` or ``AWS_SECRET_KEY`` or ``EC2_SECRET_KEY``, ``AWS_SECURITY_TOKEN`` or ``EC2_SECURITY_TOKEN``, ``AWS_REGION`` or ``EC2_REGION``, ``AWS_CA_BUNDLE``
- - Ansible uses the boto configuration file (typically ~/.boto) if no credentials are provided. See https://boto.readthedocs.io/en/latest/boto_config_tut.html
- - ``AWS_REGION`` or ``EC2_REGION`` can be typically be used to specify the AWS region, when required, but this can also be configured in the boto config file
+ - When no credentials are explicitly provided the AWS SDK (boto3) that Ansible uses will fall back to its configuration files (typically ``~/.aws/credentials``). See https://boto3.amazonaws.com/v1/documentation/api/latest/guide/credentials.html for more information.
+ - Modules based on the original AWS SDK (boto) may read their default configuration from different files. See https://boto.readthedocs.io/en/latest/boto_config_tut.html for more information.
+ - ``AWS_REGION`` or ``EC2_REGION`` can be typically be used to specify the AWS region, when required, but this can also be defined in the configuration files.
diff --git a/docs/community.aws.s3_sync_module.rst b/docs/community.aws.s3_sync_module.rst
index bc674a64e25..348639b2c2e 100644
--- a/docs/community.aws.s3_sync_module.rst
+++ b/docs/community.aws.s3_sync_module.rst
@@ -25,11 +25,9 @@ Requirements
------------
The below requirements are needed on the host that executes this module.
-- boto
-- boto3 >= 1.4.4
-- botocore
-- python >= 2.6
-- python-dateutil
+- python >= 3.6
+- boto3 >= 1.15.0
+- botocore >= 1.18.0
Parameters
@@ -55,7 +53,7 @@ Parameters
|
- AWS access key. If not set then the value of the AWS_ACCESS_KEY_ID, AWS_ACCESS_KEY or EC2_ACCESS_KEY environment variable is used.
+ AWS access key . If not set then the value of the AWS_ACCESS_KEY_ID , AWS_ACCESS_KEY or EC2_ACCESS_KEY environment variable is used.
If profile is set this parameter is ignored.
Passing the aws_access_key and profile options at the same time has been deprecated and the options will be made mutually exclusive after 2022-06-01.
aliases: ec2_access_key, access_key
@@ -74,7 +72,7 @@ Parameters
|
The location of a CA Bundle to use when validating SSL certificates.
- Only used for boto3 based modules.
+ Not used by boto 2 based modules.
Note: The CA Bundle is read 'module' side and may need to be explicitly copied from the controller if not run locally.
|
@@ -107,7 +105,7 @@ Parameters
|
- AWS secret key. If not set then the value of the AWS_SECRET_ACCESS_KEY, AWS_SECRET_KEY, or EC2_SECRET_KEY environment variable is used.
+ AWS secret key . If not set then the value of the AWS_SECRET_ACCESS_KEY , AWS_SECRET_KEY , or EC2_SECRET_KEY environment variable is used.
If profile is set this parameter is ignored.
Passing the aws_secret_key and profile options at the same time has been deprecated and the options will be made mutually exclusive after 2022-06-01.
aliases: ec2_secret_key, secret_key
@@ -195,7 +193,7 @@ Parameters
|
|
- Url to use to connect to EC2 or your Eucalyptus cloud (by default the module will use EC2 endpoints). Ignored for modules where region is required. Must be specified for all other modules if region is not used. If not set then the value of the EC2_URL environment variable, if any, is used.
+ URL to use to connect to EC2 or your Eucalyptus cloud (by default the module will use EC2 endpoints). Ignored for modules where region is required. Must be specified for all other modules if region is not used. If not set then the value of the EC2_URL environment variable, if any, is used.
aliases: aws_endpoint_url, endpoint_url
|
@@ -360,7 +358,6 @@ Parameters
|
- Uses a boto profile. Only works with boto >= 2.24.0.
Using profile will override aws_access_key, aws_secret_key and security_token and support for passing them at the same time as profile has been deprecated.
aws_access_key, aws_secret_key and security_token will be made mutually exclusive with profile after 2022-06-01.
aliases: aws_profile
@@ -409,7 +406,7 @@ Parameters
|
|
- AWS STS security token. If not set then the value of the AWS_SECURITY_TOKEN or EC2_SECURITY_TOKEN environment variable is used.
+ AWS STS security token . If not set then the value of the AWS_SECURITY_TOKEN or EC2_SECURITY_TOKEN environment variable is used.
If profile is set this parameter is ignored.
Passing the security_token and profile options at the same time has been deprecated and the options will be made mutually exclusive after 2022-06-01.
aliases: aws_security_token, access_token
@@ -457,7 +454,7 @@ Parameters
|
- When set to "no", SSL certificates will not be validated for boto versions >= 2.6.0.
+ When set to "no", SSL certificates will not be validated for communication with the AWS APIs.
|
@@ -469,8 +466,9 @@ Notes
.. note::
- If parameters are not set within the module, the following environment variables can be used in decreasing order of precedence ``AWS_URL`` or ``EC2_URL``, ``AWS_PROFILE`` or ``AWS_DEFAULT_PROFILE``, ``AWS_ACCESS_KEY_ID`` or ``AWS_ACCESS_KEY`` or ``EC2_ACCESS_KEY``, ``AWS_SECRET_ACCESS_KEY`` or ``AWS_SECRET_KEY`` or ``EC2_SECRET_KEY``, ``AWS_SECURITY_TOKEN`` or ``EC2_SECURITY_TOKEN``, ``AWS_REGION`` or ``EC2_REGION``, ``AWS_CA_BUNDLE``
- - Ansible uses the boto configuration file (typically ~/.boto) if no credentials are provided. See https://boto.readthedocs.io/en/latest/boto_config_tut.html
- - ``AWS_REGION`` or ``EC2_REGION`` can be typically be used to specify the AWS region, when required, but this can also be configured in the boto config file
+ - When no credentials are explicitly provided the AWS SDK (boto3) that Ansible uses will fall back to its configuration files (typically ``~/.aws/credentials``). See https://boto3.amazonaws.com/v1/documentation/api/latest/guide/credentials.html for more information.
+ - Modules based on the original AWS SDK (boto) may read their default configuration from different files. See https://boto.readthedocs.io/en/latest/boto_config_tut.html for more information.
+ - ``AWS_REGION`` or ``EC2_REGION`` can be typically be used to specify the AWS region, when required, but this can also be defined in the configuration files.
@@ -490,6 +488,11 @@ Examples
file_root: roles/s3/files/
storage_class: GLACIER
+ - name: basic individual file upload
+ community.aws.s3_sync:
+ bucket: tedder
+ file_root: roles/s3/files/file_name
+
- name: all the options
community.aws.s3_sync:
bucket: tedder
diff --git a/docs/community.aws.s3_website_module.rst b/docs/community.aws.s3_website_module.rst
index 356cf0315ca..90078b3afc3 100644
--- a/docs/community.aws.s3_website_module.rst
+++ b/docs/community.aws.s3_website_module.rst
@@ -25,9 +25,9 @@ Requirements
------------
The below requirements are needed on the host that executes this module.
-- boto
-- boto3
-- python >= 2.6
+- python >= 3.6
+- boto3 >= 1.15.0
+- botocore >= 1.18.0
Parameters
@@ -53,7 +53,7 @@ Parameters
|
- AWS access key. If not set then the value of the AWS_ACCESS_KEY_ID, AWS_ACCESS_KEY or EC2_ACCESS_KEY environment variable is used.
+ AWS access key . If not set then the value of the AWS_ACCESS_KEY_ID , AWS_ACCESS_KEY or EC2_ACCESS_KEY environment variable is used.
If profile is set this parameter is ignored.
Passing the aws_access_key and profile options at the same time has been deprecated and the options will be made mutually exclusive after 2022-06-01.
aliases: ec2_access_key, access_key
@@ -72,7 +72,7 @@ Parameters
|
The location of a CA Bundle to use when validating SSL certificates.
- Only used for boto3 based modules.
+ Not used by boto 2 based modules.
Note: The CA Bundle is read 'module' side and may need to be explicitly copied from the controller if not run locally.
|
@@ -105,7 +105,7 @@ Parameters
|
- AWS secret key. If not set then the value of the AWS_SECRET_ACCESS_KEY, AWS_SECRET_KEY, or EC2_SECRET_KEY environment variable is used.
+ AWS secret key . If not set then the value of the AWS_SECRET_ACCESS_KEY , AWS_SECRET_KEY , or EC2_SECRET_KEY environment variable is used.
If profile is set this parameter is ignored.
Passing the aws_secret_key and profile options at the same time has been deprecated and the options will be made mutually exclusive after 2022-06-01.
aliases: ec2_secret_key, secret_key
@@ -142,7 +142,7 @@ Parameters
|
|
- Url to use to connect to EC2 or your Eucalyptus cloud (by default the module will use EC2 endpoints). Ignored for modules where region is required. Must be specified for all other modules if region is not used. If not set then the value of the EC2_URL environment variable, if any, is used.
+ URL to use to connect to EC2 or your Eucalyptus cloud (by default the module will use EC2 endpoints). Ignored for modules where region is required. Must be specified for all other modules if region is not used. If not set then the value of the EC2_URL environment variable, if any, is used.
aliases: aws_endpoint_url, endpoint_url
|
@@ -189,7 +189,6 @@ Parameters
|
- Uses a boto profile. Only works with boto >= 2.24.0.
Using profile will override aws_access_key, aws_secret_key and security_token and support for passing them at the same time as profile has been deprecated.
aws_access_key, aws_secret_key and security_token will be made mutually exclusive with profile after 2022-06-01.
aliases: aws_profile
@@ -238,7 +237,7 @@ Parameters
|
|
- AWS STS security token. If not set then the value of the AWS_SECURITY_TOKEN or EC2_SECURITY_TOKEN environment variable is used.
+ AWS STS security token . If not set then the value of the AWS_SECURITY_TOKEN or EC2_SECURITY_TOKEN environment variable is used.
If profile is set this parameter is ignored.
Passing the security_token and profile options at the same time has been deprecated and the options will be made mutually exclusive after 2022-06-01.
aliases: aws_security_token, access_token
@@ -296,7 +295,7 @@ Parameters
|
- When set to "no", SSL certificates will not be validated for boto versions >= 2.6.0.
+ When set to "no", SSL certificates will not be validated for communication with the AWS APIs.
|
@@ -308,8 +307,9 @@ Notes
.. note::
- If parameters are not set within the module, the following environment variables can be used in decreasing order of precedence ``AWS_URL`` or ``EC2_URL``, ``AWS_PROFILE`` or ``AWS_DEFAULT_PROFILE``, ``AWS_ACCESS_KEY_ID`` or ``AWS_ACCESS_KEY`` or ``EC2_ACCESS_KEY``, ``AWS_SECRET_ACCESS_KEY`` or ``AWS_SECRET_KEY`` or ``EC2_SECRET_KEY``, ``AWS_SECURITY_TOKEN`` or ``EC2_SECURITY_TOKEN``, ``AWS_REGION`` or ``EC2_REGION``, ``AWS_CA_BUNDLE``
- - Ansible uses the boto configuration file (typically ~/.boto) if no credentials are provided. See https://boto.readthedocs.io/en/latest/boto_config_tut.html
- - ``AWS_REGION`` or ``EC2_REGION`` can be typically be used to specify the AWS region, when required, but this can also be configured in the boto config file
+ - When no credentials are explicitly provided the AWS SDK (boto3) that Ansible uses will fall back to its configuration files (typically ``~/.aws/credentials``). See https://boto3.amazonaws.com/v1/documentation/api/latest/guide/credentials.html for more information.
+ - Modules based on the original AWS SDK (boto) may read their default configuration from different files. See https://boto.readthedocs.io/en/latest/boto_config_tut.html for more information.
+ - ``AWS_REGION`` or ``EC2_REGION`` can be typically be used to specify the AWS region, when required, but this can also be defined in the configuration files.
diff --git a/docs/community.aws.sns_module.rst b/docs/community.aws.sns_module.rst
index 83d5165b902..177cf3c3452 100644
--- a/docs/community.aws.sns_module.rst
+++ b/docs/community.aws.sns_module.rst
@@ -25,10 +25,9 @@ Requirements
------------
The below requirements are needed on the host that executes this module.
-- boto
-- boto3
-- botocore
-- python >= 2.6
+- python >= 3.6
+- boto3 >= 1.15.0
+- botocore >= 1.18.0
Parameters
@@ -69,7 +68,7 @@ Parameters
|
- AWS access key. If not set then the value of the AWS_ACCESS_KEY_ID, AWS_ACCESS_KEY or EC2_ACCESS_KEY environment variable is used.
+ AWS access key . If not set then the value of the AWS_ACCESS_KEY_ID , AWS_ACCESS_KEY or EC2_ACCESS_KEY environment variable is used.
If profile is set this parameter is ignored.
Passing the aws_access_key and profile options at the same time has been deprecated and the options will be made mutually exclusive after 2022-06-01.
aliases: ec2_access_key, access_key
@@ -88,7 +87,7 @@ Parameters
|
The location of a CA Bundle to use when validating SSL certificates.
- Only used for boto3 based modules.
+ Not used by boto 2 based modules.
Note: The CA Bundle is read 'module' side and may need to be explicitly copied from the controller if not run locally.
|
@@ -121,7 +120,7 @@ Parameters
|
- AWS secret key. If not set then the value of the AWS_SECRET_ACCESS_KEY, AWS_SECRET_KEY, or EC2_SECRET_KEY environment variable is used.
+ AWS secret key . If not set then the value of the AWS_SECRET_ACCESS_KEY , AWS_SECRET_KEY , or EC2_SECRET_KEY environment variable is used.
If profile is set this parameter is ignored.
Passing the aws_secret_key and profile options at the same time has been deprecated and the options will be made mutually exclusive after 2022-06-01.
aliases: ec2_secret_key, secret_key
@@ -158,7 +157,7 @@ Parameters
|
|
- Url to use to connect to EC2 or your Eucalyptus cloud (by default the module will use EC2 endpoints). Ignored for modules where region is required. Must be specified for all other modules if region is not used. If not set then the value of the EC2_URL environment variable, if any, is used.
+ URL to use to connect to EC2 or your Eucalyptus cloud (by default the module will use EC2 endpoints). Ignored for modules where region is required. Must be specified for all other modules if region is not used. If not set then the value of the EC2_URL environment variable, if any, is used.
aliases: aws_endpoint_url, endpoint_url
|
@@ -303,7 +302,6 @@ Parameters
|
- Uses a boto profile. Only works with boto >= 2.24.0.
Using profile will override aws_access_key, aws_secret_key and security_token and support for passing them at the same time as profile has been deprecated.
aws_access_key, aws_secret_key and security_token will be made mutually exclusive with profile after 2022-06-01.
aliases: aws_profile
@@ -337,7 +335,7 @@ Parameters
|
|
- AWS STS security token. If not set then the value of the AWS_SECURITY_TOKEN or EC2_SECURITY_TOKEN environment variable is used.
+ AWS STS security token . If not set then the value of the AWS_SECURITY_TOKEN or EC2_SECURITY_TOKEN environment variable is used.
If profile is set this parameter is ignored.
Passing the security_token and profile options at the same time has been deprecated and the options will be made mutually exclusive after 2022-06-01.
aliases: aws_security_token, access_token
@@ -420,7 +418,7 @@ Parameters
|
- When set to "no", SSL certificates will not be validated for boto versions >= 2.6.0.
+ When set to "no", SSL certificates will not be validated for communication with the AWS APIs.
|
@@ -432,8 +430,9 @@ Notes
.. note::
- If parameters are not set within the module, the following environment variables can be used in decreasing order of precedence ``AWS_URL`` or ``EC2_URL``, ``AWS_PROFILE`` or ``AWS_DEFAULT_PROFILE``, ``AWS_ACCESS_KEY_ID`` or ``AWS_ACCESS_KEY`` or ``EC2_ACCESS_KEY``, ``AWS_SECRET_ACCESS_KEY`` or ``AWS_SECRET_KEY`` or ``EC2_SECRET_KEY``, ``AWS_SECURITY_TOKEN`` or ``EC2_SECURITY_TOKEN``, ``AWS_REGION`` or ``EC2_REGION``, ``AWS_CA_BUNDLE``
- - Ansible uses the boto configuration file (typically ~/.boto) if no credentials are provided. See https://boto.readthedocs.io/en/latest/boto_config_tut.html
- - ``AWS_REGION`` or ``EC2_REGION`` can be typically be used to specify the AWS region, when required, but this can also be configured in the boto config file
+ - When no credentials are explicitly provided the AWS SDK (boto3) that Ansible uses will fall back to its configuration files (typically ``~/.aws/credentials``). See https://boto3.amazonaws.com/v1/documentation/api/latest/guide/credentials.html for more information.
+ - Modules based on the original AWS SDK (boto) may read their default configuration from different files. See https://boto.readthedocs.io/en/latest/boto_config_tut.html for more information.
+ - ``AWS_REGION`` or ``EC2_REGION`` can be typically be used to specify the AWS region, when required, but this can also be defined in the configuration files.
diff --git a/docs/community.aws.sns_topic_module.rst b/docs/community.aws.sns_topic_module.rst
index 3cf7abcd32f..321a1b958ec 100644
--- a/docs/community.aws.sns_topic_module.rst
+++ b/docs/community.aws.sns_topic_module.rst
@@ -26,8 +26,9 @@ Requirements
------------
The below requirements are needed on the host that executes this module.
-- boto
-- python >= 2.6
+- python >= 3.6
+- boto3 >= 1.15.0
+- botocore >= 1.18.0
Parameters
@@ -53,7 +54,7 @@ Parameters
|
- AWS access key. If not set then the value of the AWS_ACCESS_KEY_ID, AWS_ACCESS_KEY or EC2_ACCESS_KEY environment variable is used.
+ AWS access key . If not set then the value of the AWS_ACCESS_KEY_ID , AWS_ACCESS_KEY or EC2_ACCESS_KEY environment variable is used.
If profile is set this parameter is ignored.
Passing the aws_access_key and profile options at the same time has been deprecated and the options will be made mutually exclusive after 2022-06-01.
aliases: ec2_access_key, access_key
@@ -72,7 +73,7 @@ Parameters
|
The location of a CA Bundle to use when validating SSL certificates.
- Only used for boto3 based modules.
+ Not used by boto 2 based modules.
Note: The CA Bundle is read 'module' side and may need to be explicitly copied from the controller if not run locally.
|
@@ -105,7 +106,7 @@ Parameters
|
- AWS secret key. If not set then the value of the AWS_SECRET_ACCESS_KEY, AWS_SECRET_KEY, or EC2_SECRET_KEY environment variable is used.
+ AWS secret key . If not set then the value of the AWS_SECRET_ACCESS_KEY , AWS_SECRET_KEY , or EC2_SECRET_KEY environment variable is used.
If profile is set this parameter is ignored.
Passing the aws_secret_key and profile options at the same time has been deprecated and the options will be made mutually exclusive after 2022-06-01.
aliases: ec2_secret_key, secret_key
@@ -172,7 +173,7 @@ Parameters
|
|
- Url to use to connect to EC2 or your Eucalyptus cloud (by default the module will use EC2 endpoints). Ignored for modules where region is required. Must be specified for all other modules if region is not used. If not set then the value of the EC2_URL environment variable, if any, is used.
+ URL to use to connect to EC2 or your Eucalyptus cloud (by default the module will use EC2 endpoints). Ignored for modules where region is required. Must be specified for all other modules if region is not used. If not set then the value of the EC2_URL environment variable, if any, is used.
aliases: aws_endpoint_url, endpoint_url
|
@@ -219,7 +220,6 @@ Parameters
|
- Uses a boto profile. Only works with boto >= 2.24.0.
Using profile will override aws_access_key, aws_secret_key and security_token and support for passing them at the same time as profile has been deprecated.
aws_access_key, aws_secret_key and security_token will be made mutually exclusive with profile after 2022-06-01.
aliases: aws_profile
@@ -272,7 +272,7 @@ Parameters
|
|
- AWS STS security token. If not set then the value of the AWS_SECURITY_TOKEN or EC2_SECURITY_TOKEN environment variable is used.
+ AWS STS security token . If not set then the value of the AWS_SECURITY_TOKEN or EC2_SECURITY_TOKEN environment variable is used.
If profile is set this parameter is ignored.
Passing the security_token and profile options at the same time has been deprecated and the options will be made mutually exclusive after 2022-06-01.
aliases: aws_security_token, access_token
@@ -349,6 +349,26 @@ Parameters
|
+
+
+
+ topic_type
+
+
+ string
+
+ added in 2.0.0
+ |
+
+ Choices:
+ standard ←
+ - fifo
+
+ |
+
+ The type of topic that should be created. Either Standard for FIFO (first-in, first-out)
+ |
+
@@ -365,7 +385,7 @@ Parameters
|
- When set to "no", SSL certificates will not be validated for boto versions >= 2.6.0.
+ When set to "no", SSL certificates will not be validated for communication with the AWS APIs.
|
@@ -377,8 +397,9 @@ Notes
.. note::
- If parameters are not set within the module, the following environment variables can be used in decreasing order of precedence ``AWS_URL`` or ``EC2_URL``, ``AWS_PROFILE`` or ``AWS_DEFAULT_PROFILE``, ``AWS_ACCESS_KEY_ID`` or ``AWS_ACCESS_KEY`` or ``EC2_ACCESS_KEY``, ``AWS_SECRET_ACCESS_KEY`` or ``AWS_SECRET_KEY`` or ``EC2_SECRET_KEY``, ``AWS_SECURITY_TOKEN`` or ``EC2_SECURITY_TOKEN``, ``AWS_REGION`` or ``EC2_REGION``, ``AWS_CA_BUNDLE``
- - Ansible uses the boto configuration file (typically ~/.boto) if no credentials are provided. See https://boto.readthedocs.io/en/latest/boto_config_tut.html
- - ``AWS_REGION`` or ``EC2_REGION`` can be typically be used to specify the AWS region, when required, but this can also be configured in the boto config file
+ - When no credentials are explicitly provided the AWS SDK (boto3) that Ansible uses will fall back to its configuration files (typically ``~/.aws/credentials``). See https://boto3.amazonaws.com/v1/documentation/api/latest/guide/credentials.html for more information.
+ - Modules based on the original AWS SDK (boto) may read their default configuration from different files. See https://boto.readthedocs.io/en/latest/boto_config_tut.html for more information.
+ - ``AWS_REGION`` or ``EC2_REGION`` can be typically be used to specify the AWS region, when required, but this can also be defined in the configuration files.
diff --git a/docs/community.aws.sqs_queue_module.rst b/docs/community.aws.sqs_queue_module.rst
index 341f9ca2fc2..e32121739cb 100644
--- a/docs/community.aws.sqs_queue_module.rst
+++ b/docs/community.aws.sqs_queue_module.rst
@@ -26,9 +26,9 @@ Requirements
------------
The below requirements are needed on the host that executes this module.
-- boto
-- boto3
-- python >= 2.6
+- python >= 3.6
+- boto3 >= 1.15.0
+- botocore >= 1.18.0
Parameters
@@ -54,7 +54,7 @@ Parameters
|
- AWS access key. If not set then the value of the AWS_ACCESS_KEY_ID, AWS_ACCESS_KEY or EC2_ACCESS_KEY environment variable is used.
+ AWS access key . If not set then the value of the AWS_ACCESS_KEY_ID , AWS_ACCESS_KEY or EC2_ACCESS_KEY environment variable is used.
If profile is set this parameter is ignored.
Passing the aws_access_key and profile options at the same time has been deprecated and the options will be made mutually exclusive after 2022-06-01.
aliases: ec2_access_key, access_key
@@ -73,7 +73,7 @@ Parameters
|
The location of a CA Bundle to use when validating SSL certificates.
- Only used for boto3 based modules.
+ Not used by boto 2 based modules.
Note: The CA Bundle is read 'module' side and may need to be explicitly copied from the controller if not run locally.
|
@@ -106,7 +106,7 @@ Parameters
|
- AWS secret key. If not set then the value of the AWS_SECRET_ACCESS_KEY, AWS_SECRET_KEY, or EC2_SECRET_KEY environment variable is used.
+ AWS secret key . If not set then the value of the AWS_SECRET_ACCESS_KEY , AWS_SECRET_KEY , or EC2_SECRET_KEY environment variable is used.
If profile is set this parameter is ignored.
Passing the aws_secret_key and profile options at the same time has been deprecated and the options will be made mutually exclusive after 2022-06-01.
aliases: ec2_secret_key, secret_key
@@ -179,7 +179,7 @@ Parameters
|
|
- Url to use to connect to EC2 or your Eucalyptus cloud (by default the module will use EC2 endpoints). Ignored for modules where region is required. Must be specified for all other modules if region is not used. If not set then the value of the EC2_URL environment variable, if any, is used.
+ URL to use to connect to EC2 or your Eucalyptus cloud (by default the module will use EC2 endpoints). Ignored for modules where region is required. Must be specified for all other modules if region is not used. If not set then the value of the EC2_URL environment variable, if any, is used.
aliases: aws_endpoint_url, endpoint_url
|
@@ -287,7 +287,6 @@ Parameters
|
- Uses a boto profile. Only works with boto >= 2.24.0.
Using profile will override aws_access_key, aws_secret_key and security_token and support for passing them at the same time as profile has been deprecated.
aws_access_key, aws_secret_key and security_token will be made mutually exclusive with profile after 2022-06-01.
aliases: aws_profile
@@ -391,7 +390,7 @@ Parameters
|
|
- AWS STS security token. If not set then the value of the AWS_SECURITY_TOKEN or EC2_SECURITY_TOKEN environment variable is used.
+ AWS STS security token . If not set then the value of the AWS_SECURITY_TOKEN or EC2_SECURITY_TOKEN environment variable is used.
If profile is set this parameter is ignored.
Passing the security_token and profile options at the same time has been deprecated and the options will be made mutually exclusive after 2022-06-01.
aliases: aws_security_token, access_token
@@ -428,7 +427,7 @@ Parameters
|
|
- Tag dict to apply to the queue (requires botocore 1.5.40 or above).
+ Tag dict to apply to the queue.
To remove all tags set tags={} and purge_tags=true.
|
@@ -448,7 +447,7 @@ Parameters
- When set to "no", SSL certificates will not be validated for boto versions >= 2.6.0.
+ When set to "no", SSL certificates will not be validated for communication with the AWS APIs.
|
@@ -476,8 +475,9 @@ Notes
.. note::
- If parameters are not set within the module, the following environment variables can be used in decreasing order of precedence ``AWS_URL`` or ``EC2_URL``, ``AWS_PROFILE`` or ``AWS_DEFAULT_PROFILE``, ``AWS_ACCESS_KEY_ID`` or ``AWS_ACCESS_KEY`` or ``EC2_ACCESS_KEY``, ``AWS_SECRET_ACCESS_KEY`` or ``AWS_SECRET_KEY`` or ``EC2_SECRET_KEY``, ``AWS_SECURITY_TOKEN`` or ``EC2_SECURITY_TOKEN``, ``AWS_REGION`` or ``EC2_REGION``, ``AWS_CA_BUNDLE``
- - Ansible uses the boto configuration file (typically ~/.boto) if no credentials are provided. See https://boto.readthedocs.io/en/latest/boto_config_tut.html
- - ``AWS_REGION`` or ``EC2_REGION`` can be typically be used to specify the AWS region, when required, but this can also be configured in the boto config file
+ - When no credentials are explicitly provided the AWS SDK (boto3) that Ansible uses will fall back to its configuration files (typically ``~/.aws/credentials``). See https://boto3.amazonaws.com/v1/documentation/api/latest/guide/credentials.html for more information.
+ - Modules based on the original AWS SDK (boto) may read their default configuration from different files. See https://boto.readthedocs.io/en/latest/boto_config_tut.html for more information.
+ - ``AWS_REGION`` or ``EC2_REGION`` can be typically be used to specify the AWS region, when required, but this can also be defined in the configuration files.
diff --git a/docs/community.aws.sts_assume_role_module.rst b/docs/community.aws.sts_assume_role_module.rst
index 16b197c2bce..bfab5056a22 100644
--- a/docs/community.aws.sts_assume_role_module.rst
+++ b/docs/community.aws.sts_assume_role_module.rst
@@ -25,10 +25,9 @@ Requirements
------------
The below requirements are needed on the host that executes this module.
-- boto
-- boto3
-- botocore
-- python >= 2.6
+- python >= 3.6
+- boto3 >= 1.15.0
+- botocore >= 1.18.0
Parameters
@@ -54,7 +53,7 @@ Parameters
|
- AWS access key. If not set then the value of the AWS_ACCESS_KEY_ID, AWS_ACCESS_KEY or EC2_ACCESS_KEY environment variable is used.
+ AWS access key . If not set then the value of the AWS_ACCESS_KEY_ID , AWS_ACCESS_KEY or EC2_ACCESS_KEY environment variable is used.
If profile is set this parameter is ignored.
Passing the aws_access_key and profile options at the same time has been deprecated and the options will be made mutually exclusive after 2022-06-01.
aliases: ec2_access_key, access_key
@@ -73,7 +72,7 @@ Parameters
|
The location of a CA Bundle to use when validating SSL certificates.
- Only used for boto3 based modules.
+ Not used by boto 2 based modules.
Note: The CA Bundle is read 'module' side and may need to be explicitly copied from the controller if not run locally.
|
@@ -106,7 +105,7 @@ Parameters
|
- AWS secret key. If not set then the value of the AWS_SECRET_ACCESS_KEY, AWS_SECRET_KEY, or EC2_SECRET_KEY environment variable is used.
+ AWS secret key . If not set then the value of the AWS_SECRET_ACCESS_KEY , AWS_SECRET_KEY , or EC2_SECRET_KEY environment variable is used.
If profile is set this parameter is ignored.
Passing the aws_secret_key and profile options at the same time has been deprecated and the options will be made mutually exclusive after 2022-06-01.
aliases: ec2_secret_key, secret_key
@@ -160,7 +159,7 @@ Parameters
|
|
- Url to use to connect to EC2 or your Eucalyptus cloud (by default the module will use EC2 endpoints). Ignored for modules where region is required. Must be specified for all other modules if region is not used. If not set then the value of the EC2_URL environment variable, if any, is used.
+ URL to use to connect to EC2 or your Eucalyptus cloud (by default the module will use EC2 endpoints). Ignored for modules where region is required. Must be specified for all other modules if region is not used. If not set then the value of the EC2_URL environment variable, if any, is used.
aliases: aws_endpoint_url, endpoint_url
|
@@ -236,7 +235,6 @@ Parameters
|
- Uses a boto profile. Only works with boto >= 2.24.0.
Using profile will override aws_access_key, aws_secret_key and security_token and support for passing them at the same time as profile has been deprecated.
aws_access_key, aws_secret_key and security_token will be made mutually exclusive with profile after 2022-06-01.
aliases: aws_profile
@@ -302,7 +300,7 @@ Parameters
|
|
- AWS STS security token. If not set then the value of the AWS_SECURITY_TOKEN or EC2_SECURITY_TOKEN environment variable is used.
+ AWS STS security token . If not set then the value of the AWS_SECURITY_TOKEN or EC2_SECURITY_TOKEN environment variable is used.
If profile is set this parameter is ignored.
Passing the security_token and profile options at the same time has been deprecated and the options will be made mutually exclusive after 2022-06-01.
aliases: aws_security_token, access_token
@@ -324,7 +322,7 @@ Parameters
|
- When set to "no", SSL certificates will not be validated for boto versions >= 2.6.0.
+ When set to "no", SSL certificates will not be validated for communication with the AWS APIs.
|
@@ -337,8 +335,9 @@ Notes
.. note::
- In order to use the assumed role in a following playbook task you must pass the access_key, access_secret and access_token.
- If parameters are not set within the module, the following environment variables can be used in decreasing order of precedence ``AWS_URL`` or ``EC2_URL``, ``AWS_PROFILE`` or ``AWS_DEFAULT_PROFILE``, ``AWS_ACCESS_KEY_ID`` or ``AWS_ACCESS_KEY`` or ``EC2_ACCESS_KEY``, ``AWS_SECRET_ACCESS_KEY`` or ``AWS_SECRET_KEY`` or ``EC2_SECRET_KEY``, ``AWS_SECURITY_TOKEN`` or ``EC2_SECURITY_TOKEN``, ``AWS_REGION`` or ``EC2_REGION``, ``AWS_CA_BUNDLE``
- - Ansible uses the boto configuration file (typically ~/.boto) if no credentials are provided. See https://boto.readthedocs.io/en/latest/boto_config_tut.html
- - ``AWS_REGION`` or ``EC2_REGION`` can be typically be used to specify the AWS region, when required, but this can also be configured in the boto config file
+ - When no credentials are explicitly provided the AWS SDK (boto3) that Ansible uses will fall back to its configuration files (typically ``~/.aws/credentials``). See https://boto3.amazonaws.com/v1/documentation/api/latest/guide/credentials.html for more information.
+ - Modules based on the original AWS SDK (boto) may read their default configuration from different files. See https://boto.readthedocs.io/en/latest/boto_config_tut.html for more information.
+ - ``AWS_REGION`` or ``EC2_REGION`` can be typically be used to specify the AWS region, when required, but this can also be defined in the configuration files.
diff --git a/docs/community.aws.sts_session_token_module.rst b/docs/community.aws.sts_session_token_module.rst
index 26dae630d73..0a9b8e9c3a5 100644
--- a/docs/community.aws.sts_session_token_module.rst
+++ b/docs/community.aws.sts_session_token_module.rst
@@ -25,10 +25,9 @@ Requirements
------------
The below requirements are needed on the host that executes this module.
-- boto
-- boto3
-- botocore
-- python >= 2.6
+- python >= 3.6
+- boto3 >= 1.15.0
+- botocore >= 1.18.0
Parameters
@@ -54,7 +53,7 @@ Parameters
|
- AWS access key. If not set then the value of the AWS_ACCESS_KEY_ID, AWS_ACCESS_KEY or EC2_ACCESS_KEY environment variable is used.
+ AWS access key . If not set then the value of the AWS_ACCESS_KEY_ID , AWS_ACCESS_KEY or EC2_ACCESS_KEY environment variable is used.
If profile is set this parameter is ignored.
Passing the aws_access_key and profile options at the same time has been deprecated and the options will be made mutually exclusive after 2022-06-01.
aliases: ec2_access_key, access_key
@@ -73,7 +72,7 @@ Parameters
|
The location of a CA Bundle to use when validating SSL certificates.
- Only used for boto3 based modules.
+ Not used by boto 2 based modules.
Note: The CA Bundle is read 'module' side and may need to be explicitly copied from the controller if not run locally.
|
@@ -106,7 +105,7 @@ Parameters
|
- AWS secret key. If not set then the value of the AWS_SECRET_ACCESS_KEY, AWS_SECRET_KEY, or EC2_SECRET_KEY environment variable is used.
+ AWS secret key . If not set then the value of the AWS_SECRET_ACCESS_KEY , AWS_SECRET_KEY , or EC2_SECRET_KEY environment variable is used.
If profile is set this parameter is ignored.
Passing the aws_secret_key and profile options at the same time has been deprecated and the options will be made mutually exclusive after 2022-06-01.
aliases: ec2_secret_key, secret_key
@@ -158,7 +157,7 @@ Parameters
|
|
- Url to use to connect to EC2 or your Eucalyptus cloud (by default the module will use EC2 endpoints). Ignored for modules where region is required. Must be specified for all other modules if region is not used. If not set then the value of the EC2_URL environment variable, if any, is used.
+ URL to use to connect to EC2 or your Eucalyptus cloud (by default the module will use EC2 endpoints). Ignored for modules where region is required. Must be specified for all other modules if region is not used. If not set then the value of the EC2_URL environment variable, if any, is used.
aliases: aws_endpoint_url, endpoint_url
|
@@ -204,7 +203,6 @@ Parameters
|
- Uses a boto profile. Only works with boto >= 2.24.0.
Using profile will override aws_access_key, aws_secret_key and security_token and support for passing them at the same time as profile has been deprecated.
aws_access_key, aws_secret_key and security_token will be made mutually exclusive with profile after 2022-06-01.
aliases: aws_profile
@@ -238,7 +236,7 @@ Parameters
|
|
- AWS STS security token. If not set then the value of the AWS_SECURITY_TOKEN or EC2_SECURITY_TOKEN environment variable is used.
+ AWS STS security token . If not set then the value of the AWS_SECURITY_TOKEN or EC2_SECURITY_TOKEN environment variable is used.
If profile is set this parameter is ignored.
Passing the security_token and profile options at the same time has been deprecated and the options will be made mutually exclusive after 2022-06-01.
aliases: aws_security_token, access_token
@@ -260,7 +258,7 @@ Parameters
|
- When set to "no", SSL certificates will not be validated for boto versions >= 2.6.0.
+ When set to "no", SSL certificates will not be validated for communication with the AWS APIs.
|
@@ -273,8 +271,9 @@ Notes
.. note::
- In order to use the session token in a following playbook task you must pass the *access_key*, *access_secret* and *access_token*.
- If parameters are not set within the module, the following environment variables can be used in decreasing order of precedence ``AWS_URL`` or ``EC2_URL``, ``AWS_PROFILE`` or ``AWS_DEFAULT_PROFILE``, ``AWS_ACCESS_KEY_ID`` or ``AWS_ACCESS_KEY`` or ``EC2_ACCESS_KEY``, ``AWS_SECRET_ACCESS_KEY`` or ``AWS_SECRET_KEY`` or ``EC2_SECRET_KEY``, ``AWS_SECURITY_TOKEN`` or ``EC2_SECURITY_TOKEN``, ``AWS_REGION`` or ``EC2_REGION``, ``AWS_CA_BUNDLE``
- - Ansible uses the boto configuration file (typically ~/.boto) if no credentials are provided. See https://boto.readthedocs.io/en/latest/boto_config_tut.html
- - ``AWS_REGION`` or ``EC2_REGION`` can be typically be used to specify the AWS region, when required, but this can also be configured in the boto config file
+ - When no credentials are explicitly provided the AWS SDK (boto3) that Ansible uses will fall back to its configuration files (typically ``~/.aws/credentials``). See https://boto3.amazonaws.com/v1/documentation/api/latest/guide/credentials.html for more information.
+ - Modules based on the original AWS SDK (boto) may read their default configuration from different files. See https://boto.readthedocs.io/en/latest/boto_config_tut.html for more information.
+ - ``AWS_REGION`` or ``EC2_REGION`` can be typically be used to specify the AWS region, when required, but this can also be defined in the configuration files.
diff --git a/docs/community.aws.wafv2_ip_set_info_module.rst b/docs/community.aws.wafv2_ip_set_info_module.rst
index 204f6619644..4f654bf6060 100644
--- a/docs/community.aws.wafv2_ip_set_info_module.rst
+++ b/docs/community.aws.wafv2_ip_set_info_module.rst
@@ -25,10 +25,9 @@ Requirements
------------
The below requirements are needed on the host that executes this module.
-- boto
-- boto3
-- botocore
-- python >= 2.6
+- python >= 3.6
+- boto3 >= 1.15.0
+- botocore >= 1.18.0
Parameters
@@ -54,7 +53,7 @@ Parameters
|
- AWS access key. If not set then the value of the AWS_ACCESS_KEY_ID, AWS_ACCESS_KEY or EC2_ACCESS_KEY environment variable is used.
+ AWS access key . If not set then the value of the AWS_ACCESS_KEY_ID , AWS_ACCESS_KEY or EC2_ACCESS_KEY environment variable is used.
If profile is set this parameter is ignored.
Passing the aws_access_key and profile options at the same time has been deprecated and the options will be made mutually exclusive after 2022-06-01.
aliases: ec2_access_key, access_key
@@ -73,7 +72,7 @@ Parameters
|
The location of a CA Bundle to use when validating SSL certificates.
- Only used for boto3 based modules.
+ Not used by boto 2 based modules.
Note: The CA Bundle is read 'module' side and may need to be explicitly copied from the controller if not run locally.
|
@@ -106,7 +105,7 @@ Parameters
|
- AWS secret key. If not set then the value of the AWS_SECRET_ACCESS_KEY, AWS_SECRET_KEY, or EC2_SECRET_KEY environment variable is used.
+ AWS secret key . If not set then the value of the AWS_SECRET_ACCESS_KEY , AWS_SECRET_KEY , or EC2_SECRET_KEY environment variable is used.
If profile is set this parameter is ignored.
Passing the aws_secret_key and profile options at the same time has been deprecated and the options will be made mutually exclusive after 2022-06-01.
aliases: ec2_secret_key, secret_key
@@ -143,7 +142,7 @@ Parameters
|
|
- Url to use to connect to EC2 or your Eucalyptus cloud (by default the module will use EC2 endpoints). Ignored for modules where region is required. Must be specified for all other modules if region is not used. If not set then the value of the EC2_URL environment variable, if any, is used.
+ URL to use to connect to EC2 or your Eucalyptus cloud (by default the module will use EC2 endpoints). Ignored for modules where region is required. Must be specified for all other modules if region is not used. If not set then the value of the EC2_URL environment variable, if any, is used.
aliases: aws_endpoint_url, endpoint_url
|
@@ -175,7 +174,6 @@ Parameters
|
- Uses a boto profile. Only works with boto >= 2.24.0.
Using profile will override aws_access_key, aws_secret_key and security_token and support for passing them at the same time as profile has been deprecated.
aws_access_key, aws_secret_key and security_token will be made mutually exclusive with profile after 2022-06-01.
aliases: aws_profile
@@ -229,7 +227,7 @@ Parameters
|
|
- AWS STS security token. If not set then the value of the AWS_SECURITY_TOKEN or EC2_SECURITY_TOKEN environment variable is used.
+ AWS STS security token . If not set then the value of the AWS_SECURITY_TOKEN or EC2_SECURITY_TOKEN environment variable is used.
If profile is set this parameter is ignored.
Passing the security_token and profile options at the same time has been deprecated and the options will be made mutually exclusive after 2022-06-01.
aliases: aws_security_token, access_token
@@ -251,7 +249,7 @@ Parameters
|
- When set to "no", SSL certificates will not be validated for boto versions >= 2.6.0.
+ When set to "no", SSL certificates will not be validated for communication with the AWS APIs.
|
@@ -263,8 +261,9 @@ Notes
.. note::
- If parameters are not set within the module, the following environment variables can be used in decreasing order of precedence ``AWS_URL`` or ``EC2_URL``, ``AWS_PROFILE`` or ``AWS_DEFAULT_PROFILE``, ``AWS_ACCESS_KEY_ID`` or ``AWS_ACCESS_KEY`` or ``EC2_ACCESS_KEY``, ``AWS_SECRET_ACCESS_KEY`` or ``AWS_SECRET_KEY`` or ``EC2_SECRET_KEY``, ``AWS_SECURITY_TOKEN`` or ``EC2_SECURITY_TOKEN``, ``AWS_REGION`` or ``EC2_REGION``, ``AWS_CA_BUNDLE``
- - Ansible uses the boto configuration file (typically ~/.boto) if no credentials are provided. See https://boto.readthedocs.io/en/latest/boto_config_tut.html
- - ``AWS_REGION`` or ``EC2_REGION`` can be typically be used to specify the AWS region, when required, but this can also be configured in the boto config file
+ - When no credentials are explicitly provided the AWS SDK (boto3) that Ansible uses will fall back to its configuration files (typically ``~/.aws/credentials``). See https://boto3.amazonaws.com/v1/documentation/api/latest/guide/credentials.html for more information.
+ - Modules based on the original AWS SDK (boto) may read their default configuration from different files. See https://boto.readthedocs.io/en/latest/boto_config_tut.html for more information.
+ - ``AWS_REGION`` or ``EC2_REGION`` can be typically be used to specify the AWS region, when required, but this can also be defined in the configuration files.
diff --git a/docs/community.aws.wafv2_ip_set_module.rst b/docs/community.aws.wafv2_ip_set_module.rst
index cd08ee1d1fd..506e1b2e1e2 100644
--- a/docs/community.aws.wafv2_ip_set_module.rst
+++ b/docs/community.aws.wafv2_ip_set_module.rst
@@ -25,10 +25,9 @@ Requirements
------------
The below requirements are needed on the host that executes this module.
-- boto
-- boto3
-- botocore
-- python >= 2.6
+- python >= 3.6
+- boto3 >= 1.15.0
+- botocore >= 1.18.0
Parameters
@@ -72,7 +71,7 @@ Parameters
|
- AWS access key. If not set then the value of the AWS_ACCESS_KEY_ID, AWS_ACCESS_KEY or EC2_ACCESS_KEY environment variable is used.
+ AWS access key . If not set then the value of the AWS_ACCESS_KEY_ID , AWS_ACCESS_KEY or EC2_ACCESS_KEY environment variable is used.
If profile is set this parameter is ignored.
Passing the aws_access_key and profile options at the same time has been deprecated and the options will be made mutually exclusive after 2022-06-01.
aliases: ec2_access_key, access_key
@@ -91,7 +90,7 @@ Parameters
|
The location of a CA Bundle to use when validating SSL certificates.
- Only used for boto3 based modules.
+ Not used by boto 2 based modules.
Note: The CA Bundle is read 'module' side and may need to be explicitly copied from the controller if not run locally.
|
@@ -124,7 +123,7 @@ Parameters
|
- AWS secret key. If not set then the value of the AWS_SECRET_ACCESS_KEY, AWS_SECRET_KEY, or EC2_SECRET_KEY environment variable is used.
+ AWS secret key . If not set then the value of the AWS_SECRET_ACCESS_KEY , AWS_SECRET_KEY , or EC2_SECRET_KEY environment variable is used.
If profile is set this parameter is ignored.
Passing the aws_secret_key and profile options at the same time has been deprecated and the options will be made mutually exclusive after 2022-06-01.
aliases: ec2_secret_key, secret_key
@@ -176,7 +175,7 @@ Parameters
|
|
- Url to use to connect to EC2 or your Eucalyptus cloud (by default the module will use EC2 endpoints). Ignored for modules where region is required. Must be specified for all other modules if region is not used. If not set then the value of the EC2_URL environment variable, if any, is used.
+ URL to use to connect to EC2 or your Eucalyptus cloud (by default the module will use EC2 endpoints). Ignored for modules where region is required. Must be specified for all other modules if region is not used. If not set then the value of the EC2_URL environment variable, if any, is used.
aliases: aws_endpoint_url, endpoint_url
|
@@ -228,7 +227,6 @@ Parameters
|
- Uses a boto profile. Only works with boto >= 2.24.0.
Using profile will override aws_access_key, aws_secret_key and security_token and support for passing them at the same time as profile has been deprecated.
aws_access_key, aws_secret_key and security_token will be made mutually exclusive with profile after 2022-06-01.
aliases: aws_profile
@@ -301,7 +299,7 @@ Parameters
|
|
- AWS STS security token. If not set then the value of the AWS_SECURITY_TOKEN or EC2_SECURITY_TOKEN environment variable is used.
+ AWS STS security token . If not set then the value of the AWS_SECURITY_TOKEN or EC2_SECURITY_TOKEN environment variable is used.
If profile is set this parameter is ignored.
Passing the security_token and profile options at the same time has been deprecated and the options will be made mutually exclusive after 2022-06-01.
aliases: aws_security_token, access_token
@@ -359,7 +357,7 @@ Parameters
|
- When set to "no", SSL certificates will not be validated for boto versions >= 2.6.0.
+ When set to "no", SSL certificates will not be validated for communication with the AWS APIs.
|
@@ -371,8 +369,9 @@ Notes
.. note::
- If parameters are not set within the module, the following environment variables can be used in decreasing order of precedence ``AWS_URL`` or ``EC2_URL``, ``AWS_PROFILE`` or ``AWS_DEFAULT_PROFILE``, ``AWS_ACCESS_KEY_ID`` or ``AWS_ACCESS_KEY`` or ``EC2_ACCESS_KEY``, ``AWS_SECRET_ACCESS_KEY`` or ``AWS_SECRET_KEY`` or ``EC2_SECRET_KEY``, ``AWS_SECURITY_TOKEN`` or ``EC2_SECURITY_TOKEN``, ``AWS_REGION`` or ``EC2_REGION``, ``AWS_CA_BUNDLE``
- - Ansible uses the boto configuration file (typically ~/.boto) if no credentials are provided. See https://boto.readthedocs.io/en/latest/boto_config_tut.html
- - ``AWS_REGION`` or ``EC2_REGION`` can be typically be used to specify the AWS region, when required, but this can also be configured in the boto config file
+ - When no credentials are explicitly provided the AWS SDK (boto3) that Ansible uses will fall back to its configuration files (typically ``~/.aws/credentials``). See https://boto3.amazonaws.com/v1/documentation/api/latest/guide/credentials.html for more information.
+ - Modules based on the original AWS SDK (boto) may read their default configuration from different files. See https://boto.readthedocs.io/en/latest/boto_config_tut.html for more information.
+ - ``AWS_REGION`` or ``EC2_REGION`` can be typically be used to specify the AWS region, when required, but this can also be defined in the configuration files.
diff --git a/docs/community.aws.wafv2_resources_info_module.rst b/docs/community.aws.wafv2_resources_info_module.rst
index 3c11ea767b7..934e20ed66a 100644
--- a/docs/community.aws.wafv2_resources_info_module.rst
+++ b/docs/community.aws.wafv2_resources_info_module.rst
@@ -25,10 +25,9 @@ Requirements
------------
The below requirements are needed on the host that executes this module.
-- boto
-- boto3
-- botocore
-- python >= 2.6
+- python >= 3.6
+- boto3 >= 1.15.0
+- botocore >= 1.18.0
Parameters
@@ -54,7 +53,7 @@ Parameters
|
- AWS access key. If not set then the value of the AWS_ACCESS_KEY_ID, AWS_ACCESS_KEY or EC2_ACCESS_KEY environment variable is used.
+ AWS access key . If not set then the value of the AWS_ACCESS_KEY_ID , AWS_ACCESS_KEY or EC2_ACCESS_KEY environment variable is used.
If profile is set this parameter is ignored.
Passing the aws_access_key and profile options at the same time has been deprecated and the options will be made mutually exclusive after 2022-06-01.
aliases: ec2_access_key, access_key
@@ -73,7 +72,7 @@ Parameters
|
The location of a CA Bundle to use when validating SSL certificates.
- Only used for boto3 based modules.
+ Not used by boto 2 based modules.
Note: The CA Bundle is read 'module' side and may need to be explicitly copied from the controller if not run locally.
|
@@ -106,7 +105,7 @@ Parameters
|
- AWS secret key. If not set then the value of the AWS_SECRET_ACCESS_KEY, AWS_SECRET_KEY, or EC2_SECRET_KEY environment variable is used.
+ AWS secret key . If not set then the value of the AWS_SECRET_ACCESS_KEY , AWS_SECRET_KEY , or EC2_SECRET_KEY environment variable is used.
If profile is set this parameter is ignored.
Passing the aws_secret_key and profile options at the same time has been deprecated and the options will be made mutually exclusive after 2022-06-01.
aliases: ec2_secret_key, secret_key
@@ -143,7 +142,7 @@ Parameters
|
|
- Url to use to connect to EC2 or your Eucalyptus cloud (by default the module will use EC2 endpoints). Ignored for modules where region is required. Must be specified for all other modules if region is not used. If not set then the value of the EC2_URL environment variable, if any, is used.
+ URL to use to connect to EC2 or your Eucalyptus cloud (by default the module will use EC2 endpoints). Ignored for modules where region is required. Must be specified for all other modules if region is not used. If not set then the value of the EC2_URL environment variable, if any, is used.
aliases: aws_endpoint_url, endpoint_url
|
@@ -175,7 +174,6 @@ Parameters
|
- Uses a boto profile. Only works with boto >= 2.24.0.
Using profile will override aws_access_key, aws_secret_key and security_token and support for passing them at the same time as profile has been deprecated.
aws_access_key, aws_secret_key and security_token will be made mutually exclusive with profile after 2022-06-01.
aliases: aws_profile
@@ -229,7 +227,7 @@ Parameters
|
|
- AWS STS security token. If not set then the value of the AWS_SECURITY_TOKEN or EC2_SECURITY_TOKEN environment variable is used.
+ AWS STS security token . If not set then the value of the AWS_SECURITY_TOKEN or EC2_SECURITY_TOKEN environment variable is used.
If profile is set this parameter is ignored.
Passing the security_token and profile options at the same time has been deprecated and the options will be made mutually exclusive after 2022-06-01.
aliases: aws_security_token, access_token
@@ -251,7 +249,7 @@ Parameters
|
- When set to "no", SSL certificates will not be validated for boto versions >= 2.6.0.
+ When set to "no", SSL certificates will not be validated for communication with the AWS APIs.
|
@@ -263,8 +261,9 @@ Notes
.. note::
- If parameters are not set within the module, the following environment variables can be used in decreasing order of precedence ``AWS_URL`` or ``EC2_URL``, ``AWS_PROFILE`` or ``AWS_DEFAULT_PROFILE``, ``AWS_ACCESS_KEY_ID`` or ``AWS_ACCESS_KEY`` or ``EC2_ACCESS_KEY``, ``AWS_SECRET_ACCESS_KEY`` or ``AWS_SECRET_KEY`` or ``EC2_SECRET_KEY``, ``AWS_SECURITY_TOKEN`` or ``EC2_SECURITY_TOKEN``, ``AWS_REGION`` or ``EC2_REGION``, ``AWS_CA_BUNDLE``
- - Ansible uses the boto configuration file (typically ~/.boto) if no credentials are provided. See https://boto.readthedocs.io/en/latest/boto_config_tut.html
- - ``AWS_REGION`` or ``EC2_REGION`` can be typically be used to specify the AWS region, when required, but this can also be configured in the boto config file
+ - When no credentials are explicitly provided the AWS SDK (boto3) that Ansible uses will fall back to its configuration files (typically ``~/.aws/credentials``). See https://boto3.amazonaws.com/v1/documentation/api/latest/guide/credentials.html for more information.
+ - Modules based on the original AWS SDK (boto) may read their default configuration from different files. See https://boto.readthedocs.io/en/latest/boto_config_tut.html for more information.
+ - ``AWS_REGION`` or ``EC2_REGION`` can be typically be used to specify the AWS region, when required, but this can also be defined in the configuration files.
diff --git a/docs/community.aws.wafv2_resources_module.rst b/docs/community.aws.wafv2_resources_module.rst
index 5cce8c74359..ab010c46476 100644
--- a/docs/community.aws.wafv2_resources_module.rst
+++ b/docs/community.aws.wafv2_resources_module.rst
@@ -25,10 +25,9 @@ Requirements
------------
The below requirements are needed on the host that executes this module.
-- boto
-- boto3
-- botocore
-- python >= 2.6
+- python >= 3.6
+- boto3 >= 1.15.0
+- botocore >= 1.18.0
Parameters
@@ -70,7 +69,7 @@ Parameters
|
- AWS access key. If not set then the value of the AWS_ACCESS_KEY_ID, AWS_ACCESS_KEY or EC2_ACCESS_KEY environment variable is used.
+ AWS access key . If not set then the value of the AWS_ACCESS_KEY_ID , AWS_ACCESS_KEY or EC2_ACCESS_KEY environment variable is used.
If profile is set this parameter is ignored.
Passing the aws_access_key and profile options at the same time has been deprecated and the options will be made mutually exclusive after 2022-06-01.
aliases: ec2_access_key, access_key
@@ -89,7 +88,7 @@ Parameters
|
The location of a CA Bundle to use when validating SSL certificates.
- Only used for boto3 based modules.
+ Not used by boto 2 based modules.
Note: The CA Bundle is read 'module' side and may need to be explicitly copied from the controller if not run locally.
|
@@ -122,7 +121,7 @@ Parameters
|
- AWS secret key. If not set then the value of the AWS_SECRET_ACCESS_KEY, AWS_SECRET_KEY, or EC2_SECRET_KEY environment variable is used.
+ AWS secret key . If not set then the value of the AWS_SECRET_ACCESS_KEY , AWS_SECRET_KEY , or EC2_SECRET_KEY environment variable is used.
If profile is set this parameter is ignored.
Passing the aws_secret_key and profile options at the same time has been deprecated and the options will be made mutually exclusive after 2022-06-01.
aliases: ec2_secret_key, secret_key
@@ -159,7 +158,7 @@ Parameters
|
|
- Url to use to connect to EC2 or your Eucalyptus cloud (by default the module will use EC2 endpoints). Ignored for modules where region is required. Must be specified for all other modules if region is not used. If not set then the value of the EC2_URL environment variable, if any, is used.
+ URL to use to connect to EC2 or your Eucalyptus cloud (by default the module will use EC2 endpoints). Ignored for modules where region is required. Must be specified for all other modules if region is not used. If not set then the value of the EC2_URL environment variable, if any, is used.
aliases: aws_endpoint_url, endpoint_url
|
@@ -190,7 +189,6 @@ Parameters
|
- Uses a boto profile. Only works with boto >= 2.24.0.
Using profile will override aws_access_key, aws_secret_key and security_token and support for passing them at the same time as profile has been deprecated.
aws_access_key, aws_secret_key and security_token will be made mutually exclusive with profile after 2022-06-01.
aliases: aws_profile
@@ -243,7 +241,7 @@ Parameters
|
|
- AWS STS security token. If not set then the value of the AWS_SECURITY_TOKEN or EC2_SECURITY_TOKEN environment variable is used.
+ AWS STS security token . If not set then the value of the AWS_SECURITY_TOKEN or EC2_SECURITY_TOKEN environment variable is used.
If profile is set this parameter is ignored.
Passing the security_token and profile options at the same time has been deprecated and the options will be made mutually exclusive after 2022-06-01.
aliases: aws_security_token, access_token
@@ -285,7 +283,7 @@ Parameters
|
- When set to "no", SSL certificates will not be validated for boto versions >= 2.6.0.
+ When set to "no", SSL certificates will not be validated for communication with the AWS APIs.
|
@@ -297,8 +295,9 @@ Notes
.. note::
- If parameters are not set within the module, the following environment variables can be used in decreasing order of precedence ``AWS_URL`` or ``EC2_URL``, ``AWS_PROFILE`` or ``AWS_DEFAULT_PROFILE``, ``AWS_ACCESS_KEY_ID`` or ``AWS_ACCESS_KEY`` or ``EC2_ACCESS_KEY``, ``AWS_SECRET_ACCESS_KEY`` or ``AWS_SECRET_KEY`` or ``EC2_SECRET_KEY``, ``AWS_SECURITY_TOKEN`` or ``EC2_SECURITY_TOKEN``, ``AWS_REGION`` or ``EC2_REGION``, ``AWS_CA_BUNDLE``
- - Ansible uses the boto configuration file (typically ~/.boto) if no credentials are provided. See https://boto.readthedocs.io/en/latest/boto_config_tut.html
- - ``AWS_REGION`` or ``EC2_REGION`` can be typically be used to specify the AWS region, when required, but this can also be configured in the boto config file
+ - When no credentials are explicitly provided the AWS SDK (boto3) that Ansible uses will fall back to its configuration files (typically ``~/.aws/credentials``). See https://boto3.amazonaws.com/v1/documentation/api/latest/guide/credentials.html for more information.
+ - Modules based on the original AWS SDK (boto) may read their default configuration from different files. See https://boto.readthedocs.io/en/latest/boto_config_tut.html for more information.
+ - ``AWS_REGION`` or ``EC2_REGION`` can be typically be used to specify the AWS region, when required, but this can also be defined in the configuration files.
diff --git a/docs/community.aws.wafv2_rule_group_info_module.rst b/docs/community.aws.wafv2_rule_group_info_module.rst
index 9de423f1e64..9af6fceb5db 100644
--- a/docs/community.aws.wafv2_rule_group_info_module.rst
+++ b/docs/community.aws.wafv2_rule_group_info_module.rst
@@ -25,10 +25,9 @@ Requirements
------------
The below requirements are needed on the host that executes this module.
-- boto
-- boto3
-- botocore
-- python >= 2.6
+- python >= 3.6
+- boto3 >= 1.15.0
+- botocore >= 1.18.0
Parameters
@@ -54,7 +53,7 @@ Parameters
|
- AWS access key. If not set then the value of the AWS_ACCESS_KEY_ID, AWS_ACCESS_KEY or EC2_ACCESS_KEY environment variable is used.
+ AWS access key . If not set then the value of the AWS_ACCESS_KEY_ID , AWS_ACCESS_KEY or EC2_ACCESS_KEY environment variable is used.
If profile is set this parameter is ignored.
Passing the aws_access_key and profile options at the same time has been deprecated and the options will be made mutually exclusive after 2022-06-01.
aliases: ec2_access_key, access_key
@@ -73,7 +72,7 @@ Parameters
|
The location of a CA Bundle to use when validating SSL certificates.
- Only used for boto3 based modules.
+ Not used by boto 2 based modules.
Note: The CA Bundle is read 'module' side and may need to be explicitly copied from the controller if not run locally.
|
@@ -106,7 +105,7 @@ Parameters
|
- AWS secret key. If not set then the value of the AWS_SECRET_ACCESS_KEY, AWS_SECRET_KEY, or EC2_SECRET_KEY environment variable is used.
+ AWS secret key . If not set then the value of the AWS_SECRET_ACCESS_KEY , AWS_SECRET_KEY , or EC2_SECRET_KEY environment variable is used.
If profile is set this parameter is ignored.
Passing the aws_secret_key and profile options at the same time has been deprecated and the options will be made mutually exclusive after 2022-06-01.
aliases: ec2_secret_key, secret_key
@@ -143,7 +142,7 @@ Parameters
|
|
- Url to use to connect to EC2 or your Eucalyptus cloud (by default the module will use EC2 endpoints). Ignored for modules where region is required. Must be specified for all other modules if region is not used. If not set then the value of the EC2_URL environment variable, if any, is used.
+ URL to use to connect to EC2 or your Eucalyptus cloud (by default the module will use EC2 endpoints). Ignored for modules where region is required. Must be specified for all other modules if region is not used. If not set then the value of the EC2_URL environment variable, if any, is used.
aliases: aws_endpoint_url, endpoint_url
|
@@ -175,7 +174,6 @@ Parameters
|
- Uses a boto profile. Only works with boto >= 2.24.0.
Using profile will override aws_access_key, aws_secret_key and security_token and support for passing them at the same time as profile has been deprecated.
aws_access_key, aws_secret_key and security_token will be made mutually exclusive with profile after 2022-06-01.
aliases: aws_profile
@@ -229,7 +227,7 @@ Parameters
|
|
- AWS STS security token. If not set then the value of the AWS_SECURITY_TOKEN or EC2_SECURITY_TOKEN environment variable is used.
+ AWS STS security token . If not set then the value of the AWS_SECURITY_TOKEN or EC2_SECURITY_TOKEN environment variable is used.
If profile is set this parameter is ignored.
Passing the security_token and profile options at the same time has been deprecated and the options will be made mutually exclusive after 2022-06-01.
aliases: aws_security_token, access_token
@@ -271,7 +269,7 @@ Parameters
|
- When set to "no", SSL certificates will not be validated for boto versions >= 2.6.0.
+ When set to "no", SSL certificates will not be validated for communication with the AWS APIs.
|
@@ -283,8 +281,9 @@ Notes
.. note::
- If parameters are not set within the module, the following environment variables can be used in decreasing order of precedence ``AWS_URL`` or ``EC2_URL``, ``AWS_PROFILE`` or ``AWS_DEFAULT_PROFILE``, ``AWS_ACCESS_KEY_ID`` or ``AWS_ACCESS_KEY`` or ``EC2_ACCESS_KEY``, ``AWS_SECRET_ACCESS_KEY`` or ``AWS_SECRET_KEY`` or ``EC2_SECRET_KEY``, ``AWS_SECURITY_TOKEN`` or ``EC2_SECURITY_TOKEN``, ``AWS_REGION`` or ``EC2_REGION``, ``AWS_CA_BUNDLE``
- - Ansible uses the boto configuration file (typically ~/.boto) if no credentials are provided. See https://boto.readthedocs.io/en/latest/boto_config_tut.html
- - ``AWS_REGION`` or ``EC2_REGION`` can be typically be used to specify the AWS region, when required, but this can also be configured in the boto config file
+ - When no credentials are explicitly provided the AWS SDK (boto3) that Ansible uses will fall back to its configuration files (typically ``~/.aws/credentials``). See https://boto3.amazonaws.com/v1/documentation/api/latest/guide/credentials.html for more information.
+ - Modules based on the original AWS SDK (boto) may read their default configuration from different files. See https://boto.readthedocs.io/en/latest/boto_config_tut.html for more information.
+ - ``AWS_REGION`` or ``EC2_REGION`` can be typically be used to specify the AWS region, when required, but this can also be defined in the configuration files.
diff --git a/docs/community.aws.wafv2_rule_group_module.rst b/docs/community.aws.wafv2_rule_group_module.rst
index a158cbb7946..36094e45332 100644
--- a/docs/community.aws.wafv2_rule_group_module.rst
+++ b/docs/community.aws.wafv2_rule_group_module.rst
@@ -25,10 +25,9 @@ Requirements
------------
The below requirements are needed on the host that executes this module.
-- boto
-- boto3
-- botocore
-- python >= 2.6
+- python >= 3.6
+- boto3 >= 1.15.0
+- botocore >= 1.18.0
Parameters
@@ -54,7 +53,7 @@ Parameters
|
- AWS access key. If not set then the value of the AWS_ACCESS_KEY_ID, AWS_ACCESS_KEY or EC2_ACCESS_KEY environment variable is used.
+ AWS access key . If not set then the value of the AWS_ACCESS_KEY_ID , AWS_ACCESS_KEY or EC2_ACCESS_KEY environment variable is used.
If profile is set this parameter is ignored.
Passing the aws_access_key and profile options at the same time has been deprecated and the options will be made mutually exclusive after 2022-06-01.
aliases: ec2_access_key, access_key
@@ -73,7 +72,7 @@ Parameters
|
The location of a CA Bundle to use when validating SSL certificates.
- Only used for boto3 based modules.
+ Not used by boto 2 based modules.
Note: The CA Bundle is read 'module' side and may need to be explicitly copied from the controller if not run locally.
|
@@ -106,7 +105,7 @@ Parameters
|
- AWS secret key. If not set then the value of the AWS_SECRET_ACCESS_KEY, AWS_SECRET_KEY, or EC2_SECRET_KEY environment variable is used.
+ AWS secret key . If not set then the value of the AWS_SECRET_ACCESS_KEY , AWS_SECRET_KEY , or EC2_SECRET_KEY environment variable is used.
If profile is set this parameter is ignored.
Passing the aws_secret_key and profile options at the same time has been deprecated and the options will be made mutually exclusive after 2022-06-01.
aliases: ec2_secret_key, secret_key
@@ -192,7 +191,7 @@ Parameters
|
|
- Url to use to connect to EC2 or your Eucalyptus cloud (by default the module will use EC2 endpoints). Ignored for modules where region is required. Must be specified for all other modules if region is not used. If not set then the value of the EC2_URL environment variable, if any, is used.
+ URL to use to connect to EC2 or your Eucalyptus cloud (by default the module will use EC2 endpoints). Ignored for modules where region is required. Must be specified for all other modules if region is not used. If not set then the value of the EC2_URL environment variable, if any, is used.
aliases: aws_endpoint_url, endpoint_url
|
@@ -240,7 +239,6 @@ Parameters
|
- Uses a boto profile. Only works with boto >= 2.24.0.
Using profile will override aws_access_key, aws_secret_key and security_token and support for passing them at the same time as profile has been deprecated.
aws_access_key, aws_secret_key and security_token will be made mutually exclusive with profile after 2022-06-01.
aliases: aws_profile
@@ -348,7 +346,7 @@ Parameters
|
|
- AWS STS security token. If not set then the value of the AWS_SECURITY_TOKEN or EC2_SECURITY_TOKEN environment variable is used.
+ AWS STS security token . If not set then the value of the AWS_SECURITY_TOKEN or EC2_SECURITY_TOKEN environment variable is used.
If profile is set this parameter is ignored.
Passing the security_token and profile options at the same time has been deprecated and the options will be made mutually exclusive after 2022-06-01.
aliases: aws_security_token, access_token
@@ -405,7 +403,7 @@ Parameters
|
- When set to "no", SSL certificates will not be validated for boto versions >= 2.6.0.
+ When set to "no", SSL certificates will not be validated for communication with the AWS APIs.
|
@@ -417,8 +415,9 @@ Notes
.. note::
- If parameters are not set within the module, the following environment variables can be used in decreasing order of precedence ``AWS_URL`` or ``EC2_URL``, ``AWS_PROFILE`` or ``AWS_DEFAULT_PROFILE``, ``AWS_ACCESS_KEY_ID`` or ``AWS_ACCESS_KEY`` or ``EC2_ACCESS_KEY``, ``AWS_SECRET_ACCESS_KEY`` or ``AWS_SECRET_KEY`` or ``EC2_SECRET_KEY``, ``AWS_SECURITY_TOKEN`` or ``EC2_SECURITY_TOKEN``, ``AWS_REGION`` or ``EC2_REGION``, ``AWS_CA_BUNDLE``
- - Ansible uses the boto configuration file (typically ~/.boto) if no credentials are provided. See https://boto.readthedocs.io/en/latest/boto_config_tut.html
- - ``AWS_REGION`` or ``EC2_REGION`` can be typically be used to specify the AWS region, when required, but this can also be configured in the boto config file
+ - When no credentials are explicitly provided the AWS SDK (boto3) that Ansible uses will fall back to its configuration files (typically ``~/.aws/credentials``). See https://boto3.amazonaws.com/v1/documentation/api/latest/guide/credentials.html for more information.
+ - Modules based on the original AWS SDK (boto) may read their default configuration from different files. See https://boto.readthedocs.io/en/latest/boto_config_tut.html for more information.
+ - ``AWS_REGION`` or ``EC2_REGION`` can be typically be used to specify the AWS region, when required, but this can also be defined in the configuration files.
diff --git a/docs/community.aws.wafv2_web_acl_info_module.rst b/docs/community.aws.wafv2_web_acl_info_module.rst
index 0e1c329f840..761b4b9fd2c 100644
--- a/docs/community.aws.wafv2_web_acl_info_module.rst
+++ b/docs/community.aws.wafv2_web_acl_info_module.rst
@@ -25,10 +25,9 @@ Requirements
------------
The below requirements are needed on the host that executes this module.
-- boto
-- boto3
-- botocore
-- python >= 2.6
+- python >= 3.6
+- boto3 >= 1.15.0
+- botocore >= 1.18.0
Parameters
@@ -54,7 +53,7 @@ Parameters
|
- AWS access key. If not set then the value of the AWS_ACCESS_KEY_ID, AWS_ACCESS_KEY or EC2_ACCESS_KEY environment variable is used.
+ AWS access key . If not set then the value of the AWS_ACCESS_KEY_ID , AWS_ACCESS_KEY or EC2_ACCESS_KEY environment variable is used.
If profile is set this parameter is ignored.
Passing the aws_access_key and profile options at the same time has been deprecated and the options will be made mutually exclusive after 2022-06-01.
aliases: ec2_access_key, access_key
@@ -73,7 +72,7 @@ Parameters
|
The location of a CA Bundle to use when validating SSL certificates.
- Only used for boto3 based modules.
+ Not used by boto 2 based modules.
Note: The CA Bundle is read 'module' side and may need to be explicitly copied from the controller if not run locally.
|
@@ -106,7 +105,7 @@ Parameters
|
- AWS secret key. If not set then the value of the AWS_SECRET_ACCESS_KEY, AWS_SECRET_KEY, or EC2_SECRET_KEY environment variable is used.
+ AWS secret key . If not set then the value of the AWS_SECRET_ACCESS_KEY , AWS_SECRET_KEY , or EC2_SECRET_KEY environment variable is used.
If profile is set this parameter is ignored.
Passing the aws_secret_key and profile options at the same time has been deprecated and the options will be made mutually exclusive after 2022-06-01.
aliases: ec2_secret_key, secret_key
@@ -143,7 +142,7 @@ Parameters
|
|
- Url to use to connect to EC2 or your Eucalyptus cloud (by default the module will use EC2 endpoints). Ignored for modules where region is required. Must be specified for all other modules if region is not used. If not set then the value of the EC2_URL environment variable, if any, is used.
+ URL to use to connect to EC2 or your Eucalyptus cloud (by default the module will use EC2 endpoints). Ignored for modules where region is required. Must be specified for all other modules if region is not used. If not set then the value of the EC2_URL environment variable, if any, is used.
aliases: aws_endpoint_url, endpoint_url
|
@@ -175,7 +174,6 @@ Parameters
|
- Uses a boto profile. Only works with boto >= 2.24.0.
Using profile will override aws_access_key, aws_secret_key and security_token and support for passing them at the same time as profile has been deprecated.
aws_access_key, aws_secret_key and security_token will be made mutually exclusive with profile after 2022-06-01.
aliases: aws_profile
@@ -229,7 +227,7 @@ Parameters
|
|
- AWS STS security token. If not set then the value of the AWS_SECURITY_TOKEN or EC2_SECURITY_TOKEN environment variable is used.
+ AWS STS security token . If not set then the value of the AWS_SECURITY_TOKEN or EC2_SECURITY_TOKEN environment variable is used.
If profile is set this parameter is ignored.
Passing the security_token and profile options at the same time has been deprecated and the options will be made mutually exclusive after 2022-06-01.
aliases: aws_security_token, access_token
@@ -251,7 +249,7 @@ Parameters
|
- When set to "no", SSL certificates will not be validated for boto versions >= 2.6.0.
+ When set to "no", SSL certificates will not be validated for communication with the AWS APIs.
|
@@ -263,8 +261,9 @@ Notes
.. note::
- If parameters are not set within the module, the following environment variables can be used in decreasing order of precedence ``AWS_URL`` or ``EC2_URL``, ``AWS_PROFILE`` or ``AWS_DEFAULT_PROFILE``, ``AWS_ACCESS_KEY_ID`` or ``AWS_ACCESS_KEY`` or ``EC2_ACCESS_KEY``, ``AWS_SECRET_ACCESS_KEY`` or ``AWS_SECRET_KEY`` or ``EC2_SECRET_KEY``, ``AWS_SECURITY_TOKEN`` or ``EC2_SECURITY_TOKEN``, ``AWS_REGION`` or ``EC2_REGION``, ``AWS_CA_BUNDLE``
- - Ansible uses the boto configuration file (typically ~/.boto) if no credentials are provided. See https://boto.readthedocs.io/en/latest/boto_config_tut.html
- - ``AWS_REGION`` or ``EC2_REGION`` can be typically be used to specify the AWS region, when required, but this can also be configured in the boto config file
+ - When no credentials are explicitly provided the AWS SDK (boto3) that Ansible uses will fall back to its configuration files (typically ``~/.aws/credentials``). See https://boto3.amazonaws.com/v1/documentation/api/latest/guide/credentials.html for more information.
+ - Modules based on the original AWS SDK (boto) may read their default configuration from different files. See https://boto.readthedocs.io/en/latest/boto_config_tut.html for more information.
+ - ``AWS_REGION`` or ``EC2_REGION`` can be typically be used to specify the AWS region, when required, but this can also be defined in the configuration files.
diff --git a/docs/community.aws.wafv2_web_acl_module.rst b/docs/community.aws.wafv2_web_acl_module.rst
index a23a519e438..32324dcd9b2 100644
--- a/docs/community.aws.wafv2_web_acl_module.rst
+++ b/docs/community.aws.wafv2_web_acl_module.rst
@@ -25,10 +25,9 @@ Requirements
------------
The below requirements are needed on the host that executes this module.
-- boto
-- boto3
-- botocore
-- python >= 2.6
+- python >= 3.6
+- boto3 >= 1.15.0
+- botocore >= 1.18.0
Parameters
@@ -54,7 +53,7 @@ Parameters
|
- AWS access key. If not set then the value of the AWS_ACCESS_KEY_ID, AWS_ACCESS_KEY or EC2_ACCESS_KEY environment variable is used.
+ AWS access key . If not set then the value of the AWS_ACCESS_KEY_ID , AWS_ACCESS_KEY or EC2_ACCESS_KEY environment variable is used.
If profile is set this parameter is ignored.
Passing the aws_access_key and profile options at the same time has been deprecated and the options will be made mutually exclusive after 2022-06-01.
aliases: ec2_access_key, access_key
@@ -73,7 +72,7 @@ Parameters
|
The location of a CA Bundle to use when validating SSL certificates.
- Only used for boto3 based modules.
+ Not used by boto 2 based modules.
Note: The CA Bundle is read 'module' side and may need to be explicitly copied from the controller if not run locally.
|
@@ -106,7 +105,7 @@ Parameters
|
- AWS secret key. If not set then the value of the AWS_SECRET_ACCESS_KEY, AWS_SECRET_KEY, or EC2_SECRET_KEY environment variable is used.
+ AWS secret key . If not set then the value of the AWS_SECRET_ACCESS_KEY , AWS_SECRET_KEY , or EC2_SECRET_KEY environment variable is used.
If profile is set this parameter is ignored.
Passing the aws_secret_key and profile options at the same time has been deprecated and the options will be made mutually exclusive after 2022-06-01.
aliases: ec2_secret_key, secret_key
@@ -196,7 +195,7 @@ Parameters
|
|
- Url to use to connect to EC2 or your Eucalyptus cloud (by default the module will use EC2 endpoints). Ignored for modules where region is required. Must be specified for all other modules if region is not used. If not set then the value of the EC2_URL environment variable, if any, is used.
+ URL to use to connect to EC2 or your Eucalyptus cloud (by default the module will use EC2 endpoints). Ignored for modules where region is required. Must be specified for all other modules if region is not used. If not set then the value of the EC2_URL environment variable, if any, is used.
aliases: aws_endpoint_url, endpoint_url
|
@@ -244,7 +243,6 @@ Parameters
|
- Uses a boto profile. Only works with boto >= 2.24.0.
Using profile will override aws_access_key, aws_secret_key and security_token and support for passing them at the same time as profile has been deprecated.
aws_access_key, aws_secret_key and security_token will be made mutually exclusive with profile after 2022-06-01.
aliases: aws_profile
@@ -433,7 +431,7 @@ Parameters
|
|
- AWS STS security token. If not set then the value of the AWS_SECURITY_TOKEN or EC2_SECURITY_TOKEN environment variable is used.
+ AWS STS security token . If not set then the value of the AWS_SECURITY_TOKEN or EC2_SECURITY_TOKEN environment variable is used.
If profile is set this parameter is ignored.
Passing the security_token and profile options at the same time has been deprecated and the options will be made mutually exclusive after 2022-06-01.
aliases: aws_security_token, access_token
@@ -490,7 +488,7 @@ Parameters
|
- When set to "no", SSL certificates will not be validated for boto versions >= 2.6.0.
+ When set to "no", SSL certificates will not be validated for communication with the AWS APIs.
|
@@ -502,8 +500,9 @@ Notes
.. note::
- If parameters are not set within the module, the following environment variables can be used in decreasing order of precedence ``AWS_URL`` or ``EC2_URL``, ``AWS_PROFILE`` or ``AWS_DEFAULT_PROFILE``, ``AWS_ACCESS_KEY_ID`` or ``AWS_ACCESS_KEY`` or ``EC2_ACCESS_KEY``, ``AWS_SECRET_ACCESS_KEY`` or ``AWS_SECRET_KEY`` or ``EC2_SECRET_KEY``, ``AWS_SECURITY_TOKEN`` or ``EC2_SECURITY_TOKEN``, ``AWS_REGION`` or ``EC2_REGION``, ``AWS_CA_BUNDLE``
- - Ansible uses the boto configuration file (typically ~/.boto) if no credentials are provided. See https://boto.readthedocs.io/en/latest/boto_config_tut.html
- - ``AWS_REGION`` or ``EC2_REGION`` can be typically be used to specify the AWS region, when required, but this can also be configured in the boto config file
+ - When no credentials are explicitly provided the AWS SDK (boto3) that Ansible uses will fall back to its configuration files (typically ``~/.aws/credentials``). See https://boto3.amazonaws.com/v1/documentation/api/latest/guide/credentials.html for more information.
+ - Modules based on the original AWS SDK (boto) may read their default configuration from different files. See https://boto.readthedocs.io/en/latest/boto_config_tut.html for more information.
+ - ``AWS_REGION`` or ``EC2_REGION`` can be typically be used to specify the AWS region, when required, but this can also be defined in the configuration files.
diff --git a/galaxy.yml b/galaxy.yml
index 92e1c2419b5..52f221bf07a 100644
--- a/galaxy.yml
+++ b/galaxy.yml
@@ -1,6 +1,6 @@
namespace: community
name: aws
-version: 1.5.0
+version: 2.0.0
readme: README.md
authors:
- Ansible (https://github.com/ansible)
@@ -8,7 +8,7 @@ description: null
license_file: COPYING
tags: [community, aws, cloud, amazon]
dependencies:
- amazon.aws: '>=1.5.0'
+ amazon.aws: '>=2.0.0'
repository: https://github.com/ansible-collections/community.aws
documentation: https://github.com/ansible-collections/community.aws/tree/main/docs
homepage: https://github.com/ansible-collections/community.aws
diff --git a/meta/runtime.yml b/meta/runtime.yml
index cab11eed412..39685c11f83 100644
--- a/meta/runtime.yml
+++ b/meta/runtime.yml
@@ -1,4 +1,3 @@
----
requires_ansible: '>=2.9.10'
action_groups:
aws:
@@ -21,10 +20,7 @@ action_groups:
- ec2_elb_facts
- ec2_lc_facts
- ec2_placement_group_facts
- - ec2_vpc_endpoint_facts
- - ec2_vpc_igw_facts
- ec2_vpc_nacl_facts
- - ec2_vpc_nat_gateway_facts
- ec2_vpc_peering_facts
- ec2_vpc_route_table_facts
- ec2_vpc_vgw_facts
@@ -39,6 +35,7 @@ action_groups:
- elb_target_group_facts
- iam_mfa_device_facts
- iam_role_facts
+ - iam_cert_facts
- iam_server_certificate_facts
- lambda_facts
- rds_instance_facts
@@ -126,15 +123,8 @@ action_groups:
- ec2_transit_gateway
- ec2_transit_gateway_info
- ec2_vpc_egress_igw
- - ec2_vpc_endpoint
- - ec2_vpc_endpoint_info
- - ec2_vpc_endpoint_service_info
- - ec2_vpc_igw
- - ec2_vpc_igw_info
- ec2_vpc_nacl
- ec2_vpc_nacl_info
- - ec2_vpc_nat_gateway
- - ec2_vpc_nat_gateway_info
- ec2_vpc_peer
- ec2_vpc_peering_info
- ec2_vpc_route_table
@@ -172,6 +162,8 @@ action_groups:
- elb_target_info
- execute_lambda
- iam
+ - iam_access_key
+ - iam_access_key_info
- iam_cert
- iam_group
- iam_managed_policy
@@ -182,6 +174,7 @@ action_groups:
- iam_role
- iam_role_info
- iam_saml_federation
+ - iam_server_certificate
- iam_server_certificate_info
- iam_user
- iam_user_info
@@ -226,7 +219,6 @@ action_groups:
- wafv2_rule_group_info
- wafv2_web_acl
- wafv2_web_acl_info
-
plugin_routing:
modules:
aws_acm_facts:
@@ -305,7 +297,7 @@ plugin_routing:
ec2_instance:
redirect: amazon.aws.ec2_instance
ec2_instance_facts:
- redirect: amazon.aws.ec2_instance_info
+ redirect: amazon.aws.ec2_instance_info
ec2_instance_info:
redirect: amazon.aws.ec2_instance_info
ec2_eip_facts:
@@ -342,31 +334,25 @@ plugin_routing:
ec2_placement_group_info.
Please update your tasks.
ec2_vpc_endpoint_facts:
- deprecation:
- removal_date: 2021-12-01
- warning_text: >-
- ec2_vpc_endpoint_facts was renamed in Ansible 2.9 to
- ec2_vpc_endpoint_info.
- Please update your tasks.
+ redirect: amazon.aws.ec2_vpc_endpoint_facts
+ ec2_vpc_endpoint:
+ redirect: amazon.aws.ec2_vpc_endpoint
+ ec2_vpc_endpoint_info:
+ redirect: amazon.aws.ec2_vpc_endpoint_info
+ ec2_vpc_endpoint_service_info:
+ redirect: amazon.aws.ec2_vpc_endpoint_service_info
ec2_vpc_igw_facts:
- deprecation:
- removal_date: 2021-12-01
- warning_text: >-
- ec2_vpc_igw_facts was renamed in Ansible 2.9 to ec2_vpc_igw_info.
- Please update your tasks.
+ redirect: amazon.aws.ec2_vpc_igw_facts
+ ec2_vpc_igw:
+ redirect: amazon.aws.ec2_vpc_igw
+ ec2_vpc_igw_info:
+ redirect: amazon.aws.ec2_vpc_igw_info
ec2_vpc_nacl_facts:
deprecation:
removal_date: 2021-12-01
warning_text: >-
ec2_vpc_nacl_facts was renamed in Ansible 2.9 to ec2_vpc_nacl_info.
Please update your tasks.
- ec2_vpc_nat_gateway_facts:
- deprecation:
- removal_date: 2021-12-01
- warning_text: >-
- ec2_vpc_nat_gateway_facts was renamed in Ansible 2.9 to
- ec2_vpc_nat_gateway_info.
- Please update your tasks.
ec2_vpc_peering_facts:
deprecation:
removal_date: 2021-12-01
@@ -381,6 +367,12 @@ plugin_routing:
ec2_vpc_route_table_facts was renamed in Ansible 2.9 to
ec2_vpc_route_table_info.
Please update your tasks.
+ ec2_vpc_nat_gateway_facts:
+ redirect: amazon.aws.ec2_vpc_nat_gateway_facts
+ ec2_vpc_nat_gateway:
+ redirect: amazon.aws.ec2_vpc_nat_gateway
+ ec2_vpc_nat_gateway_info:
+ redirect: amazon.aws.ec2_vpc_nat_gateway_info
ec2_vpc_vgw_facts:
deprecation:
removal_date: 2021-12-01
@@ -449,11 +441,18 @@ plugin_routing:
elb_target_group_facts was renamed in Ansible 2.9 to
elb_target_group_info.
Please update your tasks.
+ iam:
+ deprecation:
+ removal_version: 3.0.0
+ warning_text: >-
+ The iam module is based upon a deprecated version of the AWS SDKs
+ and is deprecated in favor of the iam_user, iam_group and iam_role modules.
+ Please update your tasks.
iam_cert_facts:
deprecation:
removal_date: 2021-12-01
warning_text: >-
- iam_cert_facts was renamed in Ansible 2.9 to iam_cert_info.
+ iam_cert_facts was renamed in Ansible 2.9 to iam_server_certificate_info.
Please update your tasks.
iam_mfa_device_facts:
deprecation:
@@ -467,6 +466,13 @@ plugin_routing:
warning_text: >-
iam_role_facts was renamed in Ansible 2.9 to iam_role_info.
Please update your tasks.
+ iam_cert:
+ redirect: community.aws.iam_server_certificate
+ deprecation:
+ removal_version: 4.0.0
+ warning_text: >-
+ iam_cert has been renamed to iam_server_certificate for consistency.
+ Please update your tasks.
iam_server_certificate_facts:
deprecation:
removal_date: 2021-12-01
@@ -481,6 +487,13 @@ plugin_routing:
lambda_facts has been deprecated and will be removed.
The lambda_info module returns the same information, but not as
ansible_facts. See the module documentation for more information.
+ rds:
+ deprecation:
+ removal_version: 3.0.0
+ warning_text: >-
+ The rds module is based upon a deprecated version of the AWS SDKs
+ and is deprecated in favor of the rds_instance and rds_snapshot modules.
+ Please update your tasks.
rds_instance_facts:
deprecation:
removal_date: 2021-12-01
diff --git a/plugins/module_utils/route53.py b/plugins/module_utils/route53.py
new file mode 100644
index 00000000000..3e2940a5311
--- /dev/null
+++ b/plugins/module_utils/route53.py
@@ -0,0 +1,64 @@
+# This file is part of Ansible
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+from __future__ import absolute_import, division, print_function
+__metaclass__ = type
+
+try:
+ import botocore
+except ImportError:
+ pass # caught by AnsibleAWSModule
+
+from ansible_collections.amazon.aws.plugins.module_utils.core import is_boto3_error_code
+from ansible_collections.amazon.aws.plugins.module_utils.tagging import ansible_dict_to_boto3_tag_list
+from ansible_collections.amazon.aws.plugins.module_utils.tagging import boto3_tag_list_to_ansible_dict
+from ansible_collections.amazon.aws.plugins.module_utils.tagging import compare_aws_tags
+
+
+def manage_tags(module, client, resource_type, resource_id, new_tags, purge_tags):
+ if new_tags is None:
+ return False
+
+ old_tags = get_tags(module, client, resource_type, resource_id)
+ tags_to_set, tags_to_delete = compare_aws_tags(old_tags, new_tags, purge_tags=purge_tags)
+
+ change_params = dict()
+ if tags_to_set:
+ change_params['AddTags'] = ansible_dict_to_boto3_tag_list(tags_to_set)
+ if tags_to_delete:
+ change_params['RemoveTagKeys'] = tags_to_delete
+
+ if not change_params:
+ return False
+
+ if module.check_mode:
+ return True
+
+ try:
+ client.change_tags_for_resource(
+ ResourceType=resource_type,
+ ResourceId=resource_id,
+ **change_params
+ )
+ except (botocore.exceptions.BotoCoreError, botocore.exceptions.ClientError) as e:
+ module.fail_json_aws(e, msg='Failed to update tags on {0}'.format(resource_type),
+ resource_id=resource_id, change_params=change_params)
+ return True
+
+
+def get_tags(module, client, resource_type, resource_id):
+ try:
+ tagset = client.list_tags_for_resource(
+ ResourceType=resource_type,
+ ResourceId=resource_id,
+ )
+ except is_boto3_error_code('NoSuchHealthCheck'):
+ return {}
+ except is_boto3_error_code('NoSuchHostedZone'): # pylint: disable=duplicate-except
+ return {}
+ except (botocore.exceptions.BotoCoreError, botocore.exceptions.ClientError) as e: # pylint: disable=duplicate-except
+ module.fail_json_aws(e, msg='Failed to fetch tags on {0}'.format(resource_type),
+ resource_id=resource_id)
+
+ tags = boto3_tag_list_to_ansible_dict(tagset['ResourceTagSet']['Tags'])
+ return tags
diff --git a/plugins/modules/aws_api_gateway.py b/plugins/modules/aws_api_gateway.py
index 9eadf88d48b..5ce411195e9 100644
--- a/plugins/modules/aws_api_gateway.py
+++ b/plugins/modules/aws_api_gateway.py
@@ -19,10 +19,6 @@
stable guaranteed unique identifier for the API. If you do
not give api_id then a new API will be created each time
this is run.
- - Beware that there are very hard limits on the rate that
- you can call API Gateway's REST API. You may need to patch
- your boto. See U(https://github.com/boto/boto3/issues/876)
- and discuss it with your AWS rep.
- swagger_file and swagger_text are passed directly on to AWS
transparently whilst swagger_dict is an ansible dict which is
converted to JSON before the API definitions are uploaded.
diff --git a/plugins/modules/aws_config_delivery_channel.py b/plugins/modules/aws_config_delivery_channel.py
index e6e9d40e62c..fb3851a4ecc 100644
--- a/plugins/modules/aws_config_delivery_channel.py
+++ b/plugins/modules/aws_config_delivery_channel.py
@@ -79,7 +79,7 @@
# this waits for an IAM role to become fully available, at the cost of
# taking a long time to fail when the IAM role/policy really is invalid
-retry_unavailable_iam_on_put_delivery = AWSRetry.backoff(
+retry_unavailable_iam_on_put_delivery = AWSRetry.jittered_backoff(
catch_extra_error_codes=['InsufficientDeliveryPolicyException'],
)
diff --git a/plugins/modules/aws_direct_connect_confirm_connection.py b/plugins/modules/aws_direct_connect_confirm_connection.py
index 7ea8527db72..b583def09d9 100644
--- a/plugins/modules/aws_direct_connect_confirm_connection.py
+++ b/plugins/modules/aws_direct_connect_confirm_connection.py
@@ -69,10 +69,10 @@
from ansible_collections.amazon.aws.plugins.module_utils.direct_connect import DirectConnectError
from ansible_collections.amazon.aws.plugins.module_utils.ec2 import AWSRetry
-retry_params = {"tries": 10, "delay": 5, "backoff": 1.2, "catch_extra_error_codes": ["DirectConnectClientException"]}
+retry_params = {"retries": 10, "delay": 5, "backoff": 1.2, "catch_extra_error_codes": ["DirectConnectClientException"]}
-@AWSRetry.backoff(**retry_params)
+@AWSRetry.jittered_backoff(**retry_params)
def describe_connections(client, params):
return client.describe_connections(**params)
diff --git a/plugins/modules/aws_direct_connect_connection.py b/plugins/modules/aws_direct_connect_connection.py
index 98afd701f3d..3764b1c7802 100644
--- a/plugins/modules/aws_direct_connect_connection.py
+++ b/plugins/modules/aws_direct_connect_connection.py
@@ -167,7 +167,7 @@
from ansible_collections.amazon.aws.plugins.module_utils.direct_connect import disassociate_connection_and_lag
from ansible_collections.amazon.aws.plugins.module_utils.ec2 import AWSRetry
-retry_params = {"tries": 10, "delay": 5, "backoff": 1.2, "catch_extra_error_codes": ["DirectConnectClientException"]}
+retry_params = {"retries": 10, "delay": 5, "backoff": 1.2, "catch_extra_error_codes": ["DirectConnectClientException"]}
def connection_status(client, connection_id):
@@ -179,7 +179,7 @@ def connection_exists(client, connection_id=None, connection_name=None, verify=T
if connection_id:
params['connectionId'] = connection_id
try:
- response = AWSRetry.backoff(**retry_params)(client.describe_connections)(**params)
+ response = AWSRetry.jittered_backoff(**retry_params)(client.describe_connections)(**params)
except (BotoCoreError, ClientError) as e:
if connection_id:
msg = "Failed to describe DirectConnect ID {0}".format(connection_id)
@@ -227,7 +227,7 @@ def create_connection(client, location, bandwidth, name, lag_id):
params['lagId'] = lag_id
try:
- connection = AWSRetry.backoff(**retry_params)(client.create_connection)(**params)
+ connection = AWSRetry.jittered_backoff(**retry_params)(client.create_connection)(**params)
except (BotoCoreError, ClientError) as e:
raise DirectConnectError(msg="Failed to create DirectConnect connection {0}".format(name),
last_traceback=traceback.format_exc(),
@@ -242,7 +242,7 @@ def changed_properties(current_status, location, bandwidth):
return current_bandwidth != bandwidth or current_location != location
-@AWSRetry.backoff(**retry_params)
+@AWSRetry.jittered_backoff(**retry_params)
def update_associations(client, latest_state, connection_id, lag_id):
changed = False
if 'lagId' in latest_state and lag_id != latest_state['lagId']:
@@ -277,7 +277,7 @@ def ensure_present(client, connection_id, connection_name, location, bandwidth,
return False, connection_id
-@AWSRetry.backoff(**retry_params)
+@AWSRetry.jittered_backoff(**retry_params)
def ensure_absent(client, connection_id):
changed = False
if connection_id:
diff --git a/plugins/modules/aws_direct_connect_link_aggregation_group.py b/plugins/modules/aws_direct_connect_link_aggregation_group.py
index 7b287bd61f3..0567ba90288 100644
--- a/plugins/modules/aws_direct_connect_link_aggregation_group.py
+++ b/plugins/modules/aws_direct_connect_link_aggregation_group.py
@@ -265,7 +265,7 @@ def delete_lag(client, lag_id):
exception=e)
-@AWSRetry.backoff(tries=5, delay=2, backoff=2.0, catch_extra_error_codes=['DirectConnectClientException'])
+@AWSRetry.jittered_backoff(retries=5, delay=2, backoff=2.0, catch_extra_error_codes=['DirectConnectClientException'])
def _update_lag(client, lag_id, lag_name, min_links):
params = {}
if min_links:
diff --git a/plugins/modules/aws_direct_connect_virtual_interface.py b/plugins/modules/aws_direct_connect_virtual_interface.py
index d520f0ee84f..d2d199c5527 100644
--- a/plugins/modules/aws_direct_connect_virtual_interface.py
+++ b/plugins/modules/aws_direct_connect_virtual_interface.py
@@ -267,7 +267,7 @@ def try_except_ClientError(failure_msg):
def wrapper(f):
def run_func(*args, **kwargs):
try:
- result = AWSRetry.backoff(tries=8, delay=5, catch_extra_error_codes=['DirectConnectClientException'])(f)(*args, **kwargs)
+ result = AWSRetry.jittered_backoff(retries=8, delay=5, catch_extra_error_codes=['DirectConnectClientException'])(f)(*args, **kwargs)
except (ClientError, BotoCoreError) as e:
raise DirectConnectError(failure_msg, traceback.format_exc(), e)
return result
diff --git a/plugins/modules/aws_eks_cluster.py b/plugins/modules/aws_eks_cluster.py
index 3d8f2696d5f..64627377c41 100644
--- a/plugins/modules/aws_eks_cluster.py
+++ b/plugins/modules/aws_eks_cluster.py
@@ -281,14 +281,6 @@ def main():
supports_check_mode=True,
)
- if not module.botocore_at_least("1.10.32"):
- module.fail_json(msg='aws_eks_cluster module requires botocore >= 1.10.32')
-
- if (not module.botocore_at_least("1.12.38") and
- module.params.get('state') == 'absent' and
- module.params.get('wait')):
- module.fail_json(msg='aws_eks_cluster: wait=yes when state=absent requires botocore >= 1.12.38')
-
client = module.client('eks')
if module.params.get('state') == 'present':
diff --git a/plugins/modules/aws_inspector_target.py b/plugins/modules/aws_inspector_target.py
index ceb4abd63dd..a84e245d152 100644
--- a/plugins/modules/aws_inspector_target.py
+++ b/plugins/modules/aws_inspector_target.py
@@ -110,7 +110,7 @@
pass # caught by AnsibleAWSModule
-@AWSRetry.backoff(tries=5, delay=5, backoff=2.0)
+@AWSRetry.jittered_backoff(retries=5, delay=5, backoff=2.0)
def main():
argument_spec = dict(
name=dict(required=True),
diff --git a/plugins/modules/aws_kms.py b/plugins/modules/aws_kms.py
index 10753f63584..41a5ee63c69 100644
--- a/plugins/modules/aws_kms.py
+++ b/plugins/modules/aws_kms.py
@@ -44,7 +44,7 @@
- (deprecated) Grant or deny access.
- Used for modifying the Key Policy rather than modifying a grant and only
works on the default policy created through the AWS Console.
- - This option has been deprecated, and will be removed in 2.13. Use I(policy) instead.
+ - This option has been deprecated, and will be removed in a release after 2021-12-01. Use I(policy) instead.
default: grant
choices: [ grant, deny ]
aliases:
@@ -56,7 +56,7 @@
- One of I(policy_role_name) or I(policy_role_arn) are required.
- Used for modifying the Key Policy rather than modifying a grant and only
works on the default policy created through the AWS Console.
- - This option has been deprecated, and will be removed in 2.13. Use I(policy) instead.
+ - This option has been deprecated, and will be removed in a release after 2021-12-01. Use I(policy) instead.
required: false
aliases:
- role_name
@@ -67,7 +67,7 @@
- One of I(policy_role_name) or I(policy_role_arn) are required.
- Used for modifying the Key Policy rather than modifying a grant and only
works on the default policy created through the AWS Console.
- - This option has been deprecated, and will be removed in 2.13. Use I(policy) instead.
+ - This option has been deprecated, and will be removed in a release after 2021-12-01. Use I(policy) instead.
type: str
required: false
aliases:
@@ -78,7 +78,7 @@
- Required when I(policy_mode=grant).
- Used for modifying the Key Policy rather than modifying a grant and only
works on the default policy created through the AWS Console.
- - This option has been deprecated, and will be removed in 2.13. Use I(policy) instead.
+ - This option has been deprecated, and will be removed in a release after 2021-12-01. Use I(policy) instead.
required: false
aliases:
- grant_types
@@ -90,7 +90,7 @@
- Only cleans if changes are being made.
- Used for modifying the Key Policy rather than modifying a grant and only
works on the default policy created through the AWS Console.
- - This option has been deprecated, and will be removed in 2.13. Use I(policy) instead.
+ - This option has been deprecated, and will be removed in a release after 2021-12-01. Use I(policy) instead.
type: bool
default: true
aliases:
@@ -173,6 +173,24 @@
- policy to apply to the KMS key.
- See U(https://docs.aws.amazon.com/kms/latest/developerguide/key-policies.html)
type: json
+ key_spec:
+ aliases:
+ - customer_master_key_spec
+ description:
+ - Specifies the type of KMS key to create.
+ - The specification is not changeable once the key is created.
+ type: str
+ default: SYMMETRIC_DEFAULT
+ choices: ['SYMMETRIC_DEFAULT', 'RSA_2048', 'RSA_3072', 'RSA_4096', 'ECC_NIST_P256', 'ECC_NIST_P384', 'ECC_NIST_P521', 'ECC_SECG_P256K1']
+ version_added: 2.1.0
+ key_usage:
+ description:
+ - Determines the cryptographic operations for which you can use the KMS key.
+ - The usage is not changeable once the key is created.
+ type: str
+ default: ENCRYPT_DECRYPT
+ choices: ['ENCRYPT_DECRYPT', 'SIGN_VERIFY']
+ version_added: 2.1.0
author:
- Ted Timmons (@tedder)
- Will Thames (@willthames)
@@ -434,19 +452,19 @@
from ansible_collections.amazon.aws.plugins.module_utils.ec2 import compare_policies
-@AWSRetry.backoff(tries=5, delay=5, backoff=2.0)
+@AWSRetry.jittered_backoff(retries=5, delay=5, backoff=2.0)
def get_iam_roles_with_backoff(connection):
paginator = connection.get_paginator('list_roles')
return paginator.paginate().build_full_result()
-@AWSRetry.backoff(tries=5, delay=5, backoff=2.0)
+@AWSRetry.jittered_backoff(retries=5, delay=5, backoff=2.0)
def get_kms_keys_with_backoff(connection):
paginator = connection.get_paginator('list_keys')
return paginator.paginate().build_full_result()
-@AWSRetry.backoff(tries=5, delay=5, backoff=2.0)
+@AWSRetry.jittered_backoff(retries=5, delay=5, backoff=2.0)
def get_kms_aliases_with_backoff(connection):
paginator = connection.get_paginator('list_aliases')
return paginator.paginate().build_full_result()
@@ -465,30 +483,30 @@ def get_kms_aliases_lookup(connection):
return _aliases
-@AWSRetry.backoff(tries=5, delay=5, backoff=2.0)
+@AWSRetry.jittered_backoff(retries=5, delay=5, backoff=2.0)
def get_kms_tags_with_backoff(connection, key_id, **kwargs):
return connection.list_resource_tags(KeyId=key_id, **kwargs)
-@AWSRetry.backoff(tries=5, delay=5, backoff=2.0)
+@AWSRetry.jittered_backoff(retries=5, delay=5, backoff=2.0)
def get_kms_grants_with_backoff(connection, key_id):
params = dict(KeyId=key_id)
paginator = connection.get_paginator('list_grants')
return paginator.paginate(**params).build_full_result()
-@AWSRetry.backoff(tries=5, delay=5, backoff=2.0)
+@AWSRetry.jittered_backoff(retries=5, delay=5, backoff=2.0)
def get_kms_metadata_with_backoff(connection, key_id):
return connection.describe_key(KeyId=key_id)
-@AWSRetry.backoff(tries=5, delay=5, backoff=2.0)
+@AWSRetry.jittered_backoff(retries=5, delay=5, backoff=2.0)
def list_key_policies_with_backoff(connection, key_id):
paginator = connection.get_paginator('list_key_policies')
return paginator.paginate(KeyId=key_id).build_full_result()
-@AWSRetry.backoff(tries=5, delay=5, backoff=2.0)
+@AWSRetry.jittered_backoff(retries=5, delay=5, backoff=2.0)
def get_key_policy_with_backoff(connection, key_id, policy_name):
return connection.get_key_policy(KeyId=key_id, PolicyName=policy_name)
@@ -852,9 +870,12 @@ def update_key(connection, module, key):
def create_key(connection, module):
+ key_usage = module.params.get('key_usage')
+ key_spec = module.params.get('key_spec')
params = dict(BypassPolicyLockoutSafetyCheck=False,
Tags=ansible_dict_to_boto3_tag_list(module.params['tags'], tag_name_key_name='TagKey', tag_value_key_name='TagValue'),
- KeyUsage='ENCRYPT_DECRYPT',
+ KeyUsage=key_usage,
+ CustomerMasterKeySpec=key_spec,
Origin='AWS_KMS')
if module.check_mode:
@@ -1067,7 +1088,10 @@ def main():
policy=dict(type='json'),
purge_grants=dict(type='bool', default=False),
state=dict(default='present', choices=['present', 'absent']),
- enable_key_rotation=(dict(type='bool'))
+ enable_key_rotation=(dict(type='bool')),
+ key_spec=dict(type='str', default='SYMMETRIC_DEFAULT', aliases=['customer_master_key_spec'],
+ choices=['SYMMETRIC_DEFAULT', 'RSA_2048', 'RSA_3072', 'RSA_4096', 'ECC_NIST_P256', 'ECC_NIST_P384', 'ECC_NIST_P521', 'ECC_SECG_P256K1']),
+ key_usage=dict(type='str', default='ENCRYPT_DECRYPT', choices=['ENCRYPT_DECRYPT', 'SIGN_VERIFY']),
)
module = AnsibleAWSModule(
diff --git a/plugins/modules/aws_kms_info.py b/plugins/modules/aws_kms_info.py
index 879cf317497..a7620dad005 100644
--- a/plugins/modules/aws_kms_info.py
+++ b/plugins/modules/aws_kms_info.py
@@ -46,6 +46,17 @@
description: Whether to get full details (tags, grants etc.) of keys pending deletion
default: False
type: bool
+ keys_attr:
+ description:
+ - Whether to return the results in the C(keys) attribute as well as the
+ C(kms_keys) attribute.
+ - Returning the C(keys) attribute conflicts with the builtin keys()
+ method on dictionaries and as such has been deprecated.
+ - After version C(3.0.0) this parameter will do nothing, and after
+ version C(4.0.0) this parameter will be removed.
+ type: bool
+ default: True
+ version_added: 2.0.0
extends_documentation_fragment:
- amazon.aws.aws
- amazon.aws.ec2
@@ -70,7 +81,7 @@
'''
RETURN = '''
-keys:
+kms_keys:
description: list of keys
type: complex
returned: always
@@ -250,13 +261,13 @@
_aliases = dict()
-@AWSRetry.backoff(tries=5, delay=5, backoff=2.0)
+@AWSRetry.jittered_backoff(retries=5, delay=5, backoff=2.0)
def get_kms_keys_with_backoff(connection):
paginator = connection.get_paginator('list_keys')
return paginator.paginate().build_full_result()
-@AWSRetry.backoff(tries=5, delay=5, backoff=2.0)
+@AWSRetry.jittered_backoff(retries=5, delay=5, backoff=2.0)
def get_kms_aliases_with_backoff(connection):
paginator = connection.get_paginator('list_aliases')
return paginator.paginate().build_full_result()
@@ -275,12 +286,12 @@ def get_kms_aliases_lookup(connection):
return _aliases
-@AWSRetry.backoff(tries=5, delay=5, backoff=2.0)
+@AWSRetry.jittered_backoff(retries=5, delay=5, backoff=2.0)
def get_kms_tags_with_backoff(connection, key_id, **kwargs):
return connection.list_resource_tags(KeyId=key_id, **kwargs)
-@AWSRetry.backoff(tries=5, delay=5, backoff=2.0)
+@AWSRetry.jittered_backoff(retries=5, delay=5, backoff=2.0)
def get_kms_grants_with_backoff(connection, key_id, **kwargs):
params = dict(KeyId=key_id)
if kwargs.get('tokens'):
@@ -289,23 +300,23 @@ def get_kms_grants_with_backoff(connection, key_id, **kwargs):
return paginator.paginate(**params).build_full_result()
-@AWSRetry.backoff(tries=5, delay=5, backoff=2.0)
+@AWSRetry.jittered_backoff(retries=5, delay=5, backoff=2.0)
def get_kms_metadata_with_backoff(connection, key_id):
return connection.describe_key(KeyId=key_id)
-@AWSRetry.backoff(tries=5, delay=5, backoff=2.0)
+@AWSRetry.jittered_backoff(retries=5, delay=5, backoff=2.0)
def list_key_policies_with_backoff(connection, key_id):
paginator = connection.get_paginator('list_key_policies')
return paginator.paginate(KeyId=key_id).build_full_result()
-@AWSRetry.backoff(tries=5, delay=5, backoff=2.0)
+@AWSRetry.jittered_backoff(retries=5, delay=5, backoff=2.0)
def get_key_policy_with_backoff(connection, key_id, policy_name):
return connection.get_key_policy(KeyId=key_id, PolicyName=policy_name)
-@AWSRetry.backoff(tries=5, delay=5, backoff=2.0)
+@AWSRetry.jittered_backoff(retries=5, delay=5, backoff=2.0)
def get_enable_key_rotation_with_backoff(connection, key_id):
try:
current_rotation_status = connection.get_key_rotation_status(KeyId=key_id)
@@ -375,7 +386,7 @@ def key_matches_filters(key, filters):
if not filters:
return True
else:
- return all([key_matches_filter(key, filtr) for filtr in filters.items()])
+ return all(key_matches_filter(key, filtr) for filtr in filters.items())
def get_key_details(connection, module, key_id, tokens=None):
@@ -441,6 +452,7 @@ def main():
key_id=dict(aliases=['key_arn']),
filters=dict(type='dict'),
pending_deletion=dict(type='bool', default=False),
+ keys_attr=dict(type='bool', default=True),
)
module = AnsibleAWSModule(argument_spec=argument_spec,
@@ -455,7 +467,17 @@ def main():
module.fail_json_aws(e, msg='Failed to connect to AWS')
all_keys = get_kms_info(connection, module)
- module.exit_json(keys=[key for key in all_keys if key_matches_filters(key, module.params['filters'])])
+ filtered_keys = [key for key in all_keys if key_matches_filters(key, module.params['filters'])]
+ ret_params = dict(kms_keys=filtered_keys)
+
+ # We originally returned "keys"
+ if module.params['keys_attr']:
+ module.deprecate("Returning results in the 'keys' attribute conflicts with the builtin keys() method on "
+ "dicts and as such is deprecated. Please use the kms_keys attribute. This warning can be "
+ "silenced by setting keys_attr to False.",
+ version='3.0.0', collection_name='community.aws')
+ ret_params.update(dict(keys=filtered_keys))
+ module.exit_json(**ret_params)
if __name__ == '__main__':
diff --git a/plugins/modules/aws_msk_cluster.py b/plugins/modules/aws_msk_cluster.py
index 7f85c00a59b..d6cf35d3ba3 100644
--- a/plugins/modules/aws_msk_cluster.py
+++ b/plugins/modules/aws_msk_cluster.py
@@ -12,9 +12,6 @@
module: aws_msk_cluster
short_description: Manage Amazon MSK clusters.
version_added: "2.0.0"
-requirements:
- - botocore >= 1.17.42
- - boto3 >= 1.17.9
description:
- Create, delete and modify Amazon MSK (Managed Streaming for Apache Kafka) clusters.
author:
@@ -34,6 +31,7 @@
- The version of Apache Kafka.
- This version should exist in given configuration.
- This parameter is required when I(state=present).
+ - Update operation requires botocore version >= 1.16.19.
type: str
configuration_arn:
description:
@@ -52,7 +50,7 @@
instance_type:
description:
- The type of Amazon EC2 instances to use for Kafka brokers.
- - Update operation requires boto3 version >= 1.16.58
+ - Update operation requires botocore version >= 1.19.58.
choices:
- kafka.t3.small
- kafka.m5.large
@@ -522,7 +520,7 @@ def create_or_update_cluster(client, module):
}
},
"broker_type": {
- "boto3_version": "1.16.58",
+ "botocore_version": "1.19.58",
"current_value": cluster["BrokerNodeGroupInfo"]["InstanceType"],
"target_value": module.params.get("instance_type"),
"update_params": {
@@ -578,8 +576,8 @@ def create_or_update_cluster(client, module):
for method, options in msk_cluster_changes.items():
- if 'boto3_version' in options:
- if not module.boto3_at_least(options["boto3_version"]):
+ if 'botocore_version' in options:
+ if not module.botocore_at_least(options["botocore_version"]):
continue
try:
diff --git a/plugins/modules/aws_msk_config.py b/plugins/modules/aws_msk_config.py
index c02769152a5..f1966847422 100644
--- a/plugins/modules/aws_msk_config.py
+++ b/plugins/modules/aws_msk_config.py
@@ -13,8 +13,8 @@
short_description: Manage Amazon MSK cluster configurations.
version_added: "2.0.0"
requirements:
- - botocore >= 1.17.42
- - boto3 >= 1.17.9
+ - botocore >= 1.17.48
+ - boto3
description:
- Create, delete and modify Amazon MSK (Managed Streaming for Apache Kafka) cluster configurations.
author:
@@ -104,9 +104,6 @@
)
-BOTOCORE_MIN_VERSION = "1.17.42"
-
-
def dict_to_prop(d):
"""convert dictionary to multi-line properties"""
if len(d) == 0:
@@ -138,8 +135,6 @@ def get_configurations_with_backoff(client):
def find_active_config(client, module):
"""
looking for configuration by name
- status is not returned for list_configurations in botocore 1.17.42
- delete_configuration method was added in botocore 1.17.48
"""
name = module.params["name"]
@@ -284,13 +279,6 @@ def main():
module = AnsibleAWSModule(argument_spec=module_args, supports_check_mode=True)
- if not module.botocore_at_least(BOTOCORE_MIN_VERSION):
- module.fail_json(
- msg="aws_msk_config module requires botocore >= {0}".format(
- BOTOCORE_MIN_VERSION
- )
- )
-
client = module.client("kafka", retry_decorator=AWSRetry.jittered_backoff())
if module.params["state"] == "present":
diff --git a/plugins/modules/aws_s3_bucket_info.py b/plugins/modules/aws_s3_bucket_info.py
index 06885dfcd13..f5b9c44f04c 100644
--- a/plugins/modules/aws_s3_bucket_info.py
+++ b/plugins/modules/aws_s3_bucket_info.py
@@ -78,7 +78,9 @@
type: bool
default: False
bucket_ownership_controls:
- description: Retrive S3 ownership controls.
+ description:
+ - Retrive S3 ownership controls.
+ - Access to bucket ownership controls requires botocore>=1.18.11.
type: bool
default: False
bucket_website:
@@ -593,6 +595,9 @@ def main():
module.deprecate("The 'aws_s3_bucket_facts' module has been renamed to 'aws_s3_bucket_info', "
"and the renamed one no longer returns ansible_facts", date='2021-12-01', collection_name='community.aws')
+ if module.params.get("bucket_ownership_controls"):
+ module.require_botocore_at_least('1.18.11', reason='to retreive bucket ownership controls')
+
# Get parameters
name = module.params.get("name")
name_filter = module.params.get("name_filter")
diff --git a/plugins/modules/aws_secret.py b/plugins/modules/aws_secret.py
index 86c6d6e3521..dfe1013194d 100644
--- a/plugins/modules/aws_secret.py
+++ b/plugins/modules/aws_secret.py
@@ -367,6 +367,8 @@ def main():
elif current_secret.get("DeletedDate") and recovery_window == 0:
result = camel_dict_to_snake_dict(secrets_mgr.delete_secret(secret.name, recovery_window=recovery_window))
changed = True
+ else:
+ result = "secret already scheduled for deletion"
else:
result = "secret does not exist"
if state == 'present':
@@ -393,6 +395,7 @@ def main():
changed = True
result = camel_dict_to_snake_dict(secrets_mgr.get_secret(secret.name))
result.pop("response_metadata")
+
module.exit_json(changed=changed, secret=result)
diff --git a/plugins/modules/aws_ses_rule_set.py b/plugins/modules/aws_ses_rule_set.py
index 9b0b66cc30f..c87145eab5e 100644
--- a/plugins/modules/aws_ses_rule_set.py
+++ b/plugins/modules/aws_ses_rule_set.py
@@ -116,7 +116,7 @@ def list_rule_sets(client, module):
def rule_set_in(name, rule_sets):
- return any([s for s in rule_sets if s['Name'] == name])
+ return any(s for s in rule_sets if s['Name'] == name)
def ruleset_active(client, module, name):
diff --git a/plugins/modules/aws_sgw_info.py b/plugins/modules/aws_sgw_info.py
index fac2e346095..e59f8ecf9f1 100644
--- a/plugins/modules/aws_sgw_info.py
+++ b/plugins/modules/aws_sgw_info.py
@@ -343,13 +343,17 @@ def main():
gather_volumes=dict(type='bool', default=True)
)
- module = AnsibleAWSModule(argument_spec=argument_spec)
+ module = AnsibleAWSModule(
+ argument_spec=argument_spec,
+ supports_check_mode=True,
+ )
+
if module._name == 'aws_sgw_facts':
module.deprecate("The 'aws_sgw_facts' module has been renamed to 'aws_sgw_info'", date='2021-12-01', collection_name='community.aws')
client = module.client('storagegateway')
if client is None: # this should never happen
- module.fail_json(msg='Unknown error, failed to create storagegateway client, no information from boto.')
+ module.fail_json(msg='Unknown error, failed to create storagegateway client, no information available.')
SGWInformationManager(client, module).fetch()
diff --git a/plugins/modules/cloudformation_exports_info.py b/plugins/modules/cloudformation_exports_info.py
index e9ef34a20e7..dc8caae55a4 100644
--- a/plugins/modules/cloudformation_exports_info.py
+++ b/plugins/modules/cloudformation_exports_info.py
@@ -67,7 +67,7 @@ def main():
original_message=''
)
- module = AnsibleAWSModule(argument_spec=argument_spec, supports_check_mode=False)
+ module = AnsibleAWSModule(argument_spec=argument_spec, supports_check_mode=True)
cloudformation_client = module.client('cloudformation')
try:
diff --git a/plugins/modules/cloudformation_stack_set.py b/plugins/modules/cloudformation_stack_set.py
index 72b6aa05bef..750dceb2bf7 100644
--- a/plugins/modules/cloudformation_stack_set.py
+++ b/plugins/modules/cloudformation_stack_set.py
@@ -361,7 +361,7 @@ def compare_stack_instances(cfn, stack_set_name, accounts, regions):
return (desired_stack_instances - existing_stack_instances), existing_stack_instances, (existing_stack_instances - desired_stack_instances)
-@AWSRetry.backoff(tries=3, delay=4)
+@AWSRetry.jittered_backoff(retries=3, delay=4)
def stack_set_facts(cfn, stack_set_name):
try:
ss = cfn.describe_stack_set(StackSetName=stack_set_name)['StackSet']
@@ -529,8 +529,6 @@ def main():
mutually_exclusive=[['template_url', 'template', 'template_body']],
supports_check_mode=True
)
- if not (module.boto3_at_least('1.6.0') and module.botocore_at_least('1.10.26')):
- module.fail_json(msg="Boto3 or botocore version is too low. This module requires at least boto3 1.6 and botocore 1.10.26")
# Wrap the cloudformation client methods that this module uses with
# automatic backoff / retry for throttling error codes
diff --git a/plugins/modules/cloudfront_distribution.py b/plugins/modules/cloudfront_distribution.py
index 075a106246d..80ac6dcec4b 100644
--- a/plugins/modules/cloudfront_distribution.py
+++ b/plugins/modules/cloudfront_distribution.py
@@ -149,9 +149,16 @@
s3_origin_access_identity_enabled:
description:
- Use an origin access identity to configure the origin so that viewers can only access objects in an Amazon S3 bucket through CloudFront.
- - Will automatically create an Identity for you.
+ - Will automatically create an Identity for you if no I(s3_origin_config) is specified.
- See also U(https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/PrivateContent.html).
type: bool
+ s3_origin_config:
+ description: Specify origin access identity for S3 origins.
+ type: dict
+ suboptions:
+ origin_access_identity:
+ description: Existing origin access identity in the format C(origin-access-identity/cloudfront/OID_ID).
+ type: str
custom_origin_config:
description: Connection information about the origin.
type: dict
@@ -1275,6 +1282,15 @@
returned: always
type: str
sample: ''
+ s3_origin_config:
+ description: Origin access identity configuration for S3 Origin.
+ returned: when s3_origin_access_identity_enabled is true
+ type: dict
+ contains:
+ origin_access_identity:
+ type: str
+ description: The origin access id as a path.
+ sample: origin-access-identity/cloudfront/EXAMPLEID
quantity:
description: Count of origins.
returned: always
@@ -1575,7 +1591,8 @@ def __init__(self, module):
'TLSv1_2016',
'TLSv1.1_2016',
'TLSv1.2_2018',
- 'TLSv1.2_2019'
+ 'TLSv1.2_2019',
+ 'TLSv1.2_2021'
])
self.__valid_viewer_certificate_certificate_sources = set([
'cloudfront',
diff --git a/plugins/modules/cloudfront_info.py b/plugins/modules/cloudfront_info.py
index e5cf39ebb4b..df42ed0d1ac 100644
--- a/plugins/modules/cloudfront_info.py
+++ b/plugins/modules/cloudfront_info.py
@@ -173,7 +173,7 @@
# When the module is called as cloudfront_facts, return values are published
# in ansible_facts['cloudfront'][] and can be used as follows.
-# Note that this is deprecated and will stop working in Ansible 2.13.
+# Note that this is deprecated and will stop working in a release after 2021-12-01.
- name: Gather facts
community.aws.cloudfront_facts:
distribution: true
@@ -553,7 +553,7 @@ def main():
summary=dict(required=False, default=False, type='bool'),
)
- module = AnsibleAWSModule(argument_spec=argument_spec, supports_check_mode=False)
+ module = AnsibleAWSModule(argument_spec=argument_spec, supports_check_mode=True)
is_old_facts = module._name == 'cloudfront_facts'
if is_old_facts:
module.deprecate("The 'cloudfront_facts' module has been renamed to 'cloudfront_info', "
diff --git a/plugins/modules/cloudwatchevent_rule.py b/plugins/modules/cloudwatchevent_rule.py
index e7a200dd960..d38db416864 100644
--- a/plugins/modules/cloudwatchevent_rule.py
+++ b/plugins/modules/cloudwatchevent_rule.py
@@ -388,10 +388,10 @@ def _rule_matches_aws(self):
# The rule matches AWS only if all rule data fields are equal
# to their corresponding local value defined in the task
- return all([
+ return all(
getattr(self.rule, field) == aws_rule_data.get(field, None)
for field in self.RULE_FIELDS
- ])
+ )
def _targets_to_put(self):
"""Returns a list of targets that need to be updated or added remotely"""
diff --git a/plugins/modules/dms_endpoint.py b/plugins/modules/dms_endpoint.py
index f4ab520903a..6cc3bc3f896 100644
--- a/plugins/modules/dms_endpoint.py
+++ b/plugins/modules/dms_endpoint.py
@@ -175,10 +175,10 @@
from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
from ansible_collections.amazon.aws.plugins.module_utils.ec2 import AWSRetry
-backoff_params = dict(tries=5, delay=1, backoff=1.5)
+backoff_params = dict(retries=5, delay=1, backoff=1.5)
-@AWSRetry.backoff(**backoff_params)
+@AWSRetry.jittered_backoff(**backoff_params)
def describe_endpoints(connection, endpoint_identifier):
""" checks if the endpoint exists """
try:
@@ -189,7 +189,7 @@ def describe_endpoints(connection, endpoint_identifier):
return {'Endpoints': []}
-@AWSRetry.backoff(**backoff_params)
+@AWSRetry.jittered_backoff(**backoff_params)
def dms_delete_endpoint(client, **params):
"""deletes the DMS endpoint based on the EndpointArn"""
if module.params.get('wait'):
@@ -198,19 +198,19 @@ def dms_delete_endpoint(client, **params):
return client.delete_endpoint(**params)
-@AWSRetry.backoff(**backoff_params)
+@AWSRetry.jittered_backoff(**backoff_params)
def dms_create_endpoint(client, **params):
""" creates the DMS endpoint"""
return client.create_endpoint(**params)
-@AWSRetry.backoff(**backoff_params)
+@AWSRetry.jittered_backoff(**backoff_params)
def dms_modify_endpoint(client, **params):
""" updates the endpoint"""
return client.modify_endpoint(**params)
-@AWSRetry.backoff(**backoff_params)
+@AWSRetry.jittered_backoff(**backoff_params)
def get_endpoint_deleted_waiter(client):
return client.get_waiter('endpoint_deleted')
diff --git a/plugins/modules/dms_replication_subnet_group.py b/plugins/modules/dms_replication_subnet_group.py
index 305b6b5a85d..917f27438ff 100644
--- a/plugins/modules/dms_replication_subnet_group.py
+++ b/plugins/modules/dms_replication_subnet_group.py
@@ -66,10 +66,10 @@
from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
from ansible_collections.amazon.aws.plugins.module_utils.ec2 import AWSRetry
-backoff_params = dict(tries=5, delay=1, backoff=1.5)
+backoff_params = dict(retries=5, delay=1, backoff=1.5)
-@AWSRetry.backoff(**backoff_params)
+@AWSRetry.jittered_backoff(**backoff_params)
def describe_subnet_group(connection, subnet_group):
"""checks if instance exists"""
try:
@@ -80,18 +80,18 @@ def describe_subnet_group(connection, subnet_group):
return {'ReplicationSubnetGroups': []}
-@AWSRetry.backoff(**backoff_params)
+@AWSRetry.jittered_backoff(**backoff_params)
def replication_subnet_group_create(connection, **params):
""" creates the replication subnet group """
return connection.create_replication_subnet_group(**params)
-@AWSRetry.backoff(**backoff_params)
+@AWSRetry.jittered_backoff(**backoff_params)
def replication_subnet_group_modify(connection, **modify_params):
return connection.modify_replication_subnet_group(**modify_params)
-@AWSRetry.backoff(**backoff_params)
+@AWSRetry.jittered_backoff(**backoff_params)
def replication_subnet_group_delete(module, connection):
subnetid = module.params.get('identifier')
delete_parameters = dict(ReplicationSubnetGroupIdentifier=subnetid)
diff --git a/plugins/modules/dynamodb_table.py b/plugins/modules/dynamodb_table.py
index db9710f12d6..98d6fa632f9 100644
--- a/plugins/modules/dynamodb_table.py
+++ b/plugins/modules/dynamodb_table.py
@@ -16,11 +16,6 @@
- Can update the provisioned throughput on existing tables.
- Returns the status of the specified table.
author: Alan Loi (@loia)
-requirements:
-- python >= 3.6
-- boto >= 2.49.0
-- boto3 >= 1.13.0
-- botocore >= 1.16.0
options:
state:
description:
@@ -36,13 +31,13 @@
hash_key_name:
description:
- Name of the hash key.
- - Required when C(state=present).
+ - Required when I(state=present) and table doesn't exist.
type: str
hash_key_type:
description:
- Type of the hash key.
+ - Defaults to C('STRING') when creating a new table.
choices: ['STRING', 'NUMBER', 'BINARY']
- default: 'STRING'
type: str
range_key_name:
description:
@@ -51,18 +46,23 @@
range_key_type:
description:
- Type of the range key.
+ - Defaults to C('STRING') when creating a new range key.
choices: ['STRING', 'NUMBER', 'BINARY']
- default: 'STRING'
+ type: str
+ billing_mode:
+ description:
+ - Controls whether provisoned pr on-demand tables are created.
+ choices: ['PROVISIONED', 'PAY_PER_REQUEST']
type: str
read_capacity:
description:
- Read throughput capacity (units) to provision.
- default: 1
+ - Defaults to C(1) when creating a new table.
type: int
write_capacity:
description:
- Write throughput capacity (units) to provision.
- default: 1
+ - Defaults to C(1) when creating a new table.
type: int
indexes:
description:
@@ -77,25 +77,39 @@
type:
description:
- The type of index.
- - "Valid types: C(all), C(global_all), C(global_include), C(global_keys_only), C(include), C(keys_only)"
type: str
required: true
+ choices: ['all', 'global_all', 'global_include', 'global_keys_only', 'include', 'keys_only']
hash_key_name:
- description: The name of the hash-based key.
- required: true
+ description:
+ - The name of the hash-based key.
+ - Required if index doesn't already exist.
+ - Can not be modified once the index has been created.
+ required: false
type: str
hash_key_type:
- description: The type of the hash-based key.
+ description:
+ - The type of the hash-based key.
+ - Defaults to C('STRING') when creating a new index.
+ - Can not be modified once the index has been created.
type: str
+ choices: ['STRING', 'NUMBER', 'BINARY']
range_key_name:
- description: The name of the range-based key.
+ description:
+ - The name of the range-based key.
+ - Can not be modified once the index has been created.
type: str
range_key_type:
type: str
- description: The type of the range-based key.
+ description:
+ - The type of the range-based key.
+ - Defaults to C('STRING') when creating a new index.
+ - Can not be modified once the index has been created.
+ choices: ['STRING', 'NUMBER', 'BINARY']
includes:
type: list
description: A list of fields to include when using C(global_include) or C(include) indexes.
+ elements: str
read_capacity:
description:
- Read throughput capacity (units) to provision for the index.
@@ -110,13 +124,25 @@
tags:
description:
- A hash/dictionary of tags to add to the new instance or for starting/stopping instance by tag.
- - 'For example: C({"key":"value"}) and C({"key":"value","key2":"value2"})'
+ - 'For example: C({"key":"value"}) or C({"key":"value","key2":"value2"})'
type: dict
- wait_for_active_timeout:
+ purge_tags:
+ description:
+ - Remove tags not listed in I(tags).
+ default: True
+ type: bool
+ wait_timeout:
description:
- - how long before wait gives up, in seconds. only used when tags is set
- default: 60
+ - How long (in seconds) to wait for creation / update / deletion to complete.
+ aliases: ['wait_for_active_timeout']
+ default: 300
type: int
+ wait:
+ description:
+ - When I(wait=True) the module will wait for up to I(wait_timeout) seconds
+ for table creation or deletion to complete before returning.
+ default: True
+ type: bool
extends_documentation_fragment:
- amazon.aws.aws
- amazon.aws.ec2
@@ -144,6 +170,14 @@
read_capacity: 10
write_capacity: 10
+- name: Create pay-per-request table
+ community.aws.dynamodb_table:
+ name: my-table
+ region: us-east-1
+ hash_key_name: id
+ hash_key_type: STRING
+ billing_mode: PAY_PER_REQUEST
+
- name: set index on existing dynamo table
community.aws.dynamodb_table:
name: my-table
@@ -174,300 +208,791 @@
sample: ACTIVE
'''
-import time
-import traceback
-
try:
- import boto
- import boto.dynamodb2
- from boto.dynamodb2.table import Table
- from boto.dynamodb2.fields import HashKey, RangeKey, AllIndex, GlobalAllIndex, GlobalIncludeIndex, GlobalKeysOnlyIndex, IncludeIndex, KeysOnlyIndex
- from boto.dynamodb2.types import STRING, NUMBER, BINARY
- from boto.exception import BotoServerError, NoAuthHandlerFound, JSONResponseError
- from boto.dynamodb2.exceptions import ValidationException
- DYNAMO_TYPE_MAP = {
- 'STRING': STRING,
- 'NUMBER': NUMBER,
- 'BINARY': BINARY
- }
- # Boto 2 is mandatory, Boto3 is only needed for tagging
import botocore
except ImportError:
- pass # Handled by ec2.HAS_BOTO and ec2.HAS_BOTO3
+ pass # Handled by AnsibleAWSModule
+
+from ansible_collections.amazon.aws.plugins.module_utils.ec2 import camel_dict_to_snake_dict
from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
+from ansible_collections.amazon.aws.plugins.module_utils.core import is_boto3_error_code
+from ansible_collections.amazon.aws.plugins.module_utils.ec2 import AWSRetry
from ansible_collections.amazon.aws.plugins.module_utils.ec2 import ansible_dict_to_boto3_tag_list
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import AnsibleAWSError
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import connect_to_aws
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import get_aws_connection_info
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import HAS_BOTO
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import HAS_BOTO3
+from ansible_collections.amazon.aws.plugins.module_utils.ec2 import boto3_tag_list_to_ansible_dict
+from ansible_collections.amazon.aws.plugins.module_utils.ec2 import compare_aws_tags
DYNAMO_TYPE_DEFAULT = 'STRING'
INDEX_REQUIRED_OPTIONS = ['name', 'type', 'hash_key_name']
INDEX_OPTIONS = INDEX_REQUIRED_OPTIONS + ['hash_key_type', 'range_key_name', 'range_key_type', 'includes', 'read_capacity', 'write_capacity']
INDEX_TYPE_OPTIONS = ['all', 'global_all', 'global_include', 'global_keys_only', 'include', 'keys_only']
+# Map in both directions
+DYNAMO_TYPE_MAP_LONG = {'STRING': 'S', 'NUMBER': 'N', 'BINARY': 'B'}
+DYNAMO_TYPE_MAP_SHORT = dict((v, k) for k, v in DYNAMO_TYPE_MAP_LONG.items())
+KEY_TYPE_CHOICES = list(DYNAMO_TYPE_MAP_LONG.keys())
+
+
+# If you try to update an index while another index is updating, it throws
+# LimitExceededException/ResourceInUseException exceptions at you. This can be
+# pretty slow, so add plenty of retries...
+@AWSRetry.jittered_backoff(
+ retries=45, delay=5, max_delay=30,
+ catch_extra_error_codes=['LimitExceededException', 'ResourceInUseException', 'ResourceNotFoundException'],
+)
+def _update_table_with_long_retry(**changes):
+ return client.update_table(
+ TableName=module.params.get('name'),
+ **changes
+ )
+
+
+# ResourceNotFoundException is expected here if the table doesn't exist
+@AWSRetry.jittered_backoff(catch_extra_error_codes=['LimitExceededException', 'ResourceInUseException'])
+def _describe_table(**params):
+ return client.describe_table(**params)
-def create_or_update_dynamo_table(connection, module, boto3_dynamodb=None, boto3_sts=None, region=None):
+def wait_exists():
table_name = module.params.get('name')
- hash_key_name = module.params.get('hash_key_name')
- hash_key_type = module.params.get('hash_key_type')
- range_key_name = module.params.get('range_key_name')
- range_key_type = module.params.get('range_key_type')
- read_capacity = module.params.get('read_capacity')
- write_capacity = module.params.get('write_capacity')
- all_indexes = module.params.get('indexes')
- tags = module.params.get('tags')
- wait_for_active_timeout = module.params.get('wait_for_active_timeout')
-
- for index in all_indexes:
- validate_index(index, module)
-
- schema = get_schema_param(hash_key_name, hash_key_type, range_key_name, range_key_type)
-
- throughput = {
- 'read': read_capacity,
- 'write': write_capacity
- }
-
- indexes, global_indexes = get_indexes(all_indexes)
-
- result = dict(
- region=region,
- table_name=table_name,
+ wait_timeout = module.params.get('wait_timeout')
+
+ delay = min(wait_timeout, 5)
+ max_attempts = wait_timeout // delay
+
+ try:
+ waiter = client.get_waiter('table_exists')
+ waiter.wait(
+ WaiterConfig={'Delay': delay, 'MaxAttempts': max_attempts},
+ TableName=table_name,
+ )
+ except botocore.exceptions.WaiterError as e:
+ module.fail_json_aws(e, msg='Timeout while waiting on table creation')
+ except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: # pylint: disable=duplicate-except
+ module.fail_json_aws(e, msg='Failed while waiting on table creation')
+
+
+def wait_not_exists():
+ table_name = module.params.get('name')
+ wait_timeout = module.params.get('wait_timeout')
+
+ delay = min(wait_timeout, 5)
+ max_attempts = wait_timeout // delay
+
+ try:
+ waiter = client.get_waiter('table_not_exists')
+ waiter.wait(
+ WaiterConfig={'Delay': delay, 'MaxAttempts': max_attempts},
+ TableName=table_name,
+ )
+ except botocore.exceptions.WaiterError as e:
+ module.fail_json_aws(e, msg='Timeout while waiting on table deletion')
+ except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: # pylint: disable=duplicate-except
+ module.fail_json_aws(e, msg='Failed while waiting on table deletion')
+
+
+def _short_type_to_long(short_key):
+ if not short_key:
+ return None
+ return DYNAMO_TYPE_MAP_SHORT.get(short_key, None)
+
+
+def _long_type_to_short(long_key):
+ if not long_key:
+ return None
+ return DYNAMO_TYPE_MAP_LONG.get(long_key, None)
+
+
+def _schema_dict(key_name, key_type):
+ return dict(
+ AttributeName=key_name,
+ KeyType=key_type,
+ )
+
+
+def _merge_index_params(index, current_index):
+ idx = dict(current_index)
+ idx.update(index)
+ return idx
+
+
+def _decode_primary_index(current_table):
+ """
+ Decodes the primary index info from the current table definition
+ splitting it up into the keys we use as parameters
+ """
+ # The schema/attribute definitions are a list of dicts which need the same
+ # treatment as boto3's tag lists
+ schema = boto3_tag_list_to_ansible_dict(
+ current_table.get('key_schema', []),
+ # Map from 'HASH'/'RANGE' to attribute name
+ tag_name_key_name='key_type',
+ tag_value_key_name='attribute_name',
+ )
+ attributes = boto3_tag_list_to_ansible_dict(
+ current_table.get('attribute_definitions', []),
+ # Map from attribute name to 'S'/'N'/'B'.
+ tag_name_key_name='attribute_name',
+ tag_value_key_name='attribute_type',
+ )
+
+ hash_key_name = schema.get('HASH')
+ hash_key_type = _short_type_to_long(attributes.get(hash_key_name, None))
+ range_key_name = schema.get('RANGE', None)
+ range_key_type = _short_type_to_long(attributes.get(range_key_name, None))
+
+ return dict(
hash_key_name=hash_key_name,
hash_key_type=hash_key_type,
range_key_name=range_key_name,
range_key_type=range_key_type,
- read_capacity=read_capacity,
- write_capacity=write_capacity,
- indexes=all_indexes,
)
+
+def _decode_index(index_data, attributes, type_prefix=''):
try:
- table = Table(table_name, connection=connection)
+ index_map = dict(
+ name=index_data['index_name'],
+ )
- if dynamo_table_exists(table):
- result['changed'] = update_dynamo_table(table, throughput=throughput, check_mode=module.check_mode, global_indexes=global_indexes)
- else:
- if not module.check_mode:
- Table.create(table_name, connection=connection, schema=schema, throughput=throughput, indexes=indexes, global_indexes=global_indexes)
- result['changed'] = True
-
- if not module.check_mode:
- result['table_status'] = table.describe()['Table']['TableStatus']
-
- if tags:
- # only tables which are active can be tagged
- wait_until_table_active(module, table, wait_for_active_timeout)
- account_id = get_account_id(boto3_sts)
- boto3_dynamodb.tag_resource(
- ResourceArn='arn:aws:dynamodb:' +
- region +
- ':' +
- account_id +
- ':table/' +
- table_name,
- Tags=ansible_dict_to_boto3_tag_list(tags))
- result['tags'] = tags
-
- except BotoServerError:
- result['msg'] = 'Failed to create/update dynamo table due to error: ' + traceback.format_exc()
- module.fail_json(**result)
- else:
- module.exit_json(**result)
+ index_data = dict(index_data)
+ index_data['attribute_definitions'] = attributes
+ index_map.update(_decode_primary_index(index_data))
-def get_account_id(boto3_sts):
- return boto3_sts.get_caller_identity()["Account"]
+ throughput = index_data.get('provisioned_throughput', {})
+ index_map['provisioned_throughput'] = throughput
+ if throughput:
+ index_map['read_capacity'] = throughput.get('read_capacity_units')
+ index_map['write_capacity'] = throughput.get('write_capacity_units')
+ projection = index_data.get('projection', {})
+ if projection:
+ index_map['type'] = type_prefix + projection.get('projection_type')
+ index_map['includes'] = projection.get('non_key_attributes', [])
-def wait_until_table_active(module, table, wait_timeout):
- max_wait_time = time.time() + wait_timeout
- while (max_wait_time > time.time()) and (table.describe()['Table']['TableStatus'] != 'ACTIVE'):
- time.sleep(5)
- if max_wait_time <= time.time():
- # waiting took too long
- module.fail_json(msg="timed out waiting for table to exist")
+ return index_map
+ except Exception as e:
+ module.fail_json_aws(e, msg='Decode failure', index_data=index_data)
-def delete_dynamo_table(connection, module):
- table_name = module.params.get('name')
+def compatability_results(current_table):
+ if not current_table:
+ return dict()
+
+ billing_mode = current_table.get('billing_mode')
+
+ primary_indexes = _decode_primary_index(current_table)
+
+ hash_key_name = primary_indexes.get('hash_key_name')
+ hash_key_type = primary_indexes.get('hash_key_type')
+ range_key_name = primary_indexes.get('range_key_name')
+ range_key_type = primary_indexes.get('range_key_type')
+
+ indexes = list()
+ global_indexes = current_table.get('_global_index_map', {})
+ local_indexes = current_table.get('_local_index_map', {})
+ for index in global_indexes:
+ idx = dict(global_indexes[index])
+ idx.pop('provisioned_throughput', None)
+ indexes.append(idx)
+ for index in local_indexes:
+ idx = dict(local_indexes[index])
+ idx.pop('provisioned_throughput', None)
+ indexes.append(idx)
- result = dict(
- region=module.params.get('region'),
- table_name=table_name,
+ compat_results = dict(
+ hash_key_name=hash_key_name,
+ hash_key_type=hash_key_type,
+ range_key_name=range_key_name,
+ range_key_type=range_key_type,
+ indexes=indexes,
+ billing_mode=billing_mode,
+ region=module.region,
+ table_name=current_table.get('table_name', None),
+ table_status=current_table.get('table_status', None),
+ tags=current_table.get('tags', {}),
)
+ if billing_mode == "PROVISIONED":
+ throughput = current_table.get('provisioned_throughput', {})
+ compat_results['read_capacity'] = throughput.get('read_capacity_units', None)
+ compat_results['write_capacity'] = throughput.get('write_capacity_units', None)
+
+ return compat_results
+
+
+def get_dynamodb_table():
+ table_name = module.params.get('name')
+ try:
+ table = _describe_table(TableName=table_name)
+ except is_boto3_error_code('ResourceNotFoundException'):
+ return None
+ except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: # pylint: disable=duplicate-except
+ module.fail_json_aws(e, msg='Failed to describe table')
+
+ table = table['Table']
try:
- table = Table(table_name, connection=connection)
+ tags = client.list_tags_of_resource(aws_retry=True, ResourceArn=table['TableArn'])['Tags']
+ except is_boto3_error_code('AccessDeniedException'):
+ module.warn('Permission denied when listing tags')
+ tags = []
+ except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: # pylint: disable=duplicate-except
+ module.fail_json_aws(e, msg='Failed to list table tags')
+
+ tags = boto3_tag_list_to_ansible_dict(tags)
+
+ table = camel_dict_to_snake_dict(table)
+
+ # Put some of the values into places people will expect them
+ table['arn'] = table['table_arn']
+ table['name'] = table['table_name']
+ table['status'] = table['table_status']
+ table['id'] = table['table_id']
+ table['size'] = table['table_size_bytes']
+ table['tags'] = tags
+
+ # billing_mode_summary doesn't always seem to be set but is always set for PAY_PER_REQUEST
+ # and when updating the billing_mode
+ if 'billing_mode_summary' in table:
+ table['billing_mode'] = table['billing_mode_summary']['billing_mode']
+ else:
+ table['billing_mode'] = "PROVISIONED"
+
+ # convert indexes into something we can easily search against
+ attributes = table['attribute_definitions']
+ global_index_map = dict()
+ local_index_map = dict()
+ for index in table.get('global_secondary_indexes', []):
+ idx = _decode_index(index, attributes, type_prefix='global_')
+ global_index_map[idx['name']] = idx
+ for index in table.get('local_secondary_indexes', []):
+ idx = _decode_index(index, attributes)
+ local_index_map[idx['name']] = idx
+ table['_global_index_map'] = global_index_map
+ table['_local_index_map'] = local_index_map
+
+ return table
+
+
+def _generate_attribute_map():
+ """
+ Builds a map of Key Names to Type
+ """
+ attributes = dict()
+
+ for index in (module.params, *module.params.get('indexes')):
+ # run through hash_key_name and range_key_name
+ for t in ['hash', 'range']:
+ key_name = index.get(t + '_key_name')
+ if not key_name:
+ continue
+ key_type = index.get(t + '_key_type') or DYNAMO_TYPE_DEFAULT
+ _type = _long_type_to_short(key_type)
+ if key_name in attributes:
+ if _type != attributes[key_name]:
+ module.fail_json(msg='Conflicting attribute type',
+ type_1=_type, type_2=attributes[key_name],
+ key_name=key_name)
+ else:
+ attributes[key_name] = _type
+
+ return attributes
+
+
+def _generate_attributes():
+ attributes = _generate_attribute_map()
+
+ # Use ansible_dict_to_boto3_tag_list to generate the list of dicts
+ # format we need
+ attrs = ansible_dict_to_boto3_tag_list(
+ attributes,
+ tag_name_key_name='AttributeName',
+ tag_value_key_name='AttributeType'
+ )
+ return list(attrs)
- if dynamo_table_exists(table):
- if not module.check_mode:
- table.delete()
- result['changed'] = True
- else:
- result['changed'] = False
+def _generate_throughput(params=None):
+ if not params:
+ params = module.params
+
+ read_capacity = params.get('read_capacity') or 1
+ write_capacity = params.get('write_capacity') or 1
+ throughput = dict(
+ ReadCapacityUnits=read_capacity,
+ WriteCapacityUnits=write_capacity,
+ )
+
+ return throughput
+
+
+def _generate_schema(params=None):
+ if not params:
+ params = module.params
+
+ schema = list()
+ hash_key_name = params.get('hash_key_name')
+ range_key_name = params.get('range_key_name')
- except BotoServerError:
- result['msg'] = 'Failed to delete dynamo table due to error: ' + traceback.format_exc()
- module.fail_json(**result)
+ if hash_key_name:
+ entry = _schema_dict(hash_key_name, 'HASH')
+ schema.append(entry)
+ if range_key_name:
+ entry = _schema_dict(range_key_name, 'RANGE')
+ schema.append(entry)
+
+ return schema
+
+
+def _primary_index_changes(current_table):
+
+ primary_index = _decode_primary_index(current_table)
+
+ hash_key_name = primary_index.get('hash_key_name')
+ _hash_key_name = module.params.get('hash_key_name')
+ hash_key_type = primary_index.get('hash_key_type')
+ _hash_key_type = module.params.get('hash_key_type')
+ range_key_name = primary_index.get('range_key_name')
+ _range_key_name = module.params.get('range_key_name')
+ range_key_type = primary_index.get('range_key_type')
+ _range_key_type = module.params.get('range_key_type')
+
+ changed = list()
+
+ if _hash_key_name and (_hash_key_name != hash_key_name):
+ changed.append('hash_key_name')
+ if _hash_key_type and (_hash_key_type != hash_key_type):
+ changed.append('hash_key_type')
+ if _range_key_name and (_range_key_name != range_key_name):
+ changed.append('range_key_name')
+ if _range_key_type and (_range_key_type != range_key_type):
+ changed.append('range_key_type')
+
+ return changed
+
+
+def _throughput_changes(current_table, params=None):
+
+ if not params:
+ params = module.params
+
+ throughput = current_table.get('provisioned_throughput', {})
+ read_capacity = throughput.get('read_capacity_units', None)
+ _read_capacity = params.get('read_capacity') or read_capacity
+ write_capacity = throughput.get('write_capacity_units', None)
+ _write_capacity = params.get('write_capacity') or write_capacity
+
+ if (read_capacity != _read_capacity) or (write_capacity != _write_capacity):
+ return dict(
+ ReadCapacityUnits=_read_capacity,
+ WriteCapacityUnits=_write_capacity,
+ )
+
+ return dict()
+
+
+def _generate_global_indexes(billing_mode):
+ index_exists = dict()
+ indexes = list()
+
+ include_throughput = True
+
+ if billing_mode == "PAY_PER_REQUEST":
+ include_throughput = False
+
+ for index in module.params.get('indexes'):
+ if index.get('type') not in ['global_all', 'global_include', 'global_keys_only']:
+ continue
+ name = index.get('name')
+ if name in index_exists:
+ module.fail_json(msg='Duplicate key {0} in list of global indexes'.format(name))
+ # Convert the type name to upper case and remove the global_
+ index['type'] = index['type'].upper()[7:]
+ index = _generate_index(index, include_throughput)
+ index_exists[name] = True
+ indexes.append(index)
+
+ return indexes
+
+
+def _generate_local_indexes():
+ index_exists = dict()
+ indexes = list()
+
+ for index in module.params.get('indexes'):
+ index = dict()
+ if index.get('type') not in ['all', 'include', 'keys_only']:
+ continue
+ name = index.get('name')
+ if name in index_exists:
+ module.fail_json(msg='Duplicate key {0} in list of local indexes'.format(name))
+ index['type'] = index['type'].upper()
+ index = _generate_index(index, False)
+ index_exists[name] = True
+ indexes.append(index)
+
+ return indexes
+
+
+def _generate_global_index_map(current_table):
+ global_index_map = dict()
+ existing_indexes = current_table['_global_index_map']
+ for index in module.params.get('indexes'):
+ if index.get('type') not in ['global_all', 'global_include', 'global_keys_only']:
+ continue
+ name = index.get('name')
+ if name in global_index_map:
+ module.fail_json(msg='Duplicate key {0} in list of global indexes'.format(name))
+ idx = _merge_index_params(index, existing_indexes.get(name, {}))
+ # Convert the type name to upper case and remove the global_
+ idx['type'] = idx['type'].upper()[7:]
+ global_index_map[name] = idx
+ return global_index_map
+
+
+def _generate_local_index_map(current_table):
+ local_index_map = dict()
+ existing_indexes = current_table['_local_index_map']
+ for index in module.params.get('indexes'):
+ if index.get('type') not in ['all', 'include', 'keys_only']:
+ continue
+ name = index.get('name')
+ if name in local_index_map:
+ module.fail_json(msg='Duplicate key {0} in list of local indexes'.format(name))
+ idx = _merge_index_params(index, existing_indexes.get(name, {}))
+ # Convert the type name to upper case
+ idx['type'] = idx['type'].upper()
+ local_index_map[name] = idx
+ return local_index_map
+
+
+def _generate_index(index, include_throughput=True):
+ key_schema = _generate_schema(index)
+ throughput = _generate_throughput(index)
+ non_key_attributes = index['includes'] or []
+ projection = dict(
+ ProjectionType=index['type'],
+ )
+ if index['type'] != 'ALL':
+ projection['NonKeyAttributes'] = non_key_attributes
else:
- module.exit_json(**result)
+ if non_key_attributes:
+ module.deprecate(
+ "DynamoDB does not support specifying non-key-attributes ('includes') for "
+ "indexes of type 'all'. Attempts to set this attributes are currently "
+ "ignored, but in future will result in a failure. "
+ "Index name: {0}".format(index['name']),
+ version='3.0.0', collection_name='community.aws')
+
+ idx = dict(
+ IndexName=index['name'],
+ KeySchema=key_schema,
+ Projection=projection,
+ )
+ if include_throughput:
+ idx['ProvisionedThroughput'] = throughput
-def dynamo_table_exists(table):
- try:
- table.describe()
- return True
+ return idx
- except JSONResponseError as e:
- if e.message and e.message.startswith('Requested resource not found'):
- return False
- else:
- raise e
+def _attribute_changes(current_table):
+ # TODO (future) It would be nice to catch attempts to change types here.
+ return _generate_attributes()
-def update_dynamo_table(table, throughput=None, check_mode=False, global_indexes=None):
- table.describe() # populate table details
- throughput_changed = False
- global_indexes_changed = False
- if has_throughput_changed(table, throughput):
- if not check_mode:
- throughput_changed = table.update(throughput=throughput)
- else:
- throughput_changed = True
- removed_indexes, added_indexes, index_throughput_changes = get_changed_global_indexes(table, global_indexes)
- if removed_indexes:
- if not check_mode:
- for name, index in removed_indexes.items():
- global_indexes_changed = table.delete_global_secondary_index(name) or global_indexes_changed
- else:
- global_indexes_changed = True
+def _global_index_changes(current_table):
+ current_global_index_map = current_table['_global_index_map']
+ global_index_map = _generate_global_index_map(current_table)
+
+ current_billing_mode = current_table.get('billing_mode')
+
+ if module.params.get('billing_mode') is None:
+ billing_mode = current_billing_mode
+ else:
+ billing_mode = module.params.get('billing_mode')
+
+ include_throughput = True
+
+ if billing_mode == "PAY_PER_REQUEST":
+ include_throughput = False
+
+ index_changes = list()
+
+ # TODO (future) it would be nice to add support for deleting an index
+ for name in global_index_map:
- if added_indexes:
- if not check_mode:
- for name, index in added_indexes.items():
- global_indexes_changed = table.create_global_secondary_index(global_index=index) or global_indexes_changed
+ idx = dict(_generate_index(global_index_map[name], include_throughput=include_throughput))
+ if name not in current_global_index_map:
+ index_changes.append(dict(Create=idx))
else:
- global_indexes_changed = True
+ # The only thing we can change is the provisioned throughput.
+ # TODO (future) it would be nice to throw a deprecation here
+ # rather than dropping other changes on the floor
+ _current = current_global_index_map[name]
+ _new = global_index_map[name]
+
+ if include_throughput:
+ change = dict(_throughput_changes(_current, _new))
+ if change:
+ update = dict(
+ IndexName=name,
+ ProvisionedThroughput=change,
+ )
+ index_changes.append(dict(Update=update))
+
+ return index_changes
+
+
+def _local_index_changes(current_table):
+ # TODO (future) Changes to Local Indexes aren't possible after creation,
+ # we should probably throw a deprecation warning here (original module
+ # also just dropped these changes on the floor)
+ return []
+
+
+def _update_table(current_table):
+ changes = dict()
+ additional_global_index_changes = list()
+
+ throughput_changes = _throughput_changes(current_table)
+ if throughput_changes:
+ changes['ProvisionedThroughput'] = throughput_changes
+
+ current_billing_mode = current_table.get('billing_mode')
+ new_billing_mode = module.params.get('billing_mode')
+
+ if new_billing_mode is None:
+ new_billing_mode = current_billing_mode
- if index_throughput_changes:
- if not check_mode:
- # todo: remove try once boto has https://github.com/boto/boto/pull/3447 fixed
+ if current_billing_mode != new_billing_mode:
+ changes['BillingMode'] = new_billing_mode
+
+ global_index_changes = _global_index_changes(current_table)
+ if global_index_changes:
+ changes['GlobalSecondaryIndexUpdates'] = global_index_changes
+ # Only one index can be changed at a time except if changing the billing mode, pass the first during the
+ # main update and deal with the others on a slow retry to wait for
+ # completion
+
+ if current_billing_mode == new_billing_mode:
+ if len(global_index_changes) > 1:
+ changes['GlobalSecondaryIndexUpdates'] = [global_index_changes[0]]
+ additional_global_index_changes = global_index_changes[1:]
+
+ local_index_changes = _local_index_changes(current_table)
+ if local_index_changes:
+ changes['LocalSecondaryIndexUpdates'] = local_index_changes
+
+ if not changes:
+ return False
+
+ if module.check_mode:
+ return True
+
+ if global_index_changes or local_index_changes:
+ changes['AttributeDefinitions'] = _generate_attributes()
+
+ try:
+ client.update_table(
+ aws_retry=True,
+ TableName=module.params.get('name'),
+ **changes
+ )
+ except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
+ module.fail_json_aws(e, msg="Failed to update table")
+
+ if additional_global_index_changes:
+ for index in additional_global_index_changes:
try:
- global_indexes_changed = table.update_global_secondary_index(global_indexes=index_throughput_changes) or global_indexes_changed
- except ValidationException:
- pass
- else:
- global_indexes_changed = True
+ _update_table_with_long_retry(GlobalSecondaryIndexUpdates=[index], AttributeDefinitions=changes['AttributeDefinitions'])
+ except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
+ module.fail_json_aws(e, msg="Failed to update table", changes=changes,
+ additional_global_index_changes=additional_global_index_changes)
+
+ if module.params.get('wait'):
+ wait_exists()
- return throughput_changed or global_indexes_changed
+ return True
-def has_throughput_changed(table, new_throughput):
- if not new_throughput:
+def _update_tags(current_table):
+ _tags = module.params.get('tags')
+ if _tags is None:
return False
- return new_throughput['read'] != table.throughput['read'] or \
- new_throughput['write'] != table.throughput['write']
+ tags_to_add, tags_to_remove = compare_aws_tags(current_table['tags'], module.params.get('tags'),
+ purge_tags=module.params.get('purge_tags'))
+ # If neither need updating we can return already
+ if not (tags_to_add or tags_to_remove):
+ return False
+
+ if module.check_mode:
+ return True
+
+ if tags_to_add:
+ try:
+ client.tag_resource(
+ aws_retry=True,
+ ResourceArn=current_table['arn'],
+ Tags=ansible_dict_to_boto3_tag_list(tags_to_add),
+ )
+ except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
+ module.fail_json_aws(e, msg="Failed to tag table")
+ if tags_to_remove:
+ try:
+ client.untag_resource(
+ aws_retry=True,
+ ResourceArn=current_table['arn'],
+ TagKeys=tags_to_remove,
+ )
+ except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
+ module.fail_json_aws(e, msg="Failed to untag table")
+
+ return True
-def get_schema_param(hash_key_name, hash_key_type, range_key_name, range_key_type):
- if range_key_name:
- schema = [
- HashKey(hash_key_name, DYNAMO_TYPE_MAP.get(hash_key_type, DYNAMO_TYPE_MAP[DYNAMO_TYPE_DEFAULT])),
- RangeKey(range_key_name, DYNAMO_TYPE_MAP.get(range_key_type, DYNAMO_TYPE_MAP[DYNAMO_TYPE_DEFAULT]))
- ]
- else:
- schema = [
- HashKey(hash_key_name, DYNAMO_TYPE_MAP.get(hash_key_type, DYNAMO_TYPE_MAP[DYNAMO_TYPE_DEFAULT]))
- ]
- return schema
+def update_table(current_table):
+ primary_index_changes = _primary_index_changes(current_table)
+ if primary_index_changes:
+ module.deprecate("DynamoDB does not support updating the Primary keys on a table. "
+ "Attempts to change the keys are currently ignored, but in future will "
+ "result in a failure. "
+ "Changed paramters are {0}".format(primary_index_changes),
+ version='3.0.0', collection_name='community.aws')
-def get_changed_global_indexes(table, global_indexes):
- table.describe()
+ changed = False
+ changed |= _update_table(current_table)
+ changed |= _update_tags(current_table)
- table_index_info = dict((index.name, index.schema()) for index in table.global_indexes)
- table_index_objects = dict((index.name, index) for index in table.global_indexes)
- set_index_info = dict((index.name, index.schema()) for index in global_indexes)
- set_index_objects = dict((index.name, index) for index in global_indexes)
+ if module.params.get('wait'):
+ wait_exists()
- removed_indexes = dict((name, index) for name, index in table_index_info.items() if name not in set_index_info)
- added_indexes = dict((name, set_index_objects[name]) for name, index in set_index_info.items() if name not in table_index_info)
- # todo: uncomment once boto has https://github.com/boto/boto/pull/3447 fixed
- # for name, index in set_index_objects.items():
- # if (name not in added_indexes and
- # (index.throughput['read'] != str(table_index_objects[name].throughput['read']) or
- # index.throughput['write'] != str(table_index_objects[name].throughput['write']))):
- # index_throughput_changes[name] = index.throughput
- # todo: remove once boto has https://github.com/boto/boto/pull/3447 fixed
- index_throughput_changes = dict((name, index.throughput) for name, index in set_index_objects.items() if name not in added_indexes)
+ return changed
- return removed_indexes, added_indexes, index_throughput_changes
+def create_table():
+ table_name = module.params.get('name')
+ hash_key_name = module.params.get('hash_key_name')
+ billing_mode = module.params.get('billing_mode')
-def validate_index(index, module):
- for key, val in index.items():
- if key not in INDEX_OPTIONS:
- module.fail_json(msg='%s is not a valid option for an index' % key)
- for required_option in INDEX_REQUIRED_OPTIONS:
- if required_option not in index:
- module.fail_json(msg='%s is a required option for an index' % required_option)
- if index['type'] not in INDEX_TYPE_OPTIONS:
- module.fail_json(msg='%s is not a valid index type, must be one of %s' % (index['type'], INDEX_TYPE_OPTIONS))
+ if billing_mode is None:
+ billing_mode = "PROVISIONED"
+ tags = ansible_dict_to_boto3_tag_list(module.params.get('tags') or {})
-def get_indexes(all_indexes):
- indexes = []
- global_indexes = []
- for index in all_indexes:
- name = index['name']
- schema = get_schema_param(index.get('hash_key_name'), index.get('hash_key_type'), index.get('range_key_name'), index.get('range_key_type'))
- throughput = {
- 'read': index.get('read_capacity', 1),
- 'write': index.get('write_capacity', 1)
- }
+ if not hash_key_name:
+ module.fail_json('"hash_key_name" must be provided when creating a new table.')
- if index['type'] == 'all':
- indexes.append(AllIndex(name, parts=schema))
+ if module.check_mode:
+ return True
+
+ if billing_mode == "PROVISIONED":
+ throughput = _generate_throughput()
+
+ attributes = _generate_attributes()
+ key_schema = _generate_schema()
+ local_indexes = _generate_local_indexes()
+ global_indexes = _generate_global_indexes(billing_mode)
+
+ params = dict(
+ TableName=table_name,
+ AttributeDefinitions=attributes,
+ KeySchema=key_schema,
+ Tags=tags,
+ BillingMode=billing_mode
+ # TODO (future)
+ # StreamSpecification,
+ # SSESpecification,
+ )
- elif index['type'] == 'global_all':
- global_indexes.append(GlobalAllIndex(name, parts=schema, throughput=throughput))
+ if billing_mode == "PROVISIONED":
+ params['ProvisionedThroughput'] = throughput
+ if local_indexes:
+ params['LocalSecondaryIndexes'] = local_indexes
+ if global_indexes:
+ params['GlobalSecondaryIndexes'] = global_indexes
+
+ try:
+ client.create_table(aws_retry=True, **params)
+ except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
+ module.fail_json_aws(e, msg='Failed to create table')
+
+ if module.params.get('wait'):
+ wait_exists()
+
+ return True
+
+
+def delete_table(current_table):
+ if not current_table:
+ return False
+
+ if module.check_mode:
+ return True
- elif index['type'] == 'global_include':
- global_indexes.append(GlobalIncludeIndex(name, parts=schema, throughput=throughput, includes=index['includes']))
+ table_name = module.params.get('name')
- elif index['type'] == 'global_keys_only':
- global_indexes.append(GlobalKeysOnlyIndex(name, parts=schema, throughput=throughput))
+ # If an index is mid-update then we have to wait for the update to complete
+ # before deletion will succeed
+ long_retry = AWSRetry.jittered_backoff(
+ retries=45, delay=5, max_delay=30,
+ catch_extra_error_codes=['LimitExceededException', 'ResourceInUseException'],
+ )
- elif index['type'] == 'include':
- indexes.append(IncludeIndex(name, parts=schema, includes=index['includes']))
+ try:
+ long_retry(client.delete_table)(TableName=table_name)
+ except is_boto3_error_code('ResourceNotFoundException'):
+ return False
+ except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: # pylint: disable=duplicate-except
+ module.fail_json_aws(e, msg='Failed to delete table')
- elif index['type'] == 'keys_only':
- indexes.append(KeysOnlyIndex(name, parts=schema))
+ if module.params.get('wait'):
+ wait_not_exists()
- return indexes, global_indexes
+ return True
def main():
+
+ global module
+ global client
+
+ # TODO (future) It would be good to split global and local indexes. They have
+ # different parameters, use a separate namespace for names,
+ # and local indexes can't be updated.
+ index_options = dict(
+ name=dict(type='str', required=True),
+ # It would be nice to make this optional, but because Local and Global
+ # indexes are mixed in here we need this to be able to tell to which
+ # group of indexes the index belongs.
+ type=dict(type='str', required=True, choices=INDEX_TYPE_OPTIONS),
+ hash_key_name=dict(type='str', required=False),
+ hash_key_type=dict(type='str', required=False, choices=KEY_TYPE_CHOICES),
+ range_key_name=dict(type='str', required=False),
+ range_key_type=dict(type='str', required=False, choices=KEY_TYPE_CHOICES),
+ includes=dict(type='list', required=False, elements='str'),
+ read_capacity=dict(type='int', required=False),
+ write_capacity=dict(type='int', required=False),
+ )
+
argument_spec = dict(
state=dict(default='present', choices=['present', 'absent']),
name=dict(required=True, type='str'),
hash_key_name=dict(type='str'),
- hash_key_type=dict(default='STRING', type='str', choices=['STRING', 'NUMBER', 'BINARY']),
+ hash_key_type=dict(type='str', choices=KEY_TYPE_CHOICES),
range_key_name=dict(type='str'),
- range_key_type=dict(default='STRING', type='str', choices=['STRING', 'NUMBER', 'BINARY']),
- read_capacity=dict(default=1, type='int'),
- write_capacity=dict(default=1, type='int'),
- indexes=dict(default=[], type='list', elements='dict'),
+ range_key_type=dict(type='str', choices=KEY_TYPE_CHOICES),
+ billing_mode=dict(type='str', choices=['PROVISIONED', 'PAY_PER_REQUEST']),
+ read_capacity=dict(type='int'),
+ write_capacity=dict(type='int'),
+ indexes=dict(default=[], type='list', elements='dict', options=index_options),
tags=dict(type='dict'),
- wait_for_active_timeout=dict(default=60, type='int'),
+ purge_tags=dict(type='bool', default=True),
+ wait=dict(type='bool', default=True),
+ wait_timeout=dict(default=300, type='int', aliases=['wait_for_active_timeout']),
)
module = AnsibleAWSModule(
@@ -476,38 +1001,38 @@ def main():
check_boto3=False,
)
- if not HAS_BOTO:
- module.fail_json(msg='boto required for this module')
-
- if not HAS_BOTO3 and module.params.get('tags'):
- module.fail_json(msg='boto3 required when using tags for this module')
-
- region, ec2_url, aws_connect_params = get_aws_connection_info(module)
- if not region:
- module.fail_json(msg='region must be specified')
-
- try:
- connection = connect_to_aws(boto.dynamodb2, region, **aws_connect_params)
- except (NoAuthHandlerFound, AnsibleAWSError) as e:
- module.fail_json(msg=str(e))
+ retry_decorator = AWSRetry.jittered_backoff(
+ catch_extra_error_codes=['LimitExceededException', 'ResourceInUseException', 'ResourceNotFoundException'],
+ )
+ client = module.client('dynamodb', retry_decorator=retry_decorator)
- if module.params.get('tags'):
- try:
- boto3_dynamodb = module.client('dynamodb')
- if not hasattr(boto3_dynamodb, 'tag_resource'):
- module.fail_json(msg='boto3 connection does not have tag_resource(), likely due to using an old version')
- boto3_sts = module.client('sts')
- except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(e, msg='Failed to connect to AWS')
- else:
- boto3_dynamodb = None
- boto3_sts = None
+ current_table = get_dynamodb_table()
+ changed = False
+ table = None
+ results = dict()
state = module.params.get('state')
if state == 'present':
- create_or_update_dynamo_table(connection, module, boto3_dynamodb, boto3_sts, region)
+ if current_table:
+ changed |= update_table(current_table)
+ else:
+ changed |= create_table()
+ table = get_dynamodb_table()
elif state == 'absent':
- delete_dynamo_table(connection, module)
+ changed |= delete_table(current_table)
+
+ compat_results = compatability_results(table)
+ if compat_results:
+ results.update(compat_results)
+
+ results['changed'] = changed
+ if table:
+ # These are used to pass computed data about, not needed for users
+ table.pop('_global_index_map', None)
+ table.pop('_local_index_map', None)
+ results['table'] = table
+
+ module.exit_json(**results)
if __name__ == '__main__':
diff --git a/plugins/modules/dynamodb_ttl.py b/plugins/modules/dynamodb_ttl.py
index 490a948f9a9..2bdd9a21d45 100644
--- a/plugins/modules/dynamodb_ttl.py
+++ b/plugins/modules/dynamodb_ttl.py
@@ -120,10 +120,6 @@ def main():
argument_spec=argument_spec,
)
- if not module.botocore_at_least('1.5.24'):
- # TTL was added in 1.5.24
- module.fail_json(msg='Found botocore in version {0}, but >= {1} is required for TTL support'.format(botocore.__version__, '1.5.24'))
-
try:
dbclient = module.client('dynamodb')
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
diff --git a/plugins/modules/ec2_ami_copy.py b/plugins/modules/ec2_ami_copy.py
index 15acfe4e4a9..e5628b00034 100644
--- a/plugins/modules/ec2_ami_copy.py
+++ b/plugins/modules/ec2_ami_copy.py
@@ -212,7 +212,6 @@ def main():
tag_equality=dict(type='bool', default=False))
module = AnsibleAWSModule(argument_spec=argument_spec)
- # TODO: Check botocore version
ec2 = module.client('ec2')
copy_image(module, ec2)
diff --git a/plugins/modules/ec2_asg.py b/plugins/modules/ec2_asg.py
index 59e74040d64..46cdcbf15b8 100644
--- a/plugins/modules/ec2_asg.py
+++ b/plugins/modules/ec2_asg.py
@@ -639,21 +639,21 @@
INSTANCE_ATTRIBUTES = ('instance_id', 'health_status', 'lifecycle_state', 'launch_config_name')
-backoff_params = dict(tries=10, delay=3, backoff=1.5)
+backoff_params = dict(retries=10, delay=3, backoff=1.5)
-@AWSRetry.backoff(**backoff_params)
+@AWSRetry.jittered_backoff(**backoff_params)
def describe_autoscaling_groups(connection, group_name):
pg = connection.get_paginator('describe_auto_scaling_groups')
return pg.paginate(AutoScalingGroupNames=[group_name]).build_full_result().get('AutoScalingGroups', [])
-@AWSRetry.backoff(**backoff_params)
+@AWSRetry.jittered_backoff(**backoff_params)
def deregister_lb_instances(connection, lb_name, instance_id):
connection.deregister_instances_from_load_balancer(LoadBalancerName=lb_name, Instances=[dict(InstanceId=instance_id)])
-@AWSRetry.backoff(**backoff_params)
+@AWSRetry.jittered_backoff(**backoff_params)
def describe_instance_health(connection, lb_name, instances):
params = dict(LoadBalancerName=lb_name)
if instances:
@@ -661,28 +661,28 @@ def describe_instance_health(connection, lb_name, instances):
return connection.describe_instance_health(**params)
-@AWSRetry.backoff(**backoff_params)
+@AWSRetry.jittered_backoff(**backoff_params)
def describe_target_health(connection, target_group_arn, instances):
return connection.describe_target_health(TargetGroupArn=target_group_arn, Targets=instances)
-@AWSRetry.backoff(**backoff_params)
+@AWSRetry.jittered_backoff(**backoff_params)
def suspend_asg_processes(connection, asg_name, processes):
connection.suspend_processes(AutoScalingGroupName=asg_name, ScalingProcesses=processes)
-@AWSRetry.backoff(**backoff_params)
+@AWSRetry.jittered_backoff(**backoff_params)
def resume_asg_processes(connection, asg_name, processes):
connection.resume_processes(AutoScalingGroupName=asg_name, ScalingProcesses=processes)
-@AWSRetry.backoff(**backoff_params)
+@AWSRetry.jittered_backoff(**backoff_params)
def describe_launch_configurations(connection, launch_config_name):
pg = connection.get_paginator('describe_launch_configurations')
return pg.paginate(LaunchConfigurationNames=[launch_config_name]).build_full_result()
-@AWSRetry.backoff(**backoff_params)
+@AWSRetry.jittered_backoff(**backoff_params)
def describe_launch_templates(connection, launch_template):
if launch_template['launch_template_id'] is not None:
try:
@@ -698,12 +698,12 @@ def describe_launch_templates(connection, launch_template):
module.fail_json(msg="No launch template found matching: %s" % launch_template)
-@AWSRetry.backoff(**backoff_params)
+@AWSRetry.jittered_backoff(**backoff_params)
def create_asg(connection, **params):
connection.create_auto_scaling_group(**params)
-@AWSRetry.backoff(**backoff_params)
+@AWSRetry.jittered_backoff(**backoff_params)
def put_notification_config(connection, asg_name, topic_arn, notification_types):
connection.put_notification_configuration(
AutoScalingGroupName=asg_name,
@@ -712,7 +712,7 @@ def put_notification_config(connection, asg_name, topic_arn, notification_types)
)
-@AWSRetry.backoff(**backoff_params)
+@AWSRetry.jittered_backoff(**backoff_params)
def del_notification_config(connection, asg_name, topic_arn):
connection.delete_notification_configuration(
AutoScalingGroupName=asg_name,
@@ -720,37 +720,37 @@ def del_notification_config(connection, asg_name, topic_arn):
)
-@AWSRetry.backoff(**backoff_params)
+@AWSRetry.jittered_backoff(**backoff_params)
def attach_load_balancers(connection, asg_name, load_balancers):
connection.attach_load_balancers(AutoScalingGroupName=asg_name, LoadBalancerNames=load_balancers)
-@AWSRetry.backoff(**backoff_params)
+@AWSRetry.jittered_backoff(**backoff_params)
def detach_load_balancers(connection, asg_name, load_balancers):
connection.detach_load_balancers(AutoScalingGroupName=asg_name, LoadBalancerNames=load_balancers)
-@AWSRetry.backoff(**backoff_params)
+@AWSRetry.jittered_backoff(**backoff_params)
def attach_lb_target_groups(connection, asg_name, target_group_arns):
connection.attach_load_balancer_target_groups(AutoScalingGroupName=asg_name, TargetGroupARNs=target_group_arns)
-@AWSRetry.backoff(**backoff_params)
+@AWSRetry.jittered_backoff(**backoff_params)
def detach_lb_target_groups(connection, asg_name, target_group_arns):
connection.detach_load_balancer_target_groups(AutoScalingGroupName=asg_name, TargetGroupARNs=target_group_arns)
-@AWSRetry.backoff(**backoff_params)
+@AWSRetry.jittered_backoff(**backoff_params)
def update_asg(connection, **params):
connection.update_auto_scaling_group(**params)
-@AWSRetry.backoff(catch_extra_error_codes=['ScalingActivityInProgress'], **backoff_params)
+@AWSRetry.jittered_backoff(catch_extra_error_codes=['ScalingActivityInProgress'], **backoff_params)
def delete_asg(connection, asg_name, force_delete):
connection.delete_auto_scaling_group(AutoScalingGroupName=asg_name, ForceDelete=force_delete)
-@AWSRetry.backoff(**backoff_params)
+@AWSRetry.jittered_backoff(**backoff_params)
def terminate_asg_instance(connection, instance_id, decrement_capacity):
connection.terminate_instance_in_auto_scaling_group(InstanceId=instance_id,
ShouldDecrementDesiredCapacity=decrement_capacity)
@@ -1825,22 +1825,6 @@ def main():
]
)
- if (
- module.params.get('max_instance_lifetime') is not None
- and not module.botocore_at_least('1.13.21')
- ):
- module.fail_json(
- msg='Botocore needs to be version 1.13.21 or higher to use max_instance_lifetime.'
- )
-
- if (
- module.params.get('mixed_instances_policy') is not None
- and not module.botocore_at_least('1.12.45')
- ):
- module.fail_json(
- msg='Botocore needs to be version 1.12.45 or higher to use mixed_instances_policy.'
- )
-
state = module.params.get('state')
replace_instances = module.params.get('replace_instances')
replace_all_instances = module.params.get('replace_all_instances')
diff --git a/plugins/modules/ec2_asg_info.py b/plugins/modules/ec2_asg_info.py
index 0a6cb27d9b0..2b8cf4bc90c 100644
--- a/plugins/modules/ec2_asg_info.py
+++ b/plugins/modules/ec2_asg_info.py
@@ -438,7 +438,12 @@ def main():
name=dict(type='str'),
tags=dict(type='dict'),
)
- module = AnsibleAWSModule(argument_spec=argument_spec)
+
+ module = AnsibleAWSModule(
+ argument_spec=argument_spec,
+ supports_check_mode=True,
+ )
+
if module._name == 'ec2_asg_facts':
module.deprecate("The 'ec2_asg_facts' module has been renamed to 'ec2_asg_info'", date='2021-12-01', collection_name='community.aws')
diff --git a/plugins/modules/ec2_eip.py b/plugins/modules/ec2_eip.py
index adf6f0bda41..e38e941661f 100644
--- a/plugins/modules/ec2_eip.py
+++ b/plugins/modules/ec2_eip.py
@@ -64,6 +64,16 @@
network interface or instance to be re-associated with the specified instance or interface.
default: false
type: bool
+ tags:
+ description: A dictionary of tags to apply to the EIP.
+ type: dict
+ version_added: 2.1.0
+ purge_tags:
+ description: Whether the I(tags) argument should cause tags not in the
+ dictionary to be removed.
+ default: True
+ type: bool
+ version_added: 2.1.0
tag_name:
description:
- When I(reuse_existing_ip_allowed=true), supplement with this option to only reuse
@@ -227,6 +237,7 @@
from ansible_collections.amazon.aws.plugins.module_utils.core import is_boto3_error_code
from ansible_collections.amazon.aws.plugins.module_utils.ec2 import AWSRetry
from ansible_collections.amazon.aws.plugins.module_utils.ec2 import ansible_dict_to_boto3_filter_list
+from ansible_collections.amazon.aws.plugins.module_utils.ec2 import ensure_ec2_tags
def associate_ip_and_device(ec2, module, address, private_ip_address, device_id, allow_reassociation, check_mode, is_instance=True):
@@ -247,7 +258,7 @@ def associate_ip_and_device(ec2, module, address, private_ip_address, device_id,
params['AllocationId'] = address['AllocationId']
else:
params['PublicIp'] = address['PublicIp']
- res = ec2.associate_address(**params)
+ res = ec2.associate_address(aws_retry=True, **params)
except (botocore.exceptions.BotoCoreError, botocore.exceptions.ClientError) as e:
msg = "Couldn't associate Elastic IP address with instance '{0}'".format(device_id)
module.fail_json_aws(e, msg=msg)
@@ -344,10 +355,11 @@ def address_is_associated_with_device(ec2, module, address, device_id, is_instan
def allocate_address(ec2, module, domain, reuse_existing_ip_allowed, check_mode, tag_dict=None, public_ipv4_pool=None):
""" Allocate a new elastic IP address (when needed) and return it """
+ if not domain:
+ domain = 'standard'
+
if reuse_existing_ip_allowed:
filters = []
- if not domain:
- domain = 'standard'
filters.append({'Name': 'domain', "Values": [domain]})
if tag_dict is not None:
@@ -534,6 +546,8 @@ def main():
allow_reassociation=dict(type='bool', default=False),
wait_timeout=dict(type='int', removed_at_date='2022-06-01', removed_from_collection='community.aws'),
private_ip_address=dict(),
+ tags=dict(required=False, type='dict'),
+ purge_tags=dict(required=False, type='bool', default=True),
tag_name=dict(),
tag_value=dict(),
public_ipv4_pool=dict()
@@ -562,6 +576,8 @@ def main():
tag_name = module.params.get('tag_name')
tag_value = module.params.get('tag_value')
public_ipv4_pool = module.params.get('public_ipv4_pool')
+ tags = module.params.get('tags')
+ purge_tags = module.params.get('purge_tags')
if instance_id:
is_instance = True
@@ -574,6 +590,7 @@ def main():
module.fail_json(msg="If you are specifying an ENI, in_vpc must be true")
is_instance = False
+ # Tags for *searching* for an EIP.
tag_dict = generate_tag_dict(module, tag_name, tag_value)
try:
@@ -602,6 +619,10 @@ def main():
'public_ip': address['PublicIp'],
'allocation_id': address['AllocationId']
}
+
+ result['changed'] |= ensure_ec2_tags(
+ ec2, module, result['allocation_id'],
+ resource_type='elastic-ip', tags=tags, purge_tags=purge_tags)
else:
if device_id:
disassociated = ensure_absent(
diff --git a/plugins/modules/ec2_eip_info.py b/plugins/modules/ec2_eip_info.py
index 553930db67a..e38735c087e 100644
--- a/plugins/modules/ec2_eip_info.py
+++ b/plugins/modules/ec2_eip_info.py
@@ -97,22 +97,25 @@
'''
-from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import (ansible_dict_to_boto3_filter_list,
- boto3_tag_list_to_ansible_dict,
- camel_dict_to_snake_dict,
- )
try:
from botocore.exceptions import (BotoCoreError, ClientError)
except ImportError:
pass # caught by imported AnsibleAWSModule
+from ansible.module_utils.common.dict_transformations import camel_dict_to_snake_dict
+
+from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
+from ansible_collections.amazon.aws.plugins.module_utils.ec2 import AWSRetry
+from ansible_collections.amazon.aws.plugins.module_utils.ec2 import ansible_dict_to_boto3_filter_list
+from ansible_collections.amazon.aws.plugins.module_utils.ec2 import boto3_tag_list_to_ansible_dict
+
def get_eips_details(module):
- connection = module.client('ec2')
+ connection = module.client('ec2', retry_decorator=AWSRetry.jittered_backoff())
filters = module.params.get("filters")
try:
response = connection.describe_addresses(
+ aws_retry=True,
Filters=ansible_dict_to_boto3_filter_list(filters)
)
except (BotoCoreError, ClientError) as e:
diff --git a/plugins/modules/ec2_elb_info.py b/plugins/modules/ec2_elb_info.py
index add102ab87a..8b207111b60 100644
--- a/plugins/modules/ec2_elb_info.py
+++ b/plugins/modules/ec2_elb_info.py
@@ -109,7 +109,7 @@ def _get_tags(self, elbname):
elb_tags = self.connection.get_list('DescribeTags', params, [('member', Tag)])
return dict((tag.Key, tag.Value) for tag in elb_tags if hasattr(tag, 'Key'))
- @AWSRetry.backoff(tries=5, delay=5, backoff=2.0)
+ @AWSRetry.jittered_backoff(retries=5, delay=5, backoff=2.0)
def _get_elb_connection(self):
return connect_to_aws(boto.ec2.elb, self.region, **self.aws_connect_params)
@@ -158,7 +158,7 @@ def _get_health_check(self, health_check):
health_check_dict['ping_path'] = path
return health_check_dict
- @AWSRetry.backoff(tries=5, delay=5, backoff=2.0)
+ @AWSRetry.jittered_backoff(retries=5, delay=5, backoff=2.0)
def _get_elb_info(self, elb):
elb_info = {
'name': elb.name,
@@ -202,7 +202,7 @@ def _get_elb_info(self, elb):
def list_elbs(self):
elb_array, token = [], None
- get_elb_with_backoff = AWSRetry.backoff(tries=5, delay=5, backoff=2.0)(self.connection.get_all_load_balancers)
+ get_elb_with_backoff = AWSRetry.jittered_backoff(retries=5, delay=5, backoff=2.0)(self.connection.get_all_load_balancers)
while True:
all_elbs = get_elb_with_backoff(marker=token)
token = all_elbs.next_marker
diff --git a/plugins/modules/ec2_launch_template.py b/plugins/modules/ec2_launch_template.py
index cebae8b2fec..e96049fa347 100644
--- a/plugins/modules/ec2_launch_template.py
+++ b/plugins/modules/ec2_launch_template.py
@@ -719,9 +719,6 @@ def main():
supports_check_mode=True
)
- if not module.boto3_at_least('1.6.0'):
- module.fail_json(msg="ec2_launch_template requires boto3 >= 1.6.0")
-
for interface in (module.params.get('network_interfaces') or []):
if interface.get('ipv6_addresses'):
interface['ipv6_addresses'] = [{'ipv6_address': x} for x in interface['ipv6_addresses']]
diff --git a/plugins/modules/ec2_lc.py b/plugins/modules/ec2_lc.py
index 9aaa96538db..2cdf0463863 100644
--- a/plugins/modules/ec2_lc.py
+++ b/plugins/modules/ec2_lc.py
@@ -21,7 +21,6 @@
notes:
- Amazon ASG Autoscaling Launch Configurations are immutable once created, so modifying the configuration after it is changed will not modify the
launch configuration on AWS. You must create a new config and assign it to the ASG instead.
- - encrypted volumes are supported on versions >= 2.4
author:
@@ -188,9 +187,7 @@
EXAMPLES = r'''
-# create a launch configuration using an AMI image and instance type as a basis
-
-- name: note that encrypted volumes are only supported in >= Ansible 2.4
+- name: create a launch configuration with an encrypted volume
community.aws.ec2_lc:
name: special
image_id: ami-XXX
diff --git a/plugins/modules/ec2_lc_find.py b/plugins/modules/ec2_lc_find.py
index 6657de27349..3e525adc6cf 100644
--- a/plugins/modules/ec2_lc_find.py
+++ b/plugins/modules/ec2_lc_find.py
@@ -16,7 +16,6 @@
description:
- Returns list of matching Launch Configurations for a given name, along with other useful information.
- Results can be sorted and sliced.
- - It depends on boto.
- Based on the work by Tom Bamford U(https://github.com/tombamford)
author: "Jose Armesto (@fiunchinho)"
diff --git a/plugins/modules/ec2_lc_info.py b/plugins/modules/ec2_lc_info.py
index d3b81deaa75..ea3832e1234 100644
--- a/plugins/modules/ec2_lc_info.py
+++ b/plugins/modules/ec2_lc_info.py
@@ -207,7 +207,11 @@ def main():
sort_end=dict(required=False, type='int'),
)
- module = AnsibleAWSModule(argument_spec=argument_spec)
+ module = AnsibleAWSModule(
+ argument_spec=argument_spec,
+ supports_check_mode=True,
+ )
+
if module._name == 'ec2_lc_facts':
module.deprecate("The 'ec2_lc_facts' module has been renamed to 'ec2_lc_info'", date='2021-12-01', collection_name='community.aws')
diff --git a/plugins/modules/ec2_transit_gateway.py b/plugins/modules/ec2_transit_gateway.py
index 8435491388a..c013ea67379 100644
--- a/plugins/modules/ec2_transit_gateway.py
+++ b/plugins/modules/ec2_transit_gateway.py
@@ -245,9 +245,6 @@ def __init__(self, module, results):
self._connection = self._module.client('ec2')
self._check_mode = self._module.check_mode
- if not hasattr(self._connection, 'describe_transit_gateways'):
- self._module.fail_json(msg='transit gateway module requires boto3 >= 1.9.52')
-
def process(self):
""" Process the request based on state parameter .
state = present will search for an existing tgw based and return the object data.
diff --git a/plugins/modules/ec2_transit_gateway_info.py b/plugins/modules/ec2_transit_gateway_info.py
index c23289eaa1c..024aa5dcec9 100644
--- a/plugins/modules/ec2_transit_gateway_info.py
+++ b/plugins/modules/ec2_transit_gateway_info.py
@@ -183,9 +183,6 @@ def __init__(self, module, results):
self._connection = self._module.client('ec2')
self._check_mode = self._module.check_mode
- if not hasattr(self._connection, 'describe_transit_gateways'):
- self._module.fail_json(msg='transit gateway module requires boto3 >= 1.9.52')
-
@AWSRetry.exponential_backoff()
def describe_transit_gateways(self):
"""
diff --git a/plugins/modules/ec2_vpc_endpoint.py b/plugins/modules/ec2_vpc_endpoint.py
deleted file mode 100644
index 75ba2479afe..00000000000
--- a/plugins/modules/ec2_vpc_endpoint.py
+++ /dev/null
@@ -1,480 +0,0 @@
-#!/usr/bin/python
-# Copyright: Ansible Project
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-DOCUMENTATION = r'''
-module: ec2_vpc_endpoint
-short_description: Create and delete AWS VPC Endpoints.
-version_added: 1.0.0
-description:
- - Creates AWS VPC endpoints.
- - Deletes AWS VPC endpoints.
- - This module supports check mode.
-options:
- vpc_id:
- description:
- - Required when creating a VPC endpoint.
- required: false
- type: str
- vpc_endpoint_type:
- description:
- - The type of endpoint.
- required: false
- default: Gateway
- choices: [ "Interface", "Gateway", "GatewayLoadBalancer" ]
- type: str
- version_added: 1.5.0
- service:
- description:
- - An AWS supported vpc endpoint service. Use the M(community.aws.ec2_vpc_endpoint_info)
- module to describe the supported endpoint services.
- - Required when creating an endpoint.
- required: false
- type: str
- policy:
- description:
- - A properly formatted json policy as string, see
- U(https://github.com/ansible/ansible/issues/7005#issuecomment-42894813).
- Cannot be used with I(policy_file).
- - Option when creating an endpoint. If not provided AWS will
- utilise a default policy which provides full access to the service.
- required: false
- type: json
- policy_file:
- description:
- - The path to the properly json formatted policy file, see
- U(https://github.com/ansible/ansible/issues/7005#issuecomment-42894813)
- on how to use it properly. Cannot be used with I(policy).
- - Option when creating an endpoint. If not provided AWS will
- utilise a default policy which provides full access to the service.
- - This option has been deprecated and will be removed after 2022-12-01
- to maintain the existing functionality please use the I(policy) option
- and a file lookup.
- required: false
- aliases: [ "policy_path" ]
- type: path
- state:
- description:
- - present to ensure resource is created.
- - absent to remove resource
- required: false
- default: present
- choices: [ "present", "absent" ]
- type: str
- tags:
- description:
- - A dict of tags to apply to the internet gateway.
- - To remove all tags set I(tags={}) and I(purge_tags=true).
- type: dict
- version_added: 1.5.0
- purge_tags:
- description:
- - Delete any tags not specified in the task that are on the instance.
- This means you have to specify all the desired tags on each task affecting an instance.
- default: false
- type: bool
- version_added: 1.5.0
- wait:
- description:
- - When specified, will wait for either available status for state present.
- Unfortunately this is ignored for delete actions due to a difference in
- behaviour from AWS.
- required: false
- default: no
- type: bool
- wait_timeout:
- description:
- - Used in conjunction with wait. Number of seconds to wait for status.
- Unfortunately this is ignored for delete actions due to a difference in
- behaviour from AWS.
- required: false
- default: 320
- type: int
- route_table_ids:
- description:
- - List of one or more route table ids to attach to the endpoint. A route
- is added to the route table with the destination of the endpoint if
- provided.
- required: false
- type: list
- elements: str
- vpc_endpoint_id:
- description:
- - One or more vpc endpoint ids to remove from the AWS account
- required: false
- type: str
- client_token:
- description:
- - Optional client token to ensure idempotency
- required: false
- type: str
-author: Karen Cheng (@Etherdaemon)
-extends_documentation_fragment:
-- amazon.aws.aws
-- amazon.aws.ec2
-
-'''
-
-EXAMPLES = r'''
-# Note: These examples do not set authentication details, see the AWS Guide for details.
-
-- name: Create new vpc endpoint with a json template for policy
- community.aws.ec2_vpc_endpoint:
- state: present
- region: ap-southeast-2
- vpc_id: vpc-12345678
- service: com.amazonaws.ap-southeast-2.s3
- policy: " {{ lookup( 'template', 'endpoint_policy.json.j2') }} "
- route_table_ids:
- - rtb-12345678
- - rtb-87654321
- register: new_vpc_endpoint
-
-- name: Create new vpc endpoint with the default policy
- community.aws.ec2_vpc_endpoint:
- state: present
- region: ap-southeast-2
- vpc_id: vpc-12345678
- service: com.amazonaws.ap-southeast-2.s3
- route_table_ids:
- - rtb-12345678
- - rtb-87654321
- register: new_vpc_endpoint
-
-- name: Create new vpc endpoint with json file
- community.aws.ec2_vpc_endpoint:
- state: present
- region: ap-southeast-2
- vpc_id: vpc-12345678
- service: com.amazonaws.ap-southeast-2.s3
- policy_file: "{{ role_path }}/files/endpoint_policy.json"
- route_table_ids:
- - rtb-12345678
- - rtb-87654321
- register: new_vpc_endpoint
-
-- name: Delete newly created vpc endpoint
- community.aws.ec2_vpc_endpoint:
- state: absent
- vpc_endpoint_id: "{{ new_vpc_endpoint.result['VpcEndpointId'] }}"
- region: ap-southeast-2
-'''
-
-RETURN = r'''
-endpoints:
- description: The resulting endpoints from the module call
- returned: success
- type: list
- sample: [
- {
- "creation_timestamp": "2017-02-20T05:04:15+00:00",
- "policy_document": {
- "Id": "Policy1450910922815",
- "Statement": [
- {
- "Action": "s3:*",
- "Effect": "Allow",
- "Principal": "*",
- "Resource": [
- "arn:aws:s3:::*/*",
- "arn:aws:s3:::*"
- ],
- "Sid": "Stmt1450910920641"
- }
- ],
- "Version": "2012-10-17"
- },
- "route_table_ids": [
- "rtb-abcd1234"
- ],
- "service_name": "com.amazonaws.ap-southeast-2.s3",
- "vpc_endpoint_id": "vpce-a1b2c3d4",
- "vpc_id": "vpc-abbad0d0"
- }
- ]
-'''
-
-import datetime
-import json
-import traceback
-
-try:
- import botocore
-except ImportError:
- pass # Handled by AnsibleAWSModule
-
-from ansible.module_utils.six import string_types
-from ansible.module_utils.common.dict_transformations import camel_dict_to_snake_dict
-
-from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.core import normalize_boto3_result
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import AWSRetry
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import ansible_dict_to_boto3_filter_list
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import ansible_dict_to_boto3_tag_list
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import boto3_tag_list_to_ansible_dict
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import compare_aws_tags
-
-from ansible_collections.amazon.aws.plugins.module_utils.core import is_boto3_error_code
-from ansible_collections.amazon.aws.plugins.module_utils.waiters import get_waiter
-
-
-def get_endpoints(client, module, endpoint_id=None):
- params = dict()
- if endpoint_id:
- params['VpcEndpointIds'] = [endpoint_id]
- else:
- filters = list()
- if module.params.get('service'):
- filters.append({'Name': 'service-name', 'Values': [module.params.get('service')]})
- if module.params.get('vpc_id'):
- filters.append({'Name': 'vpc-id', 'Values': [module.params.get('vpc_id')]})
- params['Filters'] = filters
- try:
- result = client.describe_vpc_endpoints(aws_retry=True, **params)
- except (botocore.exceptions.BotoCoreError, botocore.exceptions.ClientError) as e:
- module.fail_json_aws(e, msg="Failed to get endpoints")
-
- # normalize iso datetime fields in result
- normalized_result = normalize_boto3_result(result)
- return normalized_result
-
-
-def match_endpoints(route_table_ids, service_name, vpc_id, endpoint):
- found = False
- sorted_route_table_ids = []
-
- if route_table_ids:
- sorted_route_table_ids = sorted(route_table_ids)
-
- if endpoint['VpcId'] == vpc_id and endpoint['ServiceName'] == service_name:
- sorted_endpoint_rt_ids = sorted(endpoint['RouteTableIds'])
- if sorted_endpoint_rt_ids == sorted_route_table_ids:
-
- found = True
- return found
-
-
-def ensure_tags(client, module, vpc_endpoint_id):
- changed = False
- tags = module.params['tags']
- purge_tags = module.params['purge_tags']
-
- filters = ansible_dict_to_boto3_filter_list({'resource-id': vpc_endpoint_id})
- try:
- current_tags = client.describe_tags(aws_retry=True, Filters=filters)
- except (botocore.exceptions.BotoCoreError, botocore.exceptions.ClientError) as e:
- module.fail_json_aws(e, msg="Failed to describe tags for VPC Endpoint: {0}".format(vpc_endpoint_id))
-
- tags_to_set, tags_to_unset = compare_aws_tags(boto3_tag_list_to_ansible_dict(current_tags.get('Tags')), tags, purge_tags=purge_tags)
- if purge_tags and not tags:
- tags_to_unset = current_tags
-
- if tags_to_unset:
- changed = True
- if not module.check_mode:
- try:
- client.delete_tags(aws_retry=True, Resources=[vpc_endpoint_id], Tags=[dict(Key=tagkey) for tagkey in tags_to_unset])
- except (botocore.exceptions.BotoCoreError, botocore.exceptions.ClientError) as e:
- module.fail_json_aws(e, msg="Unable to delete tags {0}".format(tags_to_unset))
-
- if tags_to_set:
- changed = True
- if not module.check_mode:
- try:
- client.create_tags(aws_retry=True, Resources=[vpc_endpoint_id], Tags=ansible_dict_to_boto3_tag_list(tags_to_set))
- except (botocore.exceptions.BotoCoreError, botocore.exceptions.ClientError) as e:
- module.fail_json_aws(e, msg="Unable to add tags {0}".format(tags_to_set))
- return changed
-
-
-def setup_creation(client, module):
- endpoint_id = module.params.get('vpc_endpoint_id')
- route_table_ids = module.params.get('route_table_ids')
- service_name = module.params.get('service')
- vpc_id = module.params.get('vpc_id')
- changed = False
-
- if not endpoint_id:
- # Try to use the module parameters to match any existing endpoints
- all_endpoints = get_endpoints(client, module, endpoint_id)
- if len(all_endpoints['VpcEndpoints']) > 0:
- for endpoint in all_endpoints['VpcEndpoints']:
- if match_endpoints(route_table_ids, service_name, vpc_id, endpoint):
- endpoint_id = endpoint['VpcEndpointId']
- break
-
- if endpoint_id:
- # If we have an endpoint now, just ensure tags and exit
- if module.params.get('tags'):
- changed = ensure_tags(client, module, endpoint_id)
- normalized_result = get_endpoints(client, module, endpoint_id=endpoint_id)['VpcEndpoints'][0]
- return changed, camel_dict_to_snake_dict(normalized_result, ignore_list=['Tags'])
-
- changed, result = create_vpc_endpoint(client, module)
-
- return changed, camel_dict_to_snake_dict(result, ignore_list=['Tags'])
-
-
-def create_vpc_endpoint(client, module):
- params = dict()
- changed = False
- token_provided = False
- params['VpcId'] = module.params.get('vpc_id')
- params['VpcEndpointType'] = module.params.get('vpc_endpoint_type')
- params['ServiceName'] = module.params.get('service')
-
- if module.check_mode:
- changed = True
- result = 'Would have created VPC Endpoint if not in check mode'
- module.exit_json(changed=changed, result=result)
-
- if module.params.get('route_table_ids'):
- params['RouteTableIds'] = module.params.get('route_table_ids')
-
- if module.params.get('client_token'):
- token_provided = True
- request_time = datetime.datetime.utcnow()
- params['ClientToken'] = module.params.get('client_token')
-
- policy = None
- if module.params.get('policy'):
- try:
- policy = json.loads(module.params.get('policy'))
- except ValueError as e:
- module.fail_json(msg=str(e), exception=traceback.format_exc(),
- **camel_dict_to_snake_dict(e.response))
-
- elif module.params.get('policy_file'):
- try:
- with open(module.params.get('policy_file'), 'r') as json_data:
- policy = json.load(json_data)
- except Exception as e:
- module.fail_json(msg=str(e), exception=traceback.format_exc(),
- **camel_dict_to_snake_dict(e.response))
-
- if policy:
- params['PolicyDocument'] = json.dumps(policy)
-
- try:
- changed = True
- result = client.create_vpc_endpoint(aws_retry=True, **params)['VpcEndpoint']
- if token_provided and (request_time > result['creation_timestamp'].replace(tzinfo=None)):
- changed = False
- elif module.params.get('wait') and not module.check_mode:
- try:
- waiter = get_waiter(client, 'vpc_endpoint_exists')
- waiter.wait(VpcEndpointIds=[result['VpcEndpointId']], WaiterConfig=dict(Delay=15, MaxAttempts=module.params.get('wait_timeout') // 15))
- except botocore.exceptions.WaiterError as e:
- module.fail_json_aws(msg='Error waiting for vpc endpoint to become available - please check the AWS console')
- except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: # pylint: disable=duplicate-except
- module.fail_json_aws(e, msg='Failure while waiting for status')
-
- except is_boto3_error_code('IdempotentParameterMismatch'): # pylint: disable=duplicate-except
- module.fail_json(msg="IdempotentParameterMismatch - updates of endpoints are not allowed by the API")
- except is_boto3_error_code('RouteAlreadyExists'): # pylint: disable=duplicate-except
- module.fail_json(msg="RouteAlreadyExists for one of the route tables - update is not allowed by the API")
- except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: # pylint: disable=duplicate-except
- module.fail_json_aws(e, msg="Failed to create VPC.")
-
- if module.params.get('tags'):
- ensure_tags(client, module, result['VpcEndpointId'])
-
- # describe and normalize iso datetime fields in result after adding tags
- normalized_result = get_endpoints(client, module, endpoint_id=result['VpcEndpointId'])['VpcEndpoints'][0]
- return changed, normalized_result
-
-
-def setup_removal(client, module):
- params = dict()
- changed = False
-
- if module.check_mode:
- try:
- exists = client.describe_vpc_endpoints(aws_retry=True, VpcEndpointIds=[module.params.get('vpc_endpoint_id')])
- if exists:
- result = {'msg': 'Would have deleted VPC Endpoint if not in check mode'}
- changed = True
- except is_boto3_error_code('InvalidVpcEndpointId.NotFound'):
- result = {'msg': 'Endpoint does not exist, nothing to delete.'}
- changed = False
- except (botocore.exceptions.BotoCoreError, botocore.exceptions.ClientError) as e: # pylint: disable=duplicate-except
- module.fail_json_aws(e, msg="Failed to get endpoints")
-
- return changed, result
-
- if isinstance(module.params.get('vpc_endpoint_id'), string_types):
- params['VpcEndpointIds'] = [module.params.get('vpc_endpoint_id')]
- else:
- params['VpcEndpointIds'] = module.params.get('vpc_endpoint_id')
- try:
- result = client.delete_vpc_endpoints(aws_retry=True, **params)['Unsuccessful']
- if len(result) < len(params['VpcEndpointIds']):
- changed = True
- # For some reason delete_vpc_endpoints doesn't throw exceptions it
- # returns a list of failed 'results' instead. Throw these so we can
- # catch them the way we expect
- for r in result:
- try:
- raise botocore.exceptions.ClientError(r, 'delete_vpc_endpoints')
- except is_boto3_error_code('InvalidVpcEndpoint.NotFound'):
- continue
-
- except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: # pylint: disable=duplicate-except
- module.fail_json_aws(e, "Failed to delete VPC endpoint")
- return changed, result
-
-
-def main():
- argument_spec = dict(
- vpc_id=dict(),
- vpc_endpoint_type=dict(default='Gateway', choices=['Interface', 'Gateway', 'GatewayLoadBalancer']),
- service=dict(),
- policy=dict(type='json'),
- policy_file=dict(type='path', aliases=['policy_path']),
- state=dict(default='present', choices=['present', 'absent']),
- wait=dict(type='bool', default=False),
- wait_timeout=dict(type='int', default=320, required=False),
- route_table_ids=dict(type='list', elements='str'),
- vpc_endpoint_id=dict(),
- client_token=dict(no_log=False),
- tags=dict(type='dict'),
- purge_tags=dict(type='bool', default=False),
- )
- module = AnsibleAWSModule(
- argument_spec=argument_spec,
- supports_check_mode=True,
- mutually_exclusive=[['policy', 'policy_file']],
- required_if=[
- ['state', 'present', ['vpc_id', 'service']],
- ['state', 'absent', ['vpc_endpoint_id']],
- ],
- )
-
- # Validate Requirements
- state = module.params.get('state')
-
- if module.params.get('policy_file'):
- module.deprecate('The policy_file option has been deprecated and'
- ' will be removed after 2022-12-01',
- date='2022-12-01', collection_name='community.aws')
-
- try:
- ec2 = module.client('ec2', retry_decorator=AWSRetry.jittered_backoff())
- except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(e, msg='Failed to connect to AWS')
-
- # Ensure resource is present
- if state == 'present':
- (changed, results) = setup_creation(ec2, module)
- else:
- (changed, results) = setup_removal(ec2, module)
-
- module.exit_json(changed=changed, result=results)
-
-
-if __name__ == '__main__':
- main()
diff --git a/plugins/modules/ec2_vpc_endpoint_facts.py b/plugins/modules/ec2_vpc_endpoint_facts.py
deleted file mode 120000
index d2a144a7b86..00000000000
--- a/plugins/modules/ec2_vpc_endpoint_facts.py
+++ /dev/null
@@ -1 +0,0 @@
-ec2_vpc_endpoint_info.py
\ No newline at end of file
diff --git a/plugins/modules/ec2_vpc_endpoint_info.py b/plugins/modules/ec2_vpc_endpoint_info.py
deleted file mode 100644
index f84434cb9af..00000000000
--- a/plugins/modules/ec2_vpc_endpoint_info.py
+++ /dev/null
@@ -1,210 +0,0 @@
-#!/usr/bin/python
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-DOCUMENTATION = r'''
-module: ec2_vpc_endpoint_info
-short_description: Retrieves AWS VPC endpoints details using AWS methods.
-version_added: 1.0.0
-description:
- - Gets various details related to AWS VPC endpoints.
- - This module was called C(ec2_vpc_endpoint_facts) before Ansible 2.9. The usage did not change.
-options:
- query:
- description:
- - Defaults to C(endpoints).
- - Specifies the query action to take.
- - I(query=endpoints) returns information about AWS VPC endpoints.
- - Retrieving information about services using I(query=services) has been
- deprecated in favour of the M(ec2_vpc_endpoint_service_info) module.
- - The I(query) option has been deprecated and will be removed after 2022-12-01.
- required: False
- choices:
- - services
- - endpoints
- type: str
- vpc_endpoint_ids:
- description:
- - The IDs of specific endpoints to retrieve the details of.
- type: list
- elements: str
- filters:
- description:
- - A dict of filters to apply. Each dict item consists of a filter key and a filter value.
- See U(https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_DescribeVpcEndpoints.html)
- for possible filters.
- type: dict
-author: Karen Cheng (@Etherdaemon)
-extends_documentation_fragment:
-- amazon.aws.aws
-- amazon.aws.ec2
-
-'''
-
-EXAMPLES = r'''
-# Simple example of listing all support AWS services for VPC endpoints
-- name: List supported AWS endpoint services
- community.aws.ec2_vpc_endpoint_info:
- query: services
- region: ap-southeast-2
- register: supported_endpoint_services
-
-- name: Get all endpoints in ap-southeast-2 region
- community.aws.ec2_vpc_endpoint_info:
- query: endpoints
- region: ap-southeast-2
- register: existing_endpoints
-
-- name: Get all endpoints with specific filters
- community.aws.ec2_vpc_endpoint_info:
- query: endpoints
- region: ap-southeast-2
- filters:
- vpc-id:
- - vpc-12345678
- - vpc-87654321
- vpc-endpoint-state:
- - available
- - pending
- register: existing_endpoints
-
-- name: Get details on specific endpoint
- community.aws.ec2_vpc_endpoint_info:
- query: endpoints
- region: ap-southeast-2
- vpc_endpoint_ids:
- - vpce-12345678
- register: endpoint_details
-'''
-
-RETURN = r'''
-service_names:
- description: AWS VPC endpoint service names
- returned: I(query) is C(services)
- type: list
- sample:
- service_names:
- - com.amazonaws.ap-southeast-2.s3
-vpc_endpoints:
- description:
- - A list of endpoints that match the query. Each endpoint has the keys creation_timestamp,
- policy_document, route_table_ids, service_name, state, vpc_endpoint_id, vpc_id.
- returned: I(query) is C(endpoints)
- type: list
- sample:
- vpc_endpoints:
- - creation_timestamp: "2017-02-16T11:06:48+00:00"
- policy_document: >
- "{\"Version\":\"2012-10-17\",\"Id\":\"Policy1450910922815\",
- \"Statement\":[{\"Sid\":\"Stmt1450910920641\",\"Effect\":\"Allow\",
- \"Principal\":\"*\",\"Action\":\"s3:*\",\"Resource\":[\"arn:aws:s3:::*/*\",\"arn:aws:s3:::*\"]}]}"
- route_table_ids:
- - rtb-abcd1234
- service_name: "com.amazonaws.ap-southeast-2.s3"
- state: "available"
- vpc_endpoint_id: "vpce-abbad0d0"
- vpc_id: "vpc-1111ffff"
-'''
-
-try:
- import botocore
-except ImportError:
- pass # Handled by AnsibleAWSModule
-
-from ansible.module_utils.common.dict_transformations import camel_dict_to_snake_dict
-
-from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.core import is_boto3_error_code
-from ansible_collections.amazon.aws.plugins.module_utils.core import normalize_boto3_result
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import AWSRetry
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import ansible_dict_to_boto3_filter_list
-
-
-@AWSRetry.jittered_backoff()
-def _describe_endpoints(client, **params):
- paginator = client.get_paginator('describe_vpc_endpoints')
- return paginator.paginate(**params).build_full_result()
-
-
-@AWSRetry.jittered_backoff()
-def _describe_endpoint_services(client, **params):
- paginator = client.get_paginator('describe_vpc_endpoint_services')
- return paginator.paginate(**params).build_full_result()
-
-
-def get_supported_services(client, module):
- try:
- services = _describe_endpoint_services(client)
- except (botocore.exceptions.BotoCoreError, botocore.exceptions.ClientError) as e:
- module.fail_json_aws(e, msg="Failed to get endpoint servicess")
-
- results = list(services['ServiceNames'])
- return dict(service_names=results)
-
-
-def get_endpoints(client, module):
- results = list()
- params = dict()
- params['Filters'] = ansible_dict_to_boto3_filter_list(module.params.get('filters'))
- if module.params.get('vpc_endpoint_ids'):
- params['VpcEndpointIds'] = module.params.get('vpc_endpoint_ids')
- try:
- results = _describe_endpoints(client, **params)['VpcEndpoints']
- results = normalize_boto3_result(results)
- except is_boto3_error_code('InvalidVpcEndpointId.NotFound'):
- module.exit_json(msg='VpcEndpoint {0} does not exist'.format(module.params.get('vpc_endpoint_ids')), vpc_endpoints=[])
- except (botocore.exceptions.BotoCoreError, botocore.exceptions.ClientError) as e: # pylint: disable=duplicate-except
- module.fail_json_aws(e, msg="Failed to get endpoints")
-
- return dict(vpc_endpoints=[camel_dict_to_snake_dict(result) for result in results])
-
-
-def main():
- argument_spec = dict(
- query=dict(choices=['services', 'endpoints'], required=False),
- filters=dict(default={}, type='dict'),
- vpc_endpoint_ids=dict(type='list', elements='str'),
- )
-
- module = AnsibleAWSModule(argument_spec=argument_spec, supports_check_mode=True)
- if module._name == 'ec2_vpc_endpoint_facts':
- module.deprecate("The 'ec2_vpc_endpoint_facts' module has been renamed to 'ec2_vpc_endpoint_info'", date='2021-12-01', collection_name='community.aws')
-
- # Validate Requirements
- try:
- connection = module.client('ec2')
- except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(e, msg='Failed to connect to AWS')
-
- query = module.params.get('query')
- if query == 'endpoints':
- module.deprecate('The query option has been deprecated and'
- ' will be removed after 2022-12-01. Searching for'
- ' `endpoints` is now the default and after'
- ' 2022-12-01 this module will only support fetching'
- ' endpoints.',
- date='2022-12-01', collection_name='community.aws')
- elif query == 'services':
- module.deprecate('Support for fetching service information with this '
- 'module has been deprecated and will be removed after'
- ' 2022-12-01. '
- 'Please use the ec2_vpc_endpoint_service_info module '
- 'instead.', date='2022-12-01',
- collection_name='community.aws')
- else:
- query = 'endpoints'
-
- invocations = {
- 'services': get_supported_services,
- 'endpoints': get_endpoints,
- }
- results = invocations[query](connection, module)
-
- module.exit_json(**results)
-
-
-if __name__ == '__main__':
- main()
diff --git a/plugins/modules/ec2_vpc_endpoint_service_info.py b/plugins/modules/ec2_vpc_endpoint_service_info.py
deleted file mode 100644
index 8dee0652b84..00000000000
--- a/plugins/modules/ec2_vpc_endpoint_service_info.py
+++ /dev/null
@@ -1,179 +0,0 @@
-#!/usr/bin/python
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-DOCUMENTATION = r'''
-module: ec2_vpc_endpoint_service_info
-short_description: retrieves AWS VPC endpoint service details
-version_added: 1.5.0
-description:
- - Gets details related to AWS VPC Endpoint Services.
-options:
- filters:
- description:
- - A dict of filters to apply.
- - Each dict item consists of a filter key and a filter value.
- See U(https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_DescribeVpcEndpointServices.html)
- for possible filters.
- type: dict
- service_names:
- description:
- - A list of service names which can be used to narrow the search results.
- type: list
- elements: str
-author:
- - Mark Chappell (@tremble)
-extends_documentation_fragment:
- - amazon.aws.aws
- - amazon.aws.ec2
-
-'''
-
-EXAMPLES = r'''
-# Simple example of listing all supported AWS services for VPC endpoints
-- name: List supported AWS endpoint services
- community.aws.ec2_vpc_endpoint_service_info:
- region: ap-southeast-2
- register: supported_endpoint_services
-'''
-
-RETURN = r'''
-service_names:
- description: List of supported AWS VPC endpoint service names.
- returned: success
- type: list
- sample:
- service_names:
- - com.amazonaws.ap-southeast-2.s3
-service_details:
- description: Detailed information about the AWS VPC endpoint services.
- returned: success
- type: complex
- contains:
- service_name:
- returned: success
- description: The ARN of the endpoint service.
- type: str
- service_id:
- returned: success
- description: The ID of the endpoint service.
- type: str
- service_type:
- returned: success
- description: The type of the service
- type: list
- availability_zones:
- returned: success
- description: The Availability Zones in which the service is available.
- type: list
- owner:
- returned: success
- description: The AWS account ID of the service owner.
- type: str
- base_endpoint_dns_names:
- returned: success
- description: The DNS names for the service.
- type: list
- private_dns_name:
- returned: success
- description: The private DNS name for the service.
- type: str
- private_dns_names:
- returned: success
- description: The private DNS names assigned to the VPC endpoint service.
- type: list
- vpc_endpoint_policy_supported:
- returned: success
- description: Whether the service supports endpoint policies.
- type: bool
- acceptance_required:
- returned: success
- description:
- Whether VPC endpoint connection requests to the service must be
- accepted by the service owner.
- type: bool
- manages_vpc_endpoints:
- returned: success
- description: Whether the service manages its VPC endpoints.
- type: bool
- tags:
- returned: success
- description: A dict of tags associated with the service
- type: dict
- private_dns_name_verification_state:
- returned: success
- description:
- - The verification state of the VPC endpoint service.
- - Consumers of an endpoint service cannot use the private name when the state is not C(verified).
- type: str
-'''
-
-try:
- import botocore
-except ImportError:
- pass # Handled by AnsibleAWSModule
-
-from ansible.module_utils.common.dict_transformations import camel_dict_to_snake_dict
-
-from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import ansible_dict_to_boto3_filter_list
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import boto3_tag_list_to_ansible_dict
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import AWSRetry
-
-
-# We're using a paginator so we can't use the client decorators
-@AWSRetry.jittered_backoff()
-def get_services(client, module):
- paginator = client.get_paginator('describe_vpc_endpoint_services')
- params = {}
- if module.params.get("filters"):
- params['Filters'] = ansible_dict_to_boto3_filter_list(module.params.get("filters"))
-
- if module.params.get("service_names"):
- params['ServiceNames'] = module.params.get("service_names")
-
- results = paginator.paginate(**params).build_full_result()
- return results
-
-
-def normalize_service(service):
- normalized = camel_dict_to_snake_dict(service, ignore_list=['Tags'])
- normalized["tags"] = boto3_tag_list_to_ansible_dict(service.get('Tags'))
- return normalized
-
-
-def normalize_result(result):
- normalized = {}
- normalized['service_details'] = [normalize_service(service) for service in result.get('ServiceDetails')]
- normalized['service_names'] = result.get('ServiceNames', [])
- return normalized
-
-
-def main():
- argument_spec = dict(
- filters=dict(default={}, type='dict'),
- service_names=dict(type='list', elements='str'),
- )
-
- module = AnsibleAWSModule(argument_spec=argument_spec, supports_check_mode=True)
-
- # Validate Requirements
- try:
- client = module.client('ec2')
- except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(e, msg='Failed to connect to AWS')
-
- try:
- results = get_services(client, module)
- except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(e, msg='Failed to connect to retrieve service details')
- normalized_result = normalize_result(results)
-
- module.exit_json(changed=False, **normalized_result)
-
-
-if __name__ == '__main__':
- main()
diff --git a/plugins/modules/ec2_vpc_igw.py b/plugins/modules/ec2_vpc_igw.py
deleted file mode 100644
index c578df12939..00000000000
--- a/plugins/modules/ec2_vpc_igw.py
+++ /dev/null
@@ -1,291 +0,0 @@
-#!/usr/bin/python
-# Copyright: Ansible Project
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-DOCUMENTATION = '''
----
-module: ec2_vpc_igw
-version_added: 1.0.0
-short_description: Manage an AWS VPC Internet gateway
-description:
- - Manage an AWS VPC Internet gateway
-author: Robert Estelle (@erydo)
-options:
- vpc_id:
- description:
- - The VPC ID for the VPC in which to manage the Internet Gateway.
- required: true
- type: str
- tags:
- description:
- - A dict of tags to apply to the internet gateway.
- - To remove all tags set I(tags={}) and I(purge_tags=true).
- aliases: [ 'resource_tags' ]
- type: dict
- purge_tags:
- description:
- - Remove tags not listed in I(tags).
- type: bool
- default: true
- version_added: 1.3.0
- state:
- description:
- - Create or terminate the IGW
- default: present
- choices: [ 'present', 'absent' ]
- type: str
-extends_documentation_fragment:
-- amazon.aws.aws
-- amazon.aws.ec2
-'''
-
-EXAMPLES = '''
-# Note: These examples do not set authentication details, see the AWS Guide for details.
-
-# Ensure that the VPC has an Internet Gateway.
-# The Internet Gateway ID is can be accessed via {{igw.gateway_id}} for use in setting up NATs etc.
-- name: Create Internet gateway
- community.aws.ec2_vpc_igw:
- vpc_id: vpc-abcdefgh
- state: present
- register: igw
-
-- name: Create Internet gateway with tags
- community.aws.ec2_vpc_igw:
- vpc_id: vpc-abcdefgh
- state: present
- tags:
- Tag1: tag1
- Tag2: tag2
- register: igw
-
-- name: Delete Internet gateway
- community.aws.ec2_vpc_igw:
- state: absent
- vpc_id: vpc-abcdefgh
- register: vpc_igw_delete
-'''
-
-RETURN = '''
-changed:
- description: If any changes have been made to the Internet Gateway.
- type: bool
- returned: always
- sample:
- changed: false
-gateway_id:
- description: The unique identifier for the Internet Gateway.
- type: str
- returned: I(state=present)
- sample:
- gateway_id: "igw-XXXXXXXX"
-tags:
- description: The tags associated the Internet Gateway.
- type: dict
- returned: I(state=present)
- sample:
- tags:
- "Ansible": "Test"
-vpc_id:
- description: The VPC ID associated with the Internet Gateway.
- type: str
- returned: I(state=present)
- sample:
- vpc_id: "vpc-XXXXXXXX"
-'''
-
-try:
- import botocore
-except ImportError:
- pass # caught by AnsibleAWSModule
-
-from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.waiters import get_waiter
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import AWSRetry
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import ansible_dict_to_boto3_filter_list
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import ansible_dict_to_boto3_tag_list
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import boto3_tag_list_to_ansible_dict
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import camel_dict_to_snake_dict
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import compare_aws_tags
-
-
-class AnsibleEc2Igw(object):
-
- def __init__(self, module, results):
- self._module = module
- self._results = results
- self._connection = self._module.client('ec2', retry_decorator=AWSRetry.jittered_backoff())
- self._check_mode = self._module.check_mode
-
- def process(self):
- vpc_id = self._module.params.get('vpc_id')
- state = self._module.params.get('state', 'present')
- tags = self._module.params.get('tags')
- purge_tags = self._module.params.get('purge_tags')
-
- if state == 'present':
- self.ensure_igw_present(vpc_id, tags, purge_tags)
- elif state == 'absent':
- self.ensure_igw_absent(vpc_id)
-
- def get_matching_igw(self, vpc_id):
- filters = ansible_dict_to_boto3_filter_list({'attachment.vpc-id': vpc_id})
- igws = []
- try:
- response = self._connection.describe_internet_gateways(aws_retry=True, Filters=filters)
- igws = response.get('InternetGateways', [])
- except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- self._module.fail_json_aws(e)
-
- igw = None
- if len(igws) > 1:
- self._module.fail_json(
- msg='EC2 returned more than one Internet Gateway for VPC {0}, aborting'.format(vpc_id))
- elif igws:
- igw = camel_dict_to_snake_dict(igws[0])
-
- return igw
-
- def ensure_tags(self, igw_id, tags, purge_tags):
- final_tags = []
-
- filters = ansible_dict_to_boto3_filter_list({'resource-id': igw_id, 'resource-type': 'internet-gateway'})
- cur_tags = None
- try:
- cur_tags = self._connection.describe_tags(aws_retry=True, Filters=filters)
- except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- self._module.fail_json_aws(e, msg="Couldn't describe tags")
-
- if tags is None:
- return boto3_tag_list_to_ansible_dict(cur_tags.get('Tags'))
-
- to_update, to_delete = compare_aws_tags(boto3_tag_list_to_ansible_dict(cur_tags.get('Tags')), tags, purge_tags)
- final_tags = boto3_tag_list_to_ansible_dict(cur_tags.get('Tags'))
-
- if to_update:
- try:
- if self._check_mode:
- final_tags.update(to_update)
- else:
- self._connection.create_tags(
- aws_retry=True,
- Resources=[igw_id],
- Tags=ansible_dict_to_boto3_tag_list(to_update)
- )
-
- self._results['changed'] = True
- except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- self._module.fail_json_aws(e, msg="Couldn't create tags")
-
- if to_delete:
- try:
- if self._check_mode:
- for key in to_delete:
- del final_tags[key]
- else:
- tags_list = []
- for key in to_delete:
- tags_list.append({'Key': key})
-
- self._connection.delete_tags(aws_retry=True, Resources=[igw_id], Tags=tags_list)
-
- self._results['changed'] = True
- except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- self._module.fail_json_aws(e, msg="Couldn't delete tags")
-
- if not self._check_mode and (to_update or to_delete):
- try:
- response = self._connection.describe_tags(aws_retry=True, Filters=filters)
- final_tags = boto3_tag_list_to_ansible_dict(response.get('Tags'))
- except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- self._module.fail_json_aws(e, msg="Couldn't describe tags")
-
- return final_tags
-
- @staticmethod
- def get_igw_info(igw):
- return {
- 'gateway_id': igw['internet_gateway_id'],
- 'tags': igw['tags'],
- 'vpc_id': igw['vpc_id']
- }
-
- def ensure_igw_absent(self, vpc_id):
- igw = self.get_matching_igw(vpc_id)
- if igw is None:
- return self._results
-
- if self._check_mode:
- self._results['changed'] = True
- return self._results
-
- try:
- self._results['changed'] = True
- self._connection.detach_internet_gateway(aws_retry=True, InternetGatewayId=igw['internet_gateway_id'], VpcId=vpc_id)
- self._connection.delete_internet_gateway(aws_retry=True, InternetGatewayId=igw['internet_gateway_id'])
- except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- self._module.fail_json_aws(e, msg="Unable to delete Internet Gateway")
-
- return self._results
-
- def ensure_igw_present(self, vpc_id, tags, purge_tags):
- igw = self.get_matching_igw(vpc_id)
-
- if igw is None:
- if self._check_mode:
- self._results['changed'] = True
- self._results['gateway_id'] = None
- return self._results
-
- try:
- response = self._connection.create_internet_gateway(aws_retry=True)
-
- # Ensure the gateway exists before trying to attach it or add tags
- waiter = get_waiter(self._connection, 'internet_gateway_exists')
- waiter.wait(InternetGatewayIds=[response['InternetGateway']['InternetGatewayId']])
-
- igw = camel_dict_to_snake_dict(response['InternetGateway'])
- self._connection.attach_internet_gateway(aws_retry=True, InternetGatewayId=igw['internet_gateway_id'], VpcId=vpc_id)
- self._results['changed'] = True
- except botocore.exceptions.WaiterError as e:
- self._module.fail_json_aws(e, msg="No Internet Gateway exists.")
- except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- self._module.fail_json_aws(e, msg='Unable to create Internet Gateway')
-
- igw['vpc_id'] = vpc_id
-
- igw['tags'] = self.ensure_tags(igw_id=igw['internet_gateway_id'], tags=tags, purge_tags=purge_tags)
-
- igw_info = self.get_igw_info(igw)
- self._results.update(igw_info)
-
- return self._results
-
-
-def main():
- argument_spec = dict(
- vpc_id=dict(required=True),
- state=dict(default='present', choices=['present', 'absent']),
- tags=dict(required=False, type='dict', aliases=['resource_tags']),
- purge_tags=dict(default=True, type='bool'),
- )
-
- module = AnsibleAWSModule(
- argument_spec=argument_spec,
- supports_check_mode=True,
- )
- results = dict(
- changed=False
- )
- igw_manager = AnsibleEc2Igw(module=module, results=results)
- igw_manager.process()
-
- module.exit_json(**results)
-
-
-if __name__ == '__main__':
- main()
diff --git a/plugins/modules/ec2_vpc_igw_facts.py b/plugins/modules/ec2_vpc_igw_facts.py
deleted file mode 120000
index b3eeb3fee6e..00000000000
--- a/plugins/modules/ec2_vpc_igw_facts.py
+++ /dev/null
@@ -1 +0,0 @@
-ec2_vpc_igw_info.py
\ No newline at end of file
diff --git a/plugins/modules/ec2_vpc_igw_info.py b/plugins/modules/ec2_vpc_igw_info.py
deleted file mode 100644
index 00ecac957ab..00000000000
--- a/plugins/modules/ec2_vpc_igw_info.py
+++ /dev/null
@@ -1,184 +0,0 @@
-#!/usr/bin/python
-# Copyright: Ansible Project
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-DOCUMENTATION = r'''
----
-module: ec2_vpc_igw_info
-version_added: 1.0.0
-short_description: Gather information about internet gateways in AWS
-description:
- - Gather information about internet gateways in AWS.
- - This module was called C(ec2_vpc_igw_facts) before Ansible 2.9. The usage did not change.
-author: "Nick Aslanidis (@naslanidis)"
-options:
- filters:
- description:
- - A dict of filters to apply. Each dict item consists of a filter key and a filter value.
- See U(https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_DescribeInternetGateways.html) for possible filters.
- type: dict
- internet_gateway_ids:
- description:
- - Get details of specific Internet Gateway ID. Provide this value as a list.
- type: list
- elements: str
- convert_tags:
- description:
- - Convert tags from boto3 format (list of dictionaries) to the standard dictionary format.
- - This currently defaults to C(False). The default will be changed to C(True) after 2022-06-22.
- type: bool
- version_added: 1.3.0
-extends_documentation_fragment:
-- amazon.aws.aws
-- amazon.aws.ec2
-
-'''
-
-EXAMPLES = r'''
-# # Note: These examples do not set authentication details, see the AWS Guide for details.
-
-- name: Gather information about all Internet Gateways for an account or profile
- community.aws.ec2_vpc_igw_info:
- region: ap-southeast-2
- profile: production
- register: igw_info
-
-- name: Gather information about a filtered list of Internet Gateways
- community.aws.ec2_vpc_igw_info:
- region: ap-southeast-2
- profile: production
- filters:
- "tag:Name": "igw-123"
- register: igw_info
-
-- name: Gather information about a specific internet gateway by InternetGatewayId
- community.aws.ec2_vpc_igw_info:
- region: ap-southeast-2
- profile: production
- internet_gateway_ids: igw-c1231234
- register: igw_info
-'''
-
-RETURN = r'''
-changed:
- description: True if listing the internet gateways succeeds.
- type: bool
- returned: always
- sample: "false"
-internet_gateways:
- description: The internet gateways for the account.
- returned: always
- type: complex
- contains:
- attachments:
- description: Any VPCs attached to the internet gateway
- returned: I(state=present)
- type: complex
- contains:
- state:
- description: The current state of the attachment
- returned: I(state=present)
- type: str
- sample: available
- vpc_id:
- description: The ID of the VPC.
- returned: I(state=present)
- type: str
- sample: vpc-02123b67
- internet_gateway_id:
- description: The ID of the internet gateway
- returned: I(state=present)
- type: str
- sample: igw-2123634d
- tags:
- description: Any tags assigned to the internet gateway
- returned: I(state=present)
- type: dict
- sample:
- tags:
- "Ansible": "Test"
-'''
-
-try:
- import botocore
-except ImportError:
- pass # Handled by AnsibleAWSModule
-
-from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.core import is_boto3_error_code
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import AWSRetry
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import boto3_tag_list_to_ansible_dict
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import ansible_dict_to_boto3_filter_list
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import camel_dict_to_snake_dict
-
-
-def get_internet_gateway_info(internet_gateway, convert_tags):
- if convert_tags:
- tags = boto3_tag_list_to_ansible_dict(internet_gateway['Tags'])
- ignore_list = ["Tags"]
- else:
- tags = internet_gateway['Tags']
- ignore_list = []
- internet_gateway_info = {'InternetGatewayId': internet_gateway['InternetGatewayId'],
- 'Attachments': internet_gateway['Attachments'],
- 'Tags': tags}
-
- internet_gateway_info = camel_dict_to_snake_dict(internet_gateway_info, ignore_list=ignore_list)
- return internet_gateway_info
-
-
-def list_internet_gateways(connection, module):
- params = dict()
-
- params['Filters'] = ansible_dict_to_boto3_filter_list(module.params.get('filters'))
- convert_tags = module.params.get('convert_tags')
-
- if module.params.get("internet_gateway_ids"):
- params['InternetGatewayIds'] = module.params.get("internet_gateway_ids")
-
- try:
- all_internet_gateways = connection.describe_internet_gateways(aws_retry=True, **params)
- except is_boto3_error_code('InvalidInternetGatewayID.NotFound'):
- module.fail_json('InternetGateway not found')
- except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: # pylint: disable=duplicate-except
- module.fail_json_aws(e, 'Unable to describe internet gateways')
-
- return [get_internet_gateway_info(igw, convert_tags)
- for igw in all_internet_gateways['InternetGateways']]
-
-
-def main():
- argument_spec = dict(
- filters=dict(type='dict', default=dict()),
- internet_gateway_ids=dict(type='list', default=None, elements='str'),
- convert_tags=dict(type='bool'),
- )
-
- module = AnsibleAWSModule(argument_spec=argument_spec, supports_check_mode=True)
- if module._name == 'ec2_vpc_igw_facts':
- module.deprecate("The 'ec2_vpc_igw_facts' module has been renamed to 'ec2_vpc_igw_info'", date='2021-12-01', collection_name='community.aws')
-
- if module.params.get('convert_tags') is None:
- module.deprecate('This module currently returns boto3 style tags by default. '
- 'This default has been deprecated and the module will return a simple dictionary in future. '
- 'This behaviour can be controlled through the convert_tags parameter.',
- date='2021-12-01', collection_name='community.aws')
-
- # Validate Requirements
- try:
- connection = module.client('ec2', retry_decorator=AWSRetry.jittered_backoff())
- except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(e, msg='Failed to connect to AWS')
-
- # call your function here
- results = list_internet_gateways(connection, module)
-
- module.exit_json(internet_gateways=results)
-
-
-if __name__ == '__main__':
- main()
diff --git a/plugins/modules/ec2_vpc_nat_gateway.py b/plugins/modules/ec2_vpc_nat_gateway.py
deleted file mode 100644
index 30a28ca1391..00000000000
--- a/plugins/modules/ec2_vpc_nat_gateway.py
+++ /dev/null
@@ -1,1000 +0,0 @@
-#!/usr/bin/python
-# Copyright: Ansible Project
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-DOCUMENTATION = r'''
----
-module: ec2_vpc_nat_gateway
-version_added: 1.0.0
-short_description: Manage AWS VPC NAT Gateways.
-description:
- - Ensure the state of AWS VPC NAT Gateways based on their id, allocation and subnet ids.
-options:
- state:
- description:
- - Ensure NAT Gateway is present or absent.
- default: "present"
- choices: ["present", "absent"]
- type: str
- nat_gateway_id:
- description:
- - The id AWS dynamically allocates to the NAT Gateway on creation.
- This is required when the absent option is present.
- type: str
- subnet_id:
- description:
- - The id of the subnet to create the NAT Gateway in. This is required
- with the present option.
- type: str
- allocation_id:
- description:
- - The id of the elastic IP allocation. If this is not passed and the
- eip_address is not passed. An EIP is generated for this NAT Gateway.
- type: str
- eip_address:
- description:
- - The elastic IP address of the EIP you want attached to this NAT Gateway.
- If this is not passed and the allocation_id is not passed,
- an EIP is generated for this NAT Gateway.
- type: str
- if_exist_do_not_create:
- description:
- - if a NAT Gateway exists already in the subnet_id, then do not create a new one.
- required: false
- default: false
- type: bool
- tags:
- description:
- - A dict of tags to apply to the NAT gateway.
- - To remove all tags set I(tags={}) and I(purge_tags=true).
- aliases: [ 'resource_tags' ]
- type: dict
- version_added: 1.4.0
- purge_tags:
- description:
- - Remove tags not listed in I(tags).
- type: bool
- default: true
- version_added: 1.4.0
- release_eip:
- description:
- - Deallocate the EIP from the VPC.
- - Option is only valid with the absent state.
- - You should use this with the wait option. Since you can not release an address while a delete operation is happening.
- default: false
- type: bool
- wait:
- description:
- - Wait for operation to complete before returning.
- default: false
- type: bool
- wait_timeout:
- description:
- - How many seconds to wait for an operation to complete before timing out.
- default: 320
- type: int
- client_token:
- description:
- - Optional unique token to be used during create to ensure idempotency.
- When specifying this option, ensure you specify the eip_address parameter
- as well otherwise any subsequent runs will fail.
- type: str
-author:
- - Allen Sanabria (@linuxdynasty)
- - Jon Hadfield (@jonhadfield)
- - Karen Cheng (@Etherdaemon)
- - Alina Buzachis (@alinabuzachis)
-extends_documentation_fragment:
-- amazon.aws.aws
-- amazon.aws.ec2
-'''
-
-EXAMPLES = r'''
-# Note: These examples do not set authentication details, see the AWS Guide for details.
-
-- name: Create new nat gateway with client token.
- community.aws.ec2_vpc_nat_gateway:
- state: present
- subnet_id: subnet-12345678
- eip_address: 52.1.1.1
- region: ap-southeast-2
- client_token: abcd-12345678
- register: new_nat_gateway
-
-- name: Create new nat gateway using an allocation-id.
- community.aws.ec2_vpc_nat_gateway:
- state: present
- subnet_id: subnet-12345678
- allocation_id: eipalloc-12345678
- region: ap-southeast-2
- register: new_nat_gateway
-
-- name: Create new nat gateway, using an EIP address and wait for available status.
- community.aws.ec2_vpc_nat_gateway:
- state: present
- subnet_id: subnet-12345678
- eip_address: 52.1.1.1
- wait: true
- region: ap-southeast-2
- register: new_nat_gateway
-
-- name: Create new nat gateway and allocate new EIP.
- community.aws.ec2_vpc_nat_gateway:
- state: present
- subnet_id: subnet-12345678
- wait: true
- region: ap-southeast-2
- register: new_nat_gateway
-
-- name: Create new nat gateway and allocate new EIP if a nat gateway does not yet exist in the subnet.
- community.aws.ec2_vpc_nat_gateway:
- state: present
- subnet_id: subnet-12345678
- wait: true
- region: ap-southeast-2
- if_exist_do_not_create: true
- register: new_nat_gateway
-
-- name: Delete nat gateway using discovered nat gateways from facts module.
- community.aws.ec2_vpc_nat_gateway:
- state: absent
- region: ap-southeast-2
- wait: true
- nat_gateway_id: "{{ item.NatGatewayId }}"
- release_eip: true
- register: delete_nat_gateway_result
- loop: "{{ gateways_to_remove.result }}"
-
-- name: Delete nat gateway and wait for deleted status.
- community.aws.ec2_vpc_nat_gateway:
- state: absent
- nat_gateway_id: nat-12345678
- wait: true
- wait_timeout: 500
- region: ap-southeast-2
-
-- name: Delete nat gateway and release EIP.
- community.aws.ec2_vpc_nat_gateway:
- state: absent
- nat_gateway_id: nat-12345678
- release_eip: true
- wait: yes
- wait_timeout: 300
- region: ap-southeast-2
-
-- name: Create new nat gateway using allocation-id and tags.
- community.aws.ec2_vpc_nat_gateway:
- state: present
- subnet_id: subnet-12345678
- allocation_id: eipalloc-12345678
- region: ap-southeast-2
- tags:
- Tag1: tag1
- Tag2: tag2
- register: new_nat_gateway
-
-- name: Update tags without purge
- community.aws.ec2_vpc_nat_gateway:
- subnet_id: subnet-12345678
- allocation_id: eipalloc-12345678
- region: ap-southeast-2
- purge_tags: no
- tags:
- Tag3: tag3
- wait: yes
- register: update_tags_nat_gateway
-'''
-
-RETURN = r'''
-create_time:
- description: The ISO 8601 date time format in UTC.
- returned: In all cases.
- type: str
- sample: "2016-03-05T05:19:20.282000+00:00'"
-nat_gateway_id:
- description: id of the VPC NAT Gateway
- returned: In all cases.
- type: str
- sample: "nat-0d1e3a878585988f8"
-subnet_id:
- description: id of the Subnet
- returned: In all cases.
- type: str
- sample: "subnet-12345"
-state:
- description: The current state of the NAT Gateway.
- returned: In all cases.
- type: str
- sample: "available"
-tags:
- description: The tags associated the VPC NAT Gateway.
- type: dict
- returned: When tags are present.
- sample:
- tags:
- "Ansible": "Test"
-vpc_id:
- description: id of the VPC.
- returned: In all cases.
- type: str
- sample: "vpc-12345"
-nat_gateway_addresses:
- description: List of dictionaries containing the public_ip, network_interface_id, private_ip, and allocation_id.
- returned: In all cases.
- type: str
- sample: [
- {
- 'public_ip': '52.52.52.52',
- 'network_interface_id': 'eni-12345',
- 'private_ip': '10.0.0.100',
- 'allocation_id': 'eipalloc-12345'
- }
- ]
-'''
-
-import datetime
-
-try:
- import botocore
-except ImportError:
- pass # Handled by AnsibleAWSModule
-
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import AWSRetry
-from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.core import is_boto3_error_code
-from ansible_collections.amazon.aws.plugins.module_utils.waiters import get_waiter
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import camel_dict_to_snake_dict
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import ansible_dict_to_boto3_filter_list
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import ansible_dict_to_boto3_tag_list
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import boto3_tag_list_to_ansible_dict
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import compare_aws_tags
-
-
-@AWSRetry.jittered_backoff(retries=10)
-def _describe_nat_gateways(client, **params):
- try:
- paginator = client.get_paginator('describe_nat_gateways')
- return paginator.paginate(**params).build_full_result()['NatGateways']
- except is_boto3_error_code('InvalidNatGatewayID.NotFound'):
- return None
-
-
-def wait_for_status(client, module, waiter_name, nat_gateway_id):
- wait_timeout = module.params.get('wait_timeout')
- try:
- waiter = get_waiter(client, waiter_name)
- attempts = 1 + int(wait_timeout / waiter.config.delay)
- waiter.wait(
- NatGatewayIds=[nat_gateway_id],
- WaiterConfig={'MaxAttempts': attempts}
- )
- except botocore.exceptions.WaiterError as e:
- module.fail_json_aws(e, msg="NAT gateway failed to reach expected state.")
- except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(e, msg="Unable to wait for NAT gateway state to update.")
-
-
-def get_nat_gateways(client, module, subnet_id=None, nat_gateway_id=None, states=None):
- """Retrieve a list of NAT Gateways
- Args:
- client (botocore.client.EC2): Boto3 client
- module: AnsibleAWSModule class instance
-
- Kwargs:
- subnet_id (str): The subnet_id the nat resides in.
- nat_gateway_id (str): The Amazon NAT id.
- states (list): States available (pending, failed, available, deleting, and deleted)
- default=None
-
- Basic Usage:
- >>> client = boto3.client('ec2')
- >>> module = AnsibleAWSModule(...)
- >>> subnet_id = 'subnet-12345678'
- >>> get_nat_gateways(client, module, subnet_id)
- [
- true,
- "",
- {
- "create_time": "2016-03-05T00:33:21.209000+00:00",
- "delete_time": "2016-03-05T00:36:37.329000+00:00",
- "nat_gateway_addresses": [
- {
- "public_ip": "55.55.55.55",
- "network_interface_id": "eni-1234567",
- "private_ip": "10.0.0.102",
- "allocation_id": "eipalloc-1234567"
- }
- ],
- "nat_gateway_id": "nat-123456789",
- "state": "deleted",
- "subnet_id": "subnet-123456789",
- "tags": {},
- "vpc_id": "vpc-12345678"
- }
-
- Returns:
- Tuple (bool, str, list)
- """
-
- params = dict()
- existing_gateways = list()
-
- if not states:
- states = ['available', 'pending']
- if nat_gateway_id:
- params['NatGatewayIds'] = [nat_gateway_id]
- else:
- params['Filter'] = [
- {
- 'Name': 'subnet-id',
- 'Values': [subnet_id]
- },
- {
- 'Name': 'state',
- 'Values': states
- }
- ]
-
- try:
- gateways = _describe_nat_gateways(client, **params)
- if gateways:
- for gw in gateways:
- existing_gateways.append(camel_dict_to_snake_dict(gw))
- except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(e)
-
- return existing_gateways
-
-
-def gateway_in_subnet_exists(client, module, subnet_id, allocation_id=None):
- """Retrieve all NAT Gateways for a subnet.
- Args:
- client (botocore.client.EC2): Boto3 client
- module: AnsibleAWSModule class instance
- subnet_id (str): The subnet_id the nat resides in.
-
- Kwargs:
- allocation_id (str): The EIP Amazon identifier.
- default = None
-
- Basic Usage:
- >>> client = boto3.client('ec2')
- >>> module = AnsibleAWSModule(...)
- >>> subnet_id = 'subnet-1234567'
- >>> allocation_id = 'eipalloc-1234567'
- >>> gateway_in_subnet_exists(client, module, subnet_id, allocation_id)
- (
- [
- {
- "create_time": "2016-03-05T00:33:21.209000+00:00",
- "delete_time": "2016-03-05T00:36:37.329000+00:00",
- "nat_gateway_addresses": [
- {
- "public_ip": "55.55.55.55",
- "network_interface_id": "eni-1234567",
- "private_ip": "10.0.0.102",
- "allocation_id": "eipalloc-1234567"
- }
- ],
- "nat_gateway_id": "nat-123456789",
- "state": "deleted",
- "subnet_id": "subnet-123456789",
- "tags": {},
- "vpc_id": "vpc-1234567"
- }
- ],
- False
- )
-
- Returns:
- Tuple (list, bool)
- """
-
- allocation_id_exists = False
- gateways = []
- states = ['available', 'pending']
-
- gws_retrieved = (get_nat_gateways(client, module, subnet_id, states=states))
-
- if gws_retrieved:
- for gw in gws_retrieved:
- for address in gw['nat_gateway_addresses']:
- if allocation_id:
- if address.get('allocation_id') == allocation_id:
- allocation_id_exists = True
- gateways.append(gw)
- else:
- gateways.append(gw)
-
- return gateways, allocation_id_exists
-
-
-def get_eip_allocation_id_by_address(client, module, eip_address):
- """Release an EIP from your EIP Pool
- Args:
- client (botocore.client.EC2): Boto3 client
- module: AnsibleAWSModule class instance
- eip_address (str): The Elastic IP Address of the EIP.
-
- Basic Usage:
- >>> client = boto3.client('ec2')
- >>> module = AnsibleAWSModule(...)
- >>> eip_address = '52.87.29.36'
- >>> get_eip_allocation_id_by_address(client, module, eip_address)
- 'eipalloc-36014da3'
-
- Returns:
- Tuple (str, str)
- """
-
- params = {
- 'PublicIps': [eip_address],
- }
- allocation_id = None
- msg = ''
-
- try:
- allocations = client.describe_addresses(aws_retry=True, **params)['Addresses']
-
- if len(allocations) == 1:
- allocation = allocations[0]
- else:
- allocation = None
-
- if allocation:
- if allocation.get('Domain') != 'vpc':
- msg = (
- "EIP {0} is a non-VPC EIP, please allocate a VPC scoped EIP"
- .format(eip_address)
- )
- else:
- allocation_id = allocation.get('AllocationId')
-
- except is_boto3_error_code('InvalidAddress.Malformed') as e:
- module.fail_json(msg='EIP address {0} is invalid.'.format(eip_address))
- except is_boto3_error_code('InvalidAddress.NotFound') as e: # pylint: disable=duplicate-except
- msg = (
- "EIP {0} does not exist".format(eip_address)
- )
- allocation_id = None
- except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: # pylint: disable=duplicate-except
- module.fail_json_aws(e)
-
- return allocation_id, msg
-
-
-def allocate_eip_address(client, module):
- """Release an EIP from your EIP Pool
- Args:
- client (botocore.client.EC2): Boto3 client
- module: AnsibleAWSModule class instance
-
- Basic Usage:
- >>> client = boto3.client('ec2')
- >>> module = AnsibleAWSModule(...)
- >>> allocate_eip_address(client, module)
- True
-
- Returns:
- Tuple (bool, str)
- """
-
- new_eip = None
- msg = ''
- params = {
- 'Domain': 'vpc',
- }
-
- if module.check_mode:
- ip_allocated = True
- new_eip = None
- return ip_allocated, msg, new_eip
-
- try:
- new_eip = client.allocate_address(aws_retry=True, **params)['AllocationId']
- ip_allocated = True
- msg = 'eipalloc id {0} created'.format(new_eip)
- except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(e)
-
- return ip_allocated, msg, new_eip
-
-
-def release_address(client, module, allocation_id):
- """Release an EIP from your EIP Pool
- Args:
- client (botocore.client.EC2): Boto3 client
- module: AnsibleAWSModule class instance
- allocation_id (str): The eip Amazon identifier.
-
- Basic Usage:
- >>> client = boto3.client('ec2')
- >>> module = AnsibleAWSModule(...)
- >>> allocation_id = "eipalloc-123456"
- >>> release_address(client, module, allocation_id)
- True
-
- Returns:
- Boolean, string
- """
-
- msg = ''
-
- if module.check_mode:
- return True, ''
-
- ip_released = False
-
- try:
- client.describe_addresses(aws_retry=True, AllocationIds=[allocation_id])
- except is_boto3_error_code('InvalidAllocationID.NotFound') as e:
- # IP address likely already released
- # Happens with gateway in 'deleted' state that
- # still lists associations
- return True, e
- except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: # pylint: disable=duplicate-except
- module.fail_json_aws(e)
-
- try:
- client.release_address(aws_retry=True, AllocationId=allocation_id)
- ip_released = True
- except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(e)
-
- return ip_released, msg
-
-
-def create(client, module, subnet_id, allocation_id, tags, purge_tags, client_token=None,
- wait=False):
- """Create an Amazon NAT Gateway.
- Args:
- client (botocore.client.EC2): Boto3 client
- module: AnsibleAWSModule class instance
- subnet_id (str): The subnet_id the nat resides in
- allocation_id (str): The eip Amazon identifier
- tags (dict): Tags to associate to the NAT gateway
- purge_tags (bool): If true, remove tags not listed in I(tags)
- type: bool
-
- Kwargs:
- wait (bool): Wait for the nat to be in the deleted state before returning.
- default = False
- client_token (str):
- default = None
-
- Basic Usage:
- >>> client = boto3.client('ec2')
- >>> module = AnsibleAWSModule(...)
- >>> subnet_id = 'subnet-1234567'
- >>> allocation_id = 'eipalloc-1234567'
- >>> create(client, module, subnet_id, allocation_id, wait=True)
- [
- true,
- "",
- {
- "create_time": "2016-03-05T00:33:21.209000+00:00",
- "delete_time": "2016-03-05T00:36:37.329000+00:00",
- "nat_gateway_addresses": [
- {
- "public_ip": "55.55.55.55",
- "network_interface_id": "eni-1234567",
- "private_ip": "10.0.0.102",
- "allocation_id": "eipalloc-1234567"
- }
- ],
- "nat_gateway_id": "nat-123456789",
- "state": "deleted",
- "subnet_id": "subnet-1234567",
- "tags": {},
- "vpc_id": "vpc-1234567"
- }
- ]
-
- Returns:
- Tuple (bool, str, list)
- """
-
- params = {
- 'SubnetId': subnet_id,
- 'AllocationId': allocation_id
- }
- request_time = datetime.datetime.utcnow()
- changed = False
- token_provided = False
- result = {}
- msg = ''
-
- if client_token:
- token_provided = True
- params['ClientToken'] = client_token
-
- if module.check_mode:
- changed = True
- return changed, result, msg
-
- try:
- result = camel_dict_to_snake_dict(client.create_nat_gateway(aws_retry=True, **params)["NatGateway"])
- changed = True
-
- create_time = result['create_time'].replace(tzinfo=None)
-
- if token_provided and (request_time > create_time):
- changed = False
-
- elif wait and result.get('state') != 'available':
- wait_for_status(client, module, 'nat_gateway_available', result['nat_gateway_id'])
-
- # Get new result
- result = camel_dict_to_snake_dict(
- _describe_nat_gateways(client, NatGatewayIds=[result['nat_gateway_id']])[0]
- )
-
- result['tags'], _tags_update_exists = ensure_tags(
- client, module, nat_gw_id=result['nat_gateway_id'], tags=tags,
- purge_tags=purge_tags
- )
- except is_boto3_error_code('IdempotentParameterMismatch') as e:
- msg = (
- 'NAT Gateway does not support update and token has already been provided:' + e
- )
- changed = False
- result = None
- except (botocore.exceptions.BotoCoreError, botocore.exceptions.ClientError) as e: # pylint: disable=duplicate-except
- module.fail_json_aws(e)
-
- return changed, result, msg
-
-
-def pre_create(client, module, subnet_id, tags, purge_tags, allocation_id=None, eip_address=None,
- if_exist_do_not_create=False, wait=False, client_token=None):
- """Create an Amazon NAT Gateway.
- Args:
- client (botocore.client.EC2): Boto3 client
- module: AnsibleAWSModule class instance
- subnet_id (str): The subnet_id the nat resides in
- tags (dict): Tags to associate to the NAT gateway
- purge_tags (bool): If true, remove tags not listed in I(tags)
-
- Kwargs:
- allocation_id (str): The EIP Amazon identifier.
- default = None
- eip_address (str): The Elastic IP Address of the EIP.
- default = None
- if_exist_do_not_create (bool): if a nat gateway already exists in this
- subnet, than do not create another one.
- default = False
- wait (bool): Wait for the nat to be in the deleted state before returning.
- default = False
- client_token (str):
- default = None
-
- Basic Usage:
- >>> client = boto3.client('ec2')
- >>> module = AnsibleAWSModule(...)
- >>> subnet_id = 'subnet-w4t12897'
- >>> allocation_id = 'eipalloc-36014da3'
- >>> pre_create(client, module, subnet_id, allocation_id, if_exist_do_not_create=True, wait=True)
- [
- true,
- "",
- {
- "create_time": "2016-03-05T00:33:21.209000+00:00",
- "delete_time": "2016-03-05T00:36:37.329000+00:00",
- "nat_gateway_addresses": [
- {
- "public_ip": "52.87.29.36",
- "network_interface_id": "eni-5579742d",
- "private_ip": "10.0.0.102",
- "allocation_id": "eipalloc-36014da3"
- }
- ],
- "nat_gateway_id": "nat-03835afb6e31df79b",
- "state": "deleted",
- "subnet_id": "subnet-w4t12897",
- "tags": {},
- "vpc_id": "vpc-w68571b5"
- }
- ]
-
- Returns:
- Tuple (bool, bool, str, list)
- """
-
- changed = False
- msg = ''
- results = {}
-
- if not allocation_id and not eip_address:
- existing_gateways, allocation_id_exists = (gateway_in_subnet_exists(client, module, subnet_id))
-
- if len(existing_gateways) > 0 and if_exist_do_not_create:
- results = existing_gateways[0]
- results['tags'], tags_update_exists = ensure_tags(
- client, module, results['nat_gateway_id'], tags, purge_tags
- )
-
- if tags_update_exists:
- changed = True
- return changed, msg, results
-
- changed = False
- msg = (
- 'NAT Gateway {0} already exists in subnet_id {1}'
- .format(
- existing_gateways[0]['nat_gateway_id'], subnet_id
- )
- )
- return changed, msg, results
- else:
- changed, msg, allocation_id = (
- allocate_eip_address(client, module)
- )
- if not changed:
- return changed, msg, dict()
-
- elif eip_address or allocation_id:
- if eip_address and not allocation_id:
- allocation_id, msg = (
- get_eip_allocation_id_by_address(
- client, module, eip_address
- )
- )
- if not allocation_id:
- changed = False
- return changed, msg, dict()
-
- existing_gateways, allocation_id_exists = (
- gateway_in_subnet_exists(
- client, module, subnet_id, allocation_id
- )
- )
-
- if len(existing_gateways) > 0 and (allocation_id_exists or if_exist_do_not_create):
- results = existing_gateways[0]
- results['tags'], tags_update_exists = ensure_tags(
- client, module, results['nat_gateway_id'], tags, purge_tags
- )
-
- if tags_update_exists:
- changed = True
- return changed, msg, results
-
- changed = False
- msg = (
- 'NAT Gateway {0} already exists in subnet_id {1}'
- .format(
- existing_gateways[0]['nat_gateway_id'], subnet_id
- )
- )
- return changed, msg, results
-
- changed, results, msg = create(
- client, module, subnet_id, allocation_id, tags, purge_tags, client_token, wait
- )
-
- return changed, msg, results
-
-
-def remove(client, module, nat_gateway_id, wait=False, release_eip=False):
- """Delete an Amazon NAT Gateway.
- Args:
- client (botocore.client.EC2): Boto3 client
- module: AnsibleAWSModule class instance
- nat_gateway_id (str): The Amazon nat id
-
- Kwargs:
- wait (bool): Wait for the nat to be in the deleted state before returning.
- release_eip (bool): Once the nat has been deleted, you can deallocate the eip from the vpc.
-
- Basic Usage:
- >>> client = boto3.client('ec2')
- >>> module = AnsibleAWSModule(...)
- >>> nat_gw_id = 'nat-03835afb6e31df79b'
- >>> remove(client, module, nat_gw_id, wait=True, release_eip=True)
- [
- true,
- "",
- {
- "create_time": "2016-03-05T00:33:21.209000+00:00",
- "delete_time": "2016-03-05T00:36:37.329000+00:00",
- "nat_gateway_addresses": [
- {
- "public_ip": "52.87.29.36",
- "network_interface_id": "eni-5579742d",
- "private_ip": "10.0.0.102",
- "allocation_id": "eipalloc-36014da3"
- }
- ],
- "nat_gateway_id": "nat-03835afb6e31df79b",
- "state": "deleted",
- "subnet_id": "subnet-w4t12897",
- "tags": {},
- "vpc_id": "vpc-w68571b5"
- }
- ]
-
- Returns:
- Tuple (bool, str, list)
- """
-
- params = {
- 'NatGatewayId': nat_gateway_id
- }
- changed = False
- results = {}
- states = ['pending', 'available']
- msg = ''
-
- if module.check_mode:
- changed = True
- return changed, msg, results
-
- try:
- gw_list = (
- get_nat_gateways(
- client, module, nat_gateway_id=nat_gateway_id,
- states=states
- )
- )
-
- if len(gw_list) == 1:
- results = gw_list[0]
- client.delete_nat_gateway(aws_retry=True, **params)
- allocation_id = (
- results['nat_gateway_addresses'][0]['allocation_id']
- )
- changed = True
- msg = (
- 'NAT gateway {0} is in a deleting state. Delete was successful'
- .format(nat_gateway_id)
- )
-
- if wait and results.get('state') != 'deleted':
- wait_for_status(client, module, 'nat_gateway_deleted', nat_gateway_id)
-
- # Get new results
- results = camel_dict_to_snake_dict(
- _describe_nat_gateways(client, NatGatewayIds=[nat_gateway_id])[0]
- )
- except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(e)
-
- if release_eip:
- eip_released, msg = (
- release_address(client, module, allocation_id))
- if not eip_released:
- module.fail_json(
- msg="Failed to release EIP {0}: {1}".format(allocation_id, msg)
- )
-
- return changed, msg, results
-
-
-def ensure_tags(client, module, nat_gw_id, tags, purge_tags):
- final_tags = []
- changed = False
-
- if module.check_mode and nat_gw_id is None:
- # We can't describe tags without an EIP id, we might get here when creating a new EIP in check_mode
- return final_tags, changed
-
- filters = ansible_dict_to_boto3_filter_list({'resource-id': nat_gw_id, 'resource-type': 'natgateway'})
- cur_tags = None
- try:
- cur_tags = client.describe_tags(aws_retry=True, Filters=filters)
- except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(e, 'Couldnt describe tags')
- if tags is None:
- return boto3_tag_list_to_ansible_dict(cur_tags['Tags']), changed
-
- to_update, to_delete = compare_aws_tags(boto3_tag_list_to_ansible_dict(cur_tags.get('Tags')), tags, purge_tags)
- final_tags = boto3_tag_list_to_ansible_dict(cur_tags.get('Tags'))
-
- if to_update:
- try:
- if module.check_mode:
- final_tags.update(to_update)
- else:
- client.create_tags(
- aws_retry=True,
- Resources=[nat_gw_id],
- Tags=ansible_dict_to_boto3_tag_list(to_update)
- )
- changed = True
- except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(e, "Couldn't create tags")
-
- if to_delete:
- try:
- if module.check_mode:
- for key in to_delete:
- del final_tags[key]
- else:
- tags_list = []
- for key in to_delete:
- tags_list.append({'Key': key})
-
- client.delete_tags(aws_retry=True, Resources=[nat_gw_id], Tags=tags_list)
- changed = True
- except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(e, "Couldn't delete tags")
-
- if not module.check_mode and (to_update or to_delete):
- try:
- response = client.describe_tags(aws_retry=True, Filters=filters)
- final_tags = boto3_tag_list_to_ansible_dict(response.get('Tags'))
- except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(e, "Couldn't describe tags")
-
- return final_tags, changed
-
-
-def main():
- argument_spec = dict(
- subnet_id=dict(type='str'),
- eip_address=dict(type='str'),
- allocation_id=dict(type='str'),
- if_exist_do_not_create=dict(type='bool', default=False),
- state=dict(default='present', choices=['present', 'absent']),
- wait=dict(type='bool', default=False),
- wait_timeout=dict(type='int', default=320, required=False),
- release_eip=dict(type='bool', default=False),
- nat_gateway_id=dict(type='str'),
- client_token=dict(type='str', no_log=False),
- tags=dict(required=False, type='dict', aliases=['resource_tags']),
- purge_tags=dict(default=True, type='bool'),
- )
-
- module = AnsibleAWSModule(
- argument_spec=argument_spec,
- supports_check_mode=True,
- mutually_exclusive=[
- ['allocation_id', 'eip_address']
- ],
- required_if=[['state', 'absent', ['nat_gateway_id']],
- ['state', 'present', ['subnet_id']]],
- )
-
- state = module.params.get('state').lower()
- subnet_id = module.params.get('subnet_id')
- allocation_id = module.params.get('allocation_id')
- eip_address = module.params.get('eip_address')
- nat_gateway_id = module.params.get('nat_gateway_id')
- wait = module.params.get('wait')
- release_eip = module.params.get('release_eip')
- client_token = module.params.get('client_token')
- if_exist_do_not_create = module.params.get('if_exist_do_not_create')
- tags = module.params.get('tags')
- purge_tags = module.params.get('purge_tags')
-
- try:
- client = module.client('ec2', retry_decorator=AWSRetry.jittered_backoff())
- except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(e, msg='Failed to connect to AWS.')
-
- changed = False
- msg = ''
-
- if state == 'present':
- changed, msg, results = (
- pre_create(
- client, module, subnet_id, tags, purge_tags, allocation_id, eip_address,
- if_exist_do_not_create, wait, client_token
- )
- )
- else:
- changed, msg, results = (
- remove(
- client, module, nat_gateway_id, wait, release_eip
- )
- )
-
- module.exit_json(msg=msg, changed=changed, **results)
-
-
-if __name__ == '__main__':
- main()
diff --git a/plugins/modules/ec2_vpc_nat_gateway_facts.py b/plugins/modules/ec2_vpc_nat_gateway_facts.py
deleted file mode 120000
index fd969989977..00000000000
--- a/plugins/modules/ec2_vpc_nat_gateway_facts.py
+++ /dev/null
@@ -1 +0,0 @@
-ec2_vpc_nat_gateway_info.py
\ No newline at end of file
diff --git a/plugins/modules/ec2_vpc_nat_gateway_info.py b/plugins/modules/ec2_vpc_nat_gateway_info.py
deleted file mode 100644
index 5acd59a819a..00000000000
--- a/plugins/modules/ec2_vpc_nat_gateway_info.py
+++ /dev/null
@@ -1,218 +0,0 @@
-#!/usr/bin/python
-# Copyright: Ansible Project
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-DOCUMENTATION = r'''
-module: ec2_vpc_nat_gateway_info
-short_description: Retrieves AWS VPC Managed Nat Gateway details using AWS methods.
-version_added: 1.0.0
-description:
- - Gets various details related to AWS VPC Managed Nat Gateways
- - This module was called C(ec2_vpc_nat_gateway_facts) before Ansible 2.9. The usage did not change.
-options:
- nat_gateway_ids:
- description:
- - List of specific nat gateway IDs to fetch details for.
- type: list
- elements: str
- filters:
- description:
- - A dict of filters to apply. Each dict item consists of a filter key and a filter value.
- See U(https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_DescribeNatGateways.html)
- for possible filters.
- type: dict
-author: Karen Cheng (@Etherdaemon)
-extends_documentation_fragment:
-- amazon.aws.aws
-- amazon.aws.ec2
-'''
-
-EXAMPLES = r'''
-# Simple example of listing all nat gateways
-- name: List all managed nat gateways in ap-southeast-2
- community.aws.ec2_vpc_nat_gateway_info:
- region: ap-southeast-2
- register: all_ngws
-
-- name: Debugging the result
- ansible.builtin.debug:
- msg: "{{ all_ngws.result }}"
-
-- name: Get details on specific nat gateways
- community.aws.ec2_vpc_nat_gateway_info:
- nat_gateway_ids:
- - nat-1234567891234567
- - nat-7654321987654321
- region: ap-southeast-2
- register: specific_ngws
-
-- name: Get all nat gateways with specific filters
- community.aws.ec2_vpc_nat_gateway_info:
- region: ap-southeast-2
- filters:
- state: ['pending']
- register: pending_ngws
-
-- name: Get nat gateways with specific filter
- community.aws.ec2_vpc_nat_gateway_info:
- region: ap-southeast-2
- filters:
- subnet-id: subnet-12345678
- state: ['available']
- register: existing_nat_gateways
-'''
-
-RETURN = r'''
-changed:
- description: True if listing the internet gateways succeeds
- type: bool
- returned: always
- sample: false
-result:
- description:
- - The result of the describe, converted to ansible snake case style.
- - See also U(http://boto3.readthedocs.io/en/latest/reference/services/ec2.html#EC2.Client.describe_nat_gateways)
- returned: suceess
- type: list
- contains:
- create_time:
- description: The date and time the NAT gateway was created
- returned: always
- type: str
- sample: "2021-03-11T22:43:25+00:00"
- delete_time:
- description: The date and time the NAT gateway was deleted
- returned: when the NAT gateway has been deleted
- type: str
- sample: "2021-03-11T22:43:25+00:00"
- nat_gateway_addresses:
- description: List containing a dictionary with the IP addresses and network interface associated with the NAT gateway
- returned: always
- type: dict
- contains:
- allocation_id:
- description: The allocation ID of the Elastic IP address that's associated with the NAT gateway
- returned: always
- type: str
- sample: eipalloc-0853e66a40803da76
- network_interface_id:
- description: The ID of the network interface associated with the NAT gateway
- returned: always
- type: str
- sample: eni-0a37acdbe306c661c
- private_ip:
- description: The private IP address associated with the Elastic IP address
- returned: always
- type: str
- sample: 10.0.238.227
- public_ip:
- description: The Elastic IP address associated with the NAT gateway
- returned: always
- type: str
- sample: 34.204.123.52
- nat_gateway_id:
- description: The ID of the NAT gateway
- returned: always
- type: str
- sample: nat-0c242a2397acf6173
- state:
- description: state of the NAT gateway
- returned: always
- type: str
- sample: available
- subnet_id:
- description: The ID of the subnet in which the NAT gateway is located
- returned: always
- type: str
- sample: subnet-098c447465d4344f9
- vpc_id:
- description: The ID of the VPC in which the NAT gateway is located
- returned: always
- type: str
- sample: vpc-02f37f48438ab7d4c
- tags:
- description: Tags applied to the NAT gateway
- returned: always
- type: dict
- sample:
- Tag1: tag1
- Tag_2: tag_2
-'''
-
-
-try:
- import botocore
-except ImportError:
- pass # Handled by AnsibleAWSModule
-
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import AWSRetry
-from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import camel_dict_to_snake_dict
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import ansible_dict_to_boto3_filter_list
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import boto3_tag_list_to_ansible_dict
-from ansible_collections.amazon.aws.plugins.module_utils.core import is_boto3_error_code
-from ansible_collections.amazon.aws.plugins.module_utils.core import normalize_boto3_result
-
-
-@AWSRetry.jittered_backoff(retries=10)
-def _describe_nat_gateways(client, module, **params):
- try:
- paginator = client.get_paginator('describe_nat_gateways')
- return paginator.paginate(**params).build_full_result()['NatGateways']
- except is_boto3_error_code('InvalidNatGatewayID.NotFound'):
- module.exit_json(msg="NAT gateway not found.")
- except is_boto3_error_code('NatGatewayMalformed'): # pylint: disable=duplicate-except
- module.fail_json_aws(msg="NAT gateway id is malformed.")
-
-
-def get_nat_gateways(client, module):
- params = dict()
- nat_gateways = list()
-
- params['Filter'] = ansible_dict_to_boto3_filter_list(module.params.get('filters'))
- params['NatGatewayIds'] = module.params.get('nat_gateway_ids')
-
- try:
- result = normalize_boto3_result(_describe_nat_gateways(client, module, **params))
- except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(e, 'Unable to describe NAT gateways.')
-
- for gateway in result:
- # Turn the boto3 result into ansible_friendly_snaked_names
- converted_gateway = camel_dict_to_snake_dict(gateway)
- if 'tags' in converted_gateway:
- # Turn the boto3 result into ansible friendly tag dictionary
- converted_gateway['tags'] = boto3_tag_list_to_ansible_dict(converted_gateway['tags'])
- nat_gateways.append(converted_gateway)
-
- return nat_gateways
-
-
-def main():
- argument_spec = dict(
- filters=dict(default={}, type='dict'),
- nat_gateway_ids=dict(default=[], type='list', elements='str'),
- )
-
- module = AnsibleAWSModule(argument_spec=argument_spec,
- supports_check_mode=True,)
- if module._name == 'ec2_vpc_nat_gateway_facts':
- module.deprecate("The 'ec2_vpc_nat_gateway_facts' module has been renamed to 'ec2_vpc_nat_gateway_info'",
- date='2021-12-01', collection_name='community.aws')
-
- try:
- connection = module.client('ec2', retry_decorator=AWSRetry.jittered_backoff())
- except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(e, msg='Failed to connect to AWS')
-
- results = get_nat_gateways(connection, module)
-
- module.exit_json(result=results)
-
-
-if __name__ == '__main__':
- main()
diff --git a/plugins/modules/ec2_vpc_peer.py b/plugins/modules/ec2_vpc_peer.py
index c45a003903c..b651b173ce4 100644
--- a/plugins/modules/ec2_vpc_peer.py
+++ b/plugins/modules/ec2_vpc_peer.py
@@ -423,8 +423,6 @@ def create_peer_connection(client, module):
params['VpcId'] = module.params.get('vpc_id')
params['PeerVpcId'] = module.params.get('peer_vpc_id')
if module.params.get('peer_region'):
- if not module.botocore_at_least('1.8.6'):
- module.fail_json(msg="specifying peer_region parameter requires botocore >= 1.8.6")
params['PeerRegion'] = module.params.get('peer_region')
if module.params.get('peer_owner_id'):
params['PeerOwnerId'] = str(module.params.get('peer_owner_id'))
diff --git a/plugins/modules/ec2_vpc_vgw.py b/plugins/modules/ec2_vpc_vgw.py
index 77ed96696bc..b46d0f9ac47 100644
--- a/plugins/modules/ec2_vpc_vgw.py
+++ b/plugins/modules/ec2_vpc_vgw.py
@@ -131,16 +131,16 @@ def status_code_from_exception(error):
return (error.response['Error']['Code'], error.response['Error']['Message'],)
@staticmethod
- def found(response_codes, catch_extra_error_codes=None):
+ def found(response_code, catch_extra_error_codes=None):
retry_on = ['The maximum number of mutating objects has been reached.']
if catch_extra_error_codes:
retry_on.extend(catch_extra_error_codes)
- if not isinstance(response_codes, tuple):
- response_codes = (response_codes,)
+ if not isinstance(response_code, tuple):
+ response_code = (response_code,)
- for code in response_codes:
- if super().found(response_codes, catch_extra_error_codes):
+ for code in response_code:
+ if super().found(response_code, catch_extra_error_codes):
return True
return False
diff --git a/plugins/modules/ec2_vpc_vpn.py b/plugins/modules/ec2_vpc_vpn.py
index e69d3f55e82..df060eaa4c8 100644
--- a/plugins/modules/ec2_vpc_vpn.py
+++ b/plugins/modules/ec2_vpc_vpn.py
@@ -324,16 +324,16 @@ def status_code_from_exception(error):
return (error.response['Error']['Code'], error.response['Error']['Message'],)
@staticmethod
- def found(response_codes, catch_extra_error_codes=None):
+ def found(response_code, catch_extra_error_codes=None):
retry_on = ['The maximum number of mutating objects has been reached.']
if catch_extra_error_codes:
retry_on.extend(catch_extra_error_codes)
- if not isinstance(response_codes, tuple):
- response_codes = (response_codes,)
+ if not isinstance(response_code, tuple):
+ response_code = (response_code,)
- for code in response_codes:
- if super().found(response_codes, catch_extra_error_codes):
+ for code in response_code:
+ if super().found(response_code, catch_extra_error_codes):
return True
return False
diff --git a/plugins/modules/ec2_win_password.py b/plugins/modules/ec2_win_password.py
index 3ed0afb79d4..7f977360e80 100644
--- a/plugins/modules/ec2_win_password.py
+++ b/plugins/modules/ec2_win_password.py
@@ -10,10 +10,9 @@
---
module: ec2_win_password
version_added: 1.0.0
-short_description: Gets the default administrator password for ec2 windows instances
+short_description: Gets the default administrator password for EC2 Windows instances
description:
- Gets the default administrator password from any EC2 Windows instance. The instance is referenced by its id (e.g. C(i-XXXXXXX)).
- - This module has a dependency on python-boto.
author: "Rick Mendes (@rickmendes)"
options:
instance_id:
@@ -55,10 +54,6 @@
requirements:
- cryptography
-- boto >= 2.49.0
-notes:
- - As of Ansible 2.4, this module requires the python cryptography module rather than the
- older pycrypto module.
'''
EXAMPLES = '''
@@ -110,11 +105,15 @@
except ImportError:
HAS_CRYPTOGRAPHY = False
+try:
+ import botocore
+except ImportError:
+ pass # Handled by AnsibleAWSModule
+
from ansible.module_utils._text import to_bytes
from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import HAS_BOTO
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import ec2_connect
+from ansible_collections.amazon.aws.plugins.module_utils.ec2 import AWSRetry
def setup_module_object():
@@ -126,10 +125,19 @@ def setup_module_object():
wait=dict(type='bool', default=False, required=False),
wait_timeout=dict(default=120, required=False, type='int'),
)
- module = AnsibleAWSModule(argument_spec=argument_spec)
+ mutually_exclusive = [['key_file', 'key_data']]
+ module = AnsibleAWSModule(argument_spec=argument_spec, mutually_exclusive=mutually_exclusive)
return module
+def _get_password(module, client, instance_id):
+ try:
+ data = client.get_password_data(aws_retry=True, InstanceId=instance_id)['PasswordData']
+ except (botocore.exceptions.BotoCoreError, botocore.exceptions.ClientError) as e:
+ module.fail_json_aws(e, msg='Failed to get password data')
+ return data
+
+
def ec2_win_password(module):
instance_id = module.params.get('instance_id')
key_file = module.params.get('key_file')
@@ -144,21 +152,21 @@ def ec2_win_password(module):
wait = module.params.get('wait')
wait_timeout = module.params.get('wait_timeout')
- ec2 = ec2_connect(module)
+ client = module.client('ec2', retry_decorator=AWSRetry.jittered_backoff())
if wait:
start = datetime.datetime.now()
end = start + datetime.timedelta(seconds=wait_timeout)
while datetime.datetime.now() < end:
- data = ec2.get_password_data(instance_id)
+ data = _get_password(module, client, instance_id)
decoded = b64decode(data)
if not decoded:
time.sleep(5)
else:
break
else:
- data = ec2.get_password_data(instance_id)
+ data = _get_password(module, client, instance_id)
decoded = b64decode(data)
if wait and datetime.datetime.now() >= end:
@@ -198,9 +206,6 @@ def ec2_win_password(module):
def main():
module = setup_module_object()
- if not HAS_BOTO:
- module.fail_json(msg='Boto required for this module.')
-
if not HAS_CRYPTOGRAPHY:
module.fail_json(msg='cryptography package required for this module.')
diff --git a/plugins/modules/ecs_ecr.py b/plugins/modules/ecs_ecr.py
index a20262956da..2b22147212b 100644
--- a/plugins/modules/ecs_ecr.py
+++ b/plugins/modules/ecs_ecr.py
@@ -76,7 +76,6 @@
scan_on_push:
description:
- if C(true), images are scanned for known vulnerabilities after being pushed to the repository.
- - I(scan_on_push) requires botocore >= 1.13.3
required: false
default: false
type: bool
diff --git a/plugins/modules/ecs_service.py b/plugins/modules/ecs_service.py
index 89cfaf486aa..590276e0ab1 100644
--- a/plugins/modules/ecs_service.py
+++ b/plugins/modules/ecs_service.py
@@ -130,7 +130,6 @@
network_configuration:
description:
- Network configuration of the service. Only applicable for task definitions created with I(network_mode=awsvpc).
- - I(assign_public_ip) requires botocore >= 1.8.4
type: dict
suboptions:
subnets:
@@ -146,7 +145,6 @@
assign_public_ip:
description:
- Whether the task's elastic network interface receives a public IP address.
- - This option requires botocore >= 1.8.4.
type: bool
launch_type:
description:
@@ -164,7 +162,6 @@
health_check_grace_period_seconds:
description:
- Seconds to wait before health checking the freshly added/updated services.
- - This option requires botocore >= 1.8.20.
required: false
type: int
service_registries:
@@ -516,13 +513,10 @@ def format_network_configuration(self, network_config):
self.module.fail_json_aws(e, msg="Couldn't look up security groups")
result['securityGroups'] = groups
if network_config['assign_public_ip'] is not None:
- if self.module.botocore_at_least('1.8.4'):
- if network_config['assign_public_ip'] is True:
- result['assignPublicIp'] = "ENABLED"
- else:
- result['assignPublicIp'] = "DISABLED"
+ if network_config['assign_public_ip'] is True:
+ result['assignPublicIp'] = "ENABLED"
else:
- self.module.fail_json(msg='botocore needs to be version 1.8.4 or higher to use assign_public_ip in network_configuration')
+ result['assignPublicIp'] = "DISABLED"
return dict(awsvpcConfiguration=result)
def find_in_array(self, array_of_services, service_name, field_name='serviceArn'):
@@ -640,16 +634,9 @@ def jsonize(self, service):
def delete_service(self, service, cluster=None):
return self.ecs.delete_service(cluster=cluster, service=service)
- def ecs_api_handles_network_configuration(self):
- # There doesn't seem to be a nice way to inspect botocore to look
- # for attributes (and networkConfiguration is not an explicit argument
- # to e.g. ecs.run_task, it's just passed as a keyword argument)
- return self.module.botocore_at_least('1.7.44')
-
def health_check_setable(self, params):
load_balancers = params.get('loadBalancers', [])
- # check if botocore (and thus boto3) is new enough for using the healthCheckGracePeriodSeconds parameter
- return len(load_balancers) > 0 and self.module.botocore_at_least('1.8.20')
+ return len(load_balancers) > 0
def main():
@@ -710,8 +697,6 @@ def main():
service_mgr = EcsServiceManager(module)
if module.params['network_configuration']:
- if not service_mgr.ecs_api_handles_network_configuration():
- module.fail_json(msg='botocore needs to be version 1.7.44 or higher to use network configuration')
network_configuration = service_mgr.format_network_configuration(module.params['network_configuration'])
else:
network_configuration = None
@@ -729,16 +714,6 @@ def main():
results = dict(changed=False)
- if module.params['launch_type']:
- if not module.botocore_at_least('1.8.4'):
- module.fail_json(msg='botocore needs to be version 1.8.4 or higher to use launch_type')
- if module.params['force_new_deployment']:
- if not module.botocore_at_least('1.8.4'):
- module.fail_json(msg='botocore needs to be version 1.8.4 or higher to use force_new_deployment')
- if module.params['health_check_grace_period_seconds']:
- if not module.botocore_at_least('1.8.20'):
- module.fail_json(msg='botocore needs to be version 1.8.20 or higher to use health_check_grace_period_seconds')
-
if module.params['state'] == 'present':
matching = False
@@ -773,15 +748,11 @@ def main():
# check various parameters and boto versions and give a helpful error in boto is not new enough for feature
if module.params['scheduling_strategy']:
- if not module.botocore_at_least('1.10.37'):
- module.fail_json(msg='botocore needs to be version 1.10.37 or higher to use scheduling_strategy')
- elif (existing['schedulingStrategy']) != module.params['scheduling_strategy']:
+ if (existing['schedulingStrategy']) != module.params['scheduling_strategy']:
module.fail_json(msg="It is not possible to update the scheduling strategy of an existing service")
if module.params['service_registries']:
- if not module.botocore_at_least('1.9.15'):
- module.fail_json(msg='botocore needs to be version 1.9.15 or higher to use service_registries')
- elif (existing['serviceRegistries'] or []) != serviceRegistries:
+ if (existing['serviceRegistries'] or []) != serviceRegistries:
module.fail_json(msg="It is not possible to update the service registries of an existing service")
if (existing['loadBalancers'] or []) != loadBalancers:
diff --git a/plugins/modules/ecs_service_info.py b/plugins/modules/ecs_service_info.py
index 9b47b02a714..79332e55702 100644
--- a/plugins/modules/ecs_service_info.py
+++ b/plugins/modules/ecs_service_info.py
@@ -148,7 +148,7 @@ def __init__(self, module):
self.module = module
self.ecs = module.client('ecs')
- @AWSRetry.backoff(tries=5, delay=5, backoff=2.0)
+ @AWSRetry.jittered_backoff(retries=5, delay=5, backoff=2.0)
def list_services_with_backoff(self, **kwargs):
paginator = self.ecs.get_paginator('list_services')
try:
@@ -156,7 +156,7 @@ def list_services_with_backoff(self, **kwargs):
except is_boto3_error_code('ClusterNotFoundException') as e:
self.module.fail_json_aws(e, "Could not find cluster to list services")
- @AWSRetry.backoff(tries=5, delay=5, backoff=2.0)
+ @AWSRetry.jittered_backoff(retries=5, delay=5, backoff=2.0)
def describe_services_with_backoff(self, **kwargs):
return self.ecs.describe_services(**kwargs)
diff --git a/plugins/modules/ecs_task.py b/plugins/modules/ecs_task.py
index 411121372cf..b2ca36e21de 100644
--- a/plugins/modules/ecs_task.py
+++ b/plugins/modules/ecs_task.py
@@ -63,7 +63,6 @@
network_configuration:
description:
- Network configuration of the service. Only applicable for task definitions created with I(network_mode=awsvpc).
- - I(assign_public_ip) requires botocore >= 1.8.4
type: dict
suboptions:
assign_public_ip:
@@ -235,7 +234,6 @@
'''
from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
-from ansible.module_utils.basic import missing_required_lib
from ansible_collections.amazon.aws.plugins.module_utils.ec2 import get_ec2_security_group_ids_from_names, ansible_dict_to_boto3_tag_list
try:
@@ -334,34 +332,10 @@ def stop_task(self, cluster, task):
response = self.ecs.stop_task(cluster=cluster, task=task)
return response['task']
- def ecs_api_handles_launch_type(self):
- # There doesn't seem to be a nice way to inspect botocore to look
- # for attributes (and networkConfiguration is not an explicit argument
- # to e.g. ecs.run_task, it's just passed as a keyword argument)
- return self.module.botocore_at_least('1.8.4')
-
def ecs_task_long_format_enabled(self):
account_support = self.ecs.list_account_settings(name='taskLongArnFormat', effectiveSettings=True)
return account_support['settings'][0]['value'] == 'enabled'
- def ecs_api_handles_tags(self):
- # There doesn't seem to be a nice way to inspect botocore to look
- # for attributes (and networkConfiguration is not an explicit argument
- # to e.g. ecs.run_task, it's just passed as a keyword argument)
- return self.module.botocore_at_least('1.12.46')
-
- def ecs_api_handles_network_configuration(self):
- # There doesn't seem to be a nice way to inspect botocore to look
- # for attributes (and networkConfiguration is not an explicit argument
- # to e.g. ecs.run_task, it's just passed as a keyword argument)
- return self.module.botocore_at_least('1.7.44')
-
- def ecs_api_handles_network_configuration_assignIp(self):
- # There doesn't seem to be a nice way to inspect botocore to look
- # for attributes (and networkConfiguration is not an explicit argument
- # to e.g. ecs.run_task, it's just passed as a keyword argument)
- return self.module.botocore_at_least('1.8.4')
-
def main():
argument_spec = dict(
@@ -404,18 +378,7 @@ def main():
service_mgr = EcsExecManager(module)
- if module.params['network_configuration']:
- if 'assignPublicIp' in module.params['network_configuration'] and not service_mgr.ecs_api_handles_network_configuration_assignIp():
- module.fail_json(msg='botocore needs to be version 1.8.4 or higher to use assign_public_ip in network_configuration')
- elif not service_mgr.ecs_api_handles_network_configuration():
- module.fail_json(msg='botocore needs to be version 1.7.44 or higher to use network configuration')
-
- if module.params['launch_type'] and not service_mgr.ecs_api_handles_launch_type():
- module.fail_json(msg='botocore needs to be version 1.8.4 or higher to use launch type')
-
if module.params['tags']:
- if not service_mgr.ecs_api_handles_tags():
- module.fail_json(msg=missing_required_lib("botocore >= 1.12.46", reason="to use tags"))
if not service_mgr.ecs_task_long_format_enabled():
module.fail_json(msg="Cannot set task tags: long format task arns are required to set tags")
diff --git a/plugins/modules/ecs_taskdefinition.py b/plugins/modules/ecs_taskdefinition.py
index 6696e92acb3..505a4207117 100644
--- a/plugins/modules/ecs_taskdefinition.py
+++ b/plugins/modules/ecs_taskdefinition.py
@@ -13,7 +13,10 @@
short_description: register a task definition in ecs
description:
- Registers or deregisters task definitions in the Amazon Web Services (AWS) EC2 Container Service (ECS).
-author: Mark Chance (@Java1Guy)
+author:
+ - Mark Chance (@Java1Guy)
+ - Alina Buzachis (@alinabuzachis)
+requirements: [ json, botocore, boto3 ]
options:
state:
description:
@@ -189,7 +192,7 @@
linuxParameters:
description: Linux-specific modifications that are applied to the container, such as Linux kernel capabilities.
required: False
- type: list
+ type: dict
suboptions:
capabilities:
description:
@@ -410,6 +413,8 @@
description: The type of the ulimit.
type: str
required: False
+ choices: ['core', 'cpu', 'data', 'fsize', 'locks', 'memlock', 'msgqueue', 'nice', 'nofile', 'nproc', 'rss',
+ 'rtprio', 'rttime', 'sigpending', 'stack']
softLimit:
description: The soft limit for the ulimit type.
type: int
@@ -466,7 +471,6 @@
network_mode:
description:
- The Docker networking mode to use for the containers in the task.
- - C(awsvpc) mode was added in Ansible 2.5
- Windows containers must use I(network_mode=default), which will utilize docker NAT networking.
- Setting I(network_mode=default) for a Linux container will use C(bridge) mode.
required: false
@@ -513,6 +517,22 @@
- If I(launch_type=FARGATE), this field is required and is limited by the CPU.
required: false
type: str
+ placement_constraints:
+ version_added: 2.1.0
+ description:
+ - Placement constraint objects to use for the task.
+ - You can specify a maximum of 10 constraints per task.
+ - Task placement constraints are not supported for tasks run on Fargate.
+ required: false
+ type: list
+ elements: dict
+ suboptions:
+ type:
+ description: The type of constraint.
+ type: str
+ expression:
+ description: A cluster query language expression to apply to the constraint.
+ type: str
extends_documentation_fragment:
- amazon.aws.aws
- amazon.aws.ec2
@@ -642,9 +662,9 @@
except ImportError:
pass # caught by AnsibleAWSModule
-from ansible.module_utils._text import to_text
from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
+from ansible_collections.amazon.aws.plugins.module_utils.ec2 import AWSRetry
class EcsTaskManager:
@@ -653,21 +673,22 @@ class EcsTaskManager:
def __init__(self, module):
self.module = module
- self.ecs = module.client('ecs')
+ self.ecs = module.client('ecs', AWSRetry.jittered_backoff())
def describe_task(self, task_name):
try:
- response = self.ecs.describe_task_definition(taskDefinition=task_name)
+ response = self.ecs.describe_task_definition(aws_retry=True, taskDefinition=task_name)
return response['taskDefinition']
- except botocore.exceptions.ClientError:
+ except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
return None
- def register_task(self, family, task_role_arn, execution_role_arn, network_mode, container_definitions, volumes, launch_type, cpu, memory):
+ def register_task(self, family, task_role_arn, execution_role_arn, network_mode, container_definitions,
+ volumes, launch_type, cpu, memory, placement_constraints):
validated_containers = []
# Ensures the number parameters are int as required by boto
for container in container_definitions:
- for param in ('memory', 'cpu', 'memoryReservation'):
+ for param in ('memory', 'cpu', 'memoryReservation', 'startTimeout', 'stopTimeout'):
if param in container:
container[param] = int(container[param])
@@ -681,6 +702,23 @@ def register_task(self, family, task_role_arn, execution_role_arn, network_mode,
self.module.fail_json(msg="In awsvpc network mode, host port must be set to the same as "
"container port or not be set")
+ if 'linuxParameters' in container:
+ for linux_param in container.get('linuxParameters'):
+ if linux_param == 'tmpfs':
+ for tmpfs_param in container['linuxParameters']['tmpfs']:
+ if 'size' in tmpfs_param:
+ tmpfs_param['size'] = int(tmpfs_param['size'])
+
+ for param in ('maxSwap', 'swappiness', 'sharedMemorySize'):
+ if param in linux_param:
+ container['linuxParameters'][param] = int(container['linuxParameters'][param])
+
+ if 'ulimits' in container:
+ for limits_mapping in container['ulimits']:
+ for limit in ('softLimit', 'hardLimit'):
+ if limit in limits_mapping:
+ limits_mapping[limit] = int(limits_mapping[limit])
+
validated_containers.append(container)
params = dict(
@@ -699,10 +737,12 @@ def register_task(self, family, task_role_arn, execution_role_arn, network_mode,
params['requiresCompatibilities'] = [launch_type]
if execution_role_arn:
params['executionRoleArn'] = execution_role_arn
+ if placement_constraints:
+ params['placementConstraints'] = placement_constraints
try:
- response = self.ecs.register_task_definition(**params)
- except botocore.exceptions.ClientError as e:
+ response = self.ecs.register_task_definition(aws_retry=True, **params)
+ except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
self.module.fail_json_aws(e, msg="Failed to register task")
return response['taskDefinition']
@@ -758,7 +798,9 @@ def main():
volumes=dict(required=False, type='list', elements='dict'),
launch_type=dict(required=False, choices=['EC2', 'FARGATE']),
cpu=dict(),
- memory=dict(required=False, type='str')
+ memory=dict(required=False, type='str'),
+ placement_constraints=dict(required=False, type='list', elements='dict',
+ options=dict(type=dict(type='str'), expression=dict(type='str'))),
)
module = AnsibleAWSModule(argument_spec=argument_spec,
@@ -770,14 +812,6 @@ def main():
task_mgr = EcsTaskManager(module)
results = dict(changed=False)
- if module.params['launch_type']:
- if not module.botocore_at_least('1.8.4'):
- module.fail_json(msg='botocore needs to be version 1.8.4 or higher to use launch_type')
-
- if module.params['execution_role_arn']:
- if not module.botocore_at_least('1.10.44'):
- module.fail_json(msg='botocore needs to be version 1.10.44 or higher to use execution_role_arn')
-
if module.params['state'] == 'present':
if 'containers' not in module.params or not module.params['containers']:
module.fail_json(msg="To use task definitions, a list of containers must be specified")
@@ -787,36 +821,43 @@ def main():
network_mode = module.params['network_mode']
launch_type = module.params['launch_type']
- if launch_type == 'FARGATE' and network_mode != 'awsvpc':
- module.fail_json(msg="To use FARGATE launch type, network_mode must be awsvpc")
+ placement_constraints = module.params['placement_constraints']
+ if launch_type == 'FARGATE':
+ if network_mode != 'awsvpc':
+ module.fail_json(msg="To use FARGATE launch type, network_mode must be awsvpc")
+ if placement_constraints:
+ module.fail_json(msg="Task placement constraints are not supported for tasks run on Fargate")
for container in module.params['containers']:
if container.get('links') and network_mode == 'awsvpc':
module.fail_json(msg='links parameter is not supported if network mode is awsvpc.')
for environment in container.get('environment', []):
- environment['value'] = to_text(environment['value'])
+ environment['value'] = environment['value']
for environment_file in container.get('environmentFiles', []):
if environment_file['type'] != 's3':
module.fail_json(msg='The only supported value for environmentFiles is s3.')
for linux_param in container.get('linuxParameters', {}):
- if linux_param.get('devices') and launch_type == 'FARGATE':
+ if linux_param == 'maxSwap' and launch_type == 'FARGATE':
module.fail_json(msg='devices parameter is not supported with the FARGATE launch type.')
- if linux_param.get('maxSwap') and launch_type == 'FARGATE':
+ if linux_param == 'maxSwap' and launch_type == 'FARGATE':
module.fail_json(msg='maxSwap parameter is not supported with the FARGATE launch type.')
- elif linux_param.get('maxSwap') and linux_param['maxSwap'] < 0:
+ elif linux_param == 'maxSwap' and int(container['linuxParameters']['maxSwap']) < 0:
module.fail_json(msg='Accepted values for maxSwap are 0 or any positive integer.')
- if linux_param.get('swappiness') and (linux_param['swappiness'] < 0 or linux_param['swappiness'] > 100):
+ if (
+ linux_param == 'swappiness' and
+ (int(container['linuxParameters']['swappiness']) < 0 or int(container['linuxParameters']['swappiness']) > 100)
+ ):
module.fail_json(msg='Accepted values for swappiness are whole numbers between 0 and 100.')
- if linux_param.get('sharedMemorySize') and launch_type == 'FARGATE':
+ if linux_param == 'sharedMemorySize' and launch_type == 'FARGATE':
module.fail_json(msg='sharedMemorySize parameter is not supported with the FARGATE launch type.')
- if linux_param.get('tmpfs') and launch_type == 'FARGATE':
+ if linux_param == 'tmpfs' and launch_type == 'FARGATE':
module.fail_json(msg='tmpfs parameter is not supported with the FARGATE launch type.')
if container.get('hostname') and network_mode == 'awsvpc':
@@ -862,14 +903,24 @@ def _right_has_values_of_left(left, right):
for list_val in left_list:
if list_val not in right_list:
- return False
+ # if list_val is the port mapping, the key 'protocol' may be absent (but defaults to 'tcp')
+ # fill in that default if absent and see if it is in right_list then
+ if isinstance(list_val, dict) and not list_val.get('protocol'):
+ modified_list_val = dict(list_val)
+ modified_list_val.update(protocol='tcp')
+ if modified_list_val in right_list:
+ continue
else:
return False
# Make sure right doesn't have anything that left doesn't
for k, v in right.items():
if v and k not in left:
- return False
+ # 'essential' defaults to True when not specified
+ if k == 'essential' and v is True:
+ pass
+ else:
+ return False
return True
@@ -942,7 +993,8 @@ def _task_definition_matches(requested_volumes, requested_containers, requested_
volumes,
module.params['launch_type'],
module.params['cpu'],
- module.params['memory'])
+ module.params['memory'],
+ module.params['placement_constraints'],)
results['changed'] = True
elif module.params['state'] == 'absent':
diff --git a/plugins/modules/efs.py b/plugins/modules/efs.py
index 49fbd73c9a3..0cf4f88c1d7 100644
--- a/plugins/modules/efs.py
+++ b/plugins/modules/efs.py
@@ -79,13 +79,11 @@
throughput_mode:
description:
- The throughput_mode for the file system to be created.
- - Requires botocore >= 1.10.57
choices: ['bursting', 'provisioned']
type: str
provisioned_throughput_in_mibps:
description:
- If the throughput_mode is provisioned, select the amount of throughput to provisioned in Mibps.
- - Requires botocore >= 1.10.57
type: float
wait:
description:
@@ -370,12 +368,6 @@ def get_mount_targets_in_state(self, file_system_id, states=None):
return list(targets)
- def supports_provisioned_mode(self):
- """
- Ensure boto3 includes provisioned throughput mode feature
- """
- return hasattr(self.connection, 'update_file_system')
-
def get_throughput_mode(self, **kwargs):
"""
Returns throughput mode for selected EFS instance
@@ -413,15 +405,9 @@ def create_file_system(self, name, performance_mode, encrypt, kms_key_id, throug
if kms_key_id is not None:
params['KmsKeyId'] = kms_key_id
if throughput_mode:
- if self.supports_provisioned_mode():
- params['ThroughputMode'] = throughput_mode
- else:
- self.module.fail_json(msg="throughput_mode parameter requires botocore >= 1.10.57")
+ params['ThroughputMode'] = throughput_mode
if provisioned_throughput_in_mibps:
- if self.supports_provisioned_mode():
- params['ProvisionedThroughputInMibps'] = provisioned_throughput_in_mibps
- else:
- self.module.fail_json(msg="provisioned_throughput_in_mibps parameter requires botocore >= 1.10.57")
+ params['ProvisionedThroughputInMibps'] = provisioned_throughput_in_mibps
if state in [self.STATE_DELETING, self.STATE_DELETED]:
wait_for(
@@ -731,8 +717,7 @@ def main():
module.fail_json(msg='Name parameter is required for create')
changed = connection.create_file_system(name, performance_mode, encrypt, kms_key_id, throughput_mode, provisioned_throughput_in_mibps)
- if connection.supports_provisioned_mode():
- changed = connection.update_file_system(name, throughput_mode, provisioned_throughput_in_mibps) or changed
+ changed = connection.update_file_system(name, throughput_mode, provisioned_throughput_in_mibps) or changed
changed = connection.converge_file_system(name=name, tags=tags, purge_tags=purge_tags, targets=targets,
throughput_mode=throughput_mode, provisioned_throughput_in_mibps=provisioned_throughput_in_mibps) or changed
result = first_or_default(connection.get_file_systems(CreationToken=name))
diff --git a/plugins/modules/efs_info.py b/plugins/modules/efs_info.py
index 2384af97ee1..9a6ce1786fc 100644
--- a/plugins/modules/efs_info.py
+++ b/plugins/modules/efs_info.py
@@ -148,12 +148,12 @@
sample: "generalPurpose"
throughput_mode:
description: mode of throughput for the file system
- returned: when botocore >= 1.10.57
+ returned: always
type: str
sample: "bursting"
provisioned_throughput_in_mibps:
description: throughput provisioned in Mibps
- returned: when botocore >= 1.10.57 and throughput_mode is set to "provisioned"
+ returned: when throughput_mode is set to "provisioned"
type: float
sample: 15.0
tags:
diff --git a/plugins/modules/efs_tag.py b/plugins/modules/efs_tag.py
new file mode 100644
index 00000000000..f44b28833dd
--- /dev/null
+++ b/plugins/modules/efs_tag.py
@@ -0,0 +1,181 @@
+#!/usr/bin/python
+"""
+Copyright: (c) 2021, Milan Zink
+GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+"""
+
+from __future__ import absolute_import, division, print_function
+__metaclass__ = type
+
+
+DOCUMENTATION = r'''
+---
+module: efs_tag
+version_added: 2.0.0
+short_description: create and remove tags on Amazon EFS resources
+description:
+ - Creates and removes tags for Amazon EFS resources.
+ - Resources are referenced by their ID (filesystem or filesystem access point).
+author:
+ - Milan Zink (@zeten30)
+options:
+ resource:
+ description:
+ - EFS Filesystem ID or EFS Filesystem Access Point ID.
+ type: str
+ required: True
+ state:
+ description:
+ - Whether the tags should be present or absent on the resource.
+ default: present
+ choices: ['present', 'absent']
+ type: str
+ tags:
+ description:
+ - A dictionary of tags to add or remove from the resource.
+ - If the value provided for a tag is null and I(state=absent), the tag will be removed regardless of its current value.
+ type: dict
+ required: True
+ purge_tags:
+ description:
+ - Whether unspecified tags should be removed from the resource.
+ - Note that when combined with I(state=absent), specified tags with non-matching values are not purged.
+ type: bool
+ default: false
+extends_documentation_fragment:
+- amazon.aws.aws
+- amazon.aws.ec2
+
+'''
+
+EXAMPLES = r'''
+- name: Ensure tags are present on a resource
+ community.aws.efs_tag:
+ resource: fs-123456ab
+ state: present
+ tags:
+ Name: MyEFS
+ Env: Production
+
+- name: Remove the Env tag if it's currently 'development'
+ community.aws.efs_tag:
+ resource: fsap-78945ff
+ state: absent
+ tags:
+ Env: development
+
+- name: Remove all tags except for Name
+ community.aws.efs_tag:
+ resource: fsap-78945ff
+ state: absent
+ tags:
+ Name: foo
+ purge_tags: true
+
+- name: Remove all tags
+ community.aws.efs_tag:
+ resource: fsap-78945ff
+ state: absent
+ tags: {}
+ purge_tags: true
+'''
+
+RETURN = r'''
+tags:
+ description: A dict containing the tags on the resource
+ returned: always
+ type: dict
+added_tags:
+ description: A dict of tags that were added to the resource
+ returned: If tags were added
+ type: dict
+removed_tags:
+ description: A dict of tags that were removed from the resource
+ returned: If tags were removed
+ type: dict
+'''
+
+try:
+ from botocore.exceptions import BotoCoreError, ClientError
+except ImportError:
+ # Handled by AnsibleAWSModule
+ pass
+
+from ansible_collections.amazon.aws.plugins.module_utils.ec2 import boto3_tag_list_to_ansible_dict, ansible_dict_to_boto3_tag_list, compare_aws_tags, AWSRetry
+from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
+
+MAX_AWS_RETRIES = 10 # How many retries to perform when an API call is failing
+WAIT_RETRY = 5 # how many seconds to wait between propagation status polls
+
+
+def get_tags(efs, module, resource):
+ '''
+ Get resource tags
+ '''
+ try:
+ return boto3_tag_list_to_ansible_dict(efs.list_tags_for_resource(aws_retry=True, ResourceId=resource)['Tags'])
+ except (BotoCoreError, ClientError) as get_tags_error:
+ module.fail_json_aws(get_tags_error, msg='Failed to fetch tags for resource {0}'.format(resource))
+
+
+def main():
+ '''
+ MAIN
+ '''
+ argument_spec = dict(
+ resource=dict(required=True),
+ tags=dict(type='dict', required=True),
+ purge_tags=dict(type='bool', default=False),
+ state=dict(default='present', choices=['present', 'absent'])
+ )
+
+ module = AnsibleAWSModule(argument_spec=argument_spec, supports_check_mode=True)
+ resource = module.params['resource']
+ tags = module.params['tags']
+ state = module.params['state']
+ purge_tags = module.params['purge_tags']
+
+ result = {'changed': False}
+
+ efs = module.client('efs', retry_decorator=AWSRetry.jittered_backoff())
+
+ current_tags = get_tags(efs, module, resource)
+
+ add_tags, remove = compare_aws_tags(current_tags, tags, purge_tags=purge_tags)
+
+ remove_tags = {}
+
+ if state == 'absent':
+ for key in tags:
+ if key in current_tags and (tags[key] is None or current_tags[key] == tags[key]):
+ remove_tags[key] = current_tags[key]
+
+ for key in remove:
+ remove_tags[key] = current_tags[key]
+
+ if remove_tags:
+ result['changed'] = True
+ result['removed_tags'] = remove_tags
+ if not module.check_mode:
+ try:
+ efs.untag_resource(aws_retry=True, ResourceId=resource, TagKeys=list(remove_tags.keys()))
+ except (BotoCoreError, ClientError) as remove_tag_error:
+ module.fail_json_aws(remove_tag_error, msg='Failed to remove tags {0} from resource {1}'.format(remove_tags, resource))
+
+ if state == 'present' and add_tags:
+ result['changed'] = True
+ result['added_tags'] = add_tags
+ current_tags.update(add_tags)
+ if not module.check_mode:
+ try:
+ tags = ansible_dict_to_boto3_tag_list(add_tags)
+ efs.tag_resource(aws_retry=True, ResourceId=resource, Tags=tags)
+ except (BotoCoreError, ClientError) as set_tag_error:
+ module.fail_json_aws(set_tag_error, msg='Failed to set tags {0} on resource {1}'.format(add_tags, resource))
+
+ result['tags'] = get_tags(efs, module, resource)
+ module.exit_json(**result)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/plugins/modules/elasticache_subnet_group.py b/plugins/modules/elasticache_subnet_group.py
index 44a3e39ae6f..eda678205d0 100644
--- a/plugins/modules/elasticache_subnet_group.py
+++ b/plugins/modules/elasticache_subnet_group.py
@@ -12,34 +12,36 @@
version_added: 1.0.0
short_description: manage ElastiCache subnet groups
description:
- - Creates, modifies, and deletes ElastiCache subnet groups. This module has a dependency on python-boto >= 2.5.
+ - Creates, modifies, and deletes ElastiCache subnet groups.
options:
state:
description:
- Specifies whether the subnet should be present or absent.
- required: true
choices: [ 'present' , 'absent' ]
+ default: 'present'
type: str
name:
description:
- Database subnet group identifier.
+ - This value is automatically converted to lowercase.
required: true
type: str
description:
description:
- - ElastiCache subnet group description. Only set when a new group is added.
+ - ElastiCache subnet group description.
+ - When not provided defaults to I(name) on subnet group creation.
type: str
subnets:
description:
- List of subnet IDs that make up the ElastiCache subnet group.
+ - At least one subnet must be provided when creating an ElastiCache subnet group.
type: list
elements: str
-author: "Tim Mahoney (@timmahoney)"
+author:
+ - "Tim Mahoney (@timmahoney)"
extends_documentation_fragment:
-- amazon.aws.aws
-- amazon.aws.ec2
-requirements:
-- boto >= 2.49.0
+ - amazon.aws.aws
+ - amazon.aws.ec2
'''
EXAMPLES = r'''
@@ -58,87 +60,195 @@
name: norwegian-blue
'''
+RETURN = r'''
+cache_subnet_group:
+ description: Description of the Elasticache Subnet Group.
+ returned: always
+ type: dict
+ contains:
+ arn:
+ description: The Amazon Resource Name (ARN) of the cache subnet group.
+ returned: when the subnet group exists
+ type: str
+ sample: arn:aws:elasticache:us-east-1:012345678901:subnetgroup:norwegian-blue
+ description:
+ description: The description of the cache subnet group.
+ returned: when the cache subnet group exists
+ type: str
+ sample: My Fancy Ex Parrot Subnet Group
+ name:
+ description: The name of the cache subnet group.
+ returned: when the cache subnet group exists
+ type: str
+ sample: norwegian-blue
+ vpc_id:
+ description: The VPC ID of the cache subnet group.
+ returned: when the cache subnet group exists
+ type: str
+ sample: norwegian-blue
+ subnet_ids:
+ description: The IDs of the subnets beloging to the cache subnet group.
+ returned: when the cache subnet group exists
+ type: list
+ elements: str
+ sample:
+ - subnet-aaaaaaaa
+ - subnet-bbbbbbbb
+'''
+
try:
- import boto
- from boto.elasticache import connect_to_region
- from boto.exception import BotoServerError
+ import botocore
except ImportError:
- pass # Handled by HAS_BOTO
+ pass # Handled by AnsibleAWSModule
+
+from ansible.module_utils.common.dict_transformations import camel_dict_to_snake_dict
-from ansible.module_utils._text import to_native
from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import HAS_BOTO
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import get_aws_connection_info
+from ansible_collections.amazon.aws.plugins.module_utils.core import is_boto3_error_code
+from ansible_collections.amazon.aws.plugins.module_utils.ec2 import AWSRetry
+
+
+def get_subnet_group(name):
+ try:
+ groups = client.describe_cache_subnet_groups(
+ aws_retry=True,
+ CacheSubnetGroupName=name,
+ )['CacheSubnetGroups']
+ except is_boto3_error_code('CacheSubnetGroupNotFoundFault'):
+ return None
+ except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: # pylint: disable=duplicate-except
+ module.fail_json_aws(e, msg="Failed to describe subnet group")
+
+ if not groups:
+ return None
+
+ if len(groups) > 1:
+ module.fail_aws(
+ msg="Found multiple matches for subnet group",
+ cache_subnet_groups=camel_dict_to_snake_dict(groups),
+ )
+
+ subnet_group = camel_dict_to_snake_dict(groups[0])
+
+ subnet_group['name'] = subnet_group['cache_subnet_group_name']
+ subnet_group['description'] = subnet_group['cache_subnet_group_description']
+
+ subnet_ids = list(s['subnet_identifier'] for s in subnet_group['subnets'])
+ subnet_group['subnet_ids'] = subnet_ids
+
+ return subnet_group
+
+
+def create_subnet_group(name, description, subnets):
+
+ if not subnets:
+ module.fail_json(msg='At least one subnet must be provided when creating a subnet group')
+
+ if module.check_mode:
+ return True
+
+ try:
+ if not description:
+ description = name
+ client.create_cache_subnet_group(
+ aws_retry=True,
+ CacheSubnetGroupName=name,
+ CacheSubnetGroupDescription=description,
+ SubnetIds=subnets,
+ )
+ return True
+ except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
+ module.fail_json_aws(e, msg="Failed to create subnet group")
+
+
+def update_subnet_group(subnet_group, name, description, subnets):
+ update_params = dict()
+ if description and subnet_group['description'] != description:
+ update_params['CacheSubnetGroupDescription'] = description
+ if subnets:
+ old_subnets = set(subnet_group['subnet_ids'])
+ new_subnets = set(subnets)
+ if old_subnets != new_subnets:
+ update_params['SubnetIds'] = list(subnets)
+
+ if not update_params:
+ return False
+
+ if module.check_mode:
+ return True
+
+ try:
+ client.modify_cache_subnet_group(
+ aws_retry=True,
+ CacheSubnetGroupName=name,
+ **update_params,
+ )
+ except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
+ module.fail_json_aws(e, msg="Failed to update subnet group")
+
+ return True
+
+
+def delete_subnet_group(name):
+
+ if module.check_mode:
+ return True
+
+ try:
+ client.delete_cache_subnet_group(
+ aws_retry=True,
+ CacheSubnetGroupName=name,
+ )
+ return True
+ except is_boto3_error_code('CacheSubnetGroupNotFoundFault'):
+ # AWS is "eventually consistent", cope with the race conditions where
+ # deletion hadn't completed when we ran describe
+ return False
+ except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: # pylint: disable=duplicate-except
+ module.fail_json_aws(e, msg="Failed to delete subnet group")
def main():
argument_spec = dict(
- state=dict(required=True, choices=['present', 'absent']),
+ state=dict(default='present', choices=['present', 'absent']),
name=dict(required=True),
description=dict(required=False),
subnets=dict(required=False, type='list', elements='str'),
)
- module = AnsibleAWSModule(argument_spec=argument_spec, check_boto3=False)
- if not HAS_BOTO:
- module.fail_json(msg='boto required for this module')
-
- state = module.params.get('state')
- group_name = module.params.get('name').lower()
- group_description = module.params.get('description')
- group_subnets = module.params.get('subnets') or {}
+ global module
+ global client
- if state == 'present':
- for required in ['name', 'description', 'subnets']:
- if not module.params.get(required):
- module.fail_json(msg=str("Parameter %s required for state='present'" % required))
- else:
- for not_allowed in ['description', 'subnets']:
- if module.params.get(not_allowed):
- module.fail_json(msg=str("Parameter %s not allowed for state='absent'" % not_allowed))
+ module = AnsibleAWSModule(
+ argument_spec=argument_spec,
+ supports_check_mode=True,
+ )
- # Retrieve any AWS settings from the environment.
- region, ec2_url, aws_connect_kwargs = get_aws_connection_info(module)
+ state = module.params.get('state')
+ name = module.params.get('name').lower()
+ description = module.params.get('description')
+ subnets = module.params.get('subnets')
- if not region:
- module.fail_json(msg=str("Either region or AWS_REGION or EC2_REGION environment variable or boto config aws_region or ec2_region must be set."))
+ client = module.client('elasticache', retry_decorator=AWSRetry.jittered_backoff())
- """Get an elasticache connection"""
- try:
- conn = connect_to_region(region_name=region, **aws_connect_kwargs)
- except boto.exception.NoAuthHandlerFound as e:
- module.fail_json(msg=to_native(e))
+ subnet_group = get_subnet_group(name)
+ changed = False
- try:
- changed = False
- exists = False
-
- try:
- matching_groups = conn.describe_cache_subnet_groups(group_name, max_records=100)
- exists = len(matching_groups) > 0
- except BotoServerError as e:
- if e.error_code != 'CacheSubnetGroupNotFoundFault':
- module.fail_json(msg=e.error_message)
-
- if state == 'absent':
- if exists:
- conn.delete_cache_subnet_group(group_name)
- changed = True
- else:
- if not exists:
- new_group = conn.create_cache_subnet_group(group_name, cache_subnet_group_description=group_description, subnet_ids=group_subnets)
- changed = True
- else:
- changed_group = conn.modify_cache_subnet_group(group_name, cache_subnet_group_description=group_description, subnet_ids=group_subnets)
- changed = True
-
- except BotoServerError as e:
- if e.error_message != 'No modifications were requested.':
- module.fail_json(msg=e.error_message)
+ if state == 'present':
+ if not subnet_group:
+ result = create_subnet_group(name, description, subnets)
+ changed |= result
else:
- changed = False
+ result = update_subnet_group(subnet_group, name, description, subnets)
+ changed |= result
+ subnet_group = get_subnet_group(name)
+ else:
+ if subnet_group:
+ result = delete_subnet_group(name)
+ changed |= result
+ subnet_group = None
- module.exit_json(changed=changed)
+ module.exit_json(changed=changed, cache_subnet_group=subnet_group)
if __name__ == '__main__':
diff --git a/plugins/modules/elb_instance.py b/plugins/modules/elb_instance.py
index 5759b0b2ccc..b234031ee24 100644
--- a/plugins/modules/elb_instance.py
+++ b/plugins/modules/elb_instance.py
@@ -271,7 +271,7 @@ def _get_instance_lbs(self, ec2_elbs=None):
break
if ec2_elbs:
- lbs = sorted(lb for lb in elbs if lb.name in ec2_elbs)
+ lbs = sorted([lb for lb in elbs if lb.name in ec2_elbs], key=lambda lb: lb.__repr__())
else:
lbs = []
for lb in elbs:
diff --git a/plugins/modules/elb_network_lb.py b/plugins/modules/elb_network_lb.py
index 47ac7b1d0d7..2f664c721ee 100644
--- a/plugins/modules/elb_network_lb.py
+++ b/plugins/modules/elb_network_lb.py
@@ -86,7 +86,8 @@
subnet_mappings:
description:
- A list of dicts containing the IDs of the subnets to attach to the load balancer. You can also specify the allocation ID of an Elastic IP
- to attach to the load balancer. You can specify one Elastic IP address per subnet.
+ to attach to the load balancer or the internal IP address for an internal load balancer. You can specify one Elastic IP address or internal
+ address per subnet.
- This parameter is mutually exclusive with I(subnets).
type: list
elements: dict
@@ -108,7 +109,7 @@
description:
- Create or destroy the load balancer.
- The current default is C(absent). However, this behavior is inconsistent with other modules
- and as such the default will change to C(present) in 2.14.
+ and as such the default will change to C(present) in a release after 2022-06-01.
To maintain the existing behavior explicitly set I(state=absent).
choices: [ 'present', 'absent' ]
type: str
@@ -169,6 +170,21 @@
TargetGroupName: mytargetgroup # Required. The name of the target group
state: present
+- name: Create an internal ELB with a specified IP address
+ community.aws.elb_network_lb:
+ name: myelb
+ scheme: internal
+ subnet_mappings:
+ - SubnetId: subnet-012345678
+ PrivateIPv4Address: 192.168.0.1 # Must be an address from within the CIDR of the subnet.
+ listeners:
+ - Protocol: TCP # Required. The protocol for connections from clients to the load balancer (TCP, TLS, UDP or TCP_UDP) (case-sensitive).
+ Port: 80 # Required. The port on which the load balancer is listening.
+ DefaultActions:
+ - Type: forward # Required. Only 'forward' is accepted at this time
+ TargetGroupName: mytargetgroup # Required. The name of the target group
+ state: present
+
- name: Remove an ELB
community.aws.elb_network_lb:
name: myelb
@@ -452,7 +468,7 @@ def main():
if state is None:
# See below, unless state==present we delete. Ouch.
module.deprecate('State currently defaults to absent. This is inconsistent with other modules'
- ' and the default will be changed to `present` in Ansible 2.14',
+ ' and the default will be changed to `present` in a release after 2022-06-01',
date='2022-06-01', collection_name='community.aws')
# Quick check of listeners parameters
diff --git a/plugins/modules/elb_target_group.py b/plugins/modules/elb_target_group.py
index 7bb105b6d55..9a740422293 100644
--- a/plugins/modules/elb_target_group.py
+++ b/plugins/modules/elb_target_group.py
@@ -161,6 +161,23 @@
- The identifier of the virtual private cloud (VPC). Required when I(state) is C(present).
required: false
type: str
+ preserve_client_ip_enabled:
+ description:
+ - Indicates whether client IP preservation is enabled.
+ - The default is disabled if the target group type is C(ip) address and the target group protocol is C(tcp) or C(tls).
+ Otherwise, the default is enabled. Client IP preservation cannot be disabled for C(udp) and C(tcp_udp) target groups.
+ - I(preserve_client_ip_enabled) is supported only by Network Load Balancers.
+ type: bool
+ required: false
+ version_added: 2.1.0
+ proxy_protocol_v2_enabled:
+ description:
+ - Indicates whether Proxy Protocol version 2 is enabled.
+ - The value is C(true) or C(false).
+ - I(proxy_protocol_v2_enabled) is supported only by Network Load Balancers.
+ type: bool
+ required: false
+ version_added: 2.1.0
wait:
description:
- Whether or not to wait for the target group.
@@ -454,12 +471,6 @@ def wait_for_status(connection, module, target_group_arn, targets, status):
return status_achieved, result
-def fail_if_ip_target_type_not_supported(module):
- if not module.botocore_at_least('1.7.2'):
- module.fail_json(msg="target_type ip requires botocore version 1.7.2 or later. Version %s is installed" %
- botocore.__version__)
-
-
def create_or_update_target_group(connection, module):
changed = False
@@ -480,12 +491,14 @@ def create_or_update_target_group(connection, module):
stickiness_type = module.params.get("stickiness_type")
stickiness_app_cookie_duration = module.params.get("stickiness_app_cookie_duration")
stickiness_app_cookie_name = module.params.get("stickiness_app_cookie_name")
+ preserve_client_ip_enabled = module.params.get("preserve_client_ip_enabled")
+ proxy_protocol_v2_enabled = module.params.get("proxy_protocol_v2_enabled")
health_option_keys = [
"health_check_path", "health_check_protocol", "health_check_interval", "health_check_timeout",
"healthy_threshold_count", "unhealthy_threshold_count", "successful_response_codes"
]
- health_options = any([module.params[health_option_key] is not None for health_option_key in health_option_keys])
+ health_options = any(module.params[health_option_key] is not None for health_option_key in health_option_keys)
# Set health check if anything set
if health_options:
@@ -519,10 +532,6 @@ def create_or_update_target_group(connection, module):
params['Matcher'] = {}
params['Matcher']['HttpCode'] = module.params.get("successful_response_codes")
- # Get target type
- if target_type == 'ip':
- fail_if_ip_target_type_not_supported(module)
-
# Get target group
tg = get_target_group(connection, module)
@@ -773,6 +782,13 @@ def create_or_update_target_group(connection, module):
if stickiness_app_cookie_duration is not None:
if str(stickiness_app_cookie_duration) != current_tg_attributes['stickiness_app_cookie_duration_seconds']:
update_attributes.append({'Key': 'stickiness.app_cookie.duration_seconds', 'Value': str(stickiness_app_cookie_duration)})
+ if preserve_client_ip_enabled is not None:
+ if target_type not in ('udp', 'tcp_udp'):
+ if str(preserve_client_ip_enabled).lower() != current_tg_attributes.get('preserve_client_ip_enabled'):
+ update_attributes.append({'Key': 'preserve_client_ip.enabled', 'Value': str(preserve_client_ip_enabled).lower()})
+ if proxy_protocol_v2_enabled is not None:
+ if str(proxy_protocol_v2_enabled).lower() != current_tg_attributes.get('proxy_protocol_v2_enabled'):
+ update_attributes.append({'Key': 'proxy_protocol_v2.enabled', 'Value': str(proxy_protocol_v2_enabled).lower()})
if update_attributes:
try:
@@ -862,6 +878,8 @@ def main():
targets=dict(type='list', elements='dict'),
unhealthy_threshold_count=dict(type='int'),
vpc_id=dict(),
+ preserve_client_ip_enabled=dict(type='bool'),
+ proxy_protocol_v2_enabled=dict(type='bool'),
wait_timeout=dict(type='int', default=200),
wait=dict(type='bool', default=False)
)
diff --git a/plugins/modules/iam.py b/plugins/modules/iam.py
index 67c55a277c5..4dd11aa0672 100644
--- a/plugins/modules/iam.py
+++ b/plugins/modules/iam.py
@@ -10,6 +10,11 @@
---
module: iam
version_added: 1.0.0
+deprecated:
+ removed_in: 3.0.0
+ why: The iam module is based upon a deprecated version of the AWS SDK.
+ alternative: Use M(iam_user), M(iam_group), M(iam_role), M(iam_policy) and M(iam_managed_policy) modules.
+
short_description: Manage IAM users, groups, roles and keys
description:
- Allows for the management of IAM users, user API keys, groups, roles.
@@ -644,6 +649,9 @@ def main():
check_boto3=False,
)
+ module.deprecate("The 'iam' module has been deprecated and replaced by the 'iam_user', 'iam_group'"
+ " and 'iam_role' modules'", version='3.0.0', collection_name='community.aws')
+
if not HAS_BOTO:
module.fail_json(msg='This module requires boto, please install it')
@@ -664,7 +672,7 @@ def main():
if key_state:
key_state = key_state.lower()
- if any([n in key_state for n in ['active', 'inactive']]) and not key_ids:
+ if any(n in key_state for n in ['active', 'inactive']) and not key_ids:
module.fail_json(changed=False, msg="At least one access key has to be defined in order"
" to use 'active' or 'inactive'")
@@ -727,7 +735,7 @@ def main():
if iam_type == 'user':
been_updated = False
user_groups = None
- user_exists = any([n in [name, new_name] for n in orig_user_list])
+ user_exists = any(n in [name, new_name] for n in orig_user_list)
if user_exists:
current_path = iam.get_user(name).get_user_result.user['path']
if not new_path and current_path != path:
diff --git a/plugins/modules/iam_access_key.py b/plugins/modules/iam_access_key.py
new file mode 100644
index 00000000000..1d5701e9d74
--- /dev/null
+++ b/plugins/modules/iam_access_key.py
@@ -0,0 +1,316 @@
+#!/usr/bin/python
+# Copyright (c) 2021 Ansible Project
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+from __future__ import absolute_import, division, print_function
+__metaclass__ = type
+
+
+DOCUMENTATION = r'''
+---
+module: iam_access_key
+version_added: 2.1.0
+short_description: Manage AWS IAM User access keys
+description:
+ - Manage AWS IAM user access keys.
+author: Mark Chappell (@tremble)
+options:
+ user_name:
+ description:
+ - The name of the IAM User to which the key belongs.
+ required: true
+ type: str
+ aliases: ['username']
+ id:
+ description:
+ - The ID of the access key.
+ - Required when I(state=absent).
+ - Mutually exclusive with I(rotate_keys).
+ required: false
+ type: str
+ state:
+ description:
+ - Create or remove the access key.
+ - When I(state=present) and I(id) is not defined a new key will be created.
+ required: false
+ type: str
+ default: 'present'
+ choices: [ 'present', 'absent' ]
+ active:
+ description:
+ - Whether the key should be enabled or disabled.
+ - Defaults to C(true) when creating a new key.
+ required: false
+ type: bool
+ aliases: ['enabled']
+ rotate_keys:
+ description:
+ - When there are already 2 access keys attached to the IAM user the oldest
+ key will be removed and a new key created.
+ - Ignored if I(state=absent)
+ - Mutually exclusive with I(id).
+ required: false
+ type: bool
+ default: false
+
+extends_documentation_fragment:
+- amazon.aws.aws
+- amazon.aws.ec2
+'''
+
+EXAMPLES = r'''
+# Note: These examples do not set authentication details, see the AWS Guide for details.
+
+- name: Create a new access key
+ community.aws.iam_access_key:
+ user_name: example_user
+ state: present
+
+- name: Delete the access_key
+ community.aws.iam_access_key:
+ name: example_user
+ access_key_id: AKIA1EXAMPLE1EXAMPLE
+ state: absent
+'''
+
+RETURN = r'''
+access_key:
+ description: A dictionary containing all the access key information.
+ returned: When the key exists.
+ type: complex
+ contains:
+ access_key_id:
+ description: The ID for the access key.
+ returned: success
+ type: str
+ sample: AKIA1EXAMPLE1EXAMPLE
+ create_date:
+ description: The date and time, in ISO 8601 date-time format, when the access key was created.
+ returned: success
+ type: str
+ sample: "2021-10-09T13:25:42+00:00"
+ user_name:
+ description: The name of the IAM user to which the key is attached.
+ returned: success
+ type: str
+ sample: example_user
+ status:
+ description:
+ - The status of the key.
+ - C(Active) means it can be used.
+ - C(Inactive) means it can not be used.
+ returned: success
+ type: str
+ sample: Inactive
+secret_access_key:
+ description:
+ - The secret access key.
+ - A secret access key is the equivalent of a password which can not be changed and as such should be considered sensitive data.
+ - Secret access keys can only be accessed at creation time.
+ returned: When a new key is created.
+ type: str
+ sample: example/Example+EXAMPLE+example/Example
+deleted_access_key_id:
+ description:
+ - The access key deleted during rotation.
+ returned: When a key was deleted during the rotation of access keys
+ type: str
+ sample: AKIA1EXAMPLE1EXAMPLE
+'''
+
+try:
+ import botocore
+except ImportError:
+ pass # caught by AnsibleAWSModule
+
+from ansible.module_utils.common.dict_transformations import camel_dict_to_snake_dict
+
+from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
+from ansible_collections.amazon.aws.plugins.module_utils.core import is_boto3_error_code
+from ansible_collections.amazon.aws.plugins.module_utils.core import normalize_boto3_result
+from ansible_collections.amazon.aws.plugins.module_utils.core import scrub_none_parameters
+from ansible_collections.amazon.aws.plugins.module_utils.ec2 import AWSRetry
+
+
+def delete_access_key(access_keys, user, access_key_id):
+ if not access_key_id:
+ return False
+
+ if access_key_id not in access_keys:
+ return False
+
+ if module.check_mode:
+ return True
+
+ try:
+ client.delete_access_key(
+ aws_retry=True,
+ UserName=user,
+ AccessKeyId=access_key_id,
+ )
+ except is_boto3_error_code('NoSuchEntityException'):
+ # Generally occurs when race conditions have happened and someone
+ # deleted the key while we were checking to see if it existed.
+ return False
+ except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: # pylint: disable=duplicate-except
+ module.fail_json_aws(
+ e, msg='Failed to delete access key "{0}" for user "{1}"'.format(access_key_id, user)
+ )
+
+ return True
+
+
+def update_access_key(access_keys, user, access_key_id, enabled):
+ if access_key_id not in access_keys:
+ module.fail_json(
+ msg='Access key "{0}" not found attached to User "{1}"'.format(access_key_id, user),
+ )
+
+ changes = dict()
+ access_key = access_keys.get(access_key_id)
+
+ if enabled is not None:
+ desired_status = 'Active' if enabled else 'Inactive'
+ if access_key.get('status') != desired_status:
+ changes['Status'] = desired_status
+
+ if not changes:
+ return False
+
+ if module.check_mode:
+ return True
+
+ try:
+ client.update_access_key(
+ aws_retry=True,
+ UserName=user,
+ AccessKeyId=access_key_id,
+ **changes
+ )
+ except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
+ module.fail_json_aws(
+ e, changes=changes,
+ msg='Failed to update access key "{0}" for user "{1}"'.format(access_key_id, user),
+ )
+ return True
+
+
+def create_access_key(access_keys, user, rotate_keys, enabled):
+ changed = False
+ oldest_key = False
+
+ if len(access_keys) > 1 and rotate_keys:
+ sorted_keys = sorted(list(access_keys), key=lambda k: access_keys[k].get('create_date', None))
+ oldest_key = sorted_keys[0]
+ changed |= delete_access_key(access_keys, user, oldest_key)
+
+ if module.check_mode:
+ if changed:
+ return dict(deleted_access_key=oldest_key)
+ return True
+
+ try:
+ results = client.create_access_key(aws_retry=True, UserName=user)
+ except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
+ module.fail_json_aws(e, msg='Failed to create access key for user "{0}"'.format(user))
+ results = camel_dict_to_snake_dict(results)
+ access_key = results.get('access_key')
+ access_key = normalize_boto3_result(access_key)
+
+ # Update settings which can't be managed on creation
+ if enabled is False:
+ access_key_id = access_key['access_key_id']
+ access_keys = {access_key_id: access_key}
+ update_access_key(access_keys, user, access_key_id, enabled)
+ access_key['status'] = 'Inactive'
+
+ if oldest_key:
+ access_key['deleted_access_key'] = oldest_key
+
+ return access_key
+
+
+def get_access_keys(user):
+ try:
+ results = client.list_access_keys(aws_retry=True, UserName=user)
+ except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
+ module.fail_json_aws(
+ e, msg='Failed to get access keys for user "{0}"'.format(user)
+ )
+ if not results:
+ return None
+
+ results = camel_dict_to_snake_dict(results)
+ access_keys = results.get('access_key_metadata', [])
+ if not access_keys:
+ return []
+
+ access_keys = normalize_boto3_result(access_keys)
+ access_keys = {k['access_key_id']: k for k in access_keys}
+ return access_keys
+
+
+def main():
+
+ global module
+ global client
+
+ argument_spec = dict(
+ user_name=dict(required=True, type='str', aliases=['username']),
+ id=dict(required=False, type='str'),
+ state=dict(required=False, choices=['present', 'absent'], default='present'),
+ active=dict(required=False, type='bool', aliases=['enabled']),
+ rotate_keys=dict(required=False, type='bool', default=False),
+ )
+
+ required_if = [
+ ['state', 'absent', ('id')],
+ ]
+ mutually_exclusive = [
+ ['rotate_keys', 'id'],
+ ]
+
+ module = AnsibleAWSModule(
+ argument_spec=argument_spec,
+ supports_check_mode=True
+ )
+
+ client = module.client('iam', retry_decorator=AWSRetry.jittered_backoff())
+
+ changed = False
+ state = module.params.get('state')
+ user = module.params.get('user_name')
+ access_key_id = module.params.get('id')
+ rotate_keys = module.params.get('rotate_keys')
+ enabled = module.params.get('active')
+
+ access_keys = get_access_keys(user)
+ results = dict()
+
+ if state == 'absent':
+ changed |= delete_access_key(access_keys, user, access_key_id)
+ else:
+ # If we have an ID then we should try to update it
+ if access_key_id:
+ changed |= update_access_key(access_keys, user, access_key_id, enabled)
+ access_keys = get_access_keys(user)
+ results['access_key'] = access_keys.get(access_key_id, None)
+ # Otherwise we try to create a new one
+ else:
+ secret_key = create_access_key(access_keys, user, rotate_keys, enabled)
+ if isinstance(secret_key, bool):
+ changed |= secret_key
+ else:
+ changed = True
+ results['access_key_id'] = secret_key.get('access_key_id', None)
+ results['secret_access_key'] = secret_key.pop('secret_access_key', None)
+ results['deleted_access_key_id'] = secret_key.pop('deleted_access_key', None)
+ if secret_key:
+ results['access_key'] = secret_key
+ results = scrub_none_parameters(results)
+
+ module.exit_json(changed=changed, **results)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/plugins/modules/iam_access_key_info.py b/plugins/modules/iam_access_key_info.py
new file mode 100644
index 00000000000..9251cb846f6
--- /dev/null
+++ b/plugins/modules/iam_access_key_info.py
@@ -0,0 +1,127 @@
+#!/usr/bin/python
+# Copyright (c) 2021 Ansible Project
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+from __future__ import absolute_import, division, print_function
+__metaclass__ = type
+
+
+DOCUMENTATION = r'''
+---
+module: iam_access_key_info
+version_added: 2.1.0
+short_description: fetch information about AWS IAM User access keys
+description:
+ - 'Fetches information AWS IAM user access keys.'
+ - 'Note: It is not possible to fetch the secret access key.'
+author: Mark Chappell (@tremble)
+options:
+ user_name:
+ description:
+ - The name of the IAM User to which the keys belong.
+ required: true
+ type: str
+ aliases: ['username']
+
+extends_documentation_fragment:
+- amazon.aws.aws
+- amazon.aws.ec2
+'''
+
+EXAMPLES = r'''
+# Note: These examples do not set authentication details, see the AWS Guide for details.
+
+- name: Fetch Access keys for a user
+ community.aws.iam_access_key_info:
+ user_name: example_user
+'''
+
+RETURN = r'''
+access_key:
+ description: A dictionary containing all the access key information.
+ returned: When the key exists.
+ type: list
+ elements: dict
+ contains:
+ access_key_id:
+ description: The ID for the access key.
+ returned: success
+ type: str
+ sample: AKIA1EXAMPLE1EXAMPLE
+ create_date:
+ description: The date and time, in ISO 8601 date-time format, when the access key was created.
+ returned: success
+ type: str
+ sample: "2021-10-09T13:25:42+00:00"
+ user_name:
+ description: The name of the IAM user to which the key is attached.
+ returned: success
+ type: str
+ sample: example_user
+ status:
+ description:
+ - The status of the key.
+ - C(Active) means it can be used.
+ - C(Inactive) means it can not be used.
+ returned: success
+ type: str
+ sample: Inactive
+'''
+
+try:
+ import botocore
+except ImportError:
+ pass # caught by AnsibleAWSModule
+
+from ansible.module_utils.common.dict_transformations import camel_dict_to_snake_dict
+
+from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
+from ansible_collections.amazon.aws.plugins.module_utils.core import normalize_boto3_result
+from ansible_collections.amazon.aws.plugins.module_utils.ec2 import AWSRetry
+
+
+def get_access_keys(user):
+ try:
+ results = client.list_access_keys(aws_retry=True, UserName=user)
+ except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
+ module.fail_json_aws(
+ e, msg='Failed to get access keys for user "{0}"'.format(user)
+ )
+ if not results:
+ return None
+
+ results = camel_dict_to_snake_dict(results)
+ access_keys = results.get('access_key_metadata', [])
+ if not access_keys:
+ return []
+
+ access_keys = normalize_boto3_result(access_keys)
+ access_keys = sorted(access_keys, key=lambda d: d.get('create_date', None))
+ return access_keys
+
+
+def main():
+
+ global module
+ global client
+
+ argument_spec = dict(
+ user_name=dict(required=True, type='str', aliases=['username']),
+ )
+
+ module = AnsibleAWSModule(
+ argument_spec=argument_spec,
+ supports_check_mode=True
+ )
+
+ client = module.client('iam', retry_decorator=AWSRetry.jittered_backoff())
+
+ changed = False
+ user = module.params.get('user_name')
+ access_keys = get_access_keys(user)
+
+ module.exit_json(changed=changed, access_keys=access_keys)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/plugins/modules/iam_cert.py b/plugins/modules/iam_cert.py
deleted file mode 100644
index fbe984670aa..00000000000
--- a/plugins/modules/iam_cert.py
+++ /dev/null
@@ -1,313 +0,0 @@
-#!/usr/bin/python
-# This file is part of Ansible
-#
-# Ansible is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# Ansible is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with Ansible. If not, see .
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-DOCUMENTATION = '''
----
-module: iam_cert
-version_added: 1.0.0
-short_description: Manage server certificates for use on ELBs and CloudFront
-description:
- - Allows for the management of server certificates.
-options:
- name:
- description:
- - Name of certificate to add, update or remove.
- required: true
- type: str
- new_name:
- description:
- - When I(state=present), this will update the name of the cert.
- - The I(cert), I(key) and I(cert_chain) parameters will be ignored if this is defined.
- type: str
- new_path:
- description:
- - When I(state=present), this will update the path of the cert.
- - The I(cert), I(key) and I(cert_chain) parameters will be ignored if this is defined.
- type: str
- state:
- description:
- - Whether to create (or update) or delete the certificate.
- - If I(new_path) or I(new_name) is defined, specifying present will attempt to make an update these.
- required: true
- choices: [ "present", "absent" ]
- type: str
- path:
- description:
- - When creating or updating, specify the desired path of the certificate.
- default: "/"
- type: str
- cert_chain:
- description:
- - The path to, or content of, the CA certificate chain in PEM encoded format.
- As of 2.4 content is accepted. If the parameter is not a file, it is assumed to be content.
- type: str
- cert:
- description:
- - The path to, or content of the certificate body in PEM encoded format.
- As of 2.4 content is accepted. If the parameter is not a file, it is assumed to be content.
- type: str
- key:
- description:
- - The path to, or content of the private key in PEM encoded format.
- As of 2.4 content is accepted. If the parameter is not a file, it is assumed to be content.
- type: str
- dup_ok:
- description:
- - By default the module will not upload a certificate that is already uploaded into AWS.
- - If I(dup_ok=True), it will upload the certificate as long as the name is unique.
- - Defaults to C(false).
- type: bool
-
-author: Jonathan I. Davila (@defionscode)
-extends_documentation_fragment:
-- amazon.aws.aws
-- amazon.aws.ec2
-requirements:
-- boto >= 2.49.0
-'''
-
-EXAMPLES = '''
-- name: Basic server certificate upload from local file
- community.aws.iam_cert:
- name: very_ssl
- state: present
- cert: "{{ lookup('file', 'path/to/cert') }}"
- key: "{{ lookup('file', 'path/to/key') }}"
- cert_chain: "{{ lookup('file', 'path/to/certchain') }}"
-
-- name: Basic server certificate upload
- community.aws.iam_cert:
- name: very_ssl
- state: present
- cert: path/to/cert
- key: path/to/key
- cert_chain: path/to/certchain
-
-- name: Server certificate upload using key string
- community.aws.iam_cert:
- name: very_ssl
- state: present
- path: "/a/cert/path/"
- cert: body_of_somecert
- key: vault_body_of_privcertkey
- cert_chain: body_of_myverytrustedchain
-
-- name: Basic rename of existing certificate
- community.aws.iam_cert:
- name: very_ssl
- new_name: new_very_ssl
- state: present
-
-'''
-import os
-
-try:
- import boto
- import boto.iam
- import boto.ec2
-except ImportError:
- pass # Handled by HAS_BOTO
-
-from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import get_aws_connection_info
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import connect_to_aws
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import HAS_BOTO
-
-
-def cert_meta(iam, name):
- certificate = iam.get_server_certificate(name).get_server_certificate_result.server_certificate
- ocert = certificate.certificate_body
- opath = certificate.server_certificate_metadata.path
- ocert_id = certificate.server_certificate_metadata.server_certificate_id
- upload_date = certificate.server_certificate_metadata.upload_date
- exp = certificate.server_certificate_metadata.expiration
- arn = certificate.server_certificate_metadata.arn
- return opath, ocert, ocert_id, upload_date, exp, arn
-
-
-def dup_check(module, iam, name, new_name, cert, orig_cert_names, orig_cert_bodies, dup_ok):
- update = False
-
- # IAM cert names are case insensitive
- names_lower = [n.lower() for n in [name, new_name] if n is not None]
- orig_cert_names_lower = [ocn.lower() for ocn in orig_cert_names]
-
- if any(ct in orig_cert_names_lower for ct in names_lower):
- for i_name in names_lower:
- if cert is not None:
- try:
- c_index = orig_cert_names_lower.index(i_name)
- except NameError:
- continue
- else:
- # NOTE: remove the carriage return to strictly compare the cert bodies.
- slug_cert = cert.replace('\r', '')
- slug_orig_cert_bodies = orig_cert_bodies[c_index].replace('\r', '')
- if slug_orig_cert_bodies == slug_cert:
- update = True
- break
- elif slug_cert.startswith(slug_orig_cert_bodies):
- update = True
- break
- else:
- module.fail_json(changed=False, msg='A cert with the name %s already exists and'
- ' has a different certificate body associated'
- ' with it. Certificates cannot have the same name' % orig_cert_names[c_index])
- else:
- update = True
- break
- elif cert in orig_cert_bodies and not dup_ok:
- for crt_name, crt_body in zip(orig_cert_names, orig_cert_bodies):
- if crt_body == cert:
- module.fail_json(changed=False, msg='This certificate already'
- ' exists under the name %s' % crt_name)
-
- return update
-
-
-def cert_action(module, iam, name, cpath, new_name, new_path, state,
- cert, key, cert_chain, orig_cert_names, orig_cert_bodies, dup_ok):
- if state == 'present':
- update = dup_check(module, iam, name, new_name, cert, orig_cert_names,
- orig_cert_bodies, dup_ok)
- if update:
- opath, ocert, ocert_id, upload_date, exp, arn = cert_meta(iam, name)
- changed = True
- if new_name and new_path:
- iam.update_server_cert(name, new_cert_name=new_name, new_path=new_path)
- module.exit_json(changed=changed, original_name=name, new_name=new_name,
- original_path=opath, new_path=new_path, cert_body=ocert,
- upload_date=upload_date, expiration_date=exp, arn=arn)
- elif new_name and not new_path:
- iam.update_server_cert(name, new_cert_name=new_name)
- module.exit_json(changed=changed, original_name=name, new_name=new_name,
- cert_path=opath, cert_body=ocert,
- upload_date=upload_date, expiration_date=exp, arn=arn)
- elif not new_name and new_path:
- iam.update_server_cert(name, new_path=new_path)
- module.exit_json(changed=changed, name=new_name,
- original_path=opath, new_path=new_path, cert_body=ocert,
- upload_date=upload_date, expiration_date=exp, arn=arn)
- else:
- changed = False
- module.exit_json(changed=changed, name=name, cert_path=opath, cert_body=ocert,
- upload_date=upload_date, expiration_date=exp, arn=arn,
- msg='No new path or name specified. No changes made')
- else:
- changed = True
- iam.upload_server_cert(name, cert, key, cert_chain=cert_chain, path=cpath)
- opath, ocert, ocert_id, upload_date, exp, arn = cert_meta(iam, name)
- module.exit_json(changed=changed, name=name, cert_path=opath, cert_body=ocert,
- upload_date=upload_date, expiration_date=exp, arn=arn)
- elif state == 'absent':
- if name in orig_cert_names:
- changed = True
- iam.delete_server_cert(name)
- module.exit_json(changed=changed, deleted_cert=name)
- else:
- changed = False
- module.exit_json(changed=changed, msg='Certificate with the name %s already absent' % name)
-
-
-def load_data(cert, key, cert_chain):
- # if paths are provided rather than lookups read the files and return the contents
- if cert and os.path.isfile(cert):
- with open(cert, 'r') as cert_fh:
- cert = cert_fh.read().rstrip()
- if key and os.path.isfile(key):
- with open(key, 'r') as key_fh:
- key = key_fh.read().rstrip()
- if cert_chain and os.path.isfile(cert_chain):
- with open(cert_chain, 'r') as cert_chain_fh:
- cert_chain = cert_chain_fh.read()
- return cert, key, cert_chain
-
-
-def main():
- argument_spec = dict(
- state=dict(required=True, choices=['present', 'absent']),
- name=dict(required=True),
- cert=dict(),
- key=dict(no_log=True),
- cert_chain=dict(),
- new_name=dict(),
- path=dict(default='/'),
- new_path=dict(),
- dup_ok=dict(type='bool'),
- )
-
- module = AnsibleAWSModule(
- argument_spec=argument_spec,
- mutually_exclusive=[
- ['new_path', 'key'],
- ['new_path', 'cert'],
- ['new_path', 'cert_chain'],
- ['new_name', 'key'],
- ['new_name', 'cert'],
- ['new_name', 'cert_chain'],
- ],
- check_boto3=False,
- )
-
- if not HAS_BOTO:
- module.fail_json(msg="Boto is required for this module")
-
- region, ec2_url, aws_connect_kwargs = get_aws_connection_info(module)
-
- try:
- if region:
- iam = connect_to_aws(boto.iam, region, **aws_connect_kwargs)
- else:
- iam = boto.iam.connection.IAMConnection(**aws_connect_kwargs)
- except boto.exception.NoAuthHandlerFound as e:
- module.fail_json(msg=str(e))
-
- state = module.params.get('state')
- name = module.params.get('name')
- path = module.params.get('path')
- new_name = module.params.get('new_name')
- new_path = module.params.get('new_path')
- dup_ok = module.params.get('dup_ok')
- if state == 'present' and not new_name and not new_path:
- cert, key, cert_chain = load_data(cert=module.params.get('cert'),
- key=module.params.get('key'),
- cert_chain=module.params.get('cert_chain'))
- else:
- cert = key = cert_chain = None
-
- orig_cert_names = [ctb['server_certificate_name'] for ctb in
- iam.get_all_server_certs().list_server_certificates_result.server_certificate_metadata_list]
- orig_cert_bodies = [iam.get_server_certificate(thing).get_server_certificate_result.certificate_body
- for thing in orig_cert_names]
- if new_name == name:
- new_name = None
- if new_path == path:
- new_path = None
-
- changed = False
- try:
- cert_action(module, iam, name, path, new_name, new_path, state,
- cert, key, cert_chain, orig_cert_names, orig_cert_bodies, dup_ok)
- except boto.exception.BotoServerError as err:
- module.fail_json(changed=changed, msg=str(err), debug=[cert, key])
-
-
-if __name__ == '__main__':
- main()
diff --git a/plugins/modules/iam_group.py b/plugins/modules/iam_group.py
index 7b534aa0504..5f85c4bfc8c 100644
--- a/plugins/modules/iam_group.py
+++ b/plugins/modules/iam_group.py
@@ -217,7 +217,7 @@ def compare_group_members(current_group_members, new_group_members):
def convert_friendly_names_to_arns(connection, module, policy_names):
- if not any([not policy.startswith('arn:') for policy in policy_names if policy is not None]):
+ if not any(not policy.startswith('arn:') for policy in policy_names if policy is not None):
return policy_names
allpolicies = {}
paginator = connection.get_paginator('list_policies')
diff --git a/plugins/modules/iam_managed_policy.py b/plugins/modules/iam_managed_policy.py
index a56e76d037f..d6cdd33525e 100644
--- a/plugins/modules/iam_managed_policy.py
+++ b/plugins/modules/iam_managed_policy.py
@@ -141,7 +141,7 @@
from ansible_collections.amazon.aws.plugins.module_utils.ec2 import compare_policies
-@AWSRetry.backoff(tries=5, delay=5, backoff=2.0)
+@AWSRetry.jittered_backoff(retries=5, delay=5, backoff=2.0)
def list_policies_with_backoff(iam):
paginator = iam.get_paginator('list_policies')
return paginator.paginate(Scope='Local').build_full_result()
diff --git a/plugins/modules/iam_mfa_device_info.py b/plugins/modules/iam_mfa_device_info.py
index b04b912549c..78cfe8249d0 100644
--- a/plugins/modules/iam_mfa_device_info.py
+++ b/plugins/modules/iam_mfa_device_info.py
@@ -87,7 +87,10 @@ def main():
user_name=dict(required=False, default=None),
)
- module = AnsibleAWSModule(argument_spec=argument_spec)
+ module = AnsibleAWSModule(
+ argument_spec=argument_spec,
+ supports_check_mode=True,
+ )
if module._name == 'iam_mfa_device_facts':
module.deprecate("The 'iam_mfa_device_facts' module has been renamed to 'iam_mfa_device_info'", date='2021-12-01', collection_name='community.aws')
diff --git a/plugins/modules/iam_policy.py b/plugins/modules/iam_policy.py
index 819ed369a31..570c37efa1b 100644
--- a/plugins/modules/iam_policy.py
+++ b/plugins/modules/iam_policy.py
@@ -36,7 +36,7 @@
description:
- The path to the properly json formatted policy file.
- Mutually exclusive with I(policy_json).
- - This option has been deprecated and will be removed in 2.14. The existing behavior can be
+ - This option has been deprecated and will be removed in a release after 2022-06-01. The existing behavior can be
reproduced by using the I(policy_json) option and reading the file using the lookup plugin.
type: str
policy_json:
@@ -53,9 +53,10 @@
type: str
skip_duplicates:
description:
- - When I(skip_duplicates=true) the module looks for any policies that match the document you pass in. If there is a match it will not make
- a new policy object with the same rules.
- - The current default is C(true). However, this behavior can be confusing and as such the default will change to C(false) in 2.14. To maintain
+ - When I(skip_duplicates=true) the module looks for any policies that match the document you pass in.
+ If there is a match it will not make a new policy object with the same rules.
+ - The current default is C(true). However, this behavior can be confusing and as such the default will
+ change to C(false) in a release after 2022-06-01. To maintain
the existing behavior explicitly set I(skip_duplicates=true).
type: bool
@@ -304,13 +305,13 @@ def main():
if (skip_duplicates is None):
module.deprecate('The skip_duplicates behaviour has caused confusion and'
- ' will be disabled by default in Ansible 2.14',
+ ' will be disabled by default in a release after 2022-06-01',
date='2022-06-01', collection_name='community.aws')
skip_duplicates = True
if module.params.get('policy_document'):
module.deprecate('The policy_document option has been deprecated and'
- ' will be removed in Ansible 2.14',
+ ' will be removed in a release after 2022-06-01',
date='2022-06-01', collection_name='community.aws')
args = dict(
diff --git a/plugins/modules/iam_role.py b/plugins/modules/iam_role.py
index 45551cdf188..7ca0d8c4fbb 100644
--- a/plugins/modules/iam_role.py
+++ b/plugins/modules/iam_role.py
@@ -34,7 +34,6 @@
- Boundaries cannot be set on Instance Profiles, as such if this option is specified then I(create_instance_profile) must be C(false).
- This is intended for roles/users that have permissions to create new IAM objects.
- For more information on boundaries, see U(https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies_boundaries.html).
- - Requires botocore 1.10.57 or above.
aliases: [boundary_policy_arn]
type: str
assume_role_policy_document:
@@ -44,7 +43,7 @@
type: json
managed_policies:
description:
- - A list of managed policy ARNs or, since Ansible 2.4, a list of either managed policy ARNs or friendly names.
+ - A list of managed policy ARNs, managed policy ARNs or friendly names.
- To remove all policies set I(purge_polices=true) and I(managed_policies=[None]).
- To embed an inline policy, use M(community.aws.iam_policy).
aliases: ['managed_policy']
@@ -58,7 +57,7 @@
purge_policies:
description:
- When I(purge_policies=true) any managed policies not listed in I(managed_policies) will be detatched.
- - By default I(purge_policies=true). In Ansible 2.14 this will be changed to I(purge_policies=false).
+ - By default I(purge_policies=true). In a release after 2022-06-01 this will be changed to I(purge_policies=false).
type: bool
aliases: ['purge_policy', 'purge_managed_policies']
state:
@@ -82,13 +81,23 @@
tags:
description:
- Tag dict to apply to the queue.
- - Requires botocore 1.12.46 or above.
type: dict
purge_tags:
description:
- Remove tags not listed in I(tags) when tags is specified.
default: true
type: bool
+ wait_timeout:
+ description:
+ - How long (in seconds) to wait for creation / update to complete.
+ default: 120
+ type: int
+ wait:
+ description:
+ - When I(wait=True) the module will wait for up to I(wait_timeout) seconds
+ for IAM role creation before returning.
+ default: True
+ type: bool
extends_documentation_fragment:
- amazon.aws.aws
- amazon.aws.ec2
@@ -217,16 +226,40 @@ def compare_assume_role_policy_doc(current_policy_doc, new_policy_doc):
@AWSRetry.jittered_backoff()
-def _list_policies(connection):
- paginator = connection.get_paginator('list_policies')
+def _list_policies():
+ paginator = client.get_paginator('list_policies')
return paginator.paginate().build_full_result()['Policies']
-def convert_friendly_names_to_arns(connection, module, policy_names):
- if not any([not policy.startswith('arn:') for policy in policy_names]):
+def wait_iam_exists():
+ if module.check_mode:
+ return
+ if not module.params.get('wait'):
+ return
+
+ role_name = module.params.get('name')
+ wait_timeout = module.params.get('wait_timeout')
+
+ delay = min(wait_timeout, 5)
+ max_attempts = wait_timeout // delay
+
+ try:
+ waiter = client.get_waiter('role_exists')
+ waiter.wait(
+ WaiterConfig={'Delay': delay, 'MaxAttempts': max_attempts},
+ RoleName=role_name,
+ )
+ except botocore.exceptions.WaiterError as e:
+ module.fail_json_aws(e, msg='Timeout while waiting on IAM role creation')
+ except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
+ module.fail_json_aws(e, msg='Failed while waiting on IAM role creation')
+
+
+def convert_friendly_names_to_arns(policy_names):
+ if not any(not policy.startswith('arn:') for policy in policy_names):
return policy_names
allpolicies = {}
- policies = _list_policies(connection)
+ policies = _list_policies()
for policy in policies:
allpolicies[policy['PolicyName']] = policy['Arn']
@@ -237,31 +270,31 @@ def convert_friendly_names_to_arns(connection, module, policy_names):
module.fail_json_aws(e, msg="Couldn't find policy")
-def attach_policies(connection, module, policies_to_attach, params):
+def attach_policies(policies_to_attach, params):
changed = False
for policy_arn in policies_to_attach:
try:
if not module.check_mode:
- connection.attach_role_policy(RoleName=params['RoleName'], PolicyArn=policy_arn, aws_retry=True)
+ client.attach_role_policy(RoleName=params['RoleName'], PolicyArn=policy_arn, aws_retry=True)
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
module.fail_json_aws(e, msg="Unable to attach policy {0} to role {1}".format(policy_arn, params['RoleName']))
changed = True
return changed
-def remove_policies(connection, module, policies_to_remove, params):
+def remove_policies(policies_to_remove, params):
changed = False
for policy in policies_to_remove:
try:
if not module.check_mode:
- connection.detach_role_policy(RoleName=params['RoleName'], PolicyArn=policy, aws_retry=True)
+ client.detach_role_policy(RoleName=params['RoleName'], PolicyArn=policy, aws_retry=True)
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
module.fail_json_aws(e, msg="Unable to detach policy {0} from {1}".format(policy, params['RoleName']))
changed = True
return changed
-def generate_create_params(module):
+def generate_create_params():
params = dict()
params['Path'] = module.params.get('path')
params['RoleName'] = module.params.get('name')
@@ -278,7 +311,7 @@ def generate_create_params(module):
return params
-def create_basic_role(connection, module, params):
+def create_basic_role(params):
"""
Perform the Role creation.
Assumes tests for the role existing have already been performed.
@@ -286,11 +319,11 @@ def create_basic_role(connection, module, params):
try:
if not module.check_mode:
- role = connection.create_role(aws_retry=True, **params)
+ role = client.create_role(aws_retry=True, **params)
# 'Description' is documented as key of the role returned by create_role
# but appears to be an AWS bug (the value is not returned using the AWS CLI either).
# Get the role after creating it.
- role = get_role_with_backoff(connection, module, params['RoleName'])
+ role = get_role_with_backoff(params['RoleName'])
else:
role = {'MadeInCheckMode': True}
role['AssumeRolePolicyDocument'] = json.loads(params['AssumeRolePolicyDocument'])
@@ -300,7 +333,7 @@ def create_basic_role(connection, module, params):
return role
-def update_role_assumed_policy(connection, module, params, role):
+def update_role_assumed_policy(params, role):
# Check Assumed Policy document
if compare_assume_role_policy_doc(role['AssumeRolePolicyDocument'], params['AssumeRolePolicyDocument']):
return False
@@ -309,7 +342,7 @@ def update_role_assumed_policy(connection, module, params, role):
return True
try:
- connection.update_assume_role_policy(
+ client.update_assume_role_policy(
RoleName=params['RoleName'],
PolicyDocument=json.dumps(json.loads(params['AssumeRolePolicyDocument'])),
aws_retry=True)
@@ -318,7 +351,7 @@ def update_role_assumed_policy(connection, module, params, role):
return True
-def update_role_description(connection, module, params, role):
+def update_role_description(params, role):
# Check Description update
if params.get('Description') is None:
return False
@@ -329,13 +362,13 @@ def update_role_description(connection, module, params, role):
return True
try:
- connection.update_role_description(RoleName=params['RoleName'], Description=params['Description'], aws_retry=True)
+ client.update_role(RoleName=params['RoleName'], Description=params['Description'], aws_retry=True)
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
module.fail_json_aws(e, msg="Unable to update description for role {0}".format(params['RoleName']))
return True
-def update_role_max_session_duration(connection, module, params, role):
+def update_role_max_session_duration(params, role):
# Check MaxSessionDuration update
if params.get('MaxSessionDuration') is None:
return False
@@ -346,13 +379,13 @@ def update_role_max_session_duration(connection, module, params, role):
return True
try:
- connection.update_role(RoleName=params['RoleName'], MaxSessionDuration=params['MaxSessionDuration'], aws_retry=True)
+ client.update_role(RoleName=params['RoleName'], MaxSessionDuration=params['MaxSessionDuration'], aws_retry=True)
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
module.fail_json_aws(e, msg="Unable to update maximum session duration for role {0}".format(params['RoleName']))
return True
-def update_role_permissions_boundary(connection, module, params, role):
+def update_role_permissions_boundary(params, role):
# Check PermissionsBoundary
if params.get('PermissionsBoundary') is None:
return False
@@ -364,18 +397,18 @@ def update_role_permissions_boundary(connection, module, params, role):
if params.get('PermissionsBoundary') == '':
try:
- connection.delete_role_permissions_boundary(RoleName=params['RoleName'], aws_retry=True)
+ client.delete_role_permissions_boundary(RoleName=params['RoleName'], aws_retry=True)
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
module.fail_json_aws(e, msg="Unable to remove permission boundary for role {0}".format(params['RoleName']))
else:
try:
- connection.put_role_permissions_boundary(RoleName=params['RoleName'], PermissionsBoundary=params['PermissionsBoundary'], aws_retry=True)
+ client.put_role_permissions_boundary(RoleName=params['RoleName'], PermissionsBoundary=params['PermissionsBoundary'], aws_retry=True)
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
module.fail_json_aws(e, msg="Unable to update permission boundary for role {0}".format(params['RoleName']))
return True
-def update_managed_policies(connection, module, params, role, managed_policies, purge_policies):
+def update_managed_policies(params, role, managed_policies, purge_policies):
# Check Managed Policies
if managed_policies is None:
return False
@@ -386,7 +419,7 @@ def update_managed_policies(connection, module, params, role, managed_policies,
return True
# Get list of current attached managed policies
- current_attached_policies = get_attached_policy_list(connection, module, params['RoleName'])
+ current_attached_policies = get_attached_policy_list(params['RoleName'])
current_attached_policies_arn_list = [policy['PolicyArn'] for policy in current_attached_policies]
if len(managed_policies) == 1 and managed_policies[0] is None:
@@ -398,16 +431,16 @@ def update_managed_policies(connection, module, params, role, managed_policies,
changed = False
if purge_policies:
- changed |= remove_policies(connection, module, policies_to_remove, params)
+ changed |= remove_policies(policies_to_remove, params)
- changed |= attach_policies(connection, module, policies_to_attach, params)
+ changed |= attach_policies(policies_to_attach, params)
return changed
-def create_or_update_role(connection, module):
+def create_or_update_role():
- params = generate_create_params(module)
+ params = generate_create_params()
role_name = params['RoleName']
create_instance_profile = module.params.get('create_instance_profile')
purge_policies = module.params.get('purge_policies')
@@ -416,48 +449,59 @@ def create_or_update_role(connection, module):
managed_policies = module.params.get('managed_policies')
if managed_policies:
# Attempt to list the policies early so we don't leave things behind if we can't find them.
- managed_policies = convert_friendly_names_to_arns(connection, module, managed_policies)
+ managed_policies = convert_friendly_names_to_arns(managed_policies)
changed = False
# Get role
- role = get_role(connection, module, role_name)
+ role = get_role(role_name)
# If role is None, create it
if role is None:
- role = create_basic_role(connection, module, params)
+ role = create_basic_role(params)
+
+ if not module.check_mode and module.params.get('wait'):
+ wait_iam_exists()
+
changed = True
else:
- changed |= update_role_tags(connection, module, params, role)
- changed |= update_role_assumed_policy(connection, module, params, role)
- changed |= update_role_description(connection, module, params, role)
- changed |= update_role_max_session_duration(connection, module, params, role)
- changed |= update_role_permissions_boundary(connection, module, params, role)
+ changed |= update_role_tags(params, role)
+ changed |= update_role_assumed_policy(params, role)
+ changed |= update_role_description(params, role)
+ changed |= update_role_max_session_duration(params, role)
+ changed |= update_role_permissions_boundary(params, role)
+
+ if not module.check_mode and module.params.get('wait'):
+ wait_iam_exists()
if create_instance_profile:
- changed |= create_instance_profiles(connection, module, params, role)
+ changed |= create_instance_profiles(params, role)
- changed |= update_managed_policies(connection, module, params, role, managed_policies, purge_policies)
+ if not module.check_mode and module.params.get('wait'):
+ wait_iam_exists()
+
+ changed |= update_managed_policies(params, role, managed_policies, purge_policies)
+ wait_iam_exists()
# Get the role again
if not role.get('MadeInCheckMode', False):
- role = get_role(connection, module, params['RoleName'])
- role['AttachedPolicies'] = get_attached_policy_list(connection, module, params['RoleName'])
- role['tags'] = get_role_tags(connection, module)
+ role = get_role(params['RoleName'])
+ role['AttachedPolicies'] = get_attached_policy_list(params['RoleName'])
+ role['tags'] = get_role_tags()
module.exit_json(
changed=changed, iam_role=camel_dict_to_snake_dict(role, ignore_list=['tags']),
**camel_dict_to_snake_dict(role, ignore_list=['tags']))
-def create_instance_profiles(connection, module, params, role):
+def create_instance_profiles(params, role):
if role.get('MadeInCheckMode', False):
return False
# Fetch existing Profiles
try:
- instance_profiles = connection.list_instance_profiles_for_role(RoleName=params['RoleName'], aws_retry=True)['InstanceProfiles']
+ instance_profiles = client.list_instance_profiles_for_role(RoleName=params['RoleName'], aws_retry=True)['InstanceProfiles']
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
module.fail_json_aws(e, msg="Unable to list instance profiles for role {0}".format(params['RoleName']))
@@ -470,7 +514,7 @@ def create_instance_profiles(connection, module, params, role):
# Make sure an instance profile is created
try:
- connection.create_instance_profile(InstanceProfileName=params['RoleName'], Path=params['Path'], aws_retry=True)
+ client.create_instance_profile(InstanceProfileName=params['RoleName'], Path=params['Path'], aws_retry=True)
except is_boto3_error_code('EntityAlreadyExists'):
# If the profile already exists, no problem, move on.
# Implies someone's changing things at the same time...
@@ -480,19 +524,19 @@ def create_instance_profiles(connection, module, params, role):
# And attach the role to the profile
try:
- connection.add_role_to_instance_profile(InstanceProfileName=params['RoleName'], RoleName=params['RoleName'], aws_retry=True)
+ client.add_role_to_instance_profile(InstanceProfileName=params['RoleName'], RoleName=params['RoleName'], aws_retry=True)
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
module.fail_json_aws(e, msg="Unable to attach role {0} to instance profile {0}".format(params['RoleName']))
return True
-def remove_instance_profiles(connection, module, role_params, role):
+def remove_instance_profiles(role_params, role):
role_name = module.params.get('name')
delete_profiles = module.params.get("delete_instance_profile")
try:
- instance_profiles = connection.list_instance_profiles_for_role(aws_retry=True, **role_params)['InstanceProfiles']
+ instance_profiles = client.list_instance_profiles_for_role(aws_retry=True, **role_params)['InstanceProfiles']
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
module.fail_json_aws(e, msg="Unable to list instance profiles for role {0}".format(role_name))
@@ -501,21 +545,21 @@ def remove_instance_profiles(connection, module, role_params, role):
profile_name = profile['InstanceProfileName']
try:
if not module.check_mode:
- connection.remove_role_from_instance_profile(aws_retry=True, InstanceProfileName=profile_name, **role_params)
+ client.remove_role_from_instance_profile(aws_retry=True, InstanceProfileName=profile_name, **role_params)
if profile_name == role_name:
if delete_profiles:
try:
- connection.delete_instance_profile(InstanceProfileName=profile_name, aws_retry=True)
+ client.delete_instance_profile(InstanceProfileName=profile_name, aws_retry=True)
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
module.fail_json_aws(e, msg="Unable to remove instance profile {0}".format(profile_name))
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
module.fail_json_aws(e, msg="Unable to remove role {0} from instance profile {1}".format(role_name, profile_name))
-def destroy_role(connection, module):
+def destroy_role():
role_name = module.params.get('name')
- role = get_role(connection, module, role_name)
+ role = get_role(role_name)
role_params = dict()
role_params['RoleName'] = role_name
boundary_params = dict(role_params)
@@ -528,53 +572,51 @@ def destroy_role(connection, module):
# - attached instance profiles
# - attached managed policies
# - permissions boundary
- remove_instance_profiles(connection, module, role_params, role)
- update_managed_policies(connection, module, role_params, role, [], True)
- update_role_permissions_boundary(connection, module, boundary_params, role)
+ remove_instance_profiles(role_params, role)
+ update_managed_policies(role_params, role, [], True)
+ update_role_permissions_boundary(boundary_params, role)
try:
if not module.check_mode:
- connection.delete_role(aws_retry=True, **role_params)
+ client.delete_role(aws_retry=True, **role_params)
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
module.fail_json_aws(e, msg="Unable to delete role")
module.exit_json(changed=True)
-def get_role_with_backoff(connection, module, name):
+def get_role_with_backoff(name):
try:
- return AWSRetry.jittered_backoff(catch_extra_error_codes=['NoSuchEntity'])(connection.get_role)(RoleName=name)['Role']
+ return AWSRetry.jittered_backoff(catch_extra_error_codes=['NoSuchEntity'])(client.get_role)(RoleName=name)['Role']
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
module.fail_json_aws(e, msg="Unable to get role {0}".format(name))
-def get_role(connection, module, name):
+def get_role(name):
try:
- return connection.get_role(RoleName=name, aws_retry=True)['Role']
+ return client.get_role(RoleName=name, aws_retry=True)['Role']
except is_boto3_error_code('NoSuchEntity'):
return None
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: # pylint: disable=duplicate-except
module.fail_json_aws(e, msg="Unable to get role {0}".format(name))
-def get_attached_policy_list(connection, module, name):
+def get_attached_policy_list(name):
try:
- return connection.list_attached_role_policies(RoleName=name, aws_retry=True)['AttachedPolicies']
+ return client.list_attached_role_policies(RoleName=name, aws_retry=True)['AttachedPolicies']
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
module.fail_json_aws(e, msg="Unable to list attached policies for role {0}".format(name))
-def get_role_tags(connection, module):
+def get_role_tags():
role_name = module.params.get('name')
- if not hasattr(connection, 'list_role_tags'):
- return {}
try:
- return boto3_tag_list_to_ansible_dict(connection.list_role_tags(RoleName=role_name, aws_retry=True)['Tags'])
+ return boto3_tag_list_to_ansible_dict(client.list_role_tags(RoleName=role_name, aws_retry=True)['Tags'])
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
module.fail_json_aws(e, msg="Unable to list tags for role {0}".format(role_name))
-def update_role_tags(connection, module, params, role):
+def update_role_tags(params, role):
new_tags = params.get('Tags')
if new_tags is None:
return False
@@ -584,7 +626,7 @@ def update_role_tags(connection, module, params, role):
purge_tags = module.params.get('purge_tags')
try:
- existing_tags = boto3_tag_list_to_ansible_dict(connection.list_role_tags(RoleName=role_name, aws_retry=True)['Tags'])
+ existing_tags = boto3_tag_list_to_ansible_dict(client.list_role_tags(RoleName=role_name, aws_retry=True)['Tags'])
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError, KeyError):
existing_tags = {}
@@ -593,9 +635,9 @@ def update_role_tags(connection, module, params, role):
if not module.check_mode:
try:
if tags_to_remove:
- connection.untag_role(RoleName=role_name, TagKeys=tags_to_remove, aws_retry=True)
+ client.untag_role(RoleName=role_name, TagKeys=tags_to_remove, aws_retry=True)
if tags_to_add:
- connection.tag_role(RoleName=role_name, Tags=ansible_dict_to_boto3_tag_list(tags_to_add), aws_retry=True)
+ client.tag_role(RoleName=role_name, Tags=ansible_dict_to_boto3_tag_list(tags_to_add), aws_retry=True)
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
module.fail_json_aws(e, msg='Unable to set tags for role %s' % role_name)
@@ -605,6 +647,9 @@ def update_role_tags(connection, module, params, role):
def main():
+ global module
+ global client
+
argument_spec = dict(
name=dict(type='str', required=True),
path=dict(type='str', default="/"),
@@ -619,13 +664,15 @@ def main():
purge_policies=dict(type='bool', aliases=['purge_policy', 'purge_managed_policies']),
tags=dict(type='dict'),
purge_tags=dict(type='bool', default=True),
+ wait=dict(type='bool', default=True),
+ wait_timeout=dict(default=120, type='int'),
)
module = AnsibleAWSModule(argument_spec=argument_spec,
required_if=[('state', 'present', ['assume_role_policy_document'])],
supports_check_mode=True)
if module.params.get('purge_policies') is None:
- module.deprecate('In Ansible 2.14 the default value of purge_policies will change from true to false.'
+ module.deprecate('After 2022-06-01 the default value of purge_policies will change from true to false.'
' To maintain the existing behaviour explicitly set purge_policies=true', date='2022-06-01', collection_name='community.aws')
if module.params.get('boundary'):
@@ -633,12 +680,6 @@ def main():
module.fail_json(msg="When using a boundary policy, `create_instance_profile` must be set to `false`.")
if not module.params.get('boundary').startswith('arn:aws:iam'):
module.fail_json(msg="Boundary policy must be an ARN")
- if module.params.get('tags') is not None and not module.botocore_at_least('1.12.46'):
- module.fail_json(msg="When managing tags botocore must be at least v1.12.46. "
- "Current versions: boto3-{boto3_version} botocore-{botocore_version}".format(**module._gather_versions()))
- if module.params.get('boundary') is not None and not module.botocore_at_least('1.10.57'):
- module.fail_json(msg="When using a boundary policy, botocore must be at least v1.10.57. "
- "Current versions: boto3-{boto3_version} botocore-{botocore_version}".format(**module._gather_versions()))
if module.params.get('max_session_duration'):
max_session_duration = module.params.get('max_session_duration')
if max_session_duration < 3600 or max_session_duration > 43200:
@@ -648,14 +689,14 @@ def main():
if not path.endswith('/') or not path.startswith('/'):
module.fail_json(msg="path must begin and end with /")
- connection = module.client('iam', retry_decorator=AWSRetry.jittered_backoff())
+ client = module.client('iam', retry_decorator=AWSRetry.jittered_backoff())
state = module.params.get("state")
if state == 'present':
- create_or_update_role(connection, module)
+ create_or_update_role()
else:
- destroy_role(connection, module)
+ destroy_role()
if __name__ == '__main__':
diff --git a/plugins/modules/iam_role_info.py b/plugins/modules/iam_role_info.py
index 0a627d10cc7..a08df455fad 100644
--- a/plugins/modules/iam_role_info.py
+++ b/plugins/modules/iam_role_info.py
@@ -159,25 +159,25 @@
from ansible_collections.amazon.aws.plugins.module_utils.ec2 import boto3_tag_list_to_ansible_dict
-@AWSRetry.exponential_backoff()
+@AWSRetry.jittered_backoff()
def list_iam_roles_with_backoff(client, **kwargs):
paginator = client.get_paginator('list_roles')
return paginator.paginate(**kwargs).build_full_result()
-@AWSRetry.exponential_backoff()
+@AWSRetry.jittered_backoff()
def list_iam_role_policies_with_backoff(client, role_name):
paginator = client.get_paginator('list_role_policies')
return paginator.paginate(RoleName=role_name).build_full_result()['PolicyNames']
-@AWSRetry.exponential_backoff()
+@AWSRetry.jittered_backoff()
def list_iam_attached_role_policies_with_backoff(client, role_name):
paginator = client.get_paginator('list_attached_role_policies')
return paginator.paginate(RoleName=role_name).build_full_result()['AttachedPolicies']
-@AWSRetry.exponential_backoff()
+@AWSRetry.jittered_backoff()
def list_iam_instance_profiles_for_role_with_backoff(client, role_name):
paginator = client.get_paginator('list_instance_profiles_for_role')
return paginator.paginate(RoleName=role_name).build_full_result()['InstanceProfiles']
@@ -210,7 +210,7 @@ def describe_iam_roles(module, client):
path_prefix = module.params['path_prefix']
if name:
try:
- roles = [client.get_role(RoleName=name)['Role']]
+ roles = [client.get_role(RoleName=name, aws_retry=True)['Role']]
except is_boto3_error_code('NoSuchEntity'):
return []
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: # pylint: disable=duplicate-except
@@ -245,7 +245,7 @@ def main():
if module._name == 'iam_role_facts':
module.deprecate("The 'iam_role_facts' module has been renamed to 'iam_role_info'", date='2021-12-01', collection_name='community.aws')
- client = module.client('iam')
+ client = module.client('iam', retry_decorator=AWSRetry.jittered_backoff())
module.exit_json(changed=False, iam_roles=describe_iam_roles(module, client))
diff --git a/plugins/modules/iam_saml_federation.py b/plugins/modules/iam_saml_federation.py
index a78decfe625..4b41f443134 100644
--- a/plugins/modules/iam_saml_federation.py
+++ b/plugins/modules/iam_saml_federation.py
@@ -123,23 +123,23 @@ def __init__(self, module):
self.module.fail_json_aws(e, msg="Unknown boto error")
# use retry decorator for boto3 calls
- @AWSRetry.backoff(tries=3, delay=5)
+ @AWSRetry.jittered_backoff(retries=3, delay=5)
def _list_saml_providers(self):
return self.conn.list_saml_providers()
- @AWSRetry.backoff(tries=3, delay=5)
+ @AWSRetry.jittered_backoff(retries=3, delay=5)
def _get_saml_provider(self, arn):
return self.conn.get_saml_provider(SAMLProviderArn=arn)
- @AWSRetry.backoff(tries=3, delay=5)
+ @AWSRetry.jittered_backoff(retries=3, delay=5)
def _update_saml_provider(self, arn, metadata):
return self.conn.update_saml_provider(SAMLProviderArn=arn, SAMLMetadataDocument=metadata)
- @AWSRetry.backoff(tries=3, delay=5)
+ @AWSRetry.jittered_backoff(retries=3, delay=5)
def _create_saml_provider(self, metadata, name):
return self.conn.create_saml_provider(SAMLMetadataDocument=metadata, Name=name)
- @AWSRetry.backoff(tries=3, delay=5)
+ @AWSRetry.jittered_backoff(retries=3, delay=5)
def _delete_saml_provider(self, arn):
return self.conn.delete_saml_provider(SAMLProviderArn=arn)
diff --git a/plugins/modules/iam_server_certificate.py b/plugins/modules/iam_server_certificate.py
new file mode 100644
index 00000000000..b6cad710fb3
--- /dev/null
+++ b/plugins/modules/iam_server_certificate.py
@@ -0,0 +1,449 @@
+#!/usr/bin/python
+# This file is part of Ansible
+#
+# Ansible is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Ansible is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Ansible. If not, see .
+
+from __future__ import absolute_import, division, print_function
+__metaclass__ = type
+
+
+DOCUMENTATION = '''
+---
+module: iam_server_certificate
+version_added: 1.0.0
+short_description: Manage server certificates for use on ELBs and CloudFront
+description:
+ - Allows for the management of server certificates.
+options:
+ name:
+ description:
+ - Name of certificate to add, update or remove.
+ required: true
+ type: str
+ new_name:
+ description:
+ - When I(state=present), this will update the name of the cert.
+ - The I(cert), I(key) and I(cert_chain) parameters will be ignored if this is defined.
+ type: str
+ new_path:
+ description:
+ - When I(state=present), this will update the path of the cert.
+ - The I(cert), I(key) and I(cert_chain) parameters will be ignored if this is defined.
+ type: str
+ state:
+ description:
+ - Whether to create (or update) or delete the certificate.
+ - If I(new_path) or I(new_name) is defined, specifying present will attempt to make an update these.
+ required: true
+ choices: [ "present", "absent" ]
+ type: str
+ path:
+ description:
+ - When creating or updating, specify the desired path of the certificate.
+ default: "/"
+ type: str
+ cert_chain:
+ description:
+ - The path to, or content of, the CA certificate chain in PEM encoded format.
+ - If the parameter is not a file, it is assumed to be content.
+ - Passing a file name is deprecated, and support will be dropped in
+ version 4.0.0 of this collection.
+ type: str
+ cert:
+ description:
+ - The path to, or content of the certificate body in PEM encoded format.
+ - If the parameter is not a file, it is assumed to be content.
+ - Passing a file name is deprecated, and support will be dropped in
+ version 4.0.0 of this collection.
+ type: str
+ key:
+ description:
+ - The path to, or content of the private key in PEM encoded format.
+ If the parameter is not a file, it is assumed to be content.
+ - Passing a file name is deprecated, and support will be dropped in
+ version 4.0.0 of this collection.
+ type: str
+ dup_ok:
+ description:
+ - By default the module will not upload a certificate that is already uploaded into AWS.
+ - If I(dup_ok=True), it will upload the certificate as long as the name is unique.
+ - Currently defaults to C(false), this will default to C(true) in release
+ 4.0.0.
+ type: bool
+
+author: Jonathan I. Davila (@defionscode)
+extends_documentation_fragment:
+- amazon.aws.aws
+- amazon.aws.ec2
+requirements:
+- boto >= 2.49.0
+'''
+
+EXAMPLES = '''
+- name: Basic server certificate upload from local file
+ community.aws.iam_server_certificate:
+ name: very_ssl
+ state: present
+ cert: "{{ lookup('file', 'path/to/cert') }}"
+ key: "{{ lookup('file', 'path/to/key') }}"
+ cert_chain: "{{ lookup('file', 'path/to/certchain') }}"
+
+- name: Basic server certificate upload
+ community.aws.iam_server_certificate:
+ name: very_ssl
+ state: present
+ cert: path/to/cert
+ key: path/to/key
+ cert_chain: path/to/certchain
+
+- name: Server certificate upload using key string
+ community.aws.iam_server_certificate:
+ name: very_ssl
+ state: present
+ path: "/a/cert/path/"
+ cert: body_of_somecert
+ key: vault_body_of_privcertkey
+ cert_chain: body_of_myverytrustedchain
+
+- name: Basic rename of existing certificate
+ community.aws.iam_server_certificate:
+ name: very_ssl
+ new_name: new_very_ssl
+ state: present
+
+'''
+import os
+
+try:
+ import botocore
+except ImportError:
+ pass # Handled by HAS_BOTO
+
+from ansible.module_utils.common.dict_transformations import camel_dict_to_snake_dict
+
+from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
+from ansible_collections.amazon.aws.plugins.module_utils.core import is_boto3_error_code
+from ansible_collections.amazon.aws.plugins.module_utils.ec2 import AWSRetry
+
+
+@AWSRetry.jittered_backoff()
+def _list_server_certficates():
+ paginator = client.get_paginator('list_server_certificates')
+ return paginator.paginate().build_full_result()['ServerCertificateMetadataList']
+
+
+def check_duplicate_cert(new_cert):
+ orig_cert_names = list(c['ServerCertificateName'] for c in _list_server_certficates())
+ for cert_name in orig_cert_names:
+ cert = get_server_certificate(cert_name)
+ if not cert:
+ continue
+ cert_body = cert.get('certificate_body', None)
+ if not _compare_cert(new_cert, cert_body):
+ continue
+ module.fail_json(
+ changed=False,
+ msg='This certificate already exists under the name {0} and dup_ok=False'.format(cert_name),
+ duplicate_cert=cert,
+ )
+
+
+def _compare_cert(cert_a, cert_b):
+ if not cert_a and not cert_b:
+ return True
+ if not cert_a or not cert_b:
+ return False
+ # Trim out the whitespace before comparing the certs. While this could mean
+ # an invalid cert 'matches' a valid cert, that's better than some stray
+ # whitespace breaking things
+ cert_a.replace('\r', '')
+ cert_a.replace('\n', '')
+ cert_a.replace(' ', '')
+ cert_b.replace('\r', '')
+ cert_b.replace('\n', '')
+ cert_b.replace(' ', '')
+
+ return cert_a == cert_b
+
+
+def update_server_certificate(current_cert):
+ changed = False
+
+ cert, key, cert_chain = load_data()
+
+ if not _compare_cert(cert, current_cert.get('certificate_body', None)):
+ module.fail_json(msg='Modifying the certificate body is not supported by AWS')
+ if not _compare_cert(cert_chain, current_cert.get('certificate_chain', None)):
+ module.fail_json(msg='Modifying the chaining certificate is not supported by AWS')
+ # We can't compare keys.
+
+ if module.check_mode:
+ return changed
+
+ # For now we can't make any changes. Updates to tagging would go here and
+ # update 'changed'
+
+ return changed
+
+
+def create_server_certificate():
+ cert, key, cert_chain = load_data()
+
+ if not module.params.get('dup_ok'):
+ check_duplicate_cert(cert)
+
+ path = module.params.get('path')
+ name = module.params.get('name')
+
+ params = dict(
+ ServerCertificateName=name,
+ CertificateBody=cert,
+ PrivateKey=key,
+ )
+
+ if cert_chain:
+ params['CertificateChain'] = cert_chain
+ if path:
+ params['Path'] = path
+
+ if module.check_mode:
+ return True
+
+ try:
+ client.upload_server_certificate(
+ aws_retry=True,
+ **params
+ )
+ except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
+ module.fail_json_aws(e, msg='Failed to update server certificate {0}'.format(name))
+
+ return True
+
+
+def rename_server_certificate(current_cert):
+ name = module.params.get('name')
+ new_name = module.params.get('new_name')
+ new_path = module.params.get('new_path')
+
+ changes = dict()
+
+ # Try to be nice, if we've already been renamed exit quietly.
+ if not current_cert:
+ current_cert = get_server_certificate(new_name)
+ else:
+ if new_name:
+ changes['NewServerCertificateName'] = new_name
+
+ cert_metadata = current_cert.get('server_certificate_metadata', {})
+
+ if not current_cert:
+ module.fail_json(msg='Unable to find certificate {0}'.format(name))
+
+ current_path = cert_metadata.get('path', None)
+ if new_path and current_path != new_path:
+ changes['NewPath'] = new_path
+
+ if not changes:
+ return False
+
+ if module.check_mode:
+ return True
+
+ try:
+ client.update_server_certificate(
+ aws_retry=True,
+ ServerCertificateName=name,
+ **changes
+ )
+ except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
+ module.fail_json_aws(e, msg='Failed to update server certificate {0}'.format(name),
+ changes=changes)
+
+ return True
+
+
+def delete_server_certificate(current_cert):
+ if not current_cert:
+ return False
+
+ if module.check_mode:
+ return True
+
+ name = module.params.get('name')
+
+ try:
+ result = client.delete_server_certificate(
+ aws_retry=True,
+ ServerCertificateName=name,
+ )
+ except is_boto3_error_code('NoSuchEntity'):
+ return None
+ except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: # pylint: disable=duplicate-except
+ module.fail_json_aws(e, msg='Failed to delete server certificate {0}'.format(name))
+
+ return True
+
+
+def get_server_certificate(name):
+ if not name:
+ return None
+ try:
+ result = client.get_server_certificate(
+ aws_retry=True,
+ ServerCertificateName=name,
+ )
+ except is_boto3_error_code('NoSuchEntity'):
+ return None
+ except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: # pylint: disable=duplicate-except
+ module.fail_json_aws(e, msg='Failed to get server certificate {0}'.format(name))
+ cert = dict(camel_dict_to_snake_dict(result.get('ServerCertificate')))
+ return cert
+
+
+def load_data():
+ cert = module.params.get('cert')
+ key = module.params.get('key')
+ cert_chain = module.params.get('cert_chain')
+
+ # if paths are provided rather than lookups read the files and return the contents
+ if cert and os.path.isfile(cert):
+ with open(cert, 'r') as cert_fh:
+ cert = cert_fh.read().rstrip()
+ module.deprecate(
+ 'Passing a file name as the cert argument has been deprecated. '
+ 'Please use a lookup instead, see the documentation for examples.',
+ version='4.0.0', collection_name='community.aws')
+ if key and os.path.isfile(key):
+ with open(key, 'r') as key_fh:
+ key = key_fh.read().rstrip()
+ module.deprecate(
+ 'Passing a file name as the key argument has been deprecated. '
+ 'Please use a lookup instead, see the documentation for examples.',
+ version='4.0.0', collection_name='community.aws')
+ if cert_chain and os.path.isfile(cert_chain):
+ with open(cert_chain, 'r') as cert_chain_fh:
+ cert_chain = cert_chain_fh.read()
+ module.deprecate(
+ 'Passing a file name as the cert_chain argument has been deprecated. '
+ 'Please use a lookup instead, see the documentation for examples.',
+ version='4.0.0', collection_name='community.aws')
+ return cert, key, cert_chain
+
+
+def compatability_results(current_cert):
+ compat_results = dict()
+
+ if not current_cert:
+ return compat_results
+
+ metadata = current_cert.get('server_certificate_metadata', {})
+
+ if current_cert.get('certificate_body', None):
+ compat_results['cert_body'] = current_cert.get('certificate_body')
+ if current_cert.get('certificate_chain', None):
+ compat_results['chain_cert_body'] = current_cert.get('certificate_chain')
+ if metadata.get('arn', None):
+ compat_results['arn'] = metadata.get('arn')
+ if metadata.get('expiration', None):
+ compat_results['expiration_date'] = metadata.get('expiration')
+ if metadata.get('path', None):
+ compat_results['cert_path'] = metadata.get('path')
+ if metadata.get('server_certificate_name', None):
+ compat_results['name'] = metadata.get('server_certificate_name')
+ if metadata.get('upload_date', None):
+ compat_results['upload_date'] = metadata.get('upload_date')
+
+ return compat_results
+
+
+def main():
+
+ global module
+ global client
+
+ argument_spec = dict(
+ state=dict(required=True, choices=['present', 'absent']),
+ name=dict(required=True),
+ cert=dict(),
+ key=dict(no_log=True),
+ cert_chain=dict(),
+ new_name=dict(),
+ path=dict(default='/'),
+ new_path=dict(),
+ dup_ok=dict(type='bool'),
+ )
+
+ module = AnsibleAWSModule(
+ argument_spec=argument_spec,
+ mutually_exclusive=[
+ ['new_path', 'key'],
+ ['new_path', 'cert'],
+ ['new_path', 'cert_chain'],
+ ['new_name', 'key'],
+ ['new_name', 'cert'],
+ ['new_name', 'cert_chain'],
+ ],
+ supports_check_mode=True,
+ )
+
+ client = module.client('iam', retry_decorator=AWSRetry.jittered_backoff())
+
+ state = module.params.get('state')
+ name = module.params.get('name')
+ path = module.params.get('path')
+ new_name = module.params.get('new_name')
+ new_path = module.params.get('new_path')
+ dup_ok = module.params.get('dup_ok')
+
+ if dup_ok is None:
+ module.deprecate(
+ 'The dup_ok module currently defaults to false, this will change in '
+ 'release 4.0.0 to true.', version='4.0.0', collection_name='community.aws')
+
+ current_cert = get_server_certificate(name)
+
+ results = dict()
+ if state == 'absent':
+ changed = delete_server_certificate(current_cert)
+ if changed:
+ results['deleted_cert'] = name
+ else:
+ msg = 'Certificate with the name {0} already absent'.format(name)
+ results['msg'] = msg
+ else:
+ if new_name or new_path:
+ changed = rename_server_certificate(current_cert)
+ if new_name:
+ name = new_name
+ updated_cert = get_server_certificate(name)
+ elif current_cert:
+ changed = update_server_certificate(current_cert)
+ updated_cert = get_server_certificate(name)
+ else:
+ changed = create_server_certificate()
+ updated_cert = get_server_certificate(name)
+
+ results['server_certificate'] = updated_cert
+ compat_results = compatability_results(updated_cert)
+ if compat_results:
+ results.update(compat_results)
+
+ module.exit_json(
+ changed=changed,
+ **results
+ )
+
+
+if __name__ == '__main__':
+ main()
diff --git a/plugins/modules/iam_server_certificate_info.py b/plugins/modules/iam_server_certificate_info.py
index 622e2ee8e86..a37c9e88c83 100644
--- a/plugins/modules/iam_server_certificate_info.py
+++ b/plugins/modules/iam_server_certificate_info.py
@@ -142,7 +142,11 @@ def main():
name=dict(type='str'),
)
- module = AnsibleAWSModule(argument_spec=argument_spec,)
+ module = AnsibleAWSModule(
+ argument_spec=argument_spec,
+ supports_check_mode=True,
+ )
+
if module._name == 'iam_server_certificate_facts':
module.deprecate("The 'iam_server_certificate_facts' module has been renamed to 'iam_server_certificate_info'",
date='2021-12-01', collection_name='community.aws')
diff --git a/plugins/modules/iam_user.py b/plugins/modules/iam_user.py
index b88953a6868..2a7998a6d10 100644
--- a/plugins/modules/iam_user.py
+++ b/plugins/modules/iam_user.py
@@ -41,6 +41,18 @@
default: false
type: bool
aliases: ['purge_policy', 'purge_managed_policies']
+ tags:
+ description:
+ - Tag dict to apply to the user.
+ required: false
+ type: dict
+ version_added: 2.1.0
+ purge_tags:
+ description:
+ - Remove tags not listed in I(tags) when tags is specified.
+ default: true
+ type: bool
+ version_added: 2.1.0
extends_documentation_fragment:
- amazon.aws.aws
- amazon.aws.ec2
@@ -71,6 +83,13 @@
state: present
purge_policies: true
+- name: Create user with tags
+ community.aws.iam_user:
+ name: testuser1
+ state: present
+ tags:
+ Env: Prod
+
- name: Delete the user
community.aws.iam_user:
name: testuser1
@@ -103,6 +122,11 @@
description: the path to the user
type: str
sample: /
+ tags:
+ description: user tags
+ type: dict
+ returned: always
+ sample: '{"Env": "Prod"}'
'''
try:
@@ -114,6 +138,9 @@
from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
from ansible_collections.amazon.aws.plugins.module_utils.core import is_boto3_error_code
+from ansible_collections.amazon.aws.plugins.module_utils.ec2 import ansible_dict_to_boto3_tag_list
+from ansible_collections.amazon.aws.plugins.module_utils.ec2 import boto3_tag_list_to_ansible_dict
+from ansible_collections.amazon.aws.plugins.module_utils.ec2 import compare_aws_tags
def compare_attached_policies(current_attached_policies, new_attached_policies):
@@ -137,7 +164,7 @@ def convert_friendly_names_to_arns(connection, module, policy_names):
# List comprehension that looks for any policy in the 'policy_names' list
# that does not begin with 'arn'. If there aren't any, short circuit.
# If there are, translate friendly name to the full arn
- if not any([not policy.startswith('arn:') for policy in policy_names if policy is not None]):
+ if not any(not policy.startswith('arn:') for policy in policy_names if policy is not None):
return policy_names
allpolicies = {}
paginator = connection.get_paginator('list_policies')
@@ -158,6 +185,8 @@ def create_or_update_user(connection, module):
params['UserName'] = module.params.get('name')
managed_policies = module.params.get('managed_policies')
purge_policies = module.params.get('purge_policies')
+ if module.params.get('tags') is not None:
+ params["Tags"] = ansible_dict_to_boto3_tag_list(module.params.get('tags'))
changed = False
if managed_policies:
managed_policies = convert_friendly_names_to_arns(connection, module, managed_policies)
@@ -176,6 +205,8 @@ def create_or_update_user(connection, module):
changed = True
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
module.fail_json_aws(e, msg="Unable to create user")
+ else:
+ changed = update_user_tags(connection, module, params, user)
# Manage managed policies
current_attached_policies = get_attached_policy_list(connection, module, params['UserName'])
@@ -208,13 +239,14 @@ def create_or_update_user(connection, module):
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
module.fail_json_aws(e, msg="Unable to attach policy {0} to user {1}".format(
policy_arn, params['UserName']))
+
if module.check_mode:
module.exit_json(changed=changed)
# Get the user again
user = get_user(connection, module, params['UserName'])
- module.exit_json(changed=changed, iam_user=camel_dict_to_snake_dict(user))
+ module.exit_json(changed=changed, iam_user=user)
def destroy_user(connection, module):
@@ -295,12 +327,17 @@ def get_user(connection, module, name):
params['UserName'] = name
try:
- return connection.get_user(**params)
+ user = connection.get_user(**params)
except is_boto3_error_code('NoSuchEntity'):
return None
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: # pylint: disable=duplicate-except
module.fail_json_aws(e, msg="Unable to get user {0}".format(name))
+ tags = boto3_tag_list_to_ansible_dict(user['User'].pop('Tags', []))
+ user = camel_dict_to_snake_dict(user)
+ user['user']['tags'] = tags
+ return user
+
def get_attached_policy_list(connection, module, name):
@@ -322,13 +359,40 @@ def delete_user_login_profile(connection, module, user_name):
module.fail_json_aws(e, msg="Unable to delete login profile for user {0}".format(user_name))
+def update_user_tags(connection, module, params, user):
+ user_name = params['UserName']
+ existing_tags = user['user']['tags']
+ new_tags = params.get('Tags')
+ if new_tags is None:
+ return False
+ new_tags = boto3_tag_list_to_ansible_dict(new_tags)
+
+ purge_tags = module.params.get('purge_tags')
+
+ tags_to_add, tags_to_remove = compare_aws_tags(existing_tags, new_tags, purge_tags=purge_tags)
+
+ if not module.check_mode:
+ try:
+ if tags_to_remove:
+ connection.untag_user(UserName=user_name, TagKeys=tags_to_remove)
+ if tags_to_add:
+ connection.tag_user(UserName=user_name, Tags=ansible_dict_to_boto3_tag_list(tags_to_add))
+ except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
+ module.fail_json_aws(e, msg='Unable to set tags for user %s' % user_name)
+
+ changed = bool(tags_to_add) or bool(tags_to_remove)
+ return changed
+
+
def main():
argument_spec = dict(
name=dict(required=True, type='str'),
managed_policies=dict(default=[], type='list', aliases=['managed_policy'], elements='str'),
state=dict(choices=['present', 'absent'], required=True),
- purge_policies=dict(default=False, type='bool', aliases=['purge_policy', 'purge_managed_policies'])
+ purge_policies=dict(default=False, type='bool', aliases=['purge_policy', 'purge_managed_policies']),
+ tags=dict(type='dict'),
+ purge_tags=dict(type='bool', default=True),
)
module = AnsibleAWSModule(
diff --git a/plugins/modules/iam_user_info.py b/plugins/modules/iam_user_info.py
index 5ada74c612b..10a6f2bffdc 100644
--- a/plugins/modules/iam_user_info.py
+++ b/plugins/modules/iam_user_info.py
@@ -96,6 +96,11 @@
returned: if user exists
type: str
sample: "test_user"
+ tags:
+ description: User tags.
+ type: dict
+ returned: if user exists
+ sample: '{"Env": "Prod"}'
'''
try:
@@ -107,6 +112,7 @@
from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
from ansible_collections.amazon.aws.plugins.module_utils.ec2 import AWSRetry
+from ansible_collections.amazon.aws.plugins.module_utils.ec2 import boto3_tag_list_to_ansible_dict
@AWSRetry.exponential_backoff()
@@ -115,6 +121,13 @@ def list_iam_users_with_backoff(client, operation, **kwargs):
return paginator.paginate(**kwargs).build_full_result()
+def describe_iam_user(user):
+ tags = boto3_tag_list_to_ansible_dict(user.pop('Tags', []))
+ user = camel_dict_to_snake_dict(user)
+ user['tags'] = tags
+ return user
+
+
def list_iam_users(connection, module):
name = module.params.get('name')
@@ -150,7 +163,7 @@ def list_iam_users(connection, module):
if name:
iam_users = [user for user in iam_users if user['UserName'] == name]
- module.exit_json(iam_users=[camel_dict_to_snake_dict(user) for user in iam_users])
+ module.exit_json(iam_users=[describe_iam_user(user) for user in iam_users])
def main():
diff --git a/plugins/modules/lambda.py b/plugins/modules/lambda.py
index 0a25214ca37..1605d6497db 100644
--- a/plugins/modules/lambda.py
+++ b/plugins/modules/lambda.py
@@ -105,7 +105,7 @@
type: str
tags:
description:
- - tag dict to apply to the function (requires botocore 1.5.40 or above).
+ - Tag dict to apply to the function.
type: dict
author:
- 'Steyn Huizinga (@steynovich)'
@@ -384,10 +384,6 @@ def main():
except (ClientError, BotoCoreError) as e:
module.fail_json_aws(e, msg="Trying to connect to AWS")
- if tags is not None:
- if not hasattr(client, "list_tags"):
- module.fail_json(msg="Using tags requires botocore 1.5.40 or above")
-
if state == 'present':
if re.match(r'^arn:aws(-([a-z\-]+))?:iam', role):
role_arn = role
diff --git a/plugins/modules/rds.py b/plugins/modules/rds.py
index 817f53ff779..bfbf0019f6b 100644
--- a/plugins/modules/rds.py
+++ b/plugins/modules/rds.py
@@ -10,13 +10,16 @@
---
module: rds
version_added: 1.0.0
+deprecated:
+ removed_in: 3.0.0
+ why: The rds module is based upon a deprecated version of the AWS SDK.
+ alternative: Use M(rds_instance), M(rds_instance_info), and M(rds_snapshot).
short_description: create, delete, or modify Amazon rds instances, rds snapshots, and related facts
description:
- Creates, deletes, or modifies rds resources.
- When creating an instance it can be either a new instance or a read-only replica of an existing instance.
- - This module has a dependency on python-boto >= 2.5 and will soon be deprecated.
- The 'promote' command requires boto >= 2.18.0. Certain features such as tags rely on boto.rds2 (boto >= 2.26.0).
- - Please use boto3 based M(community.aws.rds_instance) instead.
+ - Please use the boto3 based M(community.aws.rds_instance) instead.
options:
command:
description:
@@ -940,13 +943,13 @@ def await_resource(conn, resource, status, module):
if resource.name is None:
module.fail_json(msg="There was a problem waiting for RDS snapshot %s" % resource.snapshot)
# Back off if we're getting throttled, since we're just waiting anyway
- resource = AWSRetry.backoff(tries=5, delay=20, backoff=1.5)(conn.get_db_snapshot)(resource.name)
+ resource = AWSRetry.jittered_backoff(retries=5, delay=20, backoff=1.5)(conn.get_db_snapshot)(resource.name)
else:
# Temporary until all the rds2 commands have their responses parsed
if resource.name is None:
module.fail_json(msg="There was a problem waiting for RDS instance %s" % resource.instance)
# Back off if we're getting throttled, since we're just waiting anyway
- resource = AWSRetry.backoff(tries=5, delay=20, backoff=1.5)(conn.get_db_instance)(resource.name)
+ resource = AWSRetry.jittered_backoff(retries=5, delay=20, backoff=1.5)(conn.get_db_instance)(resource.name)
if resource is None:
break
# Some RDS resources take much longer than others to be ready. Check
@@ -1354,6 +1357,9 @@ def main():
check_boto3=False,
)
+ module.deprecate("The 'rds' module has been deprecated and replaced by the 'rds_instance' module'",
+ version='3.0.0', collection_name='community.aws')
+
if not HAS_BOTO:
module.fail_json(msg='boto required for this module')
diff --git a/plugins/modules/rds_instance.py b/plugins/modules/rds_instance.py
index ea6da26f0b6..92d5e257cf0 100644
--- a/plugins/modules/rds_instance.py
+++ b/plugins/modules/rds_instance.py
@@ -844,7 +844,7 @@ def get_parameters(client, module, parameters, method_name):
parameters['TargetDBInstanceIdentifier'] = module.params['db_instance_identifier']
required_options = get_boto3_client_method_parameters(client, method_name, required=True)
- if any([parameters.get(k) is None for k in required_options]):
+ if any(parameters.get(k) is None for k in required_options):
module.fail_json(msg='To {0} requires the parameters: {1}'.format(
get_rds_method_attribute(method_name, module).operation_description, required_options))
options = get_boto3_client_method_parameters(client, method_name)
@@ -989,13 +989,12 @@ def get_changing_options_with_inconsistent_keys(modify_params, instance, purge_c
def get_changing_options_with_consistent_keys(modify_params, instance):
- inconsistent_parameters = list(modify_params.keys())
changing_params = {}
for param in modify_params:
- current_option = instance.get('PendingModifiedValues', {}).get(param)
+ current_option = instance.get('PendingModifiedValues', {}).get(param, None)
if current_option is None:
- current_option = instance[param]
+ current_option = instance.get(param, None)
if modify_params[param] != current_option:
changing_params[param] = modify_params[param]
@@ -1198,9 +1197,6 @@ def main():
supports_check_mode=True
)
- if not module.boto3_at_least('1.5.0'):
- module.fail_json(msg="rds_instance requires boto3 > 1.5.0")
-
# Sanitize instance identifiers
module.params['db_instance_identifier'] = module.params['db_instance_identifier'].lower()
if module.params['new_db_instance_identifier']:
diff --git a/plugins/modules/rds_instance_info.py b/plugins/modules/rds_instance_info.py
index fba7804012a..13609972c17 100644
--- a/plugins/modules/rds_instance_info.py
+++ b/plugins/modules/rds_instance_info.py
@@ -234,6 +234,11 @@
returned: always
type: str
sample: '2017-10-10T04:00:07.434000+00:00'
+ iops:
+ description: The Provisioned IOPS value for the DB instance.
+ returned: always
+ type: int
+ sample: 1000
kms_key_id:
description: KMS Key ID
returned: always
diff --git a/plugins/modules/rds_subnet_group.py b/plugins/modules/rds_subnet_group.py
index bb0cc685a8a..7d789481c43 100644
--- a/plugins/modules/rds_subnet_group.py
+++ b/plugins/modules/rds_subnet_group.py
@@ -15,7 +15,7 @@
version_added: 1.0.0
short_description: manage RDS database subnet groups
description:
- - Creates, modifies, and deletes RDS database subnet groups. This module has a dependency on python-boto >= 2.5.
+ - Creates, modifies, and deletes RDS database subnet groups.
options:
state:
description:
@@ -142,7 +142,7 @@ def create_result(changed, subnet_group=None):
def create_subnet_list(subnets):
'''
- Construct a list of subnet ids from a list of subnets dicts returned by boto.
+ Construct a list of subnet ids from a list of subnets dicts returned by boto3.
Parameters:
subnets (list): A list of subnets definitions.
@see https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/rds.html#RDS.Client.describe_db_subnet_groups
diff --git a/plugins/modules/redshift_subnet_group.py b/plugins/modules/redshift_subnet_group.py
index fa210a5bee4..89e8bfa8042 100644
--- a/plugins/modules/redshift_subnet_group.py
+++ b/plugins/modules/redshift_subnet_group.py
@@ -9,8 +9,6 @@
DOCUMENTATION = r'''
---
-author:
- - "Jens Carl (@j-carl), Hothead Games Inc."
module: redshift_subnet_group
version_added: 1.0.0
short_description: manage Redshift cluster subnet groups
@@ -19,32 +17,33 @@
options:
state:
description:
- - Specifies whether the subnet should be present or absent.
- required: true
+ - Specifies whether the subnet group should be present or absent.
+ default: 'present'
choices: ['present', 'absent' ]
type: str
- group_name:
+ name:
description:
- Cluster subnet group name.
required: true
- aliases: ['name']
+ aliases: ['group_name']
type: str
- group_description:
+ description:
description:
- - Database subnet group description.
- aliases: ['description']
+ - Cluster subnet group description.
+ aliases: ['group_description']
type: str
- group_subnets:
+ subnets:
description:
- List of subnet IDs that make up the cluster subnet group.
- aliases: ['subnets']
+ - At least one subnet must be provided when creating a cluster subnet group.
+ aliases: ['group_subnets']
type: list
elements: str
extends_documentation_fragment:
- amazon.aws.aws
- amazon.aws.ec2
-requirements:
-- boto >= 2.49.0
+author:
+ - "Jens Carl (@j-carl), Hothead Games Inc."
'''
EXAMPLES = r'''
@@ -64,113 +63,209 @@
'''
RETURN = r'''
-group:
- description: dictionary containing all Redshift subnet group information
+cluster_subnet_group:
+ description: A dictionary containing information about the Redshift subnet group.
returned: success
- type: complex
+ type: dict
contains:
name:
- description: name of the Redshift subnet group
- returned: success
+ description: Name of the Redshift subnet group.
+ returned: when the cache subnet group exists
type: str
sample: "redshift_subnet_group_name"
vpc_id:
- description: Id of the VPC where the subnet is located
- returned: success
+ description: Id of the VPC where the subnet is located.
+ returned: when the cache subnet group exists
type: str
sample: "vpc-aabb1122"
+ description:
+ description: The description of the cache subnet group.
+ returned: when the cache subnet group exists
+ type: str
+ sample: Redshift subnet
+ subnet_ids:
+ description: The IDs of the subnets beloging to the Redshift subnet group.
+ returned: when the cache subnet group exists
+ type: list
+ elements: str
+ sample:
+ - subnet-aaaaaaaa
+ - subnet-bbbbbbbb
'''
try:
- import boto
- import boto.redshift
+ import botocore
except ImportError:
- pass # Handled by HAS_BOTO
+ pass # Handled by AnsibleAWSModule
+
+from ansible.module_utils.common.dict_transformations import camel_dict_to_snake_dict
from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import HAS_BOTO
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import connect_to_aws
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import get_aws_connection_info
+from ansible_collections.amazon.aws.plugins.module_utils.core import is_boto3_error_code
+from ansible_collections.amazon.aws.plugins.module_utils.ec2 import AWSRetry
+from ansible_collections.amazon.aws.plugins.module_utils.ec2 import boto3_tag_list_to_ansible_dict
+
+
+def get_subnet_group(name):
+ try:
+ groups = client.describe_cluster_subnet_groups(
+ aws_retry=True,
+ ClusterSubnetGroupName=name,
+ )['ClusterSubnetGroups']
+ except is_boto3_error_code('ClusterSubnetGroupNotFoundFault'):
+ return None
+ except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: # pylint: disable=duplicate-except
+ module.fail_json_aws(e, msg="Failed to describe subnet group")
+
+ if not groups:
+ return None
+
+ if len(groups) > 1:
+ module.fail_aws(
+ msg="Found multiple matches for subnet group",
+ cluster_subnet_groups=camel_dict_to_snake_dict(groups),
+ )
+
+ # No support for managing tags yet, but make sure that we don't need to
+ # change the return value structure after it's been available in a release.
+ tags = boto3_tag_list_to_ansible_dict(groups[0]['Tags'])
+
+ subnet_group = camel_dict_to_snake_dict(groups[0])
+
+ subnet_group['tags'] = tags
+ subnet_group['name'] = subnet_group['cluster_subnet_group_name']
+
+ subnet_ids = list(s['subnet_identifier'] for s in subnet_group['subnets'])
+ subnet_group['subnet_ids'] = subnet_ids
+
+ return subnet_group
+
+
+def create_subnet_group(name, description, subnets):
+
+ if not subnets:
+ module.fail_json(msg='At least one subnet must be provided when creating a subnet group')
+
+ if module.check_mode:
+ return True
+
+ try:
+ if not description:
+ description = name
+ client.create_cluster_subnet_group(
+ aws_retry=True,
+ ClusterSubnetGroupName=name,
+ Description=description,
+ SubnetIds=subnets,
+ )
+ return True
+ except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
+ module.fail_json_aws(e, msg="Failed to create subnet group")
+
+
+def update_subnet_group(subnet_group, name, description, subnets):
+ update_params = dict()
+ if description and subnet_group['description'] != description:
+ update_params['Description'] = description
+ if subnets:
+ old_subnets = set(subnet_group['subnet_ids'])
+ new_subnets = set(subnets)
+ if old_subnets != new_subnets:
+ update_params['SubnetIds'] = list(subnets)
+
+ if not update_params:
+ return False
+
+ if module.check_mode:
+ return True
+
+ # Description is optional, SubnetIds is not
+ if 'SubnetIds' not in update_params:
+ update_params['SubnetIds'] = subnet_group['subnet_ids']
+
+ try:
+ client.modify_cluster_subnet_group(
+ aws_retry=True,
+ ClusterSubnetGroupName=name,
+ **update_params,
+ )
+ except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
+ module.fail_json_aws(e, msg="Failed to update subnet group")
+
+ return True
+
+
+def delete_subnet_group(name):
+
+ if module.check_mode:
+ return True
+
+ try:
+ client.delete_cluster_subnet_group(
+ aws_retry=True,
+ ClusterSubnetGroupName=name,
+ )
+ return True
+ except is_boto3_error_code('ClusterSubnetGroupNotFoundFault'):
+ # AWS is "eventually consistent", cope with the race conditions where
+ # deletion hadn't completed when we ran describe
+ return False
+ except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: # pylint: disable=duplicate-except
+ module.fail_json_aws(e, msg="Failed to delete subnet group")
def main():
argument_spec = dict(
- state=dict(required=True, choices=['present', 'absent']),
- group_name=dict(required=True, aliases=['name']),
- group_description=dict(required=False, aliases=['description']),
- group_subnets=dict(required=False, aliases=['subnets'], type='list', elements='str'),
+ state=dict(default='present', choices=['present', 'absent']),
+ name=dict(required=True, aliases=['group_name']),
+ description=dict(required=False, aliases=['group_description']),
+ subnets=dict(required=False, aliases=['group_subnets'], type='list', elements='str'),
)
- module = AnsibleAWSModule(argument_spec=argument_spec, check_boto3=False)
- if not HAS_BOTO:
- module.fail_json(msg='boto v2.9.0+ required for this module')
+ global module
+ global client
+
+ module = AnsibleAWSModule(
+ argument_spec=argument_spec,
+ supports_check_mode=True,
+ )
state = module.params.get('state')
- group_name = module.params.get('group_name')
- group_description = module.params.get('group_description')
- group_subnets = module.params.get('group_subnets')
+ name = module.params.get('name')
+ description = module.params.get('description')
+ subnets = module.params.get('subnets')
- if state == 'present':
- for required in ('group_name', 'group_description', 'group_subnets'):
- if not module.params.get(required):
- module.fail_json(msg=str("parameter %s required for state='present'" % required))
- else:
- for not_allowed in ('group_description', 'group_subnets'):
- if module.params.get(not_allowed):
- module.fail_json(msg=str("parameter %s not allowed for state='absent'" % not_allowed))
+ client = module.client('redshift', retry_decorator=AWSRetry.jittered_backoff())
- region, ec2_url, aws_connect_params = get_aws_connection_info(module)
- if not region:
- module.fail_json(msg=str("Region must be specified as a parameter, in EC2_REGION or AWS_REGION environment variables or in boto configuration file"))
+ subnet_group = get_subnet_group(name)
+ changed = False
- # Connect to the Redshift endpoint.
- try:
- conn = connect_to_aws(boto.redshift, region, **aws_connect_params)
- except boto.exception.JSONResponseError as e:
- module.fail_json(msg=str(e))
+ if state == 'present':
+ if not subnet_group:
+ result = create_subnet_group(name, description, subnets)
+ changed |= result
+ else:
+ result = update_subnet_group(subnet_group, name, description, subnets)
+ changed |= result
+ subnet_group = get_subnet_group(name)
+ else:
+ if subnet_group:
+ result = delete_subnet_group(name)
+ changed |= result
+ subnet_group = None
- try:
- changed = False
- exists = False
- group = None
-
- try:
- matching_groups = conn.describe_cluster_subnet_groups(group_name, max_records=100)
- exists = len(matching_groups) > 0
- except boto.exception.JSONResponseError as e:
- if e.body['Error']['Code'] != 'ClusterSubnetGroupNotFoundFault':
- # if e.code != 'ClusterSubnetGroupNotFoundFault':
- module.fail_json(msg=str(e))
-
- if state == 'absent':
- if exists:
- conn.delete_cluster_subnet_group(group_name)
- changed = True
+ compat_results = dict()
+ if subnet_group:
+ compat_results['group'] = dict(
+ name=subnet_group['name'],
+ vpc_id=subnet_group['vpc_id'],
+ )
- else:
- if not exists:
- new_group = conn.create_cluster_subnet_group(group_name, group_description, group_subnets)
- group = {
- 'name': new_group['CreateClusterSubnetGroupResponse']['CreateClusterSubnetGroupResult']
- ['ClusterSubnetGroup']['ClusterSubnetGroupName'],
- 'vpc_id': new_group['CreateClusterSubnetGroupResponse']['CreateClusterSubnetGroupResult']
- ['ClusterSubnetGroup']['VpcId'],
- }
- else:
- changed_group = conn.modify_cluster_subnet_group(group_name, group_subnets, description=group_description)
- group = {
- 'name': changed_group['ModifyClusterSubnetGroupResponse']['ModifyClusterSubnetGroupResult']
- ['ClusterSubnetGroup']['ClusterSubnetGroupName'],
- 'vpc_id': changed_group['ModifyClusterSubnetGroupResponse']['ModifyClusterSubnetGroupResult']
- ['ClusterSubnetGroup']['VpcId'],
- }
-
- changed = True
-
- except boto.exception.JSONResponseError as e:
- module.fail_json(msg=str(e))
-
- module.exit_json(changed=changed, group=group)
+ module.exit_json(
+ changed=changed,
+ cluster_subnet_group=subnet_group,
+ **compat_results,
+ )
if __name__ == '__main__':
diff --git a/plugins/modules/route53.py b/plugins/modules/route53.py
index d1391cfac58..964020257db 100644
--- a/plugins/modules/route53.py
+++ b/plugins/modules/route53.py
@@ -19,8 +19,7 @@
options:
state:
description:
- - Specifies the state of the resource record. As of Ansible 2.4, the I(command) option has been changed
- to I(state) as default and the choices C(present) and C(absent) have been added, but I(command) still works as well.
+ - Specifies the state of the resource record.
required: true
aliases: [ 'command' ]
choices: [ 'present', 'absent', 'get', 'create', 'delete' ]
@@ -606,6 +605,7 @@ def main():
'TTL': ttl_in,
'ResourceRecords': [dict(Value=value) for value in value_in],
'HealthCheckId': health_check_in,
+ 'SetIdentifier': identifier_in,
})
if alias_in:
diff --git a/plugins/modules/route53_health_check.py b/plugins/modules/route53_health_check.py
index 7db80d875a5..382be93ab6d 100644
--- a/plugins/modules/route53_health_check.py
+++ b/plugins/modules/route53_health_check.py
@@ -10,7 +10,7 @@
---
module: route53_health_check
version_added: 1.0.0
-short_description: Add or delete health-checks in Amazons Route53 DNS service
+short_description: Manage health-checks in Amazons Route53 DNS service
description:
- Creates and deletes DNS Health checks in Amazons Route53 service.
- Only the port, resource_path, string_match and request_interval are
@@ -22,9 +22,18 @@
choices: [ 'present', 'absent' ]
type: str
default: 'present'
+ disabled:
+ description:
+ - Stops Route 53 from performing health checks.
+ - See the AWS documentation for more details on the exact implications.
+ U(https://docs.aws.amazon.com/Route53/latest/DeveloperGuide/health-checks-creating-values.html)
+ - Defaults to C(true) when creating a new health check.
+ type: bool
+ version_added: 2.1.0
ip_address:
description:
- IP address of the end-point to check. Either this or I(fqdn) has to be provided.
+ - IP addresses must be publicly routable.
type: str
port:
description:
@@ -44,7 +53,7 @@
health checks. The path can be any value for which your endpoint will
return an HTTP status code of 2xx or 3xx when the endpoint is healthy,
for example the file /docs/route53-health-check.html.
- - Required for all checks except TCP.
+ - Mutually exclusive with I(type='TCP').
- The path must begin with a /
- Maximum 255 characters.
type: str
@@ -74,15 +83,24 @@
- The number of consecutive health checks that an endpoint must pass or
fail for Amazon Route 53 to change the current status of the endpoint
from unhealthy to healthy or vice versa.
- default: 3
+ - Will default to C(3) if not specified on creation.
choices: [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ]
type: int
+ tags:
+ description:
+ - A hash/dictionary of tags to set on the health check.
+ type: dict
+ version_added: 2.1.0
+ purge_tags:
+ description:
+ - Delete any tags not specified in I(tags).
+ default: false
+ type: bool
+ version_added: 2.1.0
author: "zimbatm (@zimbatm)"
extends_documentation_fragment:
- amazon.aws.aws
- amazon.aws.ec2
-requirements:
-- boto >= 2.49.0
'''
EXAMPLES = '''
@@ -113,173 +131,299 @@
community.aws.route53_health_check:
state: absent
fqdn: host1.example.com
+'''
+RETURN = r'''
+health_check:
+ description: Information about the health check.
+ returned: success
+ type: dict
+ contains:
+ action:
+ description: The action performed by the module.
+ type: str
+ returned: When a change is or would be made.
+ sample: 'updated'
+ id:
+ description: The Unique ID assigned by AWS to the health check.
+ type: str
+ returned: When the health check exists.
+ sample: 50ec8a13-9623-4c66-9834-dd8c5aedc9ba
+ health_check_version:
+ description: The version number of the health check.
+ type: int
+ returned: When the health check exists.
+ sample: 14
+ health_check_config:
+ description:
+ - Detailed information about the health check.
+ - May contain additional values from Route 53 health check
+ features not yet supported by this module.
+ type: dict
+ returned: When the health check exists.
+ contains:
+ type:
+ description: The type of the health check.
+ type: str
+ returned: When the health check exists.
+ sample: 'HTTPS_STR_MATCH'
+ failure_threshold:
+ description:
+ - The number of consecutive health checks that an endpoint must pass or fail for Amazon Route 53 to
+ change the current status of the endpoint from unhealthy to healthy or vice versa.
+ type: int
+ returned: When the health check exists.
+ sample: 3
+ fully_qualified_domain_name:
+ description: The FQDN configured for the health check to test.
+ type: str
+ returned: When the health check exists and an FQDN is configured.
+ sample: 'updated'
+ ip_address:
+ description: The IPv4 or IPv6 IP address of the endpoint to be queried.
+ type: str
+ returned: When the health check exists and a specific IP address is configured.
+ sample: ''
+ port:
+ description: The port on the endpoint that the health check will query.
+ type: str
+ returned: When the health check exists.
+ sample: 'updated'
+ request_interval:
+ description: The number of seconds between health check queries.
+ type: int
+ returned: When the health check exists.
+ sample: 30
+ resource_path:
+ description: The URI path to query when performing an HTTP/HTTPS based health check.
+ type: str
+ returned: When the health check exists and a resource path has been configured.
+ sample: '/healthz'
+ search_string:
+ description: A string that must be present in the response for a health check to be considered successful.
+ type: str
+ returned: When the health check exists and a search string has been configured.
+ sample: 'ALIVE'
+ disabled:
+ description: Whether the health check has been disabled or not.
+ type: bool
+ returned: When the health check exists.
+ sample: false
+ tags:
+ description: A dictionary representing the tags on the health check.
+ type: dict
+ returned: When the health check exists.
+ sample: '{"my_key": "my_value"}'
'''
import uuid
try:
- import boto.ec2
- from boto.route53 import Route53Connection, exception
- from boto.route53.healthcheck import HealthCheck
+ import botocore
except ImportError:
pass # Handled by HAS_BOTO
+from ansible.module_utils.common.dict_transformations import camel_dict_to_snake_dict
+
from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import HAS_BOTO
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import get_aws_connection_info
+from ansible_collections.amazon.aws.plugins.module_utils.core import is_boto3_error_code
+from ansible_collections.amazon.aws.plugins.module_utils.ec2 import AWSRetry
+from ansible_collections.community.aws.plugins.module_utils.route53 import get_tags
+from ansible_collections.community.aws.plugins.module_utils.route53 import manage_tags
+
+
+def _list_health_checks(**params):
+ try:
+ results = client.list_health_checks(aws_retry=True, **params)
+ except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
+ module.fail_json_aws(e, msg='Failed to list health checks')
+ return results
-# Things that can't get changed:
-# protocol
-# ip_address or domain
-# request_interval
-# string_match if not previously enabled
-def find_health_check(conn, wanted):
+def find_health_check(ip_addr, fqdn, hc_type, request_interval, port):
"""Searches for health checks that have the exact same set of immutable values"""
- results = conn.get_list_health_checks()
+ # In lieu of an Id we perform matches against the following values:
+ # - ip_addr
+ # - fqdn
+ # - type (immutable)
+ # - request_interval
+ # - port
+
+ # Because the list and route53 provides no 'filter' mechanism,
+ # the using a paginator would result in (on average) double the
+ # number of API calls and can get really slow.
+ # Additionally, we can't properly wrap the paginator, so retrying means
+ # starting from scratch with a paginator
+ results = _list_health_checks()
while True:
- for check in results.HealthChecks:
- config = check.HealthCheckConfig
+ for check in results.get('HealthChecks'):
+ config = check.get('HealthCheckConfig')
if (
- config.get('IPAddress') == wanted.ip_addr and
- config.get('FullyQualifiedDomainName') == wanted.fqdn and
- config.get('Type') == wanted.hc_type and
- config.get('RequestInterval') == str(wanted.request_interval) and
- config.get('Port') == str(wanted.port)
+ config.get('IPAddress', None) == ip_addr and
+ config.get('FullyQualifiedDomainName', None) == fqdn and
+ config.get('Type') == hc_type and
+ config.get('RequestInterval') == request_interval and
+ config.get('Port', None) == port
):
return check
- if (results.IsTruncated == 'true'):
- results = conn.get_list_health_checks(marker=results.NextMarker)
+ if results.get('IsTruncated', False):
+ results = _list_health_checks(Marker=results.get('NextMarker'))
else:
return None
-def to_health_check(config):
- return HealthCheck(
- config.get('IPAddress'),
- int(config.get('Port')),
- config.get('Type'),
- config.get('ResourcePath'),
- fqdn=config.get('FullyQualifiedDomainName'),
- string_match=config.get('SearchString'),
- request_interval=int(config.get('RequestInterval')),
- failure_threshold=int(config.get('FailureThreshold')),
- )
+def delete_health_check(check_id):
+ if not check_id:
+ return False, None
+ if module.check_mode:
+ return True, 'delete'
-def health_check_diff(a, b):
- a = a.__dict__
- b = b.__dict__
- if a == b:
- return {}
- diff = {}
- for key in set(a.keys()) | set(b.keys()):
- if a.get(key) != b.get(key):
- diff[key] = b.get(key)
- return diff
-
-
-def to_template_params(health_check):
- params = {
- 'ip_addr_part': '',
- 'port': health_check.port,
- 'type': health_check.hc_type,
- 'resource_path_part': '',
- 'fqdn_part': '',
- 'string_match_part': '',
- 'request_interval': health_check.request_interval,
- 'failure_threshold': health_check.failure_threshold,
- }
- if health_check.ip_addr:
- params['ip_addr_part'] = HealthCheck.XMLIpAddrPart % {'ip_addr': health_check.ip_addr}
- if health_check.resource_path:
- params['resource_path_part'] = XMLResourcePathPart % {'resource_path': health_check.resource_path}
- if health_check.fqdn:
- params['fqdn_part'] = HealthCheck.XMLFQDNPart % {'fqdn': health_check.fqdn}
- if health_check.string_match:
- params['string_match_part'] = HealthCheck.XMLStringMatchPart % {'string_match': health_check.string_match}
- return params
-
-
-XMLResourcePathPart = """%(resource_path)s"""
-
-POSTXMLBody = """
-
- %(caller_ref)s
-
- %(ip_addr_part)s
- %(port)s
- %(type)s
- %(resource_path_part)s
- %(fqdn_part)s
- %(string_match_part)s
- %(request_interval)s
- %(failure_threshold)s
-
-
- """
-
-UPDATEHCXMLBody = """
-
- %(health_check_version)s
- %(ip_addr_part)s
- %(port)s
- %(resource_path_part)s
- %(fqdn_part)s
- %(string_match_part)s
- %(failure_threshold)i
-
- """
-
-
-def create_health_check(conn, health_check, caller_ref=None):
- if caller_ref is None:
- caller_ref = str(uuid.uuid4())
- uri = '/%s/healthcheck' % conn.Version
- params = to_template_params(health_check)
- params.update(xmlns=conn.XMLNameSpace, caller_ref=caller_ref)
-
- xml_body = POSTXMLBody % params
- response = conn.make_request('POST', uri, {'Content-Type': 'text/xml'}, xml_body)
- body = response.read()
- boto.log.debug(body)
- if response.status == 201:
- e = boto.jsonresponse.Element()
- h = boto.jsonresponse.XmlHandler(e, None)
- h.parse(body)
- return e
- else:
- raise exception.DNSServerError(response.status, response.reason, body)
-
-
-def update_health_check(conn, health_check_id, health_check_version, health_check):
- uri = '/%s/healthcheck/%s' % (conn.Version, health_check_id)
- params = to_template_params(health_check)
- params.update(
- xmlns=conn.XMLNameSpace,
- health_check_version=health_check_version,
+ try:
+ client.delete_health_check(
+ aws_retry=True,
+ HealthCheckId=check_id,
+ )
+ except is_boto3_error_code('NoSuchHealthCheck'):
+ # Handle the deletion race condition as cleanly as possible
+ return False, None
+ except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: # pylint: disable=duplicate-except
+ module.fail_json_aws(e, msg='Failed to list health checks')
+
+ return True, 'delete'
+
+
+def create_health_check(ip_addr_in, fqdn_in, type_in, request_interval_in, port_in):
+
+ # In general, if a request is repeated with the same CallerRef it won't
+ # result in a duplicate check appearing. This means we can safely use our
+ # retry decorators
+ caller_ref = str(uuid.uuid4())
+ missing_args = []
+
+ health_check = dict(
+ Type=type_in,
+ RequestInterval=request_interval_in,
+ Port=port_in,
)
- xml_body = UPDATEHCXMLBody % params
- response = conn.make_request('POST', uri, {'Content-Type': 'text/xml'}, xml_body)
- body = response.read()
- boto.log.debug(body)
- if response.status not in (200, 204):
- raise exception.DNSServerError(response.status,
- response.reason,
- body)
- e = boto.jsonresponse.Element()
- h = boto.jsonresponse.XmlHandler(e, None)
- h.parse(body)
- return e
+ if module.params.get('disabled') is not None:
+ health_check['Disabled'] = module.params.get('disabled')
+ if ip_addr_in:
+ health_check['IPAddress'] = ip_addr_in
+ if fqdn_in:
+ health_check['FullyQualifiedDomainName'] = fqdn_in
+
+ if type_in in ['HTTP', 'HTTPS', 'HTTP_STR_MATCH', 'HTTPS_STR_MATCH']:
+ resource_path = module.params.get('resource_path')
+ # if not resource_path:
+ # missing_args.append('resource_path')
+ if resource_path:
+ health_check['ResourcePath'] = resource_path
+ if type_in in ['HTTP_STR_MATCH', 'HTTPS_STR_MATCH']:
+ string_match = module.params.get('string_match')
+ if not string_match:
+ missing_args.append('string_match')
+ health_check['SearchString'] = module.params.get('string_match')
+
+ failure_threshold = module.params.get('failure_threshold')
+ if not failure_threshold:
+ failure_threshold = 3
+ health_check['FailureThreshold'] = failure_threshold
+
+ if missing_args:
+ module.fail_json(msg='missing required arguments for creation: {0}'.format(
+ ', '.join(missing_args)),
+ )
+
+ if module.check_mode:
+ return True, 'create', None
+
+ try:
+ result = client.create_health_check(
+ aws_retry=True,
+ CallerReference=caller_ref,
+ HealthCheckConfig=health_check,
+ )
+ except (botocore.exceptions.BotoCoreError, botocore.exceptions.ClientError) as e:
+ module.fail_json_aws(e, msg='Failed to create health check.', health_check=health_check)
+
+ check_id = result.get('HealthCheck').get('Id')
+ return True, 'create', check_id
+
+
+def update_health_check(existing_check):
+ # In theory it's also possible to update the IPAddress, Port and
+ # FullyQualifiedDomainName, however, because we use these in lieu of a
+ # 'Name' to uniquely identify the health check this isn't currently
+ # supported. If we accepted an ID it would be possible to modify them.
+
+ changes = dict()
+ existing_config = existing_check.get('HealthCheckConfig')
+
+ resource_path = module.params.get('resource_path', None)
+ if resource_path and resource_path != existing_config.get('ResourcePath'):
+ changes['ResourcePath'] = resource_path
+
+ search_string = module.params.get('string_match', None)
+ if search_string and search_string != existing_config.get('SearchString'):
+ changes['SearchString'] = search_string
+
+ failure_threshold = module.params.get('failure_threshold', None)
+ if failure_threshold and failure_threshold != existing_config.get('FailureThreshold'):
+ changes['FailureThreshold'] = failure_threshold
+
+ disabled = module.params.get('disabled', None)
+ if disabled is not None and disabled != existing_config.get('Disabled'):
+ changes['Disabled'] = module.params.get('disabled')
+
+ # No changes...
+ if not changes:
+ return False, None
+
+ if module.check_mode:
+ return True, 'update'
+
+ check_id = existing_check.get('Id')
+ # This makes sure we're starting from the version we think we are...
+ version_id = existing_check.get('HealthCheckVersion', 1)
+ try:
+ client.update_health_check(
+ HealthCheckId=check_id,
+ HealthCheckVersion=version_id,
+ **changes,
+ )
+ except (botocore.exceptions.BotoCoreError, botocore.exceptions.ClientError) as e:
+ module.fail_json_aws(e, msg='Failed to update health check.', id=check_id)
+
+ return True, 'update'
+
+
+def describe_health_check(id):
+ if not id:
+ return dict()
+
+ try:
+ result = client.get_health_check(
+ aws_retry=True,
+ HealthCheckId=id,
+ )
+ except (botocore.exceptions.BotoCoreError, botocore.exceptions.ClientError) as e:
+ module.fail_json_aws(e, msg='Failed to get health check.', id=id)
+
+ health_check = result.get('HealthCheck', {})
+ health_check = camel_dict_to_snake_dict(health_check)
+ tags = get_tags(module, client, 'healthcheck', id)
+ health_check['tags'] = tags
+ return health_check
def main():
argument_spec = dict(
state=dict(choices=['present', 'absent'], default='present'),
+ disabled=dict(type='bool'),
ip_address=dict(),
port=dict(type='int'),
type=dict(required=True, choices=['HTTP', 'HTTPS', 'HTTP_STR_MATCH', 'HTTPS_STR_MATCH', 'TCP']),
@@ -287,12 +431,28 @@ def main():
fqdn=dict(),
string_match=dict(),
request_interval=dict(type='int', choices=[10, 30], default=30),
- failure_threshold=dict(type='int', choices=[1, 2, 3, 4, 5, 6, 7, 8, 9, 10], default=3),
+ failure_threshold=dict(type='int', choices=[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]),
+ tags=dict(type='dict'),
+ purge_tags=dict(type='bool', default=False),
)
- module = AnsibleAWSModule(argument_spec=argument_spec, check_boto3=False)
- if not HAS_BOTO:
- module.fail_json(msg='boto 2.27.0+ required for this module')
+ args_one_of = [
+ ['ip_address', 'fqdn'],
+ ]
+
+ args_if = [
+ ['type', 'TCP', ('port',)],
+ ]
+
+ global module
+ global client
+
+ module = AnsibleAWSModule(
+ argument_spec=argument_spec,
+ required_one_of=args_one_of,
+ required_if=args_if,
+ supports_check_mode=True,
+ )
state_in = module.params.get('state')
ip_addr_in = module.params.get('ip_address')
@@ -304,63 +464,48 @@ def main():
request_interval_in = module.params.get('request_interval')
failure_threshold_in = module.params.get('failure_threshold')
- if ip_addr_in is None and fqdn_in is None:
- module.fail_json(msg="parameter 'ip_address' or 'fqdn' is required")
-
# Default port
if port_in is None:
if type_in in ['HTTP', 'HTTP_STR_MATCH']:
port_in = 80
elif type_in in ['HTTPS', 'HTTPS_STR_MATCH']:
port_in = 443
- else:
- module.fail_json(msg="parameter 'port' is required for 'type' TCP")
- # string_match in relation with type
- if type_in in ['HTTP_STR_MATCH', 'HTTPS_STR_MATCH']:
- if string_match_in is None:
- module.fail_json(msg="parameter 'string_match' is required for the HTTP(S)_STR_MATCH types")
- elif len(string_match_in) > 255:
+ if string_match_in:
+ if type_in not in ['HTTP_STR_MATCH', 'HTTPS_STR_MATCH']:
+ module.fail_json(msg="parameter 'string_match' argument is only for the HTTP(S)_STR_MATCH types")
+ if len(string_match_in) > 255:
module.fail_json(msg="parameter 'string_match' is limited to 255 characters max")
- elif string_match_in:
- module.fail_json(msg="parameter 'string_match' argument is only for the HTTP(S)_STR_MATCH types")
- region, ec2_url, aws_connect_kwargs = get_aws_connection_info(module)
- # connect to the route53 endpoint
- try:
- conn = Route53Connection(**aws_connect_kwargs)
- except boto.exception.BotoServerError as e:
- module.fail_json(msg=e.error_message)
+ client = module.client('route53', retry_decorator=AWSRetry.jittered_backoff())
changed = False
action = None
check_id = None
- wanted_config = HealthCheck(ip_addr_in, port_in, type_in, resource_path_in, fqdn_in, string_match_in, request_interval_in, failure_threshold_in)
- existing_check = find_health_check(conn, wanted_config)
+
+ existing_check = find_health_check(ip_addr_in, fqdn_in, type_in, request_interval_in, port_in)
+
if existing_check:
- check_id = existing_check.Id
- existing_config = to_health_check(existing_check.HealthCheckConfig)
+ check_id = existing_check.get('Id')
- if state_in == 'present':
+ if state_in == 'absent':
+ changed, action = delete_health_check(check_id)
+ check_id = None
+ elif state_in == 'present':
if existing_check is None:
- action = "create"
- check_id = create_health_check(conn, wanted_config).HealthCheck.Id
- changed = True
+ changed, action, check_id = create_health_check(ip_addr_in, fqdn_in, type_in, request_interval_in, port_in)
else:
- diff = health_check_diff(existing_config, wanted_config)
- if diff:
- action = "update"
- update_health_check(conn, existing_check.Id, int(existing_check.HealthCheckVersion), wanted_config)
- changed = True
- elif state_in == 'absent':
+ changed, action = update_health_check(existing_check)
if check_id:
- action = "delete"
- conn.delete_health_check(check_id)
- changed = True
- else:
- module.fail_json(msg="Logic Error: Unknown state")
-
- module.exit_json(changed=changed, health_check=dict(id=check_id), action=action)
+ changed |= manage_tags(module, client, 'healthcheck', check_id,
+ module.params.get('tags'), module.params.get('purge_tags'))
+
+ health_check = describe_health_check(id=check_id)
+ health_check['action'] = action
+ module.exit_json(
+ changed=changed,
+ health_check=health_check,
+ )
if __name__ == '__main__':
diff --git a/plugins/modules/route53_zone.py b/plugins/modules/route53_zone.py
index cdc5538c027..334e6d62718 100644
--- a/plugins/modules/route53_zone.py
+++ b/plugins/modules/route53_zone.py
@@ -5,7 +5,6 @@
from __future__ import absolute_import, division, print_function
__metaclass__ = type
-
DOCUMENTATION = '''
module: route53_zone
short_description: add or delete Route53 zones
@@ -47,6 +46,18 @@
- The reusable delegation set ID to be associated with the zone.
- Note that you can't associate a reusable delegation set with a private hosted zone.
type: str
+ tags:
+ description:
+ - A hash/dictionary of tags to add to the new instance or to add/remove from an existing one.
+ type: dict
+ version_added: 2.1.0
+ purge_tags:
+ description:
+ - Delete any tags not specified in the task that are on the zone.
+ This means you have to specify all the desired tags on each task affecting a zone.
+ default: false
+ type: bool
+ version_added: 2.1.0
extends_documentation_fragment:
- amazon.aws.aws
- amazon.aws.ec2
@@ -77,6 +88,21 @@
zone: example.com
comment: reusable delegation set example
delegation_set_id: A1BCDEF2GHIJKL
+
+- name: create a public zone with tags
+ community.aws.route53_zone:
+ zone: example.com
+ comment: this is an example
+ tags:
+ Owner: Ansible Team
+
+- name: modify a public zone, removing all previous tags and adding a new one
+ community.aws.route53_zone:
+ zone: example.com
+ comment: this is an example
+ tags:
+ Support: Ansible Community
+ purge_tags: true
'''
RETURN = '''
@@ -115,10 +141,16 @@
returned: for public hosted zones, if they have been associated with a reusable delegation set
type: str
sample: "A1BCDEF2GHIJKL"
+tags:
+ description: tags associated with the zone
+ returned: when tags are defined
+ type: dict
'''
import time
from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
+from ansible_collections.community.aws.plugins.module_utils.route53 import manage_tags
+from ansible_collections.community.aws.plugins.module_utils.route53 import get_tags
try:
from botocore.exceptions import BotoCoreError, ClientError
@@ -150,6 +182,8 @@ def create(module, client, matching_zones):
vpc_region = module.params.get('vpc_region')
comment = module.params.get('comment')
delegation_set_id = module.params.get('delegation_set_id')
+ tags = module.params.get('tags')
+ purge_tags = module.params.get('purge_tags')
if not zone_in.endswith('.'):
zone_in += "."
@@ -171,6 +205,14 @@ def create(module, client, matching_zones):
else:
changed, result = create_or_update_public(module, client, matching_zones, record)
+ zone_id = result.get('zone_id')
+ if zone_id:
+ if tags is not None:
+ changed |= manage_tags(module, client, 'hostedzone', zone_id, tags, purge_tags)
+ result['tags'] = get_tags(module, client, 'hostedzone', zone_id)
+ else:
+ result['tags'] = tags
+
return changed, result
@@ -394,6 +436,8 @@ def main():
comment=dict(default=''),
hosted_zone_id=dict(),
delegation_set_id=dict(),
+ tags=dict(type='dict'),
+ purge_tags=dict(type='bool', default=False),
)
mutually_exclusive = [
diff --git a/plugins/modules/s3_sync.py b/plugins/modules/s3_sync.py
index 1e7d01680f1..c9021c3dbf9 100644
--- a/plugins/modules/s3_sync.py
+++ b/plugins/modules/s3_sync.py
@@ -148,6 +148,11 @@
file_root: roles/s3/files/
storage_class: GLACIER
+- name: basic individual file upload
+ community.aws.s3_sync:
+ bucket: tedder
+ file_root: roles/s3/files/file_name
+
- name: all the options
community.aws.s3_sync:
bucket: tedder
@@ -322,41 +327,57 @@ def calculate_multipart_etag(source_path, chunk_size=DEFAULT_CHUNK_SIZE):
def gather_files(fileroot, include=None, exclude=None):
ret = []
- for (dirpath, dirnames, filenames) in os.walk(fileroot):
- for fn in filenames:
- fullpath = os.path.join(dirpath, fn)
- # include/exclude
- if include:
- found = False
- for x in include.split(','):
- if fnmatch.fnmatch(fn, x):
- found = True
- if not found:
- # not on the include list, so we don't want it.
- continue
-
- if exclude:
- found = False
- for x in exclude.split(','):
- if fnmatch.fnmatch(fn, x):
- found = True
- if found:
- # skip it, even if previously included.
- continue
-
- chopped_path = os.path.relpath(fullpath, start=fileroot)
- fstat = os.stat(fullpath)
- f_size = fstat[osstat.ST_SIZE]
- f_modified_epoch = fstat[osstat.ST_MTIME]
- ret.append({
- 'fullpath': fullpath,
- 'chopped_path': chopped_path,
- 'modified_epoch': f_modified_epoch,
- 'bytes': f_size,
- })
- # dirpath = path *to* the directory
- # dirnames = subdirs *in* our directory
- # filenames
+
+ if os.path.isfile(fileroot):
+ fullpath = fileroot
+ fstat = os.stat(fullpath)
+ path_array = fileroot.split('/')
+ chopped_path = path_array[-1]
+ f_size = fstat[osstat.ST_SIZE]
+ f_modified_epoch = fstat[osstat.ST_MTIME]
+ ret.append({
+ 'fullpath': fullpath,
+ 'chopped_path': chopped_path,
+ 'modified_epoch': f_modified_epoch,
+ 'bytes': f_size,
+ })
+
+ else:
+ for (dirpath, dirnames, filenames) in os.walk(fileroot):
+ for fn in filenames:
+ fullpath = os.path.join(dirpath, fn)
+ # include/exclude
+ if include:
+ found = False
+ for x in include.split(','):
+ if fnmatch.fnmatch(fn, x):
+ found = True
+ if not found:
+ # not on the include list, so we don't want it.
+ continue
+
+ if exclude:
+ found = False
+ for x in exclude.split(','):
+ if fnmatch.fnmatch(fn, x):
+ found = True
+ if found:
+ # skip it, even if previously included.
+ continue
+
+ chopped_path = os.path.relpath(fullpath, start=fileroot)
+ fstat = os.stat(fullpath)
+ f_size = fstat[osstat.ST_SIZE]
+ f_modified_epoch = fstat[osstat.ST_MTIME]
+ ret.append({
+ 'fullpath': fullpath,
+ 'chopped_path': chopped_path,
+ 'modified_epoch': f_modified_epoch,
+ 'bytes': f_size,
+ })
+ # dirpath = path *to* the directory
+ # dirnames = subdirs *in* our directory
+ # filenames
return ret
diff --git a/plugins/modules/sns_topic.py b/plugins/modules/sns_topic.py
index dd5af417bab..37cf573ce58 100644
--- a/plugins/modules/sns_topic.py
+++ b/plugins/modules/sns_topic.py
@@ -49,6 +49,73 @@
description:
- Delivery policy to apply to the SNS topic.
type: dict
+ suboptions:
+ http:
+ description:
+ - Delivery policy for HTTP(S) messages.
+ - See U(https://docs.aws.amazon.com/sns/latest/dg/sns-message-delivery-retries.html)
+ for more information.
+ type: dict
+ required: false
+ suboptions:
+ disableSubscriptionOverrides:
+ description:
+ - Applies this policy to all subscriptions, even if they have their own policies.
+ type: bool
+ required: false
+ defaultThrottlePolicy:
+ description:
+ - Throttle the rate of messages sent to subsriptions.
+ type: dict
+ suboptions:
+ maxReceivesPerSecond:
+ description:
+ - The maximum number of deliveries per second per subscription.
+ type: int
+ required: true
+ required: false
+ defaultHealthyRetryPolicy:
+ description:
+ - Retry policy for HTTP(S) messages.
+ type: dict
+ required: true
+ suboptions:
+ minDelayTarget:
+ description:
+ - The minimum delay for a retry.
+ type: int
+ required: true
+ maxDelayTarget:
+ description:
+ - The maximum delay for a retry.
+ type: int
+ required: true
+ numRetries:
+ description:
+ - The total number of retries.
+ type: int
+ required: true
+ numMaxDelayRetries:
+ description:
+ - The number of retries with the maximum delay between them.
+ type: int
+ required: true
+ numMinDelayRetries:
+ description:
+ - The number of retries with just the minimum delay between them.
+ type: int
+ required: true
+ numNoDelayRetries:
+ description:
+ - The number of retries to be performmed immediately.
+ type: int
+ required: true
+ backoffFunction:
+ description:
+ - The function for backoff between retries.
+ type: str
+ required: true
+ choices: ['arithmetic', 'exponential', 'geometric', 'linear']
subscriptions:
description:
- List of subscriptions to apply to the topic. Note that AWS requires
@@ -225,8 +292,12 @@
except ImportError:
pass # handled by AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule, is_boto3_error_code
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import compare_policies, AWSRetry, camel_dict_to_snake_dict
+from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
+from ansible_collections.amazon.aws.plugins.module_utils.core import is_boto3_error_code
+from ansible_collections.amazon.aws.plugins.module_utils.core import scrub_none_parameters
+from ansible_collections.amazon.aws.plugins.module_utils.ec2 import compare_policies
+from ansible_collections.amazon.aws.plugins.module_utils.ec2 import AWSRetry
+from ansible_collections.amazon.aws.plugins.module_utils.ec2 import camel_dict_to_snake_dict
class SnsTopicManager(object):
@@ -251,7 +322,7 @@ def __init__(self,
self.state = state
self.display_name = display_name
self.policy = policy
- self.delivery_policy = delivery_policy
+ self.delivery_policy = scrub_none_parameters(delivery_policy) if delivery_policy else None
self.subscriptions = subscriptions
self.subscriptions_existing = []
self.subscriptions_deleted = []
@@ -495,13 +566,39 @@ def get_info(self):
def main():
+
+ # We're kinda stuck with CamelCase here, it would be nice to switch to
+ # snake_case, but we'd need to purge out the alias entries
+ http_retry_args = dict(
+ minDelayTarget=dict(type='int', required=True),
+ maxDelayTarget=dict(type='int', required=True),
+ numRetries=dict(type='int', required=True),
+ numMaxDelayRetries=dict(type='int', required=True),
+ numMinDelayRetries=dict(type='int', required=True),
+ numNoDelayRetries=dict(type='int', required=True),
+ backoffFunction=dict(type='str', required=True, choices=['arithmetic', 'exponential', 'geometric', 'linear']),
+ )
+ http_delivery_args = dict(
+ defaultHealthyRetryPolicy=dict(type='dict', required=True, options=http_retry_args),
+ disableSubscriptionOverrides=dict(type='bool', required=False),
+ defaultThrottlePolicy=dict(
+ type='dict', required=False,
+ options=dict(
+ maxReceivesPerSecond=dict(type='int', required=True),
+ ),
+ ),
+ )
+ delivery_args = dict(
+ http=dict(type='dict', required=False, options=http_delivery_args),
+ )
+
argument_spec = dict(
name=dict(required=True),
topic_type=dict(type='str', default='standard', choices=['standard', 'fifo']),
state=dict(default='present', choices=['present', 'absent']),
display_name=dict(),
policy=dict(type='dict'),
- delivery_policy=dict(type='dict'),
+ delivery_policy=dict(type='dict', options=delivery_args),
subscriptions=dict(default=[], type='list', elements='dict'),
purge_subscriptions=dict(type='bool', default=True),
)
diff --git a/plugins/modules/sqs_queue.py b/plugins/modules/sqs_queue.py
index 0de9d205b35..45a8ccfc079 100644
--- a/plugins/modules/sqs_queue.py
+++ b/plugins/modules/sqs_queue.py
@@ -86,7 +86,7 @@
- Defaults to C(false).
tags:
description:
- - Tag dict to apply to the queue (requires botocore 1.5.40 or above).
+ - Tag dict to apply to the queue.
- To remove all tags set I(tags={}) and I(purge_tags=true).
type: dict
purge_tags:
diff --git a/plugins/modules/wafv2_resources_info.py b/plugins/modules/wafv2_resources_info.py
index 6ab7aa04ca1..d45c274d481 100644
--- a/plugins/modules/wafv2_resources_info.py
+++ b/plugins/modules/wafv2_resources_info.py
@@ -93,7 +93,8 @@ def main():
)
module = AnsibleAWSModule(
- argument_spec=arg_spec
+ argument_spec=arg_spec,
+ supports_check_mode=True,
)
name = module.params.get("name")
diff --git a/plugins/modules/wafv2_web_acl_info.py b/plugins/modules/wafv2_web_acl_info.py
index 54545c10acc..a0de1131cf6 100644
--- a/plugins/modules/wafv2_web_acl_info.py
+++ b/plugins/modules/wafv2_web_acl_info.py
@@ -119,7 +119,8 @@ def main():
)
module = AnsibleAWSModule(
- argument_spec=arg_spec
+ argument_spec=arg_spec,
+ supports_check_mode=True,
)
state = module.params.get("state")
diff --git a/requirements.txt b/requirements.txt
index 0d58b96112d..3685e404330 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,3 +1,8 @@
+# When updating the minimal requirements please also update
+# - tests/unit/constraints.txt
+# - tests/integration/constraints.txt
+# - tests/integration/targets/setup_botocore_pip
+botocore>=1.18.0
+boto3>=1.15.0
+# Final released version
boto>=2.49.0
-botocore>=1.16.0
-boto3>=1.13.0
diff --git a/test-requirements.txt b/test-requirements.txt
index fdb812e3c54..d44dc6b2012 100644
--- a/test-requirements.txt
+++ b/test-requirements.txt
@@ -1,6 +1,18 @@
+botocore
+boto3
+boto
+
coverage==4.5.4
placebo
mock
pytest-xdist
# We should avoid these two modules with py3
pytest-mock
+# Needed for ansible.netcommon.ipaddr in tests
+netaddr
+# Sometimes needed where we don't have features we need in modules
+awscli
+# Used for comparing SSH Public keys to the Amazon fingerprints
+pycrypto
+# Used by ec2_win_password
+cryptography
diff --git a/tests/config.yml b/tests/config.yml
new file mode 100644
index 00000000000..5112f726881
--- /dev/null
+++ b/tests/config.yml
@@ -0,0 +1,2 @@
+modules:
+ python_requires: '>=3.6'
diff --git a/tests/integration/constraints.txt b/tests/integration/constraints.txt
index c105f290280..bd95eb26733 100644
--- a/tests/integration/constraints.txt
+++ b/tests/integration/constraints.txt
@@ -1,3 +1,7 @@
-boto3 >= 1.9.250, <= 1.15.18 # minimum version that supports botocore 1.13.3, max that will work with ansible 2.9's other constraints
-botocore<1.19.0,>=1.13.3 # adds support for ECR image scanning
+# Specifically run tests against the oldest versions that we support
+boto3==1.15.0
+botocore==1.18.0
+# AWS CLI has `botocore==` dependencies, provide the one that matches botocore
+# to avoid needing to download over a years worth of awscli wheels.
+awscli==1.18.141
diff --git a/tests/integration/requirements.txt b/tests/integration/requirements.txt
index 2fb8f547d8a..6e870975a35 100644
--- a/tests/integration/requirements.txt
+++ b/tests/integration/requirements.txt
@@ -1,5 +1,12 @@
+# Our code is based on the AWS SDKs
+boto
+boto3
+botocore
+
# netaddr is needed for ansible.netcommon.ipv6
netaddr
virtualenv
-boto3
-botocore
+# Sometimes needed where we don't have features we need in modules
+awscli
+# Used for comparing SSH Public keys to the Amazon fingerprints
+pycrypto
diff --git a/tests/integration/targets/aws_api_gateway/tasks/main.yml b/tests/integration/targets/aws_api_gateway/tasks/main.yml
index 5c6047c33f5..51db07f0d52 100644
--- a/tests/integration/targets/aws_api_gateway/tasks/main.yml
+++ b/tests/integration/targets/aws_api_gateway/tasks/main.yml
@@ -1,4 +1,12 @@
-- block:
+- name: Wrap API Gateway tests with credentials by default
+ module_defaults:
+ group/aws:
+ aws_access_key: '{{ aws_access_key }}'
+ aws_secret_key: '{{ aws_secret_key }}'
+ security_token: '{{ security_token | default(omit) }}'
+ region: '{{ aws_region }}'
+
+ block:
# ====================== testing failure cases: ==================================
@@ -11,24 +19,11 @@
assert:
that:
- 'result.failed'
- - 'result.msg.startswith("The aws_api_gateway module requires a region")'
-
- - name: test with minimal parameters but no region
- aws_api_gateway:
- api_id: 'fake-api-doesnt-exist'
- register: result
- ignore_errors: true
-
- - name: assert failure when called with with minimal parameters but no region
- assert:
- that:
- - 'result.failed'
- - 'result.msg.startswith("The aws_api_gateway module requires a region")'
+ - '"no swagger info provided" in result.msg'
- name: test for disallowing multiple swagger sources
aws_api_gateway:
api_id: 'fake-api-doesnt-exist'
- region: '{{ec2_region}}'
swagger_file: foo.yml
swagger_text: "this is not really an API"
register: result
@@ -54,10 +49,6 @@
stage: "minimal"
endpoint_type: 'REGIONAL'
state: present
- region: '{{ec2_region}}'
- aws_access_key: '{{ec2_access_key}}'
- aws_secret_key: '{{ec2_secret_key}}'
- security_token: '{{security_token}}'
register: create_result
- name: assert deploy new API worked
@@ -71,7 +62,7 @@
- 'create_result.configure_response.endpoint_configuration.types.0 == "REGIONAL"'
- name: check if API endpoint works
- uri: url="https://{{create_result.api_id}}.execute-api.{{ec2_region}}.amazonaws.com/minimal"
+ uri: url="https://{{create_result.api_id}}.execute-api.{{aws_region}}.amazonaws.com/minimal"
register: uri_result
- name: assert API works success
@@ -80,7 +71,7 @@
- 'uri_result.status == 200'
- name: check if nonexistent endpoint causes error
- uri: url="https://{{create_result.api_id}}.execute-api.{{ec2_region}}.amazonaws.com/nominal"
+ uri: url="https://{{create_result.api_id}}.execute-api.{{aws_region}}.amazonaws.com/nominal"
register: bad_uri_result
ignore_errors: true
@@ -97,10 +88,6 @@
cache_size: '1.6'
tracing_enabled: true
state: present
- region: '{{ec2_region}}'
- aws_access_key: '{{ec2_access_key}}'
- aws_secret_key: '{{ec2_secret_key}}'
- security_token: '{{security_token}}'
register: update_result
- name: assert update result
@@ -118,10 +105,6 @@
stage: "minimal"
cache_enabled: false
state: present
- region: '{{ec2_region}}'
- aws_access_key: '{{ec2_access_key}}'
- aws_secret_key: '{{ec2_secret_key}}'
- security_token: '{{security_token}}'
register: create_result_1
- name: deploy second API rapidly after first
@@ -129,10 +112,6 @@
api_file: "{{output_dir}}/minimal-swagger-api.yml"
stage: "minimal"
state: present
- region: '{{ec2_region}}'
- aws_access_key: '{{ec2_access_key}}'
- aws_secret_key: '{{ec2_secret_key}}'
- security_token: '{{security_token}}'
register: create_result_2
- name: assert both APIs deployed successfully
@@ -148,20 +127,12 @@
aws_api_gateway:
state: absent
api_id: '{{create_result_1.api_id}}'
- region: '{{ec2_region}}'
- aws_access_key: '{{ec2_access_key}}'
- aws_secret_key: '{{ec2_secret_key}}'
- security_token: '{{security_token}}'
register: destroy_result_1
- name: destroy second API rapidly after first
aws_api_gateway:
state: absent
api_id: '{{create_result_2.api_id}}'
- region: '{{ec2_region}}'
- aws_access_key: '{{ec2_access_key}}'
- aws_secret_key: '{{ec2_secret_key}}'
- security_token: '{{security_token}}'
register: destroy_result_2
- name: assert both APIs deployed successfully
@@ -180,28 +151,16 @@
aws_api_gateway:
state: absent
api_id: '{{create_result.api_id}}'
- ec2_region: '{{ec2_region}}'
- aws_access_key: '{{ec2_access_key}}'
- aws_secret_key: '{{ec2_secret_key}}'
- security_token: '{{security_token}}'
ignore_errors: true
- name: Ensure cleanup of API deploy 1
aws_api_gateway:
state: absent
api_id: '{{create_result_1.api_id}}'
- ec2_region: '{{ec2_region}}'
- aws_access_key: '{{ec2_access_key}}'
- aws_secret_key: '{{ec2_secret_key}}'
- security_token: '{{security_token}}'
ignore_errors: true
- name: Ensure cleanup of API deploy 2
aws_api_gateway:
state: absent
api_id: '{{create_result_2.api_id}}'
- ec2_region: '{{ec2_region}}'
- aws_access_key: '{{ec2_access_key}}'
- aws_secret_key: '{{ec2_secret_key}}'
- security_token: '{{security_token}}'
ignore_errors: true
diff --git a/tests/integration/targets/aws_codebuild/defaults/main.yml b/tests/integration/targets/aws_codebuild/defaults/main.yml
index 67c13956d0a..da382aedf39 100644
--- a/tests/integration/targets/aws_codebuild/defaults/main.yml
+++ b/tests/integration/targets/aws_codebuild/defaults/main.yml
@@ -3,5 +3,4 @@
# IAM role names have to be less than 64 characters
# we hash the resource_prefix to get a shorter, unique string
-unique_id: "{{ resource_prefix | hash('md5') | truncate(8, True, '') }}"
-iam_role_name: "ansible-test-sts-{{ unique_id }}-codebuild-service-role"
+iam_role_name: "ansible-test-{{ tiny_prefix }}-codebuild-service-role"
diff --git a/tests/integration/targets/aws_codepipeline/defaults/main.yml b/tests/integration/targets/aws_codepipeline/defaults/main.yml
index b9ced058ff1..6c578ddb86d 100644
--- a/tests/integration/targets/aws_codepipeline/defaults/main.yml
+++ b/tests/integration/targets/aws_codepipeline/defaults/main.yml
@@ -1,7 +1,6 @@
---
# defaults file for aws_codepipeline
-unique_id: "{{ resource_prefix | hash('md5') }}"
-codepipeline_name: "{{ unique_id }}-test-codepipeline"
+codepipeline_name: "{{ tiny_prefix }}-test-codepipeline"
# IAM role names have to be less than 64 characters
# we hash the resource_prefix to get a shorter, unique string
-codepipeline_service_role_name: "ansible-test-sts-{{ unique_id | truncate(6, True, '') }}-codepipeline-role"
+codepipeline_service_role_name: "ansible-test-{{ tiny_prefix | truncate(6, True, '') }}-codepipeline-role"
diff --git a/tests/integration/targets/aws_eks_cluster/tasks/botocore_lt_1.10.1.yml b/tests/integration/targets/aws_eks_cluster/tasks/botocore_lt_1.10.1.yml
deleted file mode 100644
index e4c4b31fe5e..00000000000
--- a/tests/integration/targets/aws_eks_cluster/tasks/botocore_lt_1.10.1.yml
+++ /dev/null
@@ -1,12 +0,0 @@
-- name: try and use aws_eks_cluster module
- aws_eks_cluster:
- state: absent
- name: my_cluster
- ignore_errors: yes
- register: aws_eks_cluster
-
-- name: ensure that aws_eks fails with friendly error message
- assert:
- that:
- - '"msg" in aws_eks_cluster'
- - aws_eks_cluster is failed
diff --git a/tests/integration/targets/aws_eks_cluster/tasks/botocore_lt_1.12.38.yml b/tests/integration/targets/aws_eks_cluster/tasks/botocore_lt_1.12.38.yml
deleted file mode 100644
index 4feb7ab48fc..00000000000
--- a/tests/integration/targets/aws_eks_cluster/tasks/botocore_lt_1.12.38.yml
+++ /dev/null
@@ -1,13 +0,0 @@
-- name: try using aws_eks_cluster wait with state=absent
- aws_eks_cluster:
- state: absent
- name: my_cluster
- wait: yes
- ignore_errors: yes
- register: aws_eks_cluster
-
-- name: ensure that aws_eks fails with friendly error message
- assert:
- that:
- - '"msg" in aws_eks_cluster'
- - aws_eks_cluster is failed
diff --git a/tests/integration/targets/aws_eks_cluster/tasks/main.yml b/tests/integration/targets/aws_eks_cluster/tasks/main.yml
index 95fb241298e..61aa32cd19d 100644
--- a/tests/integration/targets/aws_eks_cluster/tasks/main.yml
+++ b/tests/integration/targets/aws_eks_cluster/tasks/main.yml
@@ -9,70 +9,4 @@
security_token: '{{ security_token | default(omit) }}'
region: '{{ aws_region }}'
block:
-
- - set_fact:
- virtualenv: "{{ remote_tmp_dir }}/virtualenv"
- virtualenv_command: "{{ ansible_python_interpreter }} -m virtualenv"
-
- - set_fact:
- virtualenv_interpreter: "{{ virtualenv }}/bin/python"
-
- - pip:
- name: virtualenv
-
- # Test graceful failure for missing kubernetes-validate
-
- - pip:
- name:
- - 'botocore<1.10.1'
- - boto3
- - coverage<5
- virtualenv: "{{ virtualenv }}"
- virtualenv_command: "{{ virtualenv_command }}"
- virtualenv_site_packages: no
-
- - include_tasks: botocore_lt_1.10.1.yml
- vars:
- ansible_python_interpreter: "{{ virtualenv_interpreter }}"
-
- - file:
- path: "{{ virtualenv }}"
- state: absent
-
- # Test graceful failures when botocore<1.12.38
-
- - pip:
- name:
- - 'botocore>1.10.1,<1.12.38'
- - boto3
- - coverage<5
- virtualenv: "{{ virtualenv }}"
- virtualenv_command: "{{ virtualenv_command }}"
- virtualenv_site_packages: no
-
- - include_tasks: botocore_lt_1.12.38.yml
- vars:
- ansible_python_interpreter: "{{ virtualenv_interpreter }}"
-
- - file:
- path: "{{ virtualenv }}"
- state: absent
-
- # Test validate with kubernetes-validate
-
- - pip:
- name:
- - 'botocore>=1.10.1'
- - boto3
- virtualenv: "{{ virtualenv }}"
- virtualenv_command: "{{ virtualenv_command }}"
- virtualenv_site_packages: no
-
- include_tasks: full_test.yml
- vars:
- ansible_python_interpreter: "{{ virtualenv_interpreter }}"
- playbook_namespace: ansible-test-k8s-validate
-
- - file:
- path: "{{ virtualenv }}"
- state: absent
diff --git a/tests/integration/targets/aws_kms/tasks/main.yml b/tests/integration/targets/aws_kms/tasks/main.yml
index 2f98979eb91..214f0ddc955 100644
--- a/tests/integration/targets/aws_kms/tasks/main.yml
+++ b/tests/integration/targets/aws_kms/tasks/main.yml
@@ -74,6 +74,8 @@
- create_kms.key_state == "Enabled"
- create_kms.tags['Hello'] == 'World'
- create_kms.enable_key_rotation == false
+ - create_kms.key_usage == 'ENCRYPT_DECRYPT'
+ - create_kms.customer_master_key_spec == 'SYMMETRIC_DEFAULT'
- name: Save IDs for later
set_fact:
@@ -492,6 +494,28 @@
- (( deletion_time | to_datetime ) - ( now_time | to_datetime )).days <= 7
- (( deletion_time | to_datetime ) - ( now_time | to_datetime )).days >= 6
+ # ============================================================
+ # test different key usage and specs
+ - name: create kms key with different specs
+ aws_kms:
+ alias: '{{ kms_role_name }}-diff-spec-usage'
+ purge_grants: yes
+ key_spec: ECC_NIST_P256
+ key_usage: SIGN_VERIFY
+ register: create_diff_kms
+
+ - name: verify different specs on kms key
+ assert:
+ that:
+ - '"key_id" in create_diff_kms'
+ - create_diff_kms.key_id | length >= 36
+ - not create_diff_kms.key_id.startswith("arn:aws")
+ - '"key_arn" in create_diff_kms'
+ - create_diff_kms.key_arn.endswith(create_diff_kms.key_id)
+ - create_diff_kms.key_arn.startswith("arn:aws")
+ - create_diff_kms.key_usage == 'SIGN_VERIFY'
+ - create_diff_kms.customer_master_key_spec == 'ECC_NIST_P256'
+
always:
# ============================================================
# CLEAN-UP
@@ -503,6 +527,14 @@
register: destroy_result
ignore_errors: True
+ - name: delete kms key with different specs
+ aws_kms:
+ state: absent
+ alias: '{{ kms_role_name }}-diff-spec-usage'
+ pending_window: 7
+ register: destroy_result
+ ignore_errors: True
+
# Should never exist, but just in case
- name: finish off by deleting key
aws_kms:
diff --git a/tests/integration/targets/aws_msk_cluster/aliases b/tests/integration/targets/aws_msk_cluster/aliases
index 500826a1d4f..397e3536faa 100644
--- a/tests/integration/targets/aws_msk_cluster/aliases
+++ b/tests/integration/targets/aws_msk_cluster/aliases
@@ -1,2 +1,4 @@
-cloud/aws
+# Needs to install recent botocore environment
slow
+
+cloud/aws
diff --git a/tests/integration/targets/aws_msk_cluster/defaults/main.yml b/tests/integration/targets/aws_msk_cluster/defaults/main.yml
index 25d5dafa689..f21818507fe 100644
--- a/tests/integration/targets/aws_msk_cluster/defaults/main.yml
+++ b/tests/integration/targets/aws_msk_cluster/defaults/main.yml
@@ -7,7 +7,7 @@ vpc_subnets:
vpc_subnet_name_prefix: "{{ resource_prefix }}"
msk_config_name: "{{ resource_prefix }}-config"
-msk_cluster_name: "ansible-test-{{ (resource_prefix | hash('md5'))[:7] }}-msk-cluster"
+msk_cluster_name: "{{ tiny_prefix }}-msk-cluster"
msk_version: 2.6.0
msk_broker_nodes: 2
diff --git a/tests/integration/targets/aws_msk_cluster/meta/main.yml b/tests/integration/targets/aws_msk_cluster/meta/main.yml
new file mode 100644
index 00000000000..bc4ebde80b9
--- /dev/null
+++ b/tests/integration/targets/aws_msk_cluster/meta/main.yml
@@ -0,0 +1,2 @@
+dependencies:
+ - setup_remote_tmp_dir
\ No newline at end of file
diff --git a/tests/integration/targets/aws_msk_cluster/tasks/main.yml b/tests/integration/targets/aws_msk_cluster/tasks/main.yml
index ab4f94e3305..a3049dad0b4 100644
--- a/tests/integration/targets/aws_msk_cluster/tasks/main.yml
+++ b/tests/integration/targets/aws_msk_cluster/tasks/main.yml
@@ -9,7 +9,6 @@
collections:
- amazon.aws
block:
-
- name: collect availability zone info
aws_az_info:
register: az_info
@@ -41,6 +40,7 @@
- set_fact:
subnet_ids: '{{ subnets | community.general.json_query("results[].subnet.id") | list }}'
+ # ============================================================
- name: create msk configuration
aws_msk_config:
name: "{{ msk_config_name }}"
@@ -94,4 +94,4 @@
register: removed_vpc
until: removed_vpc is success
retries: 5
- delay: 5
\ No newline at end of file
+ delay: 5
diff --git a/tests/integration/targets/aws_msk_config/aliases b/tests/integration/targets/aws_msk_config/aliases
index 4ef4b2067d0..397e3536faa 100644
--- a/tests/integration/targets/aws_msk_config/aliases
+++ b/tests/integration/targets/aws_msk_config/aliases
@@ -1 +1,4 @@
+# Needs to install recent botocore environment
+slow
+
cloud/aws
diff --git a/tests/integration/targets/aws_msk_config/meta/main.yml b/tests/integration/targets/aws_msk_config/meta/main.yml
new file mode 100644
index 00000000000..bc4ebde80b9
--- /dev/null
+++ b/tests/integration/targets/aws_msk_config/meta/main.yml
@@ -0,0 +1,2 @@
+dependencies:
+ - setup_remote_tmp_dir
\ No newline at end of file
diff --git a/tests/integration/targets/aws_msk_config/tasks/main.yml b/tests/integration/targets/aws_msk_config/tasks/main.yml
index f5343139c38..cef9e1dfc90 100644
--- a/tests/integration/targets/aws_msk_config/tasks/main.yml
+++ b/tests/integration/targets/aws_msk_config/tasks/main.yml
@@ -9,7 +9,6 @@
collections:
- amazon.aws
block:
-
- name: create msk configuration (check mode)
aws_msk_config:
name: "{{ msk_config_name }}"
diff --git a/tests/integration/targets/aws_s3_bucket_info/defaults/main.yml b/tests/integration/targets/aws_s3_bucket_info/defaults/main.yml
index 5ba35b74952..464c0a299b7 100644
--- a/tests/integration/targets/aws_s3_bucket_info/defaults/main.yml
+++ b/tests/integration/targets/aws_s3_bucket_info/defaults/main.yml
@@ -1,7 +1,5 @@
---
name_pattern: "testbucket-ansible-integration"
-unique_id: "{{ resource_prefix | hash('md5') | truncate(24, True, '') }}"
-
testing_buckets:
- - "{{ unique_id }}-{{ name_pattern }}-1"
- - "{{ unique_id }}-{{ name_pattern }}-2"
+ - "{{ tiny_prefix }}-{{ name_pattern }}-1"
+ - "{{ tiny_prefix }}-{{ name_pattern }}-2"
diff --git a/tests/integration/targets/aws_s3_bucket_info/meta/main.yml b/tests/integration/targets/aws_s3_bucket_info/meta/main.yml
index 1f64f1169a9..1368bc4f128 100644
--- a/tests/integration/targets/aws_s3_bucket_info/meta/main.yml
+++ b/tests/integration/targets/aws_s3_bucket_info/meta/main.yml
@@ -1,3 +1,4 @@
dependencies:
- prepare_tests
+ - setup_remote_tmp_dir
- setup_ec2
diff --git a/tests/integration/targets/aws_s3_bucket_info/tasks/basic.yml b/tests/integration/targets/aws_s3_bucket_info/tasks/basic.yml
new file mode 100644
index 00000000000..bf09665af4c
--- /dev/null
+++ b/tests/integration/targets/aws_s3_bucket_info/tasks/basic.yml
@@ -0,0 +1,72 @@
+---
+- name: Get simple S3 bucket list
+ aws_s3_bucket_info:
+ register: bucket_list
+
+- name: Assert result.changed == False and bucket list was retrieved
+ assert:
+ that:
+ - bucket_list.changed == False
+ - bucket_list.buckets
+
+- name: Get complex S3 bucket list
+ aws_s3_bucket_info:
+ name_filter: "{{ name_pattern }}"
+ bucket_facts:
+ bucket_accelerate_configuration: true
+ bucket_acl: true
+ bucket_cors: true
+ bucket_encryption: true
+ bucket_lifecycle_configuration: true
+ bucket_location: true
+ bucket_logging: true
+ bucket_notification_configuration: true
+ bucket_policy: true
+ bucket_policy_status: true
+ bucket_replication: true
+ bucket_request_payment: true
+ bucket_tagging: true
+ bucket_website: true
+ public_access_block: true
+ transform_location: true
+ register: bucket_list
+
+- name: Assert that buckets list contains requested bucket facts
+ assert:
+ that:
+ - item.name is search(name_pattern)
+ - item.bucket_accelerate_configuration is defined
+ - item.bucket_acl is defined
+ - item.bucket_cors is defined
+ - item.bucket_encryption is defined
+ - item.bucket_lifecycle_configuration is defined
+ - item.bucket_location is defined
+ - item.bucket_logging is defined
+ - item.bucket_notification_configuration is defined
+ - item.bucket_policy is defined
+ - item.bucket_policy_status is defined
+ - item.bucket_replication is defined
+ - item.bucket_request_payment is defined
+ - item.bucket_tagging is defined
+ - item.bucket_website is defined
+ - item.public_access_block is defined
+ loop: "{{ bucket_list.buckets }}"
+ loop_control:
+ label: "{{ item.name }}"
+
+- name: Assert that retrieved bucket facts contains valid data
+ assert:
+ that:
+ - item.bucket_acl.Owner is defined
+ - item.bucket_tagging.snake_case is defined
+ - item.bucket_tagging.CamelCase is defined
+ - item.bucket_tagging["lowercase spaced"] is defined
+ - item.bucket_tagging["Title Case"] is defined
+ - item.bucket_tagging.snake_case == 'simple_snake_case'
+ - item.bucket_tagging.CamelCase == 'SimpleCamelCase'
+ - item.bucket_tagging["lowercase spaced"] == 'hello cruel world'
+ - item.bucket_tagging["Title Case"] == 'Hello Cruel World'
+ - item.bucket_location.LocationConstraint == aws_region
+ loop: "{{ bucket_list.buckets }}"
+ loop_control:
+ label: "{{ item.name }}"
diff --git a/tests/integration/targets/aws_s3_bucket_info/tasks/bucket_ownership_controls.yml b/tests/integration/targets/aws_s3_bucket_info/tasks/bucket_ownership_controls.yml
new file mode 100644
index 00000000000..77c193043a9
--- /dev/null
+++ b/tests/integration/targets/aws_s3_bucket_info/tasks/bucket_ownership_controls.yml
@@ -0,0 +1,108 @@
+---
+- name: Test community.aws.aws_s3_bucket_info
+ block:
+ - pip:
+ name: virtualenv
+ - set_fact:
+ virtualenv: "{{ remote_tmp_dir }}/virtualenv"
+ virtualenv_command: "{{ ansible_python_interpreter }} -m virtualenv"
+ - set_fact:
+ virtualenv_interpreter: "{{ virtualenv }}/bin/python"
+ - pip:
+ name:
+ - 'boto3>=1.15.0'
+ - 'botocore==1.18.11'
+ - 'coverage<5'
+ virtualenv: '{{ virtualenv }}'
+ virtualenv_command: '{{ virtualenv_command }}'
+ virtualenv_site_packages: no
+ - name: Wrap test in virtualenv
+ vars:
+ ansible_python_interpreter: "{{ virtualenv }}/bin/python"
+ block:
+
+ - name: Get S3 bucket ownership controls
+ aws_s3_bucket_info:
+ name_filter: "{{ name_pattern }}"
+ bucket_facts:
+ bucket_ownership_controls: true
+ transform_location: true
+ register: bucket_list
+
+ - name: Assert that buckets list contains requested bucket facts
+ assert:
+ that:
+ - item.name is search(name_pattern)
+ - item.bucket_ownership_controls is defined
+ loop: "{{ bucket_list.buckets }}"
+ loop_control:
+ label: "{{ item.name }}"
+
+ - name: Get complex S3 bucket list (including ownership controls)
+ aws_s3_bucket_info:
+ name_filter: "{{ name_pattern }}"
+ bucket_facts:
+ bucket_accelerate_configuration: true
+ bucket_acl: true
+ bucket_cors: true
+ bucket_encryption: true
+ bucket_lifecycle_configuration: true
+ bucket_location: true
+ bucket_logging: true
+ bucket_notification_configuration: true
+ bucket_ownership_controls: true
+ bucket_policy: true
+ bucket_policy_status: true
+ bucket_replication: true
+ bucket_request_payment: true
+ bucket_tagging: true
+ bucket_website: true
+ public_access_block: true
+ transform_location: true
+ register: bucket_list
+
+ - name: Assert that buckets list contains requested bucket facts
+ assert:
+ that:
+ - item.name is search(name_pattern)
+ - item.bucket_accelerate_configuration is defined
+ - item.bucket_acl is defined
+ - item.bucket_cors is defined
+ - item.bucket_encryption is defined
+ - item.bucket_lifecycle_configuration is defined
+ - item.bucket_location is defined
+ - item.bucket_logging is defined
+ - item.bucket_notification_configuration is defined
+ - item.bucket_ownership_controls is defined
+ - item.bucket_policy is defined
+ - item.bucket_policy_status is defined
+ - item.bucket_replication is defined
+ - item.bucket_request_payment is defined
+ - item.bucket_tagging is defined
+ - item.bucket_website is defined
+ - item.public_access_block is defined
+ loop: "{{ bucket_list.buckets }}"
+ loop_control:
+ label: "{{ item.name }}"
+
+ - name: Assert that retrieved bucket facts contains valid data
+ assert:
+ that:
+ - item.bucket_acl.Owner is defined
+ - item.bucket_tagging.snake_case is defined
+ - item.bucket_tagging.CamelCase is defined
+ - item.bucket_tagging["lowercase spaced"] is defined
+ - item.bucket_tagging["Title Case"] is defined
+ - item.bucket_tagging.snake_case == 'simple_snake_case'
+ - item.bucket_tagging.CamelCase == 'SimpleCamelCase'
+ - item.bucket_tagging["lowercase spaced"] == 'hello cruel world'
+ - item.bucket_tagging["Title Case"] == 'Hello Cruel World'
+ - item.bucket_location.LocationConstraint == aws_region
+ loop: "{{ bucket_list.buckets }}"
+ loop_control:
+ label: "{{ item.name }}"
+
+ always:
+ - file:
+ path: "{{ virtualenv }}"
+ state: absent
diff --git a/tests/integration/targets/aws_s3_bucket_info/tasks/main.yml b/tests/integration/targets/aws_s3_bucket_info/tasks/main.yml
index 5afdf8d7841..47d24cd0e3b 100644
--- a/tests/integration/targets/aws_s3_bucket_info/tasks/main.yml
+++ b/tests/integration/targets/aws_s3_bucket_info/tasks/main.yml
@@ -7,7 +7,7 @@
security_token: "{{ security_token | default(omit) }}"
region: "{{ aws_region }}"
block:
- - name: Create simple s3_buckets
+ - name: Create a simple s3_bucket
s3_bucket:
name: "{{ item }}"
state: present
@@ -19,79 +19,8 @@
register: output
loop: "{{ testing_buckets }}"
- - name: Get simple S3 bucket list
- aws_s3_bucket_info:
- register: bucket_list
-
- - name: Assert result.changed == False and bucket list was retrieved
- assert:
- that:
- - bucket_list.changed == False
- - bucket_list.buckets
-
- - name: Get complex S3 bucket list
- aws_s3_bucket_info:
- name_filter: "{{ name_pattern }}"
- bucket_facts:
- bucket_accelerate_configuration: true
- bucket_acl: true
- bucket_cors: true
- bucket_encryption: true
- bucket_lifecycle_configuration: true
- bucket_location: true
- bucket_logging: true
- bucket_notification_configuration: true
- bucket_ownership_controls: true
- bucket_policy: true
- bucket_policy_status: true
- bucket_replication: true
- bucket_request_payment: true
- bucket_tagging: true
- bucket_website: true
- public_access_block: true
- transform_location: true
- register: bucket_list
-
- - name: Assert that buckets list contains requested bucket facts
- assert:
- that:
- - item.name is search(name_pattern)
- - item.bucket_accelerate_configuration is defined
- - item.bucket_acl is defined
- - item.bucket_cors is defined
- - item.bucket_encryption is defined
- - item.bucket_lifecycle_configuration is defined
- - item.bucket_location is defined
- - item.bucket_logging is defined
- - item.bucket_notification_configuration is defined
- - item.bucket_ownership_controls is defined
- - item.bucket_policy is defined
- - item.bucket_policy_status is defined
- - item.bucket_replication is defined
- - item.bucket_request_payment is defined
- - item.bucket_tagging is defined
- - item.bucket_website is defined
- - item.public_access_block is defined
- loop: "{{ bucket_list.buckets }}"
- loop_control:
- label: "{{ item.name }}"
-
- - name: Assert that retrieved bucket facts contains valid data
- assert:
- that:
- - item.bucket_acl.Owner is defined
- - item.bucket_tagging.snake_case is defined
- - item.bucket_tagging.CamelCase is defined
- - item.bucket_tagging["lowercase spaced"] is defined
- - item.bucket_tagging["Title Case"] is defined
- - item.bucket_tagging.snake_case == 'simple_snake_case'
- - item.bucket_tagging.CamelCase == 'SimpleCamelCase'
- - item.bucket_tagging["lowercase spaced"] == 'hello cruel world'
- - item.bucket_tagging["Title Case"] == 'Hello Cruel World'
- - item.bucket_location.LocationConstraint == aws_region
- loop: "{{ bucket_list.buckets }}"
- loop_control:
- label: "{{ item.name }}"
+ - include_tasks: basic.yml
+ - include_tasks: bucket_ownership_controls.yml
always:
- name: Delete simple s3_buckets
diff --git a/tests/integration/targets/aws_secret/aliases b/tests/integration/targets/aws_secret/aliases
index da76731e85b..4ef4b2067d0 100644
--- a/tests/integration/targets/aws_secret/aliases
+++ b/tests/integration/targets/aws_secret/aliases
@@ -1,6 +1 @@
-# reason: missing-policy
-# reason: broken
-# The tests for configuring secret rotation seem to be missing a permission
-disabled
-
cloud/aws
diff --git a/tests/integration/targets/aws_secret/tasks/basic.yml b/tests/integration/targets/aws_secret/tasks/basic.yml
new file mode 100644
index 00000000000..884fdc40d36
--- /dev/null
+++ b/tests/integration/targets/aws_secret/tasks/basic.yml
@@ -0,0 +1,160 @@
+---
+- block:
+ # ============================================================
+ # Module parameter testing
+ # ============================================================
+ - name: test with no parameters
+ aws_secret:
+ register: result
+ ignore_errors: true
+ check_mode: true
+
+ - name: assert failure when called with no parameters
+ assert:
+ that:
+ - result.failed
+ - 'result.msg.startswith("missing required arguments:")'
+
+ # ============================================================
+ # Creation/Deletion testing
+ # ============================================================
+ - name: add secret to AWS Secrets Manager
+ aws_secret:
+ name: "{{ secret_name }}"
+ state: present
+ secret_type: 'string'
+ secret: "{{ super_secret_string }}"
+ register: result
+
+ - name: assert correct keys are returned
+ assert:
+ that:
+ - result.changed
+ - result.arn is not none
+ - result.name is not none
+ - result.tags is not none
+ - result.version_ids_to_stages is not none
+
+ - name: no changes to secret
+ aws_secret:
+ name: "{{ secret_name }}"
+ state: present
+ secret_type: 'string'
+ secret: "{{ super_secret_string }}"
+ register: result
+
+ - name: assert correct keys are returned
+ assert:
+ that:
+ - not result.changed
+ - result.arn is not none
+
+ - name: make change to secret
+ aws_secret:
+ name: "{{ secret_name }}"
+ description: 'this is a change to this secret'
+ state: present
+ secret_type: 'string'
+ secret: "{{ super_secret_string }}"
+ register: result
+
+ - debug:
+ var: result
+
+ - name: assert correct keys are returned
+ assert:
+ that:
+ - result.changed
+ - result.arn is not none
+ - result.name is not none
+ - result.tags is not none
+ - result.version_ids_to_stages is not none
+
+ - name: add tags to secret
+ aws_secret:
+ name: "{{ secret_name }}"
+ description: 'this is a change to this secret'
+ state: present
+ secret_type: 'string'
+ secret: "{{ super_secret_string }}"
+ tags:
+ Foo: 'Bar'
+ Test: 'Tag'
+ register: result
+
+ - name: assert correct keys are returned
+ assert:
+ that:
+ - result.changed
+
+ - name: remove tags from secret
+ aws_secret:
+ name: "{{ secret_name }}"
+ description: 'this is a change to this secret'
+ state: present
+ secret_type: 'string'
+ secret: "{{ super_secret_string }}"
+ register: result
+
+ - name: assert correct keys are returned
+ assert:
+ that:
+ - result.changed
+
+ - name: remove secret
+ aws_secret:
+ name: "{{ secret_name }}"
+ state: absent
+ recovery_window: 7
+ register: result
+
+ - name: assert key is deleted
+ assert:
+ that:
+ - result.changed
+
+ - name: remove secret (idempotency)
+ aws_secret:
+ name: "{{ secret_name }}"
+ state: absent
+ recovery_window: 7
+ register: result
+
+ - name: assert no change happened
+ assert:
+ that:
+ - not result.changed
+
+ - name: immediate secret removal
+ aws_secret:
+ name: "{{ secret_name }}"
+ state: absent
+ recovery_window: 0
+ register: result
+
+ - name: assert key is deleted
+ assert:
+ that:
+ - result.changed
+
+ # AWS Doesn't expose when the secret will be removed, all we can do is
+ # check that we didn't throw an error
+ - name: immediate secret removal
+ aws_secret:
+ name: "{{ secret_name }}"
+ state: absent
+ recovery_window: 0
+ register: result
+
+ - name: assert no change happened
+ assert:
+ that:
+ - not result.failed
+
+ always:
+ - name: remove secret
+ aws_secret:
+ name: "{{ secret_name }}"
+ state: absent
+ recovery_window: 0
+ ignore_errors: yes
diff --git a/tests/integration/targets/aws_secret/tasks/main.yaml b/tests/integration/targets/aws_secret/tasks/main.yaml
index 483be47553c..00a859b5d50 100644
--- a/tests/integration/targets/aws_secret/tasks/main.yaml
+++ b/tests/integration/targets/aws_secret/tasks/main.yaml
@@ -9,245 +9,6 @@
- amazon.aws
block:
- - name: retrieve caller facts
- aws_caller_info:
- register: test_caller_facts
-
- - name: ensure IAM role exists
- iam_role:
- name: "{{ secret_manager_role }}"
- assume_role_policy_document: "{{ lookup('file','secretsmanager-trust-policy.json') }}"
- state: present
- create_instance_profile: no
- managed_policy:
- - 'arn:aws:iam::aws:policy/SecretsManagerReadWrite'
- register: iam_role
- ignore_errors: yes
-
- - name: wait 10 seconds for role to become available
- pause:
- seconds: 10
- when: iam_role.changed
-
- # CI does not remove the role and comparing policies has a bug on Python3; fall back to use iam_role_info
- - name: get IAM role
- iam_role_info:
- name: "{{ secret_manager_role }}"
- register: iam_role_info
-
- - name: set iam_role_output
- set_fact:
- iam_role_output: "{{ iam_role_info.iam_roles[0] }}"
- when: iam_role_info is defined
-
- - name: create a temporary directory
- tempfile:
- state: directory
- register: tmp
-
- - name: move lambda into place for upload
- copy:
- src: "files/hello_world.zip"
- dest: "{{ tmp.path }}/hello_world.zip"
-
- - name: dummy lambda for testing
- lambda:
- name: "{{ lambda_name }}"
- state: present
- zip_file: "{{ tmp.path }}/hello_world.zip"
- runtime: 'python2.7'
- role: "{{ iam_role_output.arn }}"
- handler: 'hello_world.lambda_handler'
- register: lambda_output
- until: not lambda_output.failed
- retries: 10
- delay: 5
-
- - debug:
- var: lambda_output
-
- # ============================================================
- # Module parameter testing
- # ============================================================
- - name: test with no parameters
- aws_secret:
- register: result
- ignore_errors: true
- check_mode: true
-
- - name: assert failure when called with no parameters
- assert:
- that:
- - result.failed
- - 'result.msg.startswith("missing required arguments:")'
-
- # ============================================================
- # Creation/Deletion testing
- # ============================================================
- - name: add secret to AWS Secrets Manager
- aws_secret:
- name: "{{ secret_name }}"
- state: present
- secret_type: 'string'
- secret: "{{ super_secret_string }}"
- register: result
-
- - name: assert correct keys are returned
- assert:
- that:
- - result.changed
- - result.arn is not none
- - result.name is not none
- - result.tags is not none
- - result.version_ids_to_stages is not none
-
- - name: no changes to secret
- aws_secret:
- name: "{{ secret_name }}"
- state: present
- secret_type: 'string'
- secret: "{{ super_secret_string }}"
- register: result
-
- - name: assert correct keys are returned
- assert:
- that:
- - not result.changed
- - result.arn is not none
-
- - name: make change to secret
- aws_secret:
- name: "{{ secret_name }}"
- description: 'this is a change to this secret'
- state: present
- secret_type: 'string'
- secret: "{{ super_secret_string }}"
- register: result
-
- - debug:
- var: result
-
- - name: assert correct keys are returned
- assert:
- that:
- - result.changed
- - result.arn is not none
- - result.name is not none
- - result.tags is not none
- - result.version_ids_to_stages is not none
-
- - name: add tags to secret
- aws_secret:
- name: "{{ secret_name }}"
- description: 'this is a change to this secret'
- state: present
- secret_type: 'string'
- secret: "{{ super_secret_string }}"
- tags:
- Foo: 'Bar'
- Test: 'Tag'
- register: result
-
- - name: assert correct keys are returned
- assert:
- that:
- - result.changed
-
- - name: remove tags from secret
- aws_secret:
- name: "{{ secret_name }}"
- description: 'this is a change to this secret'
- state: present
- secret_type: 'string'
- secret: "{{ super_secret_string }}"
- register: result
-
- - name: assert correct keys are returned
- assert:
- that:
- - result.changed
-
- - name: lambda policy for secrets manager
- lambda_policy:
- state: present
- function_name: "{{ lambda_name }}"
- statement_id: LambdaSecretsManagerTestPolicy
- action: 'lambda:InvokeFunction'
- principal: "secretsmanager.amazonaws.com"
-
- - name: add rotation lambda to secret
- aws_secret:
- name: "{{ secret_name }}"
- description: 'this is a change to this secret'
- state: present
- secret_type: 'string'
- secret: "{{ super_secret_string }}"
- rotation_lambda: "arn:aws:lambda:{{ aws_region }}:{{ test_caller_facts.account }}:function:{{ lambda_name }}"
- register: result
- retries: 100
- delay: 5
- until: not result.failed
-
- - name: assert correct keys are returned
- assert:
- that:
- - result.changed
-
- - name: remove rotation lambda from secret
- aws_secret:
- name: "{{ secret_name }}"
- description: 'this is a change to this secret'
- state: present
- secret_type: 'string'
- secret: "{{ super_secret_string }}"
- register: result
-
- - name: assert correct keys are returned
- assert:
- that:
- - result.changed
-
- always:
- - name: remove secret
- aws_secret:
- name: "{{ secret_name }}"
- state: absent
- secret_type: 'string'
- secret: "{{ super_secret_string }}"
- recovery_window: 0
- ignore_errors: yes
-
- - name: remove lambda policy
- lambda_policy:
- state: absent
- function_name: "{{ lambda_name }}"
- statement_id: lambda-secretsmanager-test-policy
- action: lambda:InvokeFunction
- principal: secretsmanager.amazonaws.com
- ignore_errors: yes
-
- - name: remove dummy lambda
- lambda:
- name: "{{ lambda_name }}"
- state: absent
- zip_file: "{{ tmp.path }}/hello_world.zip"
- runtime: 'python2.7'
- role: "{{ secret_manager_role }}"
- handler: 'hello_world.lambda_handler'
- ignore_errors: yes
-
- # CI does not remove the IAM role
- - name: remove IAM role
- iam_role:
- name: "{{ secret_manager_role }}"
- assume_role_policy_document: "{{ lookup('file','secretsmanager-trust-policy.json') }}"
- state: absent
- create_instance_profile: no
- managed_policy:
- - 'arn:aws:iam::aws:policy/SecretsManagerReadWrite'
- ignore_errors: yes
-
- - name: remove temporary dir
- file:
- path: "{{ tmp.path }}"
- state: absent
+ - include_tasks: 'basic.yml'
+ # Permissions missing
+ #- include_tasks: 'rotation.yml'
diff --git a/tests/integration/targets/aws_secret/tasks/rotation.yml b/tests/integration/targets/aws_secret/tasks/rotation.yml
new file mode 100644
index 00000000000..823696dbcfc
--- /dev/null
+++ b/tests/integration/targets/aws_secret/tasks/rotation.yml
@@ -0,0 +1,191 @@
+---
+- module_defaults:
+ group/aws:
+ aws_access_key: "{{ aws_access_key }}"
+ aws_secret_key: "{{ aws_secret_key }}"
+ security_token: "{{ security_token | default(omit) }}"
+ region: "{{ aws_region }}"
+ collections:
+ - amazon.aws
+
+ block:
+ - name: retrieve caller facts
+ aws_caller_info:
+ register: test_caller_facts
+
+ - name: ensure IAM role exists
+ iam_role:
+ name: "{{ secret_manager_role }}"
+ assume_role_policy_document: "{{ lookup('file','secretsmanager-trust-policy.json') }}"
+ state: present
+ create_instance_profile: no
+ managed_policy:
+ - 'arn:aws:iam::aws:policy/SecretsManagerReadWrite'
+ register: iam_role
+ ignore_errors: yes
+
+ - name: wait 10 seconds for role to become available
+ pause:
+ seconds: 10
+ when: iam_role.changed
+
+ # CI does not remove the role and comparing policies has a bug on Python3; fall back to use iam_role_info
+ - name: get IAM role
+ iam_role_info:
+ name: "{{ secret_manager_role }}"
+ register: iam_role_info
+
+ - name: set iam_role_output
+ set_fact:
+ iam_role_output: "{{ iam_role_info.iam_roles[0] }}"
+ when: iam_role_info is defined
+
+ - name: create a temporary directory
+ tempfile:
+ state: directory
+ register: tmp
+
+ - name: move lambda into place for upload
+ copy:
+ src: "files/hello_world.zip"
+ dest: "{{ tmp.path }}/hello_world.zip"
+
+ - name: dummy lambda for testing
+ lambda:
+ name: "{{ lambda_name }}"
+ state: present
+ zip_file: "{{ tmp.path }}/hello_world.zip"
+ runtime: 'python2.7'
+ role: "{{ iam_role_output.arn }}"
+ handler: 'hello_world.lambda_handler'
+ register: lambda_output
+ until: not lambda_output.failed
+ retries: 10
+ delay: 5
+
+ - debug:
+ var: lambda_output
+
+ # ============================================================
+ # Creation/Deletion testing
+ # ============================================================
+ - name: add secret to AWS Secrets Manager
+ aws_secret:
+ name: "{{ secret_name }}-rotate"
+ state: present
+ secret_type: 'string'
+ secret: "{{ super_secret_string }}"
+ register: result
+
+ - name: assert correct keys are returned
+ assert:
+ that:
+ - result.changed
+ - result.arn is not none
+ - result.name is not none
+ - result.tags is not none
+ - result.version_ids_to_stages is not none
+
+ - name: lambda policy for secrets manager
+ lambda_policy:
+ state: present
+ function_name: "{{ lambda_name }}"
+ statement_id: LambdaSecretsManagerTestPolicy
+ action: 'lambda:InvokeFunction'
+ principal: "secretsmanager.amazonaws.com"
+
+ - name: add rotation lambda to secret
+ aws_secret:
+ name: "{{ secret_name }}-rotate"
+ description: 'this is a change to this secret'
+ state: present
+ secret_type: 'string'
+ secret: "{{ super_secret_string }}"
+ rotation_lambda: "arn:aws:lambda:{{ aws_region }}:{{ test_caller_facts.account }}:function:{{ lambda_name }}"
+ register: result
+ retries: 100
+ delay: 5
+ until: not result.failed
+
+ - name: assert correct keys are returned
+ assert:
+ that:
+ - result.changed
+
+ - name: remove rotation lambda from secret
+ aws_secret:
+ name: "{{ secret_name }}-rotate"
+ description: 'this is a change to this secret'
+ state: present
+ secret_type: 'string'
+ secret: "{{ super_secret_string }}"
+ register: result
+
+ - name: assert correct keys are returned
+ assert:
+ that:
+ - result.changed
+
+ - name: remove rotation lambda from secret
+ aws_secret:
+ name: "{{ secret_name }}-rotate"
+ description: 'this is a change to this secret'
+ state: present
+ secret_type: 'string'
+ secret: "{{ super_secret_string }}"
+ register: result
+
+ - name: assert correct keys are returned
+ assert:
+ that:
+ - not result.changed
+
+ - name: remove secret
+ aws_secret:
+ name: "{{ secret_name }}-rotate"
+ state: absent
+ recovery_window: 0
+ ignore_errors: yes
+
+ always:
+ - name: remove secret
+ aws_secret:
+ name: "{{ secret_name }}-rotate"
+ state: absent
+ recovery_window: 0
+ ignore_errors: yes
+
+ - name: remove lambda policy
+ lambda_policy:
+ state: absent
+ function_name: "{{ lambda_name }}"
+ statement_id: lambda-secretsmanager-test-policy
+ action: lambda:InvokeFunction
+ principal: secretsmanager.amazonaws.com
+ ignore_errors: yes
+
+ - name: remove dummy lambda
+ lambda:
+ name: "{{ lambda_name }}"
+ state: absent
+ zip_file: "{{ tmp.path }}/hello_world.zip"
+ runtime: 'python2.7'
+ role: "{{ secret_manager_role }}"
+ handler: 'hello_world.lambda_handler'
+ ignore_errors: yes
+
+ # CI does not remove the IAM role
+ - name: remove IAM role
+ iam_role:
+ name: "{{ secret_manager_role }}"
+ assume_role_policy_document: "{{ lookup('file','secretsmanager-trust-policy.json') }}"
+ state: absent
+ create_instance_profile: no
+ managed_policy:
+ - 'arn:aws:iam::aws:policy/SecretsManagerReadWrite'
+ ignore_errors: yes
+
+ - name: remove temporary dir
+ file:
+ path: "{{ tmp.path }}"
+ state: absent
diff --git a/tests/integration/targets/aws_ses_rule_set/defaults/main.yaml b/tests/integration/targets/aws_ses_rule_set/defaults/main.yaml
index 36351dfc9d6..53fbc388b20 100644
--- a/tests/integration/targets/aws_ses_rule_set/defaults/main.yaml
+++ b/tests/integration/targets/aws_ses_rule_set/defaults/main.yaml
@@ -1,6 +1,6 @@
---
-default_rule_set: "{{ resource_prefix | hash('md5') }}-default-rule-set"
-second_rule_set: "{{ resource_prefix | hash('md5') }}-second-rule-set"
+default_rule_set: "{{ tiny_prefix }}-default-rule-set"
+second_rule_set: "{{ tiny_prefix }}-second-rule-set"
# See comment in obtain-lock.yaml for definitions of these variables
max_obtain_lock_attempts: 10
diff --git a/tests/integration/targets/aws_step_functions_state_machine/defaults/main.yml b/tests/integration/targets/aws_step_functions_state_machine/defaults/main.yml
index b8d8d85dd1a..dd0965e8827 100644
--- a/tests/integration/targets/aws_step_functions_state_machine/defaults/main.yml
+++ b/tests/integration/targets/aws_step_functions_state_machine/defaults/main.yml
@@ -1,5 +1,4 @@
# the random_num is generated in a set_fact task at the start of the testsuite
-state_machine_name: "{{ resource_prefix | hash('md5') }}_step_function_{{ random_num }}"
-unique_id: "{{ resource_prefix | hash('md5') }}"
-step_functions_role_name: "ansible-test-{{ unique_id }}-step-function"
+state_machine_name: "{{ tiny_prefix }}_step_function_{{ random_num }}"
+step_functions_role_name: "ansible-test-{{ tiny_prefix }}-step-function"
execution_name: "{{ resource_prefix }}_sfn_execution"
diff --git a/tests/integration/targets/cloudformation_stack_set/playbooks/full_test.yml b/tests/integration/targets/cloudformation_stack_set/playbooks/full_test.yml
deleted file mode 100644
index 257e1e48a51..00000000000
--- a/tests/integration/targets/cloudformation_stack_set/playbooks/full_test.yml
+++ /dev/null
@@ -1,6 +0,0 @@
-- hosts: localhost
- connection: local
- environment: "{{ ansible_test.environment }}"
-
- roles:
- - ../../cloudformation_stack_set
diff --git a/tests/integration/targets/cloudformation_stack_set/runme.sh b/tests/integration/targets/cloudformation_stack_set/runme.sh
deleted file mode 100755
index d499c679b26..00000000000
--- a/tests/integration/targets/cloudformation_stack_set/runme.sh
+++ /dev/null
@@ -1,8 +0,0 @@
-#!/usr/bin/env bash
-
-set -eux
-
-# Run full test suite
-source virtualenv.sh
-pip install 'botocore>1.10.26' boto3
-ansible-playbook -i ../../inventory -v playbooks/full_test.yml "$@"
diff --git a/tests/integration/targets/dynamodb_table/aliases b/tests/integration/targets/dynamodb_table/aliases
new file mode 100644
index 00000000000..4ef4b2067d0
--- /dev/null
+++ b/tests/integration/targets/dynamodb_table/aliases
@@ -0,0 +1 @@
+cloud/aws
diff --git a/tests/integration/targets/dynamodb_table/defaults/main.yml b/tests/integration/targets/dynamodb_table/defaults/main.yml
new file mode 100644
index 00000000000..96df5538146
--- /dev/null
+++ b/tests/integration/targets/dynamodb_table/defaults/main.yml
@@ -0,0 +1,72 @@
+---
+table_name: "{{ resource_prefix }}"
+table_name_on_demand: "{{ resource_prefix }}-pay-per-request"
+
+table_index: "id"
+table_index_type: "NUMBER"
+
+range_index: "variety"
+range_index_type: "STRING"
+
+indexes:
+ - name: NamedIndex
+ type: global_include
+ hash_key_name: idx
+ range_key_name: create_time
+ includes:
+ - other_field
+ - other_field2
+ read_capacity: 10
+ write_capacity: 10
+ - name: AnotherIndex
+ type: global_all
+ hash_key_name: foo
+ range_key_name: bar
+ includes:
+ - another_field
+ - another_field2
+ read_capacity: 5
+ write_capacity: 5
+
+indexes_pay_per_request:
+ - name: NamedIndex
+ type: global_include
+ hash_key_name: idx
+ range_key_name: create_time
+ includes:
+ - other_field
+ - other_field2
+ - name: AnotherIndex
+ type: global_all
+ hash_key_name: foo
+ range_key_name: bar
+ includes:
+ - another_field
+ - another_field2
+
+index_updated:
+ - name: NamedIndex
+ type: global_include
+ read_capacity: 3
+ write_capacity: 3
+ - name: AnotherIndex
+ type: global_all
+ read_capacity: 4
+
+tags_default:
+ snake_case_key: snake_case_value
+ camelCaseKey: camelCaseValue
+ PascalCaseKey: PascalCaseValue
+ "key with spaces": value with spaces
+ "Upper With Spaces": Upper With Spaces
+
+partial_tags:
+ snake_case_key: snake_case_value
+ camelCaseKey: camelCaseValue
+
+updated_tags:
+ updated_snake_case_key: updated_snake_case_value
+ updatedCamelCaseKey: updatedCamelCaseValue
+ UpdatedPascalCaseKey: UpdatedPascalCaseValue
+ "updated key with spaces": updated value with spaces
+ "updated Upper With Spaces": Updated Upper With Spaces
diff --git a/tests/integration/targets/dynamodb_table/meta/main.yml b/tests/integration/targets/dynamodb_table/meta/main.yml
new file mode 100644
index 00000000000..07faa217762
--- /dev/null
+++ b/tests/integration/targets/dynamodb_table/meta/main.yml
@@ -0,0 +1,2 @@
+dependencies:
+ - prepare_tests
diff --git a/tests/integration/targets/dynamodb_table/tasks/main.yml b/tests/integration/targets/dynamodb_table/tasks/main.yml
new file mode 100644
index 00000000000..a5f3f7a3882
--- /dev/null
+++ b/tests/integration/targets/dynamodb_table/tasks/main.yml
@@ -0,0 +1,912 @@
+---
+# dynamodb_table integration tests
+#
+# Current module limitations:
+# - changed very flakey
+# - various parameters have defaults set so reset undefined value
+#
+- module_defaults:
+ group/aws:
+ aws_access_key: '{{ aws_access_key }}'
+ aws_secret_key: '{{ aws_secret_key }}'
+ security_token: '{{ security_token | default(omit) }}'
+ region: '{{ aws_region }}'
+ block:
+
+ - include: "test_pay_per_request.yml"
+
+ # ==============================================
+
+ - name: Create table - check_mode
+ dynamodb_table:
+ state: present
+ name: '{{ table_name }}'
+ hash_key_name: '{{ table_index }}'
+ hash_key_type: '{{ table_index_type }}'
+ register: create_table
+ check_mode: True
+
+ - name: Check results - Create table - check_mode
+ assert:
+ that:
+ - create_table is successful
+ - create_table is changed
+
+ - name: Create table
+ dynamodb_table:
+ state: present
+ name: '{{ table_name }}'
+ hash_key_name: '{{ table_index }}'
+ hash_key_type: '{{ table_index_type }}'
+ register: create_table
+
+ - name: Check results - Create table
+ assert:
+ that:
+ - create_table is successful
+ - create_table is changed
+ - '"hash_key_name" in create_table'
+ - '"hash_key_type" in create_table'
+ - '"indexes" in create_table'
+ - '"range_key_name" in create_table'
+ - '"range_key_type" in create_table'
+ - '"read_capacity" in create_table'
+ - '"region" in create_table'
+ - '"table_name" in create_table'
+ - '"table_status" in create_table'
+ - '"tags" in create_table'
+ - '"write_capacity" in create_table'
+ - create_table.hash_key_name == table_index
+ - create_table.hash_key_type == table_index_type
+ - create_table.indexes | length == 0
+ - create_table.range_key_name is none
+ # We used to return "STRING" even if there wasn't a key
+ - create_table.range_key_type is none
+ - create_table.read_capacity == 1
+ - create_table.table_name == table_name
+ - create_table.write_capacity == 1
+
+ - name: Create table - idempotent - check_mode
+ dynamodb_table:
+ state: present
+ name: '{{ table_name }}'
+ hash_key_name: '{{ table_index }}'
+ hash_key_type: '{{ table_index_type }}'
+ register: create_table
+ check_mode: True
+
+ - name: Check results - Create table - idempotent - check_mode
+ assert:
+ that:
+ - create_table is successful
+ - create_table is not changed
+
+ - name: Create table - idempotent
+ dynamodb_table:
+ state: present
+ name: '{{ table_name }}'
+ hash_key_name: '{{ table_index }}'
+ hash_key_type: '{{ table_index_type }}'
+ register: create_table
+
+ - name: Check results - Create table - idempotent
+ assert:
+ that:
+ - create_table is successful
+ - create_table is not changed
+ - '"hash_key_name" in create_table'
+ - '"hash_key_type" in create_table'
+ - '"indexes" in create_table'
+ - '"range_key_name" in create_table'
+ - '"range_key_type" in create_table'
+ - '"read_capacity" in create_table'
+ - '"region" in create_table'
+ - '"table_name" in create_table'
+ - '"table_status" in create_table'
+ - '"tags" in create_table'
+ - '"write_capacity" in create_table'
+ - create_table.hash_key_name == table_index
+ - create_table.hash_key_type == table_index_type
+ - create_table.indexes | length == 0
+ - create_table.range_key_name is none
+ # We used to return "STRING" even if there wasn't a key
+ - create_table.range_key_type is none
+ - create_table.read_capacity == 1
+ - create_table.table_name == table_name
+ - create_table.write_capacity == 1
+
+ # ==============================================
+
+ - name: Tag table - check_mode
+ dynamodb_table:
+ state: present
+ name: '{{ table_name }}'
+ tags: '{{ tags_default }}'
+ register: tag_table
+ check_mode: True
+
+ - name: Check results - Tag table - check_mode
+ assert:
+ that:
+ - tag_table is successful
+ - tag_table is changed
+
+ - name: Tag table
+ dynamodb_table:
+ state: present
+ name: '{{ table_name }}'
+ tags: '{{ tags_default }}'
+ register: tag_table
+
+ - name: Check results - Tag table
+ assert:
+ that:
+ - tag_table is successful
+ - tag_table is changed
+ - '"hash_key_name" in tag_table'
+ - '"hash_key_type" in tag_table'
+ - '"indexes" in tag_table'
+ - '"range_key_name" in tag_table'
+ - '"range_key_type" in tag_table'
+ - '"read_capacity" in tag_table'
+ - '"region" in tag_table'
+ - '"table_name" in tag_table'
+ - '"table_status" in tag_table'
+ - '"tags" in tag_table'
+ - '"write_capacity" in tag_table'
+ - tag_table.hash_key_name == table_index
+ - tag_table.hash_key_type == table_index_type
+ - tag_table.indexes | length == 0
+ - tag_table.range_key_name is none
+ # We used to return "STRING" even if there wasn't a key
+ - tag_table.range_key_type is none
+ - tag_table.read_capacity == 1
+ - tag_table.table_name == table_name
+ - tag_table.write_capacity == 1
+ - tag_table.tags == tags_default
+
+ - name: Tag table - idempotent - check_mode
+ dynamodb_table:
+ state: present
+ name: '{{ table_name }}'
+ tags: '{{ tags_default }}'
+ register: tag_table
+ check_mode: True
+
+ - name: Check results - Tag table - idempotent - check_mode
+ assert:
+ that:
+ - tag_table is successful
+ - tag_table is not changed
+
+ - name: Tag table - idempotent
+ dynamodb_table:
+ state: present
+ name: '{{ table_name }}'
+ tags: '{{ tags_default }}'
+ register: tag_table
+
+ - name: Check results - Tag table - idempotent
+ assert:
+ that:
+ - tag_table is successful
+ - tag_table is not changed
+ - '"hash_key_name" in tag_table'
+ - '"hash_key_type" in tag_table'
+ - '"indexes" in tag_table'
+ - '"range_key_name" in tag_table'
+ - '"range_key_type" in tag_table'
+ - '"read_capacity" in tag_table'
+ - '"region" in tag_table'
+ - '"table_name" in tag_table'
+ - '"table_status" in tag_table'
+ - '"tags" in tag_table'
+ - '"write_capacity" in tag_table'
+ - tag_table.hash_key_name == table_index
+ - tag_table.hash_key_type == table_index_type
+ - tag_table.indexes | length == 0
+ - tag_table.range_key_name is none
+ # We used to return "STRING" even if there wasn't a key
+ - tag_table.range_key_type is none
+ - tag_table.read_capacity == 1
+ - tag_table.table_name == table_name
+ - tag_table.write_capacity == 1
+ - tag_table.tags == tags_default
+
+ # ==============================================
+
+ - name: Update table read capacity - check_mode
+ dynamodb_table:
+ state: present
+ name: '{{ table_name }}'
+ read_capacity: 3
+ register: update_read
+ check_mode: True
+
+ - name: Check results - Update table read capacity - check_mode
+ assert:
+ that:
+ - update_read is successful
+ - update_read is changed
+
+ - name: Update table read capacity
+ dynamodb_table:
+ state: present
+ name: '{{ table_name }}'
+ read_capacity: 3
+ register: update_read
+
+ - name: Check results - Update table read capacity
+ assert:
+ that:
+ - update_read is successful
+ - update_read is changed
+ - '"hash_key_name" in update_read'
+ - '"hash_key_type" in update_read'
+ - '"indexes" in update_read'
+ - '"range_key_name" in update_read'
+ - '"range_key_type" in update_read'
+ - '"read_capacity" in update_read'
+ - '"region" in update_read'
+ - '"table_name" in update_read'
+ - '"table_status" in update_read'
+ - '"tags" in update_read'
+ - '"write_capacity" in update_read'
+ - update_read.hash_key_name == table_index
+ - update_read.hash_key_type == table_index_type
+ - update_read.indexes | length == 0
+ - update_read.range_key_name is none
+ # We used to return "STRING" even if there wasn't a key
+ - update_read.range_key_type is none
+ - update_read.read_capacity == 3
+ - update_read.table_name == table_name
+ - update_read.write_capacity == 1
+ - update_read.tags == tags_default
+
+ - name: Update table read capacity - idempotent - check_mode
+ dynamodb_table:
+ state: present
+ name: '{{ table_name }}'
+ read_capacity: 3
+ register: update_read
+ check_mode: True
+
+ - name: Check results - Update table read capacity - idempotent - check_mode
+ assert:
+ that:
+ - update_read is successful
+ - update_read is not changed
+
+ - name: Update table read capacity - idempotent
+ dynamodb_table:
+ state: present
+ name: '{{ table_name }}'
+ read_capacity: 3
+ register: update_read
+
+ - name: Check results - Update table read capacity - idempotent
+ assert:
+ that:
+ - update_read is successful
+ - update_read is not changed
+ - '"hash_key_name" in update_read'
+ - '"hash_key_type" in update_read'
+ - '"indexes" in update_read'
+ - '"range_key_name" in update_read'
+ - '"range_key_type" in update_read'
+ - '"read_capacity" in update_read'
+ - '"region" in update_read'
+ - '"table_name" in update_read'
+ - '"table_status" in update_read'
+ - '"tags" in update_read'
+ - '"write_capacity" in update_read'
+ - update_read.hash_key_name == table_index
+ - update_read.hash_key_type == table_index_type
+ - update_read.indexes | length == 0
+ - update_read.range_key_name is none
+ # We used to return "STRING" even if there wasn't a key
+ - update_read.range_key_type is none
+ - update_read.read_capacity == 3
+ - update_read.table_name == table_name
+ - update_read.write_capacity == 1
+ - update_read.tags == tags_default
+
+ # ==============================================
+
+ - name: Update table write capacity - check_mode
+ dynamodb_table:
+ state: present
+ name: '{{ table_name }}'
+ write_capacity: 3
+ register: update_write
+ check_mode: True
+
+ - name: Check results - Update table write capacity - check_mode
+ assert:
+ that:
+ - update_write is successful
+ - update_write is changed
+
+ - name: Update table write capacity
+ dynamodb_table:
+ state: present
+ name: '{{ table_name }}'
+ write_capacity: 3
+ register: update_write
+
+ - name: Check results - Update table write capacity
+ assert:
+ that:
+ - update_write is successful
+ - update_write is changed
+ - '"hash_key_name" in update_write'
+ - '"hash_key_type" in update_write'
+ - '"indexes" in update_write'
+ - '"range_key_name" in update_write'
+ - '"range_key_type" in update_write'
+ - '"read_capacity" in update_write'
+ - '"region" in update_write'
+ - '"table_name" in update_write'
+ - '"table_status" in update_write'
+ - '"tags" in update_write'
+ - '"write_capacity" in update_write'
+ - update_write.hash_key_name == table_index
+ - update_write.hash_key_type == table_index_type
+ - update_write.indexes | length == 0
+ - update_write.range_key_name is none
+ # We used to return "STRING" even if there wasn't a key
+ - update_write.range_key_type is none
+ - update_write.read_capacity == 3
+ - update_write.table_name == table_name
+ - update_write.write_capacity == 3
+ - update_write.tags == tags_default
+
+ - name: Update table write capacity - idempotent - check_mode
+ dynamodb_table:
+ state: present
+ name: '{{ table_name }}'
+ write_capacity: 3
+ register: update_write
+ check_mode: True
+
+ - name: Check results - Update table write capacity - idempotent - check_mode
+ assert:
+ that:
+ - update_write is successful
+ - update_write is not changed
+
+ - name: Update table write capacity - idempotent
+ dynamodb_table:
+ state: present
+ name: '{{ table_name }}'
+ write_capacity: 3
+ register: update_write
+
+ - name: Check results - Update table write capacity - idempotent
+ assert:
+ that:
+ - update_write is successful
+ - update_write is not changed
+ - '"hash_key_name" in update_write'
+ - '"hash_key_type" in update_write'
+ - '"indexes" in update_write'
+ - '"range_key_name" in update_write'
+ - '"range_key_type" in update_write'
+ - '"read_capacity" in update_write'
+ - '"region" in update_write'
+ - '"table_name" in update_write'
+ - '"table_status" in update_write'
+ - '"tags" in update_write'
+ - '"write_capacity" in update_write'
+ - update_write.hash_key_name == table_index
+ - update_write.hash_key_type == table_index_type
+ - update_write.indexes | length == 0
+ - update_write.range_key_name is none
+ # We used to return "STRING" even if there wasn't a key
+ - update_write.range_key_type is none
+ - update_write.read_capacity == 3
+ - update_write.table_name == table_name
+ - update_write.write_capacity == 3
+ - update_write.tags == tags_default
+
+ # ==============================================
+ # Updating the indexes used to simply be ignored
+ # We've deprecated accepting this, but dropping
+ # support would be a breaking change.
+
+ - name: Update table add range index - check_mode
+ dynamodb_table:
+ state: present
+ name: '{{ table_name }}'
+ range_key_name: '{{ range_index }}'
+ range_key_type: '{{ range_index_type }}'
+ register: update_range_index
+ check_mode: True
+
+ - name: Check results - Update table add range index - check_mode
+ assert:
+ that:
+ - update_range_index is successful
+ # - update_range_index is changed
+
+ - name: Update table add range index
+ dynamodb_table:
+ state: present
+ name: '{{ table_name }}'
+ range_key_name: '{{ range_index }}'
+ range_key_type: '{{ range_index_type }}'
+ register: update_range_index
+
+ - name: Check results - Update table add range index
+ assert:
+ that:
+ - update_range_index is successful
+ # - update_range_index is changed
+ - '"hash_key_name" in update_range_index'
+ - '"hash_key_type" in update_range_index'
+ - '"indexes" in update_range_index'
+ - '"range_key_name" in update_range_index'
+ - '"range_key_type" in update_range_index'
+ - '"read_capacity" in update_range_index'
+ - '"region" in update_range_index'
+ - '"table_name" in update_range_index'
+ - '"table_status" in update_range_index'
+ - '"tags" in update_range_index'
+ - '"write_capacity" in update_range_index'
+ - update_range_index.hash_key_name == table_index
+ - update_range_index.hash_key_type == table_index_type
+ - update_range_index.indexes | length == 0
+ # - update_range_index.range_key_name == range_index
+ # - update_range_index.range_key_type == range_index_type
+ - update_range_index.read_capacity == 3
+ - update_range_index.table_name == table_name
+ - update_range_index.write_capacity == 3
+ - update_range_index.tags == tags_default
+
+ - name: Update table add range index - idempotent - check_mode
+ dynamodb_table:
+ state: present
+ name: '{{ table_name }}'
+ range_key_name: '{{ range_index }}'
+ range_key_type: '{{ range_index_type }}'
+ register: update_range_index
+ check_mode: True
+
+ - name: Check results - Update table add range index - idempotent - check_mode
+ assert:
+ that:
+ - update_range_index is successful
+ # - update_range_index is not changed
+
+ - name: Update table add range index - idempotent
+ dynamodb_table:
+ state: present
+ name: '{{ table_name }}'
+ range_key_name: '{{ range_index }}'
+ range_key_type: '{{ range_index_type }}'
+ register: update_range_index
+
+ - name: Check results - Update table add range index - idempotent
+ assert:
+ that:
+ - update_range_index is successful
+ # - update_range_index is not changed
+ - '"hash_key_name" in update_range_index'
+ - '"hash_key_type" in update_range_index'
+ - '"indexes" in update_range_index'
+ - '"range_key_name" in update_range_index'
+ - '"range_key_type" in update_range_index'
+ - '"read_capacity" in update_range_index'
+ - '"region" in update_range_index'
+ - '"table_name" in update_range_index'
+ - '"table_status" in update_range_index'
+ - '"tags" in update_range_index'
+ - '"write_capacity" in update_range_index'
+ - update_range_index.hash_key_name == table_index
+ - update_range_index.hash_key_type == table_index_type
+ - update_range_index.indexes | length == 0
+ # - update_range_index.range_key_name == range_index
+ # - update_range_index.range_key_type == range_index_type
+ - update_range_index.read_capacity == 3
+ - update_range_index.table_name == table_name
+ - update_range_index.write_capacity == 3
+ - update_range_index.tags == tags_default
+
+ # ==============================================
+
+ - name: Update table add indexes - check_mode
+ dynamodb_table:
+ state: present
+ name: '{{ table_name }}'
+ indexes: '{{ indexes }}'
+ register: update_indexes
+ check_mode: True
+
+ - name: Check results - Update table add indexes - check_mode
+ assert:
+ that:
+ - update_indexes is successful
+ - update_indexes is changed
+
+ - name: Update table add indexes
+ dynamodb_table:
+ state: present
+ name: '{{ table_name }}'
+ indexes: '{{ indexes }}'
+ register: update_indexes
+
+ - name: Check results - Update table add indexes
+ assert:
+ that:
+ - update_indexes is successful
+ - update_indexes is changed
+ - '"hash_key_name" in update_indexes'
+ - '"hash_key_type" in update_indexes'
+ - '"indexes" in update_indexes'
+ - '"range_key_name" in update_indexes'
+ - '"range_key_type" in update_indexes'
+ - '"read_capacity" in update_indexes'
+ - '"region" in update_indexes'
+ - '"table_name" in update_indexes'
+ - '"table_status" in update_indexes'
+ - '"tags" in update_indexes'
+ - '"write_capacity" in update_indexes'
+ - update_indexes.hash_key_name == table_index
+ - update_indexes.hash_key_type == table_index_type
+ - update_indexes.indexes | length == 2
+ # - update_indexes.range_key_name == range_index
+ # - update_indexes.range_key_type == range_index_type
+ - update_indexes.read_capacity == 3
+ - update_indexes.table_name == table_name
+ - update_indexes.write_capacity == 3
+ - update_indexes.tags == tags_default
+
+ - name: Update table add indexes - idempotent - check_mode
+ dynamodb_table:
+ state: present
+ name: '{{ table_name }}'
+ indexes: '{{ indexes }}'
+ register: update_indexes
+ check_mode: True
+
+ - name: Check results - Update table add indexes - idempotent - check_mode
+ assert:
+ that:
+ - update_indexes is successful
+ - update_indexes is not changed
+
+ - name: Update table add indexes - idempotent
+ dynamodb_table:
+ state: present
+ name: '{{ table_name }}'
+ indexes: '{{ indexes }}'
+ register: update_indexes
+
+ - name: Check results - Update table add indexes - idempotent
+ assert:
+ that:
+ - update_indexes is successful
+ - update_indexes is not changed
+ - '"hash_key_name" in update_indexes'
+ - '"hash_key_type" in update_indexes'
+ - '"indexes" in update_indexes'
+ - '"range_key_name" in update_indexes'
+ - '"range_key_type" in update_indexes'
+ - '"read_capacity" in update_indexes'
+ - '"region" in update_indexes'
+ - '"table_name" in update_indexes'
+ - '"table_status" in update_indexes'
+ - '"tags" in update_indexes'
+ - '"write_capacity" in update_indexes'
+ - update_indexes.hash_key_name == table_index
+ - update_indexes.hash_key_type == table_index_type
+ - update_indexes.indexes | length == 2
+ # - update_indexes.range_key_name == range_index
+ # - update_indexes.range_key_type == range_index_type
+ - update_indexes.read_capacity == 3
+ - update_indexes.table_name == table_name
+ - update_indexes.write_capacity == 3
+ - update_indexes.tags == tags_default
+
+ # ==============================================
+
+ - name: Delete table - check_mode
+ dynamodb_table:
+ state: absent
+ name: '{{ table_name }}'
+ register: delete_table
+ check_mode: True
+
+ - name: Check results - Delete table - check_mode
+ assert:
+ that:
+ - delete_table is successful
+ - delete_table is changed
+
+ - name: Delete table
+ dynamodb_table:
+ state: absent
+ name: '{{ table_name }}'
+ register: delete_table
+
+ - name: Check results - Delete table
+ assert:
+ that:
+ - delete_table is successful
+ - delete_table is changed
+
+ - name: Delete table - idempotent - check_mode
+ dynamodb_table:
+ state: absent
+ name: '{{ table_name }}'
+ register: delete_table
+ check_mode: True
+
+ - name: Check results - Delete table - idempotent - check_mode
+ assert:
+ that:
+ - delete_table is successful
+ - delete_table is not changed
+
+ - name: Delete table - idempotent
+ dynamodb_table:
+ state: absent
+ name: '{{ table_name }}'
+ register: delete_table
+
+ - name: Check results - Delete table - idempotent
+ assert:
+ that:
+ - delete_table is successful
+ - delete_table is not changed
+
+ # ==============================================
+
+ - name: Create complex table - check_mode
+ dynamodb_table:
+ state: present
+ name: '{{ table_name }}'
+ hash_key_name: '{{ table_index }}'
+ hash_key_type: '{{ table_index_type }}'
+ range_key_name: '{{ range_index }}'
+ range_key_type: '{{ range_index_type }}'
+ read_capacity: 3
+ write_capacity: 3
+ tags: '{{ tags_default }}'
+ indexes: '{{ indexes }}'
+ register: create_complex_table
+ check_mode: True
+
+ - name: Check results - Create complex table - check_mode
+ assert:
+ that:
+ - create_complex_table is successful
+ - create_complex_table is changed
+
+ - name: Create complex table
+ dynamodb_table:
+ state: present
+ name: '{{ table_name }}'
+ hash_key_name: '{{ table_index }}'
+ hash_key_type: '{{ table_index_type }}'
+ range_key_name: '{{ range_index }}'
+ range_key_type: '{{ range_index_type }}'
+ read_capacity: 3
+ write_capacity: 3
+ tags: '{{ tags_default }}'
+ indexes: '{{ indexes }}'
+ register: create_complex_table
+
+ - name: Check results - Create complex table
+ assert:
+ that:
+ - create_complex_table is successful
+ - create_complex_table is changed
+ - '"hash_key_name" in create_complex_table'
+ - '"hash_key_type" in create_complex_table'
+ - '"indexes" in create_complex_table'
+ - '"range_key_name" in create_complex_table'
+ - '"range_key_type" in create_complex_table'
+ - '"read_capacity" in create_complex_table'
+ - '"region" in create_complex_table'
+ - '"table_name" in create_complex_table'
+ - '"table_status" in create_complex_table'
+ - '"tags" in create_complex_table'
+ - '"write_capacity" in create_complex_table'
+ - create_complex_table.hash_key_name == table_index
+ - create_complex_table.hash_key_type == table_index_type
+ - create_complex_table.indexes | length == 2
+ - create_complex_table.range_key_name == range_index
+ - create_complex_table.range_key_type == range_index_type
+ - create_complex_table.read_capacity == 3
+ - create_complex_table.table_name == table_name
+ - create_complex_table.write_capacity == 3
+ - create_complex_table.tags == tags_default
+
+ - name: Create complex table - idempotent - check_mode
+ dynamodb_table:
+ state: present
+ name: '{{ table_name }}'
+ hash_key_name: '{{ table_index }}'
+ hash_key_type: '{{ table_index_type }}'
+ range_key_name: '{{ range_index }}'
+ range_key_type: '{{ range_index_type }}'
+ read_capacity: 3
+ write_capacity: 3
+ tags: '{{ tags_default }}'
+ indexes: '{{ indexes }}'
+ register: create_complex_table
+ check_mode: True
+
+ - name: Check results - Create complex table - idempotent - check_mode
+ assert:
+ that:
+ - create_complex_table is successful
+ - create_complex_table is not changed
+
+ - name: Create complex table - idempotent
+ dynamodb_table:
+ state: present
+ name: '{{ table_name }}'
+ hash_key_name: '{{ table_index }}'
+ hash_key_type: '{{ table_index_type }}'
+ range_key_name: '{{ range_index }}'
+ range_key_type: '{{ range_index_type }}'
+ read_capacity: 3
+ write_capacity: 3
+ tags: '{{ tags_default }}'
+ indexes: '{{ indexes }}'
+ register: create_complex_table
+
+ - name: Check results - Create complex table - idempotent
+ assert:
+ that:
+ - create_complex_table is successful
+ - create_complex_table is not changed
+ - '"hash_key_name" in create_complex_table'
+ - '"hash_key_type" in create_complex_table'
+ - '"indexes" in create_complex_table'
+ - '"range_key_name" in create_complex_table'
+ - '"range_key_type" in create_complex_table'
+ - '"read_capacity" in create_complex_table'
+ - '"region" in create_complex_table'
+ - '"table_name" in create_complex_table'
+ - '"table_status" in create_complex_table'
+ - '"tags" in create_complex_table'
+ - '"write_capacity" in create_complex_table'
+ - create_complex_table.hash_key_name == table_index
+ - create_complex_table.hash_key_type == table_index_type
+ - create_complex_table.indexes | length == 2
+ - create_complex_table.range_key_name == range_index
+ - create_complex_table.range_key_type == range_index_type
+ - create_complex_table.read_capacity == 3
+ - create_complex_table.table_name == table_name
+ - create_complex_table.write_capacity == 3
+ - create_complex_table.tags == tags_default
+
+ # ==============================================
+
+ - name: Update table update index - check_mode
+ dynamodb_table:
+ state: present
+ name: '{{ table_name }}'
+ indexes: '{{ index_updated }}'
+ register: update_index
+ check_mode: True
+
+ - name: Check results - Update table update index - check_mode
+ assert:
+ that:
+ - update_index is successful
+ - update_index is changed
+
+ - name: Update table update index
+ dynamodb_table:
+ state: present
+ name: '{{ table_name }}'
+ indexes: '{{ index_updated }}'
+ register: update_index
+
+ - name: Check results - Update table update index
+ assert:
+ that:
+ - update_index is successful
+ - update_index is changed
+ - '"hash_key_name" in update_index'
+ - '"hash_key_type" in update_index'
+ - '"indexes" in update_index'
+ - '"range_key_name" in update_index'
+ - '"range_key_type" in update_index'
+ - '"read_capacity" in update_index'
+ - '"region" in update_index'
+ - '"table_name" in update_index'
+ - '"table_status" in update_index'
+ - '"tags" in update_index'
+ - '"write_capacity" in update_index'
+ - update_index.hash_key_name == table_index
+ - update_index.hash_key_type == table_index_type
+ - update_index.indexes | length == 2
+ - update_index.range_key_name == range_index
+ - update_index.range_key_type == range_index_type
+ - update_index.read_capacity == 3
+ - update_index.table_name == table_name
+ - update_index.write_capacity == 3
+ - update_index.tags == tags_default
+
+ - name: Pause to allow index to finish updating
+ pause:
+ seconds: 20
+
+ - name: Update table update index - idempotent - check_mode
+ dynamodb_table:
+ state: present
+ name: '{{ table_name }}'
+ indexes: '{{ index_updated }}'
+ register: update_index
+ check_mode: True
+
+ - name: Check results - Update table update index - idempotent - check_mode
+ assert:
+ that:
+ - update_index is successful
+ - update_index is not changed
+
+ - name: Update table update index - idempotent
+ dynamodb_table:
+ state: present
+ name: '{{ table_name }}'
+ indexes: '{{ index_updated }}'
+ register: update_index
+
+ - name: Check results - Update table update index - idempotent
+ assert:
+ that:
+ - update_index is successful
+ - update_index is not changed
+ - '"hash_key_name" in update_index'
+ - '"hash_key_type" in update_index'
+ - '"indexes" in update_index'
+ - '"range_key_name" in update_index'
+ - '"range_key_type" in update_index'
+ - '"read_capacity" in update_index'
+ - '"region" in update_index'
+ - '"table_name" in update_index'
+ - '"table_status" in update_index'
+ - '"tags" in update_index'
+ - '"write_capacity" in update_index'
+ - update_index.hash_key_name == table_index
+ - update_index.hash_key_type == table_index_type
+ - update_index.indexes | length == 2
+ - update_index.range_key_name == range_index
+ - update_index.range_key_type == range_index_type
+ - update_index.read_capacity == 3
+ - update_index.table_name == table_name
+ - update_index.write_capacity == 3
+ - update_index.tags == tags_default
+
+ # ==============================================
+
+ - name: Delete table
+ dynamodb_table:
+ state: absent
+ name: '{{ table_name }}'
+ register: delete_table
+
+ - name: Check results - Delete table
+ assert:
+ that:
+ - delete_table is successful
+ - delete_table is changed
+
+ always:
+
+ ################################################
+ # TEARDOWN STARTS HERE
+ ################################################
+
+ - name: Clean up table
+ dynamodb_table:
+ state: absent
+ name: '{{ table_name }}'
+ wait: false
+ register: delete_table
diff --git a/tests/integration/targets/dynamodb_table/tasks/test_pay_per_request.yml b/tests/integration/targets/dynamodb_table/tasks/test_pay_per_request.yml
new file mode 100644
index 00000000000..059561dea05
--- /dev/null
+++ b/tests/integration/targets/dynamodb_table/tasks/test_pay_per_request.yml
@@ -0,0 +1,114 @@
+---
+- name: Create table - pay-per-request - check_mode
+ dynamodb_table:
+ state: present
+ name: "{{ table_name_on_demand }}"
+ hash_key_name: "{{ table_index }}"
+ hash_key_type: "{{ table_index_type }}"
+ billing_mode: PAY_PER_REQUEST
+ register: create_table
+ check_mode: True
+
+- name: Check results - Create table - check_mode
+ assert:
+ that:
+ - create_table is successful
+ - create_table is changed
+
+- name: Create table - pay-per-request
+ dynamodb_table:
+ state: present
+ name: "{{ table_name_on_demand }}"
+ hash_key_name: "{{ table_index }}"
+ hash_key_type: "{{ table_index_type }}"
+ billing_mode: PAY_PER_REQUEST
+ register: create_table
+
+- name: Check results - Create table
+ assert:
+ that:
+ - create_table is successful
+ - create_table is changed
+ - create_table.billing_mode == "PAY_PER_REQUEST"
+
+# ==============================================
+
+- name: Create complex table - check_mode
+ dynamodb_table:
+ state: present
+ name: "{{ table_name_on_demand }}"
+ hash_key_name: "{{ table_index }}"
+ hash_key_type: "{{ table_index_type }}"
+ range_key_name: "{{ range_index }}"
+ range_key_type: "{{ range_index_type }}"
+ billing_mode: PAY_PER_REQUEST
+ tags: "{{ tags_default }}"
+ indexes: "{{ indexes_pay_per_request }}"
+ register: create_complex_table
+ check_mode: True
+
+- name: Check results - Create complex table - check_mode
+ assert:
+ that:
+ - create_complex_table is successful
+ - create_complex_table is changed
+
+- name: Create complex table
+ dynamodb_table:
+ state: present
+ name: "{{ table_name_on_demand }}"
+ hash_key_name: "{{ table_index }}"
+ hash_key_type: "{{ table_index_type }}"
+ billing_mode: PAY_PER_REQUEST
+ tags: "{{ tags_default }}"
+ indexes: "{{ indexes_pay_per_request }}"
+ register: create_complex_table
+
+- name: Check results - Create complex table
+ assert:
+ that:
+ - create_complex_table is successful
+ - create_complex_table is changed
+ - '"hash_key_name" in create_complex_table'
+ - '"hash_key_type" in create_complex_table'
+ - '"indexes" in create_complex_table'
+ - '"range_key_name" in create_complex_table'
+ - '"range_key_type" in create_complex_table'
+ - '"billing_mode" in create_complex_table'
+ - '"region" in create_complex_table'
+ - '"table_name" in create_complex_table'
+ - '"table_status" in create_complex_table'
+ - '"tags" in create_complex_table'
+ - create_complex_table.hash_key_name == table_index
+ - create_complex_table.hash_key_type == table_index_type
+ - create_complex_table.indexes | length == 2
+ - create_complex_table.table_name == table_name_on_demand
+ - create_complex_table.tags == tags_default
+
+- name: Update complex table billing_mode
+ dynamodb_table:
+ state: present
+ name: "{{ table_name_on_demand }}"
+ hash_key_name: "{{ table_index }}"
+ hash_key_type: "{{ table_index_type }}"
+ billing_mode: PROVISIONED
+ read_capacity: 1
+ write_capacity: 1
+ tags: "{{ tags_default }}"
+ indexes: "{{ indexes }}"
+ register: convert_complex_table
+
+- name: Check results - Update complex table billing_mode
+ assert:
+ that:
+ - convert_complex_table is successful
+ - convert_complex_table is changed
+ - '"billing_mode" in convert_complex_table'
+ - convert_complex_table.billing_mode == "PROVISIONED"
+
+- name: Delete table
+ dynamodb_table:
+ state: absent
+ name: "{{ table_name_on_demand }}"
+ wait: false
+ register: delete_table
diff --git a/tests/integration/targets/ec2_asg/tasks/main.yml b/tests/integration/targets/ec2_asg/tasks/main.yml
index 6c4b77b238e..7f196442904 100644
--- a/tests/integration/targets/ec2_asg/tasks/main.yml
+++ b/tests/integration/targets/ec2_asg/tasks/main.yml
@@ -1,54 +1,6 @@
---
# tasks file for test_ec2_asg
-- name: Test incomplete credentials with ec2_asg
- collections:
- - amazon.aws
-
- block:
-
- # ============================================================
-
- - name: test invalid profile
- ec2_asg:
- name: "{{ resource_prefix }}-asg"
- region: "{{ aws_region }}"
- profile: notavalidprofile
- ignore_errors: yes
- register: result
-
- - name:
- assert:
- that:
- - "'The config profile (notavalidprofile) could not be found' in result.msg"
-
- - name: test partial credentials
- ec2_asg:
- name: "{{ resource_prefix }}-asg"
- region: "{{ aws_region }}"
- aws_access_key: "{{ aws_access_key }}"
- ignore_errors: yes
- register: result
-
- - name:
- assert:
- that:
- - "'Partial credentials found in explicit, missing: aws_secret_access_key' in result.msg"
-
- - name: test without specifying region
- ec2_asg:
- name: "{{ resource_prefix }}-asg"
- aws_access_key: "{{ aws_access_key }}"
- aws_secret_key: "{{ aws_secret_key }}"
- security_token: "{{ security_token | default(omit) }}"
- ignore_errors: yes
- register: result
-
- - name:
- assert:
- that:
- - result.msg == 'The ec2_asg module requires a region and none was found in configuration, environment variables or module parameters'
-
# ============================================================
- name: Test incomplete arguments with ec2_asg
diff --git a/tests/integration/targets/ec2_eip/defaults/main.yml b/tests/integration/targets/ec2_eip/defaults/main.yml
index bbaeb04820c..03b1ba51de0 100644
--- a/tests/integration/targets/ec2_eip/defaults/main.yml
+++ b/tests/integration/targets/ec2_eip/defaults/main.yml
@@ -3,3 +3,4 @@
# run multiple copies of the test concurrently.
vpc_cidr: '10.{{ 256 | random(seed=resource_prefix) }}.0.0/16'
subnet_cidr: '10.{{ 256 | random(seed=resource_prefix) }}.42.0/24'
+subnet_az: '{{ ec2_availability_zone_names[0] }}'
diff --git a/tests/integration/targets/ec2_eip/meta/main.yml b/tests/integration/targets/ec2_eip/meta/main.yml
index 1f64f1169a9..930e8622824 100644
--- a/tests/integration/targets/ec2_eip/meta/main.yml
+++ b/tests/integration/targets/ec2_eip/meta/main.yml
@@ -1,3 +1,3 @@
dependencies:
- prepare_tests
- - setup_ec2
+ - setup_ec2_facts
diff --git a/tests/integration/targets/ec2_eip/tasks/main.yml b/tests/integration/targets/ec2_eip/tasks/main.yml
index 83093572697..48db1d1048a 100644
--- a/tests/integration/targets/ec2_eip/tasks/main.yml
+++ b/tests/integration/targets/ec2_eip/tasks/main.yml
@@ -17,9 +17,6 @@
- name: list available AZs
aws_az_info: null
register: region_azs
- - name: pick an AZ for testing
- set_fact:
- subnet_az: '{{ region_azs.availability_zones[0].zone_name }}'
- name: create a VPC
ec2_vpc_net:
name: '{{ resource_prefix }}-vpc'
@@ -40,12 +37,6 @@
state: present
vpc_id: '{{ vpc_result.vpc.id }}'
register: vpc_igw
- - name: "Find AMI to use"
- ec2_ami_info:
- owners: 'amazon'
- filters:
- name: 'amzn2-ami-hvm-2.0.20190612-x86_64-gp2'
- register: ec2_amis
- name: "create a security group"
ec2_group:
state: present
@@ -61,10 +52,11 @@
- name: Create instance for attaching
ec2_instance:
name: '{{ resource_prefix }}-instance'
- image_id: '{{ ec2_amis.images[0].image_id }}'
+ image_id: '{{ ec2_ami_id }}'
security_group: '{{ security_group.group_id }}'
vpc_subnet_id: '{{ vpc_subnet_create.subnet.id }}'
- wait: no ## Don't delay the tests, we'll check again before we need it
+ wait: yes
+ state: running
register: create_ec2_instance_result
# =====================================================
@@ -91,6 +83,7 @@
tags:
AnsibleEIPTest: Running
AnsibleEIPTestPrefix: '{{ resource_prefix }}'
+
# =====================================================
- name: Get current state of EIPs
ec2_eip_info: null
@@ -101,10 +94,14 @@
- eip_info_start is defined
- '"addresses" in eip_info_start'
- ( eip_info_start.addresses | length ) == ( eip_info_start | community.general.json_query("addresses[].association_id") | length )
+
- name: Allocate a new eip (no conditions)
ec2_eip:
state: present
+ tags:
+ AnsibleEIPTestPrefix: '{{ resource_prefix }}'
register: eip
+
- ec2_eip_info: null
register: eip_info
- assert:
@@ -114,6 +111,7 @@
- eip.public_ip is defined and ( eip.public_ip | ansible.netcommon.ipaddr )
- eip.allocation_id is defined and eip.allocation_id.startswith("eipalloc-")
- ( eip_info_start.addresses | length ) + 1 == ( eip_info.addresses | length )
+
- ec2_eip_info:
filters:
public-ip: '{{ eip.public_ip }}'
@@ -124,6 +122,9 @@
- eip_info.addresses[0].allocation_id == eip.allocation_id
- eip_info.addresses[0].domain == "vpc"
- eip_info.addresses[0].public_ip == eip.public_ip
+ - '"AnsibleEIPTestPrefix" in eip_info.addresses[0].tags'
+ - eip_info.addresses[0].tags['AnsibleEIPTestPrefix'] == resource_prefix
+
- ec2_eip_info:
filters:
allocation-id: '{{ eip.allocation_id }}'
@@ -134,6 +135,7 @@
- eip_info.addresses[0].allocation_id == eip.allocation_id
- eip_info.addresses[0].domain == "vpc"
- eip_info.addresses[0].public_ip == eip.public_ip
+
- name: Release eip
ec2_eip:
state: absent
@@ -146,6 +148,7 @@
- eip_release is defined
- eip_release is changed
- ( eip_info_start.addresses | length ) == ( eip_info.addresses | length )
+
- name: Allocate a new eip - attempt reusing unallocated ones (none available)
ec2_eip:
state: present
@@ -160,6 +163,7 @@
- eip.public_ip is defined and ( eip.public_ip | ansible.netcommon.ipaddr )
- eip.allocation_id is defined and eip.allocation_id.startswith("eipalloc-")
- ( eip_info_start.addresses | length ) + 1 == ( eip_info.addresses | length )
+
- name: Re-Allocate a new eip - attempt reusing unallocated ones (one available)
ec2_eip:
state: present
@@ -174,6 +178,7 @@
- reallocate_eip.public_ip is defined and ( reallocate_eip.public_ip | ansible.netcommon.ipaddr )
- reallocate_eip.allocation_id is defined and reallocate_eip.allocation_id.startswith("eipalloc-")
- ( eip_info_start.addresses | length ) + 1 == ( eip_info.addresses | length )
+
- name: Release eip
ec2_eip:
state: absent
@@ -186,6 +191,7 @@
- ( eip_info_start.addresses | length ) == ( eip_info.addresses | length )
- eip_release is defined
- eip_release is changed
+
- name: Allocate a new eip
ec2_eip:
state: present
@@ -199,6 +205,7 @@
- eip.public_ip is defined and ( eip.public_ip | ansible.netcommon.ipaddr )
- eip.allocation_id is defined and eip.allocation_id.startswith("eipalloc-")
- ( eip_info_start.addresses | length ) + 1 == ( eip_info.addresses | length )
+
- name: Match an existing eip (changed == false)
ec2_eip:
state: present
@@ -213,6 +220,7 @@
- reallocate_eip.public_ip is defined and ( reallocate_eip.public_ip | ansible.netcommon.ipaddr )
- reallocate_eip.allocation_id is defined and reallocate_eip.allocation_id.startswith("eipalloc-")
- ( eip_info_start.addresses | length ) + 1 == ( eip_info.addresses | length )
+
- name: Release eip
ec2_eip:
state: absent
@@ -225,6 +233,7 @@
- eip_release is defined
- eip_release is changed
- ( eip_info_start.addresses | length ) == ( eip_info.addresses | length )
+
- name: Allocate a new eip (no tags)
ec2_eip:
state: present
@@ -238,6 +247,7 @@
- eip.public_ip is defined and ( eip.public_ip | ansible.netcommon.ipaddr )
- eip.allocation_id is defined and eip.allocation_id.startswith("eipalloc-")
- ( eip_info_start.addresses | length ) + 1 == ( eip_info.addresses | length )
+
- name: attempt reusing an existing eip with a tag (No match available)
ec2_eip:
state: present
@@ -253,12 +263,14 @@
- no_tagged_eip.public_ip is defined and ( no_tagged_eip.public_ip | ansible.netcommon.ipaddr )
- no_tagged_eip.allocation_id is defined and no_tagged_eip.allocation_id.startswith("eipalloc-")
- ( eip_info_start.addresses | length ) + 2 == ( eip_info.addresses | length )
+
- name: tag eip so we can try matching it
- ec2_tag:
+ ec2_eip:
state: present
- resource: '{{ eip.allocation_id }}'
+ public_ip: '{{ eip.public_ip }}'
tags:
Team: Frontend
+
- name: attempt reusing an existing eip with a tag (Match available)
ec2_eip:
state: present
@@ -274,6 +286,7 @@
- reallocate_eip.public_ip is defined and ( reallocate_eip.public_ip | ansible.netcommon.ipaddr )
- reallocate_eip.allocation_id is defined and reallocate_eip.allocation_id.startswith("eipalloc-")
- ( eip_info_start.addresses | length ) + 2 == ( eip_info.addresses | length )
+
- name: attempt reusing an existing eip with a tag and it's value (no match available)
ec2_eip:
state: present
@@ -290,12 +303,14 @@
- backend_eip.public_ip is defined and ( backend_eip.public_ip | ansible.netcommon.ipaddr )
- backend_eip.allocation_id is defined and backend_eip.allocation_id.startswith("eipalloc-")
- ( eip_info_start.addresses | length ) + 3 == ( eip_info.addresses | length )
+
- name: tag eip so we can try matching it
- ec2_tag:
+ ec2_eip:
state: present
- resource: '{{ eip.allocation_id }}'
+ public_ip: '{{ eip.public_ip }}'
tags:
Team: Backend
+
- name: attempt reusing an existing eip with a tag and it's value (match available)
ec2_eip:
state: present
@@ -312,6 +327,7 @@
- reallocate_eip.public_ip is defined and reallocate_eip.public_ip != ""
- reallocate_eip.allocation_id is defined and reallocate_eip.allocation_id != ""
- ( eip_info_start.addresses | length ) + 3 == ( eip_info.addresses | length )
+
- name: Release backend_eip
ec2_eip:
state: absent
@@ -324,6 +340,7 @@
- eip_release is defined
- eip_release is changed
- ( eip_info_start.addresses | length ) + 2 == ( eip_info.addresses | length )
+
- name: Release no_tagged_eip
ec2_eip:
state: absent
@@ -336,6 +353,7 @@
- eip_release is defined
- eip_release is changed
- ( eip_info_start.addresses | length ) + 1 == ( eip_info.addresses | length )
+
- name: Release eip
ec2_eip:
state: absent
@@ -348,6 +366,7 @@
- eip_release is defined
- eip_release is changed
- ( eip_info_start.addresses | length ) == ( eip_info.addresses | length )
+
- name: allocate a new eip from a pool
ec2_eip:
state: present
@@ -362,14 +381,17 @@
- eip.public_ip is defined and ( eip.public_ip | ansible.netcommon.ipaddr )
- eip.allocation_id is defined and eip.allocation_id.startswith("eipalloc-")
- ( eip_info_start.addresses | length ) + 1 == ( eip_info.addresses | length )
+
- name: create ENI A
ec2_eni:
subnet_id: '{{ vpc_subnet_create.subnet.id }}'
register: eni_create_a
+
- name: create ENI B
ec2_eni:
subnet_id: '{{ vpc_subnet_create.subnet.id }}'
register: eni_create_b
+
- name: Attach EIP to ENI A
ec2_eip:
public_ip: '{{ eip.public_ip }}'
@@ -393,6 +415,7 @@
- eip_info.addresses[0].network_interface_id == eni_create_a.interface.id
- eip_info.addresses[0].private_ip_address is defined and ( eip_info.addresses[0].private_ip_address | ansible.netcommon.ipaddr )
- eip_info.addresses[0].network_interface_owner_id == caller_info.account
+
- name: Re-Attach EIP to ENI A (no change)
ec2_eip:
public_ip: '{{ eip.public_ip }}'
@@ -415,6 +438,7 @@
- eip_info.addresses[0].association_id is defined and eip_info.addresses[0].association_id.startswith("eipassoc-")
- eip_info.addresses[0].network_interface_id == eni_create_a.interface.id
- eip_info.addresses[0].private_ip_address is defined and ( eip_info.addresses[0].private_ip_address | ansible.netcommon.ipaddr )
+
- name: Attach EIP to ENI B (should fail, already associated)
ec2_eip:
public_ip: '{{ eip.public_ip }}'
@@ -436,6 +460,7 @@
- eip_info.addresses[0].association_id is defined and eip_info.addresses[0].association_id.startswith("eipassoc-")
- eip_info.addresses[0].network_interface_id == eni_create_a.interface.id
- eip_info.addresses[0].private_ip_address is defined and ( eip_info.addresses[0].private_ip_address | ansible.netcommon.ipaddr )
+
- name: Attach EIP to ENI B
ec2_eip:
public_ip: '{{ eip.public_ip }}'
@@ -459,6 +484,7 @@
- eip_info.addresses[0].association_id is defined and eip_info.addresses[0].association_id.startswith("eipassoc-")
- eip_info.addresses[0].network_interface_id == eni_create_b.interface.id
- eip_info.addresses[0].private_ip_address is defined and ( eip_info.addresses[0].private_ip_address | ansible.netcommon.ipaddr )
+
- name: Detach EIP from ENI B, without enabling release on disassociation
ec2_eip:
state: absent
@@ -474,6 +500,7 @@
- associate_eip is defined
- associate_eip is changed
- eip_info.addresses | length == 1
+
- name: Re-detach EIP from ENI B, without enabling release on disassociation
ec2_eip:
state: absent
@@ -489,6 +516,7 @@
- associate_eip is defined
- associate_eip is not changed
- eip_info.addresses | length == 1
+
- name: Attach EIP to ENI A
ec2_eip:
public_ip: '{{ eip.public_ip }}'
@@ -505,6 +533,7 @@
- associate_eip.public_ip is defined and eip.public_ip == associate_eip.public_ip
- associate_eip.allocation_id is defined and eip.allocation_id == associate_eip.allocation_id
- eip_info.addresses[0].network_interface_id == eni_create_a.interface.id
+
- name: Detach EIP from ENI A, enabling release on disassociation
ec2_eip:
state: absent
@@ -521,6 +550,7 @@
- associate_eip is defined
- associate_eip is changed
- eip_info.addresses | length == 0
+
- name: Re-detach EIP from ENI A, enabling release on disassociation
ec2_eip:
state: absent
@@ -537,28 +567,26 @@
- associate_eip is defined
- associate_eip is not changed
- eip_info.addresses | length == 0
+
- ec2_eip_info: null
register: eip_info
- assert:
that:
- ( eip_info_start.addresses | length ) == ( eip_info.addresses | length )
+
- name: Cleanup ENI B
ec2_eni:
state: absent
eni_id: '{{ eni_create_b.interface.id }}'
+
- name: Cleanup ENI A
ec2_eni:
state: absent
eni_id: '{{ eni_create_a.interface.id }}'
- - name: Make sure the instance is ready
- ec2_instance_info:
- filters:
- "tag:Name": '{{ resource_prefix }}-instance'
- register: instance_info
- until: instance_info.instances[0].state.name == 'running'
+
- name: Attach eip to an EC2 instance
ec2_eip:
- device_id: '{{ instance_info.instances[0].instance_id }}'
+ device_id: '{{ create_ec2_instance_result.instance_ids[0] }}'
state: present
release_on_disassociation: yes
register: instance_eip
@@ -570,11 +598,12 @@
that:
- instance_eip is success
- eip_info.addresses[0].allocation_id is defined
- - eip_info.addresses[0].instance_id == '{{ instance_info.instances[0].instance_id }}'
+ - eip_info.addresses[0].instance_id == '{{ create_ec2_instance_result.instance_ids[0] }}'
+
- name: Attach eip to an EC2 instance with private Ip specified
ec2_eip:
- device_id: '{{ instance_info.instances[0].instance_id }}'
- private_ip_address: '{{ instance_info.instances[0].private_ip_address }}'
+ device_id: '{{ create_ec2_instance_result.instance_ids[0] }}'
+ private_ip_address: '{{ create_ec2_instance_result.instances[0].private_ip_address }}'
state: present
release_on_disassociation: yes
register: instance_eip
@@ -586,12 +615,15 @@
that:
- instance_eip is success
- eip_info.addresses[0].allocation_id is defined
- - eip_info.addresses[0].instance_id == '{{ instance_info.instances[0].instance_id }}'
+ - eip_info.addresses[0].instance_id == '{{ create_ec2_instance_result.instance_ids[0] }}'
+
# =====================================================
+
- name: Cleanup instance
ec2_instance:
instance_ids: '{{ create_ec2_instance_result.instance_ids }}'
state: absent
+
- name: Cleanup instance eip
ec2_eip:
state: absent
@@ -600,26 +632,31 @@
retries: 5
delay: 5
until: eip_cleanup is successful
+
- name: Cleanup IGW
ec2_vpc_igw:
state: absent
vpc_id: '{{ vpc_result.vpc.id }}'
register: vpc_igw
+
- name: Cleanup security group
ec2_group:
state: absent
name: '{{ resource_prefix }}-sg'
+
- name: Cleanup Subnet
ec2_vpc_subnet:
state: absent
cidr: '{{ subnet_cidr }}'
vpc_id: '{{ vpc_result.vpc.id }}'
+
- name: Release eip
ec2_eip:
state: absent
public_ip: '{{ eip.public_ip }}'
register: eip_release
ignore_errors: true
+
- name: allocate a new eip
ec2_eip:
state: present
@@ -633,6 +670,129 @@
- eip.public_ip is defined and ( eip.public_ip | ansible.netcommon.ipaddr )
- eip.allocation_id is defined and eip.allocation_id.startswith("eipalloc-")
- ( eip_info_start.addresses | length ) + 1 == ( eip_info.addresses | length )
+
+ #############################################################################################
+
+ - name: Tag EIP
+ ec2_eip:
+ state: present
+ public_ip: '{{ eip.public_ip }}'
+ tags:
+ AnsibleEIPTestPrefix: '{{ resource_prefix }}'
+ another_tag: 'another Value {{ resource_prefix }}'
+ register: tag_eip
+ - ec2_eip_info: null
+ register: eip_info
+ - assert:
+ that:
+ - tag_eip is defined
+ - tag_eip is changed
+ - '"AnsibleEIPTestPrefix" in eip_info.addresses[0].tags'
+ - '"another_tag" in eip_info.addresses[0].tags'
+ - eip_info.addresses[0].tags['AnsibleEIPTestPrefix'] == resource_prefix
+ - eip_info.addresses[0].tags['another_tag'] == 'another Value ' + resource_prefix
+
+ - name: Tag EIP
+ ec2_eip:
+ state: present
+ public_ip: '{{ eip.public_ip }}'
+ tags:
+ AnsibleEIPTestPrefix: '{{ resource_prefix }}'
+ another_tag: 'another Value {{ resource_prefix }}'
+ register: tag_eip
+ - ec2_eip_info: null
+ register: eip_info
+ - assert:
+ that:
+ - tag_eip is defined
+ - tag_eip is not changed
+ - '"AnsibleEIPTestPrefix" in eip_info.addresses[0].tags'
+ - '"another_tag" in eip_info.addresses[0].tags'
+ - eip_info.addresses[0].tags['AnsibleEIPTestPrefix'] == resource_prefix
+ - eip_info.addresses[0].tags['another_tag'] == 'another Value ' + resource_prefix
+
+ - name: Add another Tag
+ ec2_eip:
+ state: present
+ public_ip: '{{ eip.public_ip }}'
+ tags:
+ "third tag": 'Third tag - {{ resource_prefix }}'
+ purge_tags: False
+ register: tag_eip
+ - ec2_eip_info: null
+ register: eip_info
+ - assert:
+ that:
+ - tag_eip is defined
+ - tag_eip is changed
+ - '"AnsibleEIPTestPrefix" in eip_info.addresses[0].tags'
+ - '"another_tag" in eip_info.addresses[0].tags'
+ - '"third tag" in eip_info.addresses[0].tags'
+ - eip_info.addresses[0].tags['AnsibleEIPTestPrefix'] == resource_prefix
+ - eip_info.addresses[0].tags['another_tag'] == 'another Value ' + resource_prefix
+ - eip_info.addresses[0].tags['third tag'] == 'Third tag - ' + resource_prefix
+
+ - name: Add another Tag
+ ec2_eip:
+ state: present
+ public_ip: '{{ eip.public_ip }}'
+ tags:
+ "third tag": 'Third tag - {{ resource_prefix }}'
+ purge_tags: False
+ register: tag_eip
+ - ec2_eip_info: null
+ register: eip_info
+ - assert:
+ that:
+ - tag_eip is defined
+ - tag_eip is not changed
+ - '"AnsibleEIPTestPrefix" in eip_info.addresses[0].tags'
+ - '"another_tag" in eip_info.addresses[0].tags'
+ - '"third tag" in eip_info.addresses[0].tags'
+ - eip_info.addresses[0].tags['AnsibleEIPTestPrefix'] == resource_prefix
+ - eip_info.addresses[0].tags['another_tag'] == 'another Value ' + resource_prefix
+ - eip_info.addresses[0].tags['third tag'] == 'Third tag - ' + resource_prefix
+
+ - name: Purge most tags
+ ec2_eip:
+ state: present
+ public_ip: '{{ eip.public_ip }}'
+ tags:
+ "third tag": 'Third tag - {{ resource_prefix }}'
+ purge_tags: True
+ register: tag_eip
+ - ec2_eip_info: null
+ register: eip_info
+ - assert:
+ that:
+ - tag_eip is defined
+ - tag_eip is changed
+ - '"AnsibleEIPTestPrefix" not in eip_info.addresses[0].tags'
+ - '"another_tag" not in eip_info.addresses[0].tags'
+ - '"third tag" in eip_info.addresses[0].tags'
+ - eip_info.addresses[0].tags['third tag'] == 'Third tag - ' + resource_prefix
+
+ - name: Purge most tags
+ ec2_eip:
+ state: present
+ public_ip: '{{ eip.public_ip }}'
+ tags:
+ "third tag": 'Third tag - {{ resource_prefix }}'
+ purge_tags: True
+ register: tag_eip
+ - ec2_eip_info: null
+ register: eip_info
+ - assert:
+ that:
+ - tag_eip is defined
+ - tag_eip is not changed
+ - '"AnsibleEIPTestPrefix" not in eip_info.addresses[0].tags'
+ - '"another_tag" not in eip_info.addresses[0].tags'
+ - '"third tag" in eip_info.addresses[0].tags'
+ - eip_info.addresses[0].tags['third tag'] == 'Third tag - ' + resource_prefix
+
+ #############################################################################################
+
- name: Release eip
ec2_eip:
state: absent
@@ -662,6 +822,25 @@
state: absent
name: '{{ resource_prefix }}-vpc'
cidr_block: '{{ vpc_cidr }}'
+
+ - name: Create an EIP outside a VPC
+ ec2_eip:
+ state: present
+ in_vpc: '{{ omit }}'
+ register: unbound_eip
+ - assert:
+ that:
+ - unbound_eip is successful
+ - unbound_eip is changed
+ - name: Release EIP
+ ec2_eip:
+ state: absent
+ public_ip: '{{ unbound_eip.public_ip }}'
+ register: release_unbound_eip
+ - assert:
+ that:
+ - release_unbound_eip is successful
+ - release_unbound_eip is changed
# =====================================================
always:
- name: Cleanup instance (by id)
@@ -735,6 +914,12 @@
public_ip: '{{ no_tagged_eip.public_ip }}'
when: no_tagged_eip is changed
ignore_errors: true
+ - name: Cleanup unbound_eip
+ ec2_eip:
+ state: absent
+ public_ip: '{{ unbound_eip.public_ip }}'
+ when: unbound_eip is changed
+ ignore_errors: true
- name: Cleanup VPC
ec2_vpc_net:
state: absent
diff --git a/tests/integration/targets/ec2_launch_template/defaults/main.yml b/tests/integration/targets/ec2_launch_template/defaults/main.yml
index fc011134986..5018ad56983 100644
--- a/tests/integration/targets/ec2_launch_template/defaults/main.yml
+++ b/tests/integration/targets/ec2_launch_template/defaults/main.yml
@@ -1,3 +1,3 @@
---
ec2_ami_name: amzn2-ami-hvm-2.*-x86_64-gp2
-test_role_name: ansible-test-{{ resource_prefix | hash('md5') }}
+test_role_name: ansible-test-{{ tiny_prefix }}
diff --git a/tests/integration/targets/ec2_launch_template/tasks/graceful_failure.yml b/tests/integration/targets/ec2_launch_template/tasks/graceful_failure.yml
deleted file mode 100644
index 208add29667..00000000000
--- a/tests/integration/targets/ec2_launch_template/tasks/graceful_failure.yml
+++ /dev/null
@@ -1,21 +0,0 @@
-- block:
- - name: create c4.large template (failure expected)
- ec2_launch_template:
- state: present
- name: "ansible-test-{{ resource_prefix | regex_search('([0-9]+)$') }}-tpl"
- instance_type: c4.large
- register: ec2_lt
- ignore_errors: yes
-
- - name: check that graceful error message is returned when creation with cpu_options and old botocore
- assert:
- that:
- - ec2_lt is failed
- - 'ec2_lt.msg == "ec2_launch_template requires boto3 >= 1.6.0"'
-
- always:
- - name: delete the c4.large template just in case it was created
- ec2_launch_template:
- state: absent
- name: "ansible-test-{{ resource_prefix | regex_search('([0-9]+)$') }}-tpl"
- ignore_errors: yes
diff --git a/tests/integration/targets/ec2_launch_template/tasks/main.yml b/tests/integration/targets/ec2_launch_template/tasks/main.yml
index 8aba8e918c0..813c0fdf211 100644
--- a/tests/integration/targets/ec2_launch_template/tasks/main.yml
+++ b/tests/integration/targets/ec2_launch_template/tasks/main.yml
@@ -6,32 +6,6 @@
security_token: "{{ security_token | default(omit) }}"
region: "{{ aws_region }}"
block:
-
- - set_fact:
- virtualenv: "{{ remote_tmp_dir }}/virtualenv"
- virtualenv_command: "{{ ansible_python_interpreter }} -m virtualenv"
-
- - set_fact:
- virtualenv_interpreter: "{{ virtualenv }}/bin/python"
-
- - pip:
- name: virtualenv
-
- - pip:
- name:
- - 'boto3<1.6.0'
- - botocore
- - boto
- - coverage<5
- - cryptography
- virtualenv: "{{ virtualenv }}"
- virtualenv_command: "{{ virtualenv_command }}"
- virtualenv_site_packages: no
-
- - include_tasks: graceful_failure.yml
- vars:
- ansible_python_interpreter: "{{ virtualenv_interpreter }}"
-
- name: Find AMI to use
ec2_ami_info:
owners: 'amazon'
@@ -46,9 +20,3 @@
- include_tasks: versions.yml
- include_tasks: instance-metadata.yml
- include_tasks: network_interfaces.yml
-
- always:
-
- - file:
- path: "{{ virtualenv }}"
- state: absent
diff --git a/tests/integration/targets/ec2_metric_alarm/tasks/main.yml b/tests/integration/targets/ec2_metric_alarm/tasks/main.yml
index e2980616ca3..1241655a9b9 100644
--- a/tests/integration/targets/ec2_metric_alarm/tasks/main.yml
+++ b/tests/integration/targets/ec2_metric_alarm/tasks/main.yml
@@ -12,12 +12,6 @@
- set_fact:
alarm_full_name: "{{ alarm_prefix }}-{{ resource_prefix }}-cpu-low"
- # until there's a module to get info about alarms, awscli is needed
- - name: install awscli
- pip:
- state: present
- name: awscli
-
- name: set up environment for testing.
include_tasks: env_setup.yml
diff --git a/tests/integration/targets/ec2_transit_gateway/tasks/main.yml b/tests/integration/targets/ec2_transit_gateway/tasks/main.yml
index 9c5f3947952..6cb279f7716 100644
--- a/tests/integration/targets/ec2_transit_gateway/tasks/main.yml
+++ b/tests/integration/targets/ec2_transit_gateway/tasks/main.yml
@@ -14,34 +14,6 @@
set_fact:
tgw_description: "{{ resource_prefix }}-tgw"
- - name: test create transit gateway without permissions
- ec2_transit_gateway:
- aws_access_key: '{{ omit }}'
- aws_secret_key: '{{ omit }}'
- security_token: '{{ omit }}'
- description: "{{ tgw_description }}"
- register: result
- ignore_errors: yes
-
- - name: assert nice message returned
- assert:
- that:
- - result is failed
- - "result.msg != 'MODULE FAILURE'"
-
- - name: test create transit gateway without region
- ec2_transit_gateway:
- description: "{{ tgw_description }}"
- region: '{{ omit }}'
- register: result
- ignore_errors: yes
-
- - name: assert failure when called with minimal parameters but no region
- assert:
- that:
- - 'result.failed'
- - 'result.msg.startswith("The ec2_transit_gateway module requires a region")'
-
- name: test create transit gateway without tags
ec2_transit_gateway:
description: "{{ tgw_description }}"
diff --git a/tests/integration/targets/ec2_vpc_endpoint/aliases b/tests/integration/targets/ec2_vpc_endpoint/aliases
deleted file mode 100644
index 506820fc14b..00000000000
--- a/tests/integration/targets/ec2_vpc_endpoint/aliases
+++ /dev/null
@@ -1,3 +0,0 @@
-cloud/aws
-disabled
-ec2_vpc_endpoint_info
diff --git a/tests/integration/targets/ec2_vpc_endpoint/defaults/main.yml b/tests/integration/targets/ec2_vpc_endpoint/defaults/main.yml
deleted file mode 100644
index f0041c402e5..00000000000
--- a/tests/integration/targets/ec2_vpc_endpoint/defaults/main.yml
+++ /dev/null
@@ -1,8 +0,0 @@
----
-vpc_name: '{{ resource_prefix }}-vpc'
-vpc_seed: '{{ resource_prefix }}'
-vpc_cidr: '10.{{ 256 | random(seed=vpc_seed) }}.22.0/24'
-
-# S3 and EC2 should generally be available...
-endpoint_service_a: 'com.amazonaws.{{ aws_region }}.s3'
-endpoint_service_b: 'com.amazonaws.{{ aws_region }}.ec2'
diff --git a/tests/integration/targets/ec2_vpc_endpoint/tasks/main.yml b/tests/integration/targets/ec2_vpc_endpoint/tasks/main.yml
deleted file mode 100644
index 0bd2beed8c5..00000000000
--- a/tests/integration/targets/ec2_vpc_endpoint/tasks/main.yml
+++ /dev/null
@@ -1,818 +0,0 @@
----
-- name: ec2_vpc_endpoint tests
- collections:
- - amazon.aws
-
- module_defaults:
- group/aws:
- aws_access_key: "{{ aws_access_key }}"
- aws_secret_key: "{{ aws_secret_key }}"
- security_token: "{{ security_token | default(omit) }}"
- region: "{{ aws_region }}"
- block:
- # ============================================================
- # BEGIN PRE-TEST SETUP
- - name: create a VPC
- ec2_vpc_net:
- state: present
- name: "{{ vpc_name }}"
- cidr_block: "{{ vpc_cidr }}"
- tags:
- AnsibleTest: 'ec2_vpc_endpoint'
- AnsibleRun: '{{ resource_prefix }}'
- register: vpc_creation
- - name: Assert success
- assert:
- that:
- - vpc_creation is successful
-
- - name: Create an IGW
- ec2_vpc_igw:
- vpc_id: "{{ vpc_creation.vpc.id }}"
- state: present
- tags:
- Name: "{{ resource_prefix }}"
- AnsibleTest: 'ec2_vpc_endpoint'
- AnsibleRun: '{{ resource_prefix }}'
- register: igw_creation
- - name: Assert success
- assert:
- that:
- - igw_creation is successful
-
- - name: Create a minimal route table (no routes)
- ec2_vpc_route_table:
- vpc_id: '{{ vpc_creation.vpc.id }}'
- tags:
- AnsibleTest: 'ec2_vpc_endpoint'
- AnsibleRun: '{{ resource_prefix }}'
- Name: '{{ resource_prefix }}-empty'
- subnets: []
- routes: []
- register: rtb_creation_empty
-
- - name: Create a minimal route table (with IGW)
- ec2_vpc_route_table:
- vpc_id: '{{ vpc_creation.vpc.id }}'
- tags:
- AnsibleTest: 'ec2_vpc_endpoint'
- AnsibleRun: '{{ resource_prefix }}'
- Name: '{{ resource_prefix }}-igw'
- subnets: []
- routes:
- - dest: 0.0.0.0/0
- gateway_id: "{{ igw_creation.gateway_id }}"
- register: rtb_creation_igw
-
- - name: Save VPC info in a fact
- set_fact:
- vpc_id: '{{ vpc_creation.vpc.id }}'
- rtb_empty_id: '{{ rtb_creation_empty.route_table.id }}'
- rtb_igw_id: '{{ rtb_creation_igw.route_table.id }}'
-
- # ============================================================
- # BEGIN TESTS
-
- # Minimal check_mode with _info
- - name: Fetch Endpoints in check_mode
- ec2_vpc_endpoint_info:
- query: endpoints
- register: endpoint_info
- check_mode: True
- - name: Assert success
- assert:
- that:
- # May be run in parallel, the only thing we can guarantee is
- # - we shouldn't error
- # - we should return 'vpc_endpoints' (even if it's empty)
- - endpoint_info is successful
- - '"vpc_endpoints" in endpoint_info'
-
- - name: Fetch Services in check_mode
- ec2_vpc_endpoint_info:
- query: services
- register: endpoint_info
- check_mode: True
- - name: Assert success
- assert:
- that:
- - endpoint_info is successful
- - '"service_names" in endpoint_info'
- # This is just 2 arbitrary AWS services that should (generally) be
- # available. The actual list will vary over time and between regions
- - endpoint_service_a in endpoint_info.service_names
- - endpoint_service_b in endpoint_info.service_names
-
- # Fetch services without check mode
- # Note: Filters not supported on services via this module, this is all we can test for now
- - name: Fetch Services
- ec2_vpc_endpoint_info:
- query: services
- register: endpoint_info
- - name: Assert success
- assert:
- that:
- - endpoint_info is successful
- - '"service_names" in endpoint_info'
- # This is just 2 arbitrary AWS services that should (generally) be
- # available. The actual list will vary over time and between regions
- - endpoint_service_a in endpoint_info.service_names
- - endpoint_service_b in endpoint_info.service_names
-
- # Attempt to create an endpoint
- - name: Create minimal endpoint (check mode)
- ec2_vpc_endpoint:
- state: present
- vpc_id: '{{ vpc_id }}'
- service: '{{ endpoint_service_a }}'
- register: create_endpoint_check
- check_mode: True
- - name: Assert changed
- assert:
- that:
- - create_endpoint_check is changed
-
- - name: Create minimal endpoint
- ec2_vpc_endpoint:
- state: present
- vpc_id: '{{ vpc_id }}'
- service: '{{ endpoint_service_a }}'
- wait: true
- register: create_endpoint
- - name: Check standard return values
- assert:
- that:
- - create_endpoint is changed
- - '"result" in create_endpoint'
- - '"creation_timestamp" in create_endpoint.result'
- - '"dns_entries" in create_endpoint.result'
- - '"groups" in create_endpoint.result'
- - '"network_interface_ids" in create_endpoint.result'
- - '"owner_id" in create_endpoint.result'
- - '"policy_document" in create_endpoint.result'
- - '"private_dns_enabled" in create_endpoint.result'
- - create_endpoint.result.private_dns_enabled == False
- - '"requester_managed" in create_endpoint.result'
- - create_endpoint.result.requester_managed == False
- - '"service_name" in create_endpoint.result'
- - create_endpoint.result.service_name == endpoint_service_a
- - '"state" in create_endpoint.result'
- - create_endpoint.result.state == "available"
- - '"vpc_endpoint_id" in create_endpoint.result'
- - create_endpoint.result.vpc_endpoint_id.startswith("vpce-")
- - '"vpc_endpoint_type" in create_endpoint.result'
- - create_endpoint.result.vpc_endpoint_type == "Gateway"
- - '"vpc_id" in create_endpoint.result'
- - create_endpoint.result.vpc_id == vpc_id
-
- - name: Save Endpoint info in a fact
- set_fact:
- endpoint_id: '{{ create_endpoint.result.vpc_endpoint_id }}'
-
- # Pull info about the endpoints
- - name: Fetch Endpoints (all)
- ec2_vpc_endpoint_info:
- query: endpoints
- register: endpoint_info
- - name: Assert success
- assert:
- that:
- # We're fetching all endpoints, there's no guarantee what the values
- # will be
- - endpoint_info is successful
- - '"vpc_endpoints" in endpoint_info'
- - '"creation_timestamp" in first_endpoint'
- - '"policy_document" in first_endpoint'
- - '"route_table_ids" in first_endpoint'
- - first_endpoint.route_table_ids | length == 0
- - '"service_name" in first_endpoint'
- - '"state" in first_endpoint'
- - '"vpc_endpoint_id" in first_endpoint'
- - '"vpc_id" in first_endpoint'
- # Not yet documented, but returned
- - '"dns_entries" in first_endpoint'
- - '"groups" in first_endpoint'
- - '"network_interface_ids" in first_endpoint'
- - '"owner_id" in first_endpoint'
- - '"private_dns_enabled" in first_endpoint'
- - '"requester_managed" in first_endpoint'
- - '"subnet_ids" in first_endpoint'
- - '"tags" in first_endpoint'
- - '"vpc_endpoint_type" in first_endpoint'
- # Make sure our endpoint is included
- - endpoint_id in ( endpoint_info | community.general.json_query("vpc_endpoints[*].vpc_endpoint_id") | list | flatten )
- vars:
- first_endpoint: '{{ endpoint_info.vpc_endpoints[0] }}'
-
- - name: Fetch Endpoints (targetted by ID)
- ec2_vpc_endpoint_info:
- query: endpoints
- vpc_endpoint_ids: '{{ endpoint_id }}'
- register: endpoint_info
- - name: Assert success
- assert:
- that:
- - endpoint_info is successful
- - '"vpc_endpoints" in endpoint_info'
- - '"creation_timestamp" in first_endpoint'
- - '"policy_document" in first_endpoint'
- - '"route_table_ids" in first_endpoint'
- - first_endpoint.route_table_ids | length == 0
- - '"service_name" in first_endpoint'
- - first_endpoint.service_name == endpoint_service_a
- - '"state" in first_endpoint'
- - first_endpoint.state == "available"
- - '"vpc_endpoint_id" in first_endpoint'
- - first_endpoint.vpc_endpoint_id == endpoint_id
- - '"vpc_id" in first_endpoint'
- - first_endpoint.vpc_id == vpc_id
- # Not yet documented, but returned
- - '"dns_entries" in first_endpoint'
- - '"groups" in first_endpoint'
- - '"network_interface_ids" in first_endpoint'
- - '"owner_id" in first_endpoint'
- - '"private_dns_enabled" in first_endpoint'
- - first_endpoint.private_dns_enabled == False
- - '"requester_managed" in first_endpoint'
- - first_endpoint.requester_managed == False
- - '"subnet_ids" in first_endpoint'
- - '"tags" in first_endpoint'
- - '"vpc_endpoint_type" in first_endpoint'
- vars:
- first_endpoint: '{{ endpoint_info.vpc_endpoints[0] }}'
-
- - name: Fetch Endpoints (targetted by VPC)
- ec2_vpc_endpoint_info:
- query: endpoints
- filters:
- vpc-id:
- - '{{ vpc_id }}'
- register: endpoint_info
- - name: Assert success
- assert:
- that:
- - endpoint_info is successful
- - '"vpc_endpoints" in endpoint_info'
- - '"creation_timestamp" in first_endpoint'
- - '"policy_document" in first_endpoint'
- - '"route_table_ids" in first_endpoint'
- - '"service_name" in first_endpoint'
- - first_endpoint.service_name == endpoint_service_a
- - '"state" in first_endpoint'
- - first_endpoint.state == "available"
- - '"vpc_endpoint_id" in first_endpoint'
- - first_endpoint.vpc_endpoint_id == endpoint_id
- - '"vpc_id" in first_endpoint'
- - first_endpoint.vpc_id == vpc_id
- # Not yet documented, but returned
- - '"dns_entries" in first_endpoint'
- - '"groups" in first_endpoint'
- - '"network_interface_ids" in first_endpoint'
- - '"owner_id" in first_endpoint'
- - '"private_dns_enabled" in first_endpoint'
- - first_endpoint.private_dns_enabled == False
- - '"requester_managed" in first_endpoint'
- - first_endpoint.requester_managed == False
- - '"subnet_ids" in first_endpoint'
- - '"tags" in first_endpoint'
- - '"vpc_endpoint_type" in first_endpoint'
- vars:
- first_endpoint: '{{ endpoint_info.vpc_endpoints[0] }}'
-
-
- # matches on parameters without explicitly passing the endpoint ID
- - name: Create minimal endpoint - idempotency (check mode)
- ec2_vpc_endpoint:
- state: present
- vpc_id: '{{ vpc_id }}'
- service: '{{ endpoint_service_a }}'
- register: create_endpoint_idem_check
- check_mode: True
- - assert:
- that:
- - create_endpoint_idem_check is not changed
-
- - name: Create minimal endpoint - idempotency
- ec2_vpc_endpoint:
- state: present
- vpc_id: '{{ vpc_id }}'
- service: '{{ endpoint_service_a }}'
- register: create_endpoint_idem
- - assert:
- that:
- - create_endpoint_idem is not changed
-
- - name: Delete minimal endpoint by ID (check_mode)
- ec2_vpc_endpoint:
- state: absent
- vpc_endpoint_id: "{{ endpoint_id }}"
- check_mode: true
- register: endpoint_delete_check
- - assert:
- that:
- - endpoint_delete_check is changed
-
-
- - name: Delete minimal endpoint by ID
- ec2_vpc_endpoint:
- state: absent
- vpc_endpoint_id: "{{ endpoint_id }}"
- register: endpoint_delete_check
- - assert:
- that:
- - endpoint_delete_check is changed
-
- - name: Delete minimal endpoint by ID - idempotency (check_mode)
- ec2_vpc_endpoint:
- state: absent
- vpc_endpoint_id: "{{ endpoint_id }}"
- check_mode: true
- register: endpoint_delete_check
- - assert:
- that:
- - endpoint_delete_check is not changed
-
- - name: Delete minimal endpoint by ID - idempotency
- ec2_vpc_endpoint:
- state: absent
- vpc_endpoint_id: "{{ endpoint_id }}"
- register: endpoint_delete_check
- - assert:
- that:
- - endpoint_delete_check is not changed
-
- - name: Fetch Endpoints by ID (expect failed)
- ec2_vpc_endpoint_info:
- query: endpoints
- vpc_endpoint_ids: "{{ endpoint_id }}"
- ignore_errors: True
- register: endpoint_info
- - name: Assert endpoint does not exist
- assert:
- that:
- - endpoint_info is successful
- - '"does not exist" in endpoint_info.msg'
- - endpoint_info.vpc_endpoints | length == 0
-
- # Attempt to create an endpoint with a route table
- - name: Create an endpoint with route table (check mode)
- ec2_vpc_endpoint:
- state: present
- vpc_id: '{{ vpc_id }}'
- service: '{{ endpoint_service_a }}'
- route_table_ids:
- - '{{ rtb_empty_id }}'
- register: create_endpoint_check
- check_mode: True
- - name: Assert changed
- assert:
- that:
- - create_endpoint_check is changed
-
- - name: Create an endpoint with route table
- ec2_vpc_endpoint:
- state: present
- vpc_id: '{{ vpc_id }}'
- service: '{{ endpoint_service_a }}'
- route_table_ids:
- - '{{ rtb_empty_id }}'
- wait: true
- register: create_rtb_endpoint
- - name: Check standard return values
- assert:
- that:
- - create_rtb_endpoint is changed
- - '"result" in create_rtb_endpoint'
- - '"creation_timestamp" in create_rtb_endpoint.result'
- - '"dns_entries" in create_rtb_endpoint.result'
- - '"groups" in create_rtb_endpoint.result'
- - '"network_interface_ids" in create_rtb_endpoint.result'
- - '"owner_id" in create_rtb_endpoint.result'
- - '"policy_document" in create_rtb_endpoint.result'
- - '"private_dns_enabled" in create_rtb_endpoint.result'
- - '"route_table_ids" in create_rtb_endpoint.result'
- - create_rtb_endpoint.result.route_table_ids | length == 1
- - create_rtb_endpoint.result.route_table_ids[0] == '{{ rtb_empty_id }}'
- - create_rtb_endpoint.result.private_dns_enabled == False
- - '"requester_managed" in create_rtb_endpoint.result'
- - create_rtb_endpoint.result.requester_managed == False
- - '"service_name" in create_rtb_endpoint.result'
- - create_rtb_endpoint.result.service_name == endpoint_service_a
- - '"state" in create_endpoint.result'
- - create_rtb_endpoint.result.state == "available"
- - '"vpc_endpoint_id" in create_rtb_endpoint.result'
- - create_rtb_endpoint.result.vpc_endpoint_id.startswith("vpce-")
- - '"vpc_endpoint_type" in create_rtb_endpoint.result'
- - create_rtb_endpoint.result.vpc_endpoint_type == "Gateway"
- - '"vpc_id" in create_rtb_endpoint.result'
- - create_rtb_endpoint.result.vpc_id == vpc_id
-
- - name: Save Endpoint info in a fact
- set_fact:
- rtb_endpoint_id: '{{ create_rtb_endpoint.result.vpc_endpoint_id }}'
-
- - name: Create an endpoint with route table - idempotency (check mode)
- ec2_vpc_endpoint:
- state: present
- vpc_id: '{{ vpc_id }}'
- service: '{{ endpoint_service_a }}'
- route_table_ids:
- - '{{ rtb_empty_id }}'
- register: create_endpoint_check
- check_mode: True
- - name: Assert changed
- assert:
- that:
- - create_endpoint_check is not changed
-
- - name: Create an endpoint with route table - idempotency
- ec2_vpc_endpoint:
- state: present
- vpc_id: '{{ vpc_id }}'
- service: '{{ endpoint_service_a }}'
- route_table_ids:
- - '{{ rtb_empty_id }}'
- register: create_endpoint_check
- check_mode: True
- - name: Assert changed
- assert:
- that:
- - create_endpoint_check is not changed
-
-# # Endpoint modifications are not yet supported by the module
-# # A Change the route table for the endpoint
-# - name: Change the route table for the endpoint (check_mode)
-# ec2_vpc_endpoint:
-# state: present
-# vpc_id: '{{ vpc_id }}'
-# vpc_endpoint_id: "{{ rtb_endpoint_id }}"
-# service: '{{ endpoint_service_a }}'
-# route_table_ids:
-# - '{{ rtb_igw_id }}'
-# check_mode: True
-# register: check_two_rtbs_endpoint
-#
-# - name: Assert second route table would be added
-# assert:
-# that:
-# - check_two_rtbs_endpoint.changed
-#
-# - name: Change the route table for the endpoint
-# ec2_vpc_endpoint:
-# state: present
-# vpc_id: '{{ vpc_id }}'
-# vpc_endpoint_id: "{{ rtb_endpoint_id }}"
-# service: '{{ endpoint_service_a }}'
-# route_table_ids:
-# - '{{ rtb_igw_id }}'
-# register: two_rtbs_endpoint
-#
-# - name: Assert second route table would be added
-# assert:
-# that:
-# - check_two_rtbs_endpoint.changed
-# - two_rtbs_endpoint.result.route_table_ids | length == 1
-# - two_rtbs_endpoint.result.route_table_ids[0] == '{{ rtb_igw_id }}'
-#
-# - name: Change the route table for the endpoint - idempotency (check_mode)
-# ec2_vpc_endpoint:
-# state: present
-# vpc_id: '{{ vpc_id }}'
-# vpc_endpoint_id: "{{ rtb_endpoint_id }}"
-# service: '{{ endpoint_service_a }}'
-# route_table_ids:
-# - '{{ rtb_igw_id }}'
-# check_mode: True
-# register: check_two_rtbs_endpoint
-#
-# - name: Assert route table would not change
-# assert:
-# that:
-# - not check_two_rtbs_endpoint.changed
-#
-# - name: Change the route table for the endpoint - idempotency
-# ec2_vpc_endpoint:
-# state: present
-# vpc_id: '{{ vpc_id }}'
-# vpc_endpoint_id: "{{ rtb_endpoint_id }}"
-# service: '{{ endpoint_service_a }}'
-# route_table_ids:
-# - '{{ rtb_igw_id }}'
-# register: two_rtbs_endpoint
-#
-# - name: Assert route table would not change
-# assert:
-# that:
-# - not check_two_rtbs_endpoint.changed
-
- - name: Tag the endpoint (check_mode)
- ec2_vpc_endpoint:
- state: present
- vpc_id: '{{ vpc_id }}'
- vpc_endpoint_id: "{{ rtb_endpoint_id }}"
- service: '{{ endpoint_service_a }}'
- route_table_ids:
- - '{{ rtb_empty_id }}'
- tags:
- camelCase: "helloWorld"
- PascalCase: "HelloWorld"
- snake_case: "hello_world"
- "Title Case": "Hello World"
- "lowercase spaced": "hello world"
- check_mode: true
- register: check_tag_vpc_endpoint
-
- - name: Assert tags would have changed
- assert:
- that:
- - check_tag_vpc_endpoint.changed
-
- - name: Tag the endpoint
- ec2_vpc_endpoint:
- state: present
- vpc_id: '{{ vpc_id }}'
- vpc_endpoint_id: "{{ rtb_endpoint_id }}"
- service: '{{ endpoint_service_a }}'
- route_table_ids:
- - '{{ rtb_igw_id }}'
- tags:
- testPrefix: '{{ resource_prefix }}'
- camelCase: "helloWorld"
- PascalCase: "HelloWorld"
- snake_case: "hello_world"
- "Title Case": "Hello World"
- "lowercase spaced": "hello world"
- register: tag_vpc_endpoint
-
- - name: Assert tags are successful
- assert:
- that:
- - tag_vpc_endpoint.changed
- - tag_vpc_endpoint.result.tags | length == 6
- - endpoint_tags["testPrefix"] == resource_prefix
- - endpoint_tags["camelCase"] == "helloWorld"
- - endpoint_tags["PascalCase"] == "HelloWorld"
- - endpoint_tags["snake_case"] == "hello_world"
- - endpoint_tags["Title Case"] == "Hello World"
- - endpoint_tags["lowercase spaced"] == "hello world"
- vars:
- endpoint_tags: "{{ tag_vpc_endpoint.result.tags | items2dict(key_name='Key', value_name='Value') }}"
-
- - name: Query by tag
- ec2_vpc_endpoint_info:
- query: endpoints
- filters:
- "tag:testPrefix":
- - "{{ resource_prefix }}"
- register: tag_result
-
- - name: Assert tag lookup found endpoint
- assert:
- that:
- - tag_result is successful
- - '"vpc_endpoints" in tag_result'
- - first_endpoint.vpc_endpoint_id == rtb_endpoint_id
- vars:
- first_endpoint: '{{ tag_result.vpc_endpoints[0] }}'
-
- - name: Tag the endpoint - idempotency (check_mode)
- ec2_vpc_endpoint:
- state: present
- vpc_id: '{{ vpc_id }}'
- vpc_endpoint_id: "{{ rtb_endpoint_id }}"
- service: '{{ endpoint_service_a }}'
- route_table_ids:
- - '{{ rtb_igw_id }}'
- tags:
- testPrefix: '{{ resource_prefix }}'
- camelCase: "helloWorld"
- PascalCase: "HelloWorld"
- snake_case: "hello_world"
- "Title Case": "Hello World"
- "lowercase spaced": "hello world"
- register: tag_vpc_endpoint_again
-
- - name: Assert tags would not change
- assert:
- that:
- - not tag_vpc_endpoint_again.changed
-
- - name: Tag the endpoint - idempotency
- ec2_vpc_endpoint:
- state: present
- vpc_id: '{{ vpc_id }}'
- vpc_endpoint_id: "{{ rtb_endpoint_id }}"
- service: '{{ endpoint_service_a }}'
- route_table_ids:
- - '{{ rtb_igw_id }}'
- tags:
- testPrefix: '{{ resource_prefix }}'
- camelCase: "helloWorld"
- PascalCase: "HelloWorld"
- snake_case: "hello_world"
- "Title Case": "Hello World"
- "lowercase spaced": "hello world"
- register: tag_vpc_endpoint_again
-
- - name: Assert tags would not change
- assert:
- that:
- - not tag_vpc_endpoint_again.changed
-
- - name: Add a tag (check_mode)
- ec2_vpc_endpoint:
- state: present
- vpc_id: '{{ vpc_id }}'
- vpc_endpoint_id: "{{ rtb_endpoint_id }}"
- service: '{{ endpoint_service_a }}'
- route_table_ids:
- - '{{ rtb_igw_id }}'
- tags:
- new_tag: "ANewTag"
- check_mode: true
- register: check_tag_vpc_endpoint
-
- - name: Assert tags would have changed
- assert:
- that:
- - check_tag_vpc_endpoint.changed
-
- - name: Add a tag (purge_tags=False)
- ec2_vpc_endpoint:
- state: present
- vpc_id: '{{ vpc_id }}'
- vpc_endpoint_id: "{{ rtb_endpoint_id }}"
- service: '{{ endpoint_service_a }}'
- route_table_ids:
- - '{{ rtb_igw_id }}'
- tags:
- new_tag: "ANewTag"
- register: add_tag_vpc_endpoint
-
- - name: Assert tags changed
- assert:
- that:
- - add_tag_vpc_endpoint.changed
- - add_tag_vpc_endpoint.result.tags | length == 7
- - endpoint_tags["testPrefix"] == resource_prefix
- - endpoint_tags["camelCase"] == "helloWorld"
- - endpoint_tags["PascalCase"] == "HelloWorld"
- - endpoint_tags["snake_case"] == "hello_world"
- - endpoint_tags["Title Case"] == "Hello World"
- - endpoint_tags["lowercase spaced"] == "hello world"
- - endpoint_tags["new_tag"] == "ANewTag"
- vars:
- endpoint_tags: "{{ add_tag_vpc_endpoint.result.tags | items2dict(key_name='Key', value_name='Value') }}"
-
- - name: Add a tag (purge_tags=True)
- ec2_vpc_endpoint:
- state: present
- vpc_id: '{{ vpc_id }}'
- vpc_endpoint_id: "{{ rtb_endpoint_id }}"
- service: '{{ endpoint_service_a }}'
- route_table_ids:
- - '{{ rtb_igw_id }}'
- tags:
- another_new_tag: "AnotherNewTag"
- purge_tags: True
- register: purge_tag_vpc_endpoint
-
- - name: Assert tags changed
- assert:
- that:
- - purge_tag_vpc_endpoint.changed
- - purge_tag_vpc_endpoint.result.tags | length == 1
- - endpoint_tags["another_new_tag"] == "AnotherNewTag"
- vars:
- endpoint_tags: "{{ purge_tag_vpc_endpoint.result.tags | items2dict(key_name='Key', value_name='Value') }}"
-
- - name: Delete minimal route table (no routes)
- ec2_vpc_route_table:
- state: absent
- lookup: id
- route_table_id: "{{ rtb_empty_id }}"
- register: rtb_delete
- - assert:
- that:
- - rtb_delete is changed
-
- - name: Delete minimal route table (IGW route)
- ec2_vpc_route_table:
- state: absent
- lookup: id
- route_table_id: "{{ rtb_igw_id }}"
- - assert:
- that:
- - rtb_delete is changed
-
- - name: Delete route table endpoint by ID
- ec2_vpc_endpoint:
- state: absent
- vpc_endpoint_id: "{{ rtb_endpoint_id }}"
- register: endpoint_delete_check
- - assert:
- that:
- - endpoint_delete_check is changed
-
- - name: Delete minimal endpoint by ID - idempotency (check_mode)
- ec2_vpc_endpoint:
- state: absent
- vpc_endpoint_id: "{{ rtb_endpoint_id }}"
- check_mode: true
- register: endpoint_delete_check
- - assert:
- that:
- - endpoint_delete_check is not changed
-
- - name: Delete endpoint by ID - idempotency
- ec2_vpc_endpoint:
- state: absent
- vpc_endpoint_id: "{{ endpoint_id }}"
- register: endpoint_delete_check
- - assert:
- that:
- - endpoint_delete_check is not changed
-
- - name: Create interface endpoint
- ec2_vpc_endpoint:
- state: present
- vpc_id: '{{ vpc_id }}'
- service: '{{ endpoint_service_a }}'
- vpc_endpoint_type: Interface
- register: create_interface_endpoint
- - name: Check that the interface endpoint was created properly
- assert:
- that:
- - create_interface_endpoint is changed
- - create_interface_endpoint.result.vpc_endpoint_type == "Interface"
- - name: Delete interface endpoint
- ec2_vpc_endpoint:
- state: absent
- vpc_endpoint_id: "{{ create_interface_endpoint.result.vpc_endpoint_id }}"
- register: interface_endpoint_delete_check
- - assert:
- that:
- - interface_endpoint_delete_check is changed
-
- # ============================================================
- # BEGIN POST-TEST CLEANUP
- always:
- # Delete the routes first - you can't delete an endpoint with a route
- # attached.
- - name: Delete minimal route table (no routes)
- ec2_vpc_route_table:
- state: absent
- lookup: id
- route_table_id: "{{ rtb_creation_empty.route_table.id }}"
- ignore_errors: True
-
- - name: Delete minimal route table (IGW route)
- ec2_vpc_route_table:
- state: absent
- lookup: id
- route_table_id: "{{ rtb_creation_igw.route_table.id }}"
- ignore_errors: True
-
- - name: Delete endpoint
- ec2_vpc_endpoint:
- state: absent
- vpc_endpoint_id: "{{ create_endpoint.result.vpc_endpoint_id }}"
- ignore_errors: True
-
- - name: Delete endpoint
- ec2_vpc_endpoint:
- state: absent
- vpc_endpoint_id: "{{ create_rtb_endpoint.result.vpc_endpoint_id }}"
- ignore_errors: True
-
- - name: Query any remain endpoints we created (idempotency work is ongoing) # FIXME
- ec2_vpc_endpoint_info:
- query: endpoints
- filters:
- vpc-id:
- - '{{ vpc_id }}'
- register: test_endpoints
-
- - name: Delete all endpoints
- ec2_vpc_endpoint:
- state: absent
- vpc_endpoint_id: '{{ item.vpc_endpoint_id }}'
- with_items: '{{ test_endpoints.vpc_endpoints }}'
- ignore_errors: True
-
- - name: Remove IGW
- ec2_vpc_igw:
- state: absent
- vpc_id: "{{ vpc_id }}"
- register: igw_deletion
- retries: 10
- delay: 5
- until: igw_deletion is success
- ignore_errors: yes
-
- - name: Remove VPC
- ec2_vpc_net:
- state: absent
- name: "{{ vpc_name }}"
- cidr_block: "{{ vpc_cidr }}"
- ignore_errors: true
diff --git a/tests/integration/targets/ec2_vpc_endpoint_service_info/aliases b/tests/integration/targets/ec2_vpc_endpoint_service_info/aliases
deleted file mode 100644
index 760a04f5d2b..00000000000
--- a/tests/integration/targets/ec2_vpc_endpoint_service_info/aliases
+++ /dev/null
@@ -1,2 +0,0 @@
-cloud/aws
-ec2_vpc_endpoint_service_info
diff --git a/tests/integration/targets/ec2_vpc_endpoint_service_info/defaults/main.yml b/tests/integration/targets/ec2_vpc_endpoint_service_info/defaults/main.yml
deleted file mode 100644
index 445cc7f3c52..00000000000
--- a/tests/integration/targets/ec2_vpc_endpoint_service_info/defaults/main.yml
+++ /dev/null
@@ -1,3 +0,0 @@
-search_service_names:
-- 'com.amazonaws.{{ aws_region }}.s3'
-- 'com.amazonaws.{{ aws_region }}.ec2'
diff --git a/tests/integration/targets/ec2_vpc_endpoint_service_info/tasks/main.yml b/tests/integration/targets/ec2_vpc_endpoint_service_info/tasks/main.yml
deleted file mode 100644
index 40eb0a88924..00000000000
--- a/tests/integration/targets/ec2_vpc_endpoint_service_info/tasks/main.yml
+++ /dev/null
@@ -1,139 +0,0 @@
----
-- module_defaults:
- group/aws:
- aws_access_key: '{{ aws_access_key }}'
- aws_secret_key: '{{ aws_secret_key }}'
- security_token: '{{ security_token | default(omit) }}'
- region: '{{ aws_region }}'
- # Needed until added to the group in Ansible 2.9
- ec2_vpc_endpoint_service_info:
- aws_access_key: '{{ aws_access_key }}'
- aws_secret_key: '{{ aws_secret_key }}'
- security_token: '{{ security_token | default(omit) }}'
- region: '{{ aws_region }}'
-
- block:
-
- - name: 'List all available services (Check Mode)'
- ec2_vpc_endpoint_service_info:
- check_mode: True
- register: services_check
-
- - name: 'Verify services (Check Mode)'
- vars:
- first_service: '{{ services_check.service_details[0] }}'
- assert:
- that:
- - services_check is successful
- - services_check is not changed
- - '"service_names" in services_check'
- - '"service_details" in services_check'
- - '"acceptance_required" in first_service'
- - '"availability_zones" in first_service'
- - '"base_endpoint_dns_names" in first_service'
- - '"manages_vpc_endpoints" in first_service'
- - '"owner" in first_service'
- - '"private_dns_name" in first_service'
- - '"private_dns_name_verification_state" in first_service'
- - '"service_id" in first_service'
- - '"service_name" in first_service'
- - '"service_type" in first_service'
- - '"tags" in first_service'
- - '"vpc_endpoint_policy_supported" in first_service'
-
- - name: 'List all available services'
- ec2_vpc_endpoint_service_info:
- register: services_info
-
- - name: 'Verify services'
- vars:
- first_service: '{{ services_info.service_details[0] }}'
- assert:
- that:
- - services_info is successful
- - services_info is not changed
- - '"service_names" in services_info'
- - '"service_details" in services_info'
- - '"acceptance_required" in first_service'
- - '"availability_zones" in first_service'
- - '"base_endpoint_dns_names" in first_service'
- - '"manages_vpc_endpoints" in first_service'
- - '"owner" in first_service'
- - '"private_dns_name" in first_service'
- - '"private_dns_name_verification_state" in first_service'
- - '"service_id" in first_service'
- - '"service_name" in first_service'
- - '"service_type" in first_service'
- - '"tags" in first_service'
- - '"vpc_endpoint_policy_supported" in first_service'
-
- - name: 'Limit services by name'
- ec2_vpc_endpoint_service_info:
- service_names: '{{ search_service_names }}'
- register: services_info
-
- - name: 'Verify services'
- vars:
- first_service: '{{ services_info.service_details[0] }}'
- # The same service sometimes pop up twice. s3 for example has
- # s3.us-east-1.amazonaws.com and s3.us-east-1.vpce.amazonaws.com which are
- # part of com.amazonaws.us-east-1.s3 so we need to run the results through
- # the unique filter to know if we've got what we think we have
- unique_names: '{{ services_info.service_names | unique | list }}'
- unique_detail_names: '{{ services_info.service_details | map(attribute="service_name") | unique | list }}'
- assert:
- that:
- - services_info is successful
- - services_info is not changed
- - '"service_names" in services_info'
- - (unique_names | length) == (search_service_names | length)
- - (unique_detail_names | length ) == (search_service_names | length)
- - (unique_names | difference(search_service_names) | length) == 0
- - (unique_detail_names | difference(search_service_names) | length) == 0
- - '"service_details" in services_info'
- - '"acceptance_required" in first_service'
- - '"availability_zones" in first_service'
- - '"base_endpoint_dns_names" in first_service'
- - '"manages_vpc_endpoints" in first_service'
- - '"owner" in first_service'
- - '"private_dns_name" in first_service'
- - '"private_dns_name_verification_state" in first_service'
- - '"service_id" in first_service'
- - '"service_name" in first_service'
- - '"service_type" in first_service'
- - '"tags" in first_service'
- - '"vpc_endpoint_policy_supported" in first_service'
-
- - name: 'Grab single service details to test filters'
- set_fact:
- example_service: '{{ services_info.service_details[0] }}'
-
- - name: 'Limit services by filter'
- ec2_vpc_endpoint_service_info:
- filters:
- service-name: '{{ example_service.service_name }}'
- register: filtered_service
-
- - name: 'Verify services'
- vars:
- first_service: '{{ filtered_service.service_details[0] }}'
- assert:
- that:
- - filtered_service is successful
- - filtered_service is not changed
- - '"service_names" in filtered_service'
- - filtered_service.service_names | length == 1
- - '"service_details" in filtered_service'
- - filtered_service.service_details | length == 1
- - '"acceptance_required" in first_service'
- - '"availability_zones" in first_service'
- - '"base_endpoint_dns_names" in first_service'
- - '"manages_vpc_endpoints" in first_service'
- - '"owner" in first_service'
- - '"private_dns_name" in first_service'
- - '"private_dns_name_verification_state" in first_service'
- - '"service_id" in first_service'
- - '"service_name" in first_service'
- - '"service_type" in first_service'
- - '"tags" in first_service'
- - '"vpc_endpoint_policy_supported" in first_service'
diff --git a/tests/integration/targets/ec2_vpc_igw/aliases b/tests/integration/targets/ec2_vpc_igw/aliases
deleted file mode 100644
index 877a442d752..00000000000
--- a/tests/integration/targets/ec2_vpc_igw/aliases
+++ /dev/null
@@ -1,3 +0,0 @@
-cloud/aws
-
-ec2_vpc_igw_info
diff --git a/tests/integration/targets/ec2_vpc_igw/defaults/main.yml b/tests/integration/targets/ec2_vpc_igw/defaults/main.yml
deleted file mode 100644
index eeda091c81c..00000000000
--- a/tests/integration/targets/ec2_vpc_igw/defaults/main.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-vpc_name: '{{ resource_prefix }}-vpc'
-vpc_seed: '{{ resource_prefix }}'
-vpc_cidr: '10.{{ 256 | random(seed=vpc_seed) }}.0.0/16'
diff --git a/tests/integration/targets/ec2_vpc_igw/tasks/main.yml b/tests/integration/targets/ec2_vpc_igw/tasks/main.yml
deleted file mode 100644
index 6697493127d..00000000000
--- a/tests/integration/targets/ec2_vpc_igw/tasks/main.yml
+++ /dev/null
@@ -1,571 +0,0 @@
----
-- name: ec2_vpc_igw tests
- collections:
- - amazon.aws
-
- module_defaults:
- group/aws:
- aws_access_key: "{{ aws_access_key }}"
- aws_secret_key: "{{ aws_secret_key }}"
- security_token: "{{ security_token | default(omit) }}"
- region: "{{ aws_region }}"
- block:
- # ============================================================
- - name: Fetch IGWs in check_mode
- ec2_vpc_igw_info:
- register: igw_info
- check_mode: True
-
- - name: Assert success
- assert:
- that:
- - igw_info is successful
- - '"internet_gateways" in igw_info'
-
- # ============================================================
- - name: create a VPC
- ec2_vpc_net:
- name: "{{ vpc_name }}"
- state: present
- cidr_block: "{{ vpc_cidr }}"
- tags:
- Name: "{{ resource_prefix }}-vpc"
- Description: "Created by ansible-test"
- register: vpc_result
-
- - name: Assert success
- assert:
- that:
- - vpc_result is successful
- - '"vpc" in vpc_result'
- - '"id" in vpc_result.vpc'
- - vpc_result.vpc.state == 'available'
- - '"tags" in vpc_result.vpc'
- - vpc_result.vpc.tags | length == 2
- - vpc_result.vpc.tags["Name"] == "{{ resource_prefix }}-vpc"
- - vpc_result.vpc.tags["Description"] == "Created by ansible-test"
-
- # ============================================================
- - name: Search for internet gateway by VPC - no matches
- ec2_vpc_igw_info:
- filters:
- attachment.vpc-id: '{{ vpc_result.vpc.id }}'
- register: igw_info
-
- - name: Assert success
- assert:
- that:
- - igw_info is successful
- - '"internet_gateways" in igw_info'
- - (igw_info.internet_gateways | length) == 0
-
- # ============================================================
- - name: create internet gateway (expected changed=true) - CHECK_MODE
- ec2_vpc_igw:
- state: present
- vpc_id: "{{ vpc_result.vpc.id }}"
- tags:
- tag_one: '{{ resource_prefix }} One'
- "Tag Two": 'two {{ resource_prefix }}'
- register: vpc_igw_create
- check_mode: yes
-
- - name: assert creation would happen (expected changed=true) - CHECK_MODE
- assert:
- that:
- - vpc_igw_create is changed
-
- - name: create internet gateway (expected changed=true)
- ec2_vpc_igw:
- state: present
- vpc_id: "{{ vpc_result.vpc.id }}"
- tags:
- tag_one: '{{ resource_prefix }} One'
- "Tag Two": 'two {{ resource_prefix }}'
- register: vpc_igw_create
-
- - name: assert creation happened (expected changed=true)
- assert:
- that:
- - vpc_igw_create is changed
- - 'vpc_igw_create.gateway_id.startswith("igw-")'
- - 'vpc_igw_create.vpc_id == vpc_result.vpc.id'
- - '"tags" in vpc_igw_create'
- - vpc_igw_create.tags | length == 2
- - vpc_igw_create.tags["tag_one"] == '{{ resource_prefix }} One'
- - vpc_igw_create.tags["Tag Two"] == 'two {{ resource_prefix }}'
- - '"gateway_id" in vpc_igw_create'
-
- # ============================================================
- - name: Save IDs for later
- set_fact:
- igw_id: '{{ vpc_igw_create.gateway_id }}'
- vpc_id: '{{ vpc_result.vpc.id }}'
-
- # ============================================================
- - name: Search for internet gateway by VPC
- ec2_vpc_igw_info:
- filters:
- attachment.vpc-id: '{{ vpc_id }}'
- register: igw_info
-
- - name: 'Check standard IGW details'
- assert:
- that:
- - '"internet_gateways" in igw_info'
- - igw_info.internet_gateways | length == 1
- - '"attachments" in current_igw'
- - current_igw.attachments | length == 1
- - '"state" in current_igw.attachments[0]'
- - current_igw.attachments[0].state == "available"
- - '"vpc_id" in current_igw.attachments[0]'
- - current_igw.attachments[0].vpc_id == vpc_id
- - '"internet_gateway_id" in current_igw'
- - current_igw.internet_gateway_id == igw_id
- - '"tags" in current_igw'
- - current_igw.tags | length == 2
- - '"key" in current_igw.tags[0]'
- - '"value" in current_igw.tags[0]'
- - '"key" in current_igw.tags[1]'
- - '"value" in current_igw.tags[1]'
- # Order isn't guaranteed in boto3 style, so just check the keys and
- # values we expect are in there.
- - current_igw.tags[0].key in ["tag_one", "Tag Two"]
- - current_igw.tags[1].key in ["tag_one", "Tag Two"]
- - current_igw.tags[0].value in [resource_prefix + " One", "two " + resource_prefix]
- - current_igw.tags[1].value in [resource_prefix + " One", "two " + resource_prefix]
- vars:
- current_igw: '{{ igw_info.internet_gateways[0] }}'
-
- # ============================================================
- - name: Fetch IGW by ID
- ec2_vpc_igw_info:
- internet_gateway_ids: '{{ igw_id }}'
- convert_tags: yes
- register: igw_info
-
- - name: 'Check standard IGW details'
- assert:
- that:
- - '"internet_gateways" in igw_info'
- - igw_info.internet_gateways | length == 1
- - '"attachments" in current_igw'
- - current_igw.attachments | length == 1
- - '"state" in current_igw.attachments[0]'
- - current_igw.attachments[0].state == "available"
- - '"vpc_id" in current_igw.attachments[0]'
- - current_igw.attachments[0].vpc_id == vpc_id
- - '"internet_gateway_id" in current_igw'
- - current_igw.internet_gateway_id == igw_id
- - '"tags" in current_igw'
- - current_igw.tags | length == 2
- - '"tag_one" in current_igw.tags'
- - '"Tag Two" in current_igw.tags'
- - current_igw.tags["tag_one"] == '{{ resource_prefix }} One'
- - current_igw.tags["Tag Two"] == 'two {{ resource_prefix }}'
- vars:
- current_igw: '{{ igw_info.internet_gateways[0] }}'
-
- # ============================================================
- - name: Fetch IGW by ID (list)
- ec2_vpc_igw_info:
- internet_gateway_ids:
- - '{{ igw_id }}'
- register: igw_info
-
- - name: 'Check standard IGW details'
- assert:
- that:
- - '"internet_gateways" in igw_info'
- - igw_info.internet_gateways | length == 1
- - '"attachments" in current_igw'
- - current_igw.attachments | length == 1
- - '"state" in current_igw.attachments[0]'
- - current_igw.attachments[0].state == "available"
- - '"vpc_id" in current_igw.attachments[0]'
- - current_igw.attachments[0].vpc_id == vpc_id
- - '"internet_gateway_id" in current_igw'
- - current_igw.internet_gateway_id == igw_id
- - '"tags" in current_igw'
- vars:
- current_igw: '{{ igw_info.internet_gateways[0] }}'
-
- # ============================================================
- - name: attempt to recreate internet gateway on VPC (expected changed=false) - CHECK_MODE
- ec2_vpc_igw:
- state: present
- vpc_id: "{{ vpc_result.vpc.id }}"
- register: vpc_igw_recreate
- check_mode: yes
-
- - name: assert recreation would do nothing (expected changed=false) - CHECK_MODE
- assert:
- that:
- - vpc_igw_recreate is not changed
- - vpc_igw_recreate.gateway_id == igw_id
- - vpc_igw_recreate.vpc_id == vpc_id
- - '"tags" in vpc_igw_create'
- - vpc_igw_create.tags | length == 2
- - vpc_igw_create.tags["tag_one"] == '{{ resource_prefix }} One'
- - vpc_igw_create.tags["Tag Two"] == 'two {{ resource_prefix }}'
-
- - name: attempt to recreate internet gateway on VPC (expected changed=false)
- ec2_vpc_igw:
- state: present
- vpc_id: "{{ vpc_result.vpc.id }}"
- register: vpc_igw_recreate
-
- - name: assert recreation did nothing (expected changed=false)
- assert:
- that:
- - vpc_igw_recreate is not changed
- - vpc_igw_recreate.gateway_id == igw_id
- - vpc_igw_recreate.vpc_id == vpc_id
- - '"tags" in vpc_igw_create'
- - vpc_igw_create.tags | length == 2
- - vpc_igw_create.tags["tag_one"] == '{{ resource_prefix }} One'
- - vpc_igw_create.tags["Tag Two"] == 'two {{ resource_prefix }}'
-
- # ============================================================
- - name: Update the tags (no change) - CHECK_MODE
- ec2_vpc_igw:
- state: present
- vpc_id: "{{ vpc_result.vpc.id }}"
- tags:
- tag_one: '{{ resource_prefix }} One'
- "Tag Two": 'two {{ resource_prefix }}'
- register: vpc_igw_recreate
- check_mode: yes
-
- - name: assert tag update would do nothing (expected changed=false) - CHECK_MODE
- assert:
- that:
- - vpc_igw_recreate is not changed
- - vpc_igw_recreate.gateway_id == igw_id
- - vpc_igw_recreate.vpc_id == vpc_id
- - '"tags" in vpc_igw_recreate'
- - vpc_igw_recreate.tags | length == 2
- - vpc_igw_recreate.tags["tag_one"] == '{{ resource_prefix }} One'
- - vpc_igw_recreate.tags["Tag Two"] == 'two {{ resource_prefix }}'
-
- - name: Update the tags (no change)
- ec2_vpc_igw:
- state: present
- vpc_id: "{{ vpc_result.vpc.id }}"
- tags:
- tag_one: '{{ resource_prefix }} One'
- "Tag Two": 'two {{ resource_prefix }}'
- register: vpc_igw_recreate
-
- - name: assert tag update did nothing (expected changed=false)
- assert:
- that:
- - vpc_igw_recreate is not changed
- - vpc_igw_recreate.gateway_id == igw_id
- - vpc_igw_recreate.vpc_id == vpc_id
- - '"tags" in vpc_igw_recreate'
- - vpc_igw_recreate.tags | length == 2
- - vpc_igw_recreate.tags["tag_one"] == '{{ resource_prefix }} One'
- - vpc_igw_recreate.tags["Tag Two"] == 'two {{ resource_prefix }}'
-
- # ============================================================
- - name: Update the tags - remove and add - CHECK_MODE
- ec2_vpc_igw:
- state: present
- vpc_id: "{{ vpc_result.vpc.id }}"
- tags:
- tag_three: '{{ resource_prefix }} Three'
- "Tag Two": 'two {{ resource_prefix }}'
- register: vpc_igw_update
- check_mode: yes
-
- - name: assert tag update would happen (expected changed=true) - CHECK_MODE
- assert:
- that:
- - vpc_igw_update is changed
- - vpc_igw_update.gateway_id == igw_id
- - vpc_igw_update.vpc_id == vpc_id
- - '"tags" in vpc_igw_update'
- - vpc_igw_update.tags | length == 2
- - vpc_igw_update.tags["tag_three"] == '{{ resource_prefix }} Three'
- - vpc_igw_update.tags["Tag Two"] == 'two {{ resource_prefix }}'
-
-
- - name: Update the tags - remove and add
- ec2_vpc_igw:
- state: present
- vpc_id: "{{ vpc_result.vpc.id }}"
- tags:
- tag_three: '{{ resource_prefix }} Three'
- "Tag Two": 'two {{ resource_prefix }}'
- register: vpc_igw_update
-
- - name: assert tags are updated (expected changed=true)
- assert:
- that:
- - vpc_igw_update is changed
- - vpc_igw_update.gateway_id == igw_id
- - vpc_igw_update.vpc_id == vpc_id
- - '"tags" in vpc_igw_update'
- - vpc_igw_update.tags | length == 2
- - vpc_igw_update.tags["tag_three"] == '{{ resource_prefix }} Three'
- - vpc_igw_update.tags["Tag Two"] == 'two {{ resource_prefix }}'
-
- # ============================================================
- - name: Update the tags add without purge - CHECK_MODE
- ec2_vpc_igw:
- state: present
- vpc_id: "{{ vpc_result.vpc.id }}"
- purge_tags: no
- tags:
- tag_one: '{{ resource_prefix }} One'
- register: vpc_igw_update
- check_mode: yes
-
- - name: assert tags would be added - CHECK_MODE
- assert:
- that:
- - vpc_igw_update is changed
- - vpc_igw_update.gateway_id == igw_id
- - vpc_igw_update.vpc_id == vpc_id
- - '"tags" in vpc_igw_update'
- - vpc_igw_update.tags | length == 3
- - vpc_igw_update.tags["tag_one"] == '{{ resource_prefix }} One'
- - vpc_igw_update.tags["tag_three"] == '{{ resource_prefix }} Three'
- - vpc_igw_update.tags["Tag Two"] == 'two {{ resource_prefix }}'
-
- - name: Update the tags add without purge
- ec2_vpc_igw:
- state: present
- vpc_id: "{{ vpc_result.vpc.id }}"
- purge_tags: no
- tags:
- tag_one: '{{ resource_prefix }} One'
- register: vpc_igw_update
-
- - name: assert tags added
- assert:
- that:
- - vpc_igw_update is changed
- - vpc_igw_update.gateway_id == igw_id
- - vpc_igw_update.vpc_id == vpc_id
- - '"tags" in vpc_igw_update'
- - vpc_igw_update.tags | length == 3
- - vpc_igw_update.tags["tag_one"] == '{{ resource_prefix }} One'
- - vpc_igw_update.tags["tag_three"] == '{{ resource_prefix }} Three'
- - vpc_igw_update.tags["Tag Two"] == 'two {{ resource_prefix }}'
-
-
- # ============================================================
- - name: Update with CamelCase tags - CHECK_MODE
- ec2_vpc_igw:
- state: present
- vpc_id: "{{ vpc_result.vpc.id }}"
- tags:
- "lowercase spaced": 'hello cruel world ❤️'
- "Title Case": 'Hello Cruel World ❤️'
- CamelCase: 'SimpleCamelCase ❤️'
- snake_case: 'simple_snake_case ❤️'
- register: vpc_igw_update
- check_mode: yes
-
- - name: assert tag update would happen (expected changed=true) - CHECK_MODE
- assert:
- that:
- - vpc_igw_update is changed
- - vpc_igw_update.gateway_id == igw_id
- - vpc_igw_update.vpc_id == vpc_id
- - '"tags" in vpc_igw_update'
- - vpc_igw_update.tags | length == 4
- - vpc_igw_update.tags["lowercase spaced"] == 'hello cruel world ❤️'
- - vpc_igw_update.tags["Title Case"] == 'Hello Cruel World ❤️'
- - vpc_igw_update.tags["CamelCase"] == 'SimpleCamelCase ❤️'
- - vpc_igw_update.tags["snake_case"] == 'simple_snake_case ❤️'
-
-
- - name: Update the tags - remove and add
- ec2_vpc_igw:
- state: present
- vpc_id: "{{ vpc_result.vpc.id }}"
- tags:
- "lowercase spaced": 'hello cruel world ❤️'
- "Title Case": 'Hello Cruel World ❤️'
- CamelCase: 'SimpleCamelCase ❤️'
- snake_case: 'simple_snake_case ❤️'
- register: vpc_igw_update
-
- - name: assert tags are updated (expected changed=true)
- assert:
- that:
- - vpc_igw_update is changed
- - vpc_igw_update.gateway_id == igw_id
- - vpc_igw_update.vpc_id == vpc_id
- - '"tags" in vpc_igw_update'
- - vpc_igw_update.tags | length == 4
- - vpc_igw_update.tags["lowercase spaced"] == 'hello cruel world ❤️'
- - vpc_igw_update.tags["Title Case"] == 'Hello Cruel World ❤️'
- - vpc_igw_update.tags["CamelCase"] == 'SimpleCamelCase ❤️'
- - vpc_igw_update.tags["snake_case"] == 'simple_snake_case ❤️'
-
- # ============================================================
- - name: Gather information about a filtered list of Internet Gateways using tags
- ec2_vpc_igw_info:
- filters:
- "tag:Title Case": 'Hello Cruel World ❤️'
- register: igw_info
-
- - name: Assert success
- assert:
- that:
- - igw_info is successful
- - '"internet_gateways" in igw_info'
- - igw_info.internet_gateways | selectattr("internet_gateway_id",'equalto',"{{ igw_id }}")
-
- - name: Gather information about a filtered list of Internet Gateways using tags - CHECK_MODE
- ec2_vpc_igw_info:
- filters:
- "tag:Title Case": 'Hello Cruel World ❤️'
- register: igw_info
- check_mode: yes
-
- - name: Assert success - CHECK_MODE
- assert:
- that:
- - igw_info is successful
- - '"internet_gateways" in igw_info'
- - igw_info.internet_gateways | selectattr("internet_gateway_id",'equalto',"{{ igw_id }}")
-
- # ============================================================
- - name: Gather information about a filtered list of Internet Gateways using tags (no match)
- ec2_vpc_igw_info:
- filters:
- "tag:tag_one": '{{ resource_prefix }} One'
- register: igw_info
-
- - name: Assert success
- assert:
- that:
- - igw_info is successful
- - '"internet_gateways" in igw_info'
- - igw_info.internet_gateways | length == 0
-
- - name: Gather information about a filtered list of Internet Gateways using tags (no match) - CHECK_MODE
- ec2_vpc_igw_info:
- filters:
- "tag:tag_one": '{{ resource_prefix }} One'
- register: igw_info
- check_mode: yes
-
- - name: Assert success - CHECK_MODE
- assert:
- that:
- - igw_info is successful
- - '"internet_gateways" in igw_info'
- - igw_info.internet_gateways | length == 0
-
- # ============================================================
- - name: Remove all tags - CHECK_MODE
- ec2_vpc_igw:
- state: present
- vpc_id: "{{ vpc_result.vpc.id }}"
- tags: {}
- register: vpc_igw_update
- check_mode: yes
-
- - name: assert tags would be removed - CHECK_MODE
- assert:
- that:
- - vpc_igw_update is changed
-
- - name: Remove all tags
- ec2_vpc_igw:
- state: present
- vpc_id: "{{ vpc_result.vpc.id }}"
- tags: {}
- register: vpc_igw_update
-
- - name: assert tags removed
- assert:
- that:
- - vpc_igw_update is changed
- - vpc_igw_update.gateway_id == igw_id
- - vpc_igw_update.vpc_id == vpc_id
- - '"tags" in vpc_igw_update'
- - vpc_igw_update.tags | length == 0
-
- # ============================================================
- - name: test state=absent (expected changed=true) - CHECK_MODE
- ec2_vpc_igw:
- state: absent
- vpc_id: "{{ vpc_result.vpc.id }}"
- register: vpc_igw_delete
- check_mode: yes
-
- - name: assert state=absent (expected changed=true) - CHECK_MODE
- assert:
- that:
- - vpc_igw_delete is changed
-
- - name: test state=absent (expected changed=true)
- ec2_vpc_igw:
- state: absent
- vpc_id: "{{ vpc_result.vpc.id }}"
- register: vpc_igw_delete
-
- - name: assert state=absent (expected changed=true)
- assert:
- that:
- - vpc_igw_delete is changed
-
- # ============================================================
- - name: Fetch IGW by ID (list)
- ec2_vpc_igw_info:
- internet_gateway_ids:
- - '{{ igw_id }}'
- register: igw_info
- ignore_errors: True
-
- - name: 'Check IGW does not exist'
- assert:
- that:
- # Deliberate choice not to change bevahiour when searching by ID
- - igw_info is failed
-
- # ============================================================
- - name: test state=absent when already deleted (expected changed=false) - CHECK_MODE
- ec2_vpc_igw:
- state: absent
- vpc_id: "{{ vpc_result.vpc.id }}"
- register: vpc_igw_delete
- check_mode: yes
-
- - name: assert state=absent (expected changed=false) - CHECK_MODE
- assert:
- that:
- - vpc_igw_delete is not changed
-
- - name: test state=absent when already deleted (expected changed=false)
- ec2_vpc_igw:
- state: absent
- vpc_id: "{{ vpc_result.vpc.id }}"
- register: vpc_igw_delete
-
- - name: assert state=absent (expected changed=false)
- assert:
- that:
- - vpc_igw_delete is not changed
-
- always:
- # ============================================================
- - name: tidy up IGW
- ec2_vpc_igw:
- state: absent
- vpc_id: "{{ vpc_result.vpc.id }}"
- ignore_errors: true
-
- - name: tidy up VPC
- ec2_vpc_net:
- name: "{{ vpc_name }}"
- state: absent
- cidr_block: "{{ vpc_cidr }}"
- ignore_errors: true
diff --git a/tests/integration/targets/ec2_vpc_nat_gateway/aliases b/tests/integration/targets/ec2_vpc_nat_gateway/aliases
deleted file mode 100644
index f5291520b8b..00000000000
--- a/tests/integration/targets/ec2_vpc_nat_gateway/aliases
+++ /dev/null
@@ -1,2 +0,0 @@
-cloud/aws
-ec2_vpc_nat_gateway_info
diff --git a/tests/integration/targets/ec2_vpc_nat_gateway/defaults/main.yml b/tests/integration/targets/ec2_vpc_nat_gateway/defaults/main.yml
deleted file mode 100644
index 6ea912c898e..00000000000
--- a/tests/integration/targets/ec2_vpc_nat_gateway/defaults/main.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-vpc_name: "{{ resource_prefix }}-vpc"
-vpc_seed: "{{ resource_prefix }}"
-vpc_cidr: "10.0.0.0/16"
-subnet_cidr: "10.0.{{ 256 | random(seed=vpc_seed) }}.0/24"
diff --git a/tests/integration/targets/ec2_vpc_nat_gateway/tasks/main.yml b/tests/integration/targets/ec2_vpc_nat_gateway/tasks/main.yml
deleted file mode 100644
index e7e215559f9..00000000000
--- a/tests/integration/targets/ec2_vpc_nat_gateway/tasks/main.yml
+++ /dev/null
@@ -1,946 +0,0 @@
----
-- name: ec2_vpc_nat_gateway tests
- module_defaults:
- group/aws:
- aws_access_key: "{{ aws_access_key }}"
- aws_secret_key: "{{ aws_secret_key }}"
- security_token: "{{ security_token | default(omit) }}"
- region: "{{ aws_region }}"
- collections:
- - amazon.aws
-
- block:
-
- # ============================================================
- - name: Create a VPC
- ec2_vpc_net:
- name: "{{ vpc_name }}"
- state: present
- cidr_block: "{{ vpc_cidr }}"
- register: vpc_result
-
- - name: Assert success
- assert:
- that:
- - vpc_result is successful
- - '"vpc" in vpc_result'
- - '"cidr_block" in vpc_result.vpc'
- - vpc_result.vpc.cidr_block == vpc_cidr
- - '"id" in vpc_result.vpc'
- - vpc_result.vpc.id.startswith("vpc-")
- - '"state" in vpc_result.vpc'
- - vpc_result.vpc.state == 'available'
- - '"tags" in vpc_result.vpc'
-
- - name: "set fact: VPC ID"
- set_fact:
- vpc_id: "{{ vpc_result.vpc.id }}"
-
-
- # ============================================================
- - name: Allocate a new EIP
- ec2_eip:
- in_vpc: true
- reuse_existing_ip_allowed: true
- tag_name: FREE
- register: eip_result
-
- - name: Assert success
- assert:
- that:
- - eip_result is successful
- - '"allocation_id" in eip_result'
- - 'eip_result.allocation_id.startswith("eipalloc-")'
- - '"public_ip" in eip_result'
-
- - name: "set fact: EIP allocation ID and EIP public IP"
- set_fact:
- eip_address: "{{ eip_result.public_ip }}"
- allocation_id: "{{ eip_result.allocation_id }}"
-
-
- # ============================================================
- - name: Create subnet and associate to the VPC
- ec2_vpc_subnet:
- state: present
- vpc_id: "{{ vpc_id }}"
- cidr: "{{ subnet_cidr }}"
- register: subnet_result
-
- - name: Assert success
- assert:
- that:
- - subnet_result is successful
- - '"subnet" in subnet_result'
- - '"cidr_block" in subnet_result.subnet'
- - subnet_result.subnet.cidr_block == subnet_cidr
- - '"id" in subnet_result.subnet'
- - subnet_result.subnet.id.startswith("subnet-")
- - '"state" in subnet_result.subnet'
- - subnet_result.subnet.state == 'available'
- - '"tags" in subnet_result.subnet'
- - subnet_result.subnet.vpc_id == vpc_id
-
- - name: "set fact: VPC subnet ID"
- set_fact:
- subnet_id: "{{ subnet_result.subnet.id }}"
-
-
- # ============================================================
- - name: Search for NAT gateways by subnet (no matches) - CHECK_MODE
- ec2_vpc_nat_gateway_info:
- filters:
- subnet-id: "{{ subnet_id }}"
- state: ['available']
- register: existing_ngws
- check_mode: yes
-
- - name: Assert no NAT gateway found - CHECK_MODE
- assert:
- that:
- - existing_ngws is successful
- - (existing_ngws.result|length) == 0
-
- - name: Search for NAT gateways by subnet - no matches
- ec2_vpc_nat_gateway_info:
- filters:
- subnet-id: "{{ subnet_id }}"
- state: ['available']
- register: existing_ngws
-
- - name: Assert no NAT gateway found
- assert:
- that:
- - existing_ngws is successful
- - (existing_ngws.result|length) == 0
-
-
- # ============================================================
- - name: Create IGW
- ec2_vpc_igw:
- vpc_id: "{{ vpc_id }}"
- register: create_igw
-
- - name: Assert success
- assert:
- that:
- - create_igw is successful
- - create_igw.gateway_id.startswith("igw-")
- - create_igw.vpc_id == vpc_id
- - '"gateway_id" in create_igw'
-
-
- # ============================================================
- - name: Create new NAT gateway with eip allocation-id - CHECK_MODE
- ec2_vpc_nat_gateway:
- subnet_id: "{{ subnet_id }}"
- allocation_id: "{{ allocation_id }}"
- wait: yes
- register: create_ngw
- check_mode: yes
-
- - name: Assert creation happened (expected changed=true) - CHECK_MODE
- assert:
- that:
- - create_ngw.changed
-
- - name: Create new NAT gateway with eip allocation-id
- ec2_vpc_nat_gateway:
- subnet_id: "{{ subnet_id }}"
- allocation_id: "{{ allocation_id }}"
- wait: yes
- register: create_ngw
-
- - name: Assert creation happened (expected changed=true)
- assert:
- that:
- - create_ngw.changed
- - '"create_time" in create_ngw'
- - '"nat_gateway_addresses" in create_ngw'
- - '"nat_gateway_id" in create_ngw'
- - create_ngw.nat_gateway_addresses[0].allocation_id == allocation_id
- - create_ngw.nat_gateway_id.startswith("nat-")
- - '"state" in create_ngw'
- - create_ngw.state == 'available'
- - '"subnet_id" in create_ngw'
- - create_ngw.subnet_id == subnet_id
- - '"tags" in create_ngw'
- - '"vpc_id" in create_ngw'
- - create_ngw.vpc_id == vpc_id
-
- - name: "set facts: NAT gateway ID"
- set_fact:
- nat_gateway_id: "{{ create_ngw.nat_gateway_id }}"
- network_interface_id: "{{ create_ngw.nat_gateway_addresses[0].network_interface_id }}"
-
-
- # ============================================================
- - name: Get NAT gateway with specific filters (state and subnet)
- ec2_vpc_nat_gateway_info:
- filters:
- subnet-id: "{{ subnet_id }}"
- state: ['available']
- register: avalaible_ngws
-
- - name: Assert success
- assert:
- that:
- - avalaible_ngws is successful
- - avalaible_ngws.result | length == 1
- - '"create_time" in first_ngw'
- - '"nat_gateway_addresses" in first_ngw'
- - '"nat_gateway_id" in first_ngw'
- - first_ngw.nat_gateway_id == nat_gateway_id
- - '"state" in first_ngw'
- - first_ngw.state == 'available'
- - '"subnet_id" in first_ngw'
- - first_ngw.subnet_id == subnet_id
- - '"tags" in first_ngw'
- - '"vpc_id" in first_ngw'
- - first_ngw.vpc_id == vpc_id
- vars:
- first_ngw: '{{ avalaible_ngws.result[0] }}'
-
- # ============================================================
- - name: Trying this again for idempotency - create new NAT gateway with eip allocation-id - CHECK_MODE
- ec2_vpc_nat_gateway:
- subnet_id: "{{ subnet_id }}"
- allocation_id: "{{ allocation_id }}"
- wait: yes
- register: create_ngw
- check_mode: yes
-
- - name: Assert recreation would do nothing (expected changed=false) - CHECK_MODE
- assert:
- that:
- - not create_ngw.changed
- - '"create_time" in create_ngw'
- - '"nat_gateway_addresses" in create_ngw'
- - '"nat_gateway_id" in create_ngw'
- - create_ngw.nat_gateway_addresses[0].allocation_id == allocation_id
- - create_ngw.nat_gateway_id.startswith("nat-")
- - '"state" in create_ngw'
- - create_ngw.state == 'available'
- - '"subnet_id" in create_ngw'
- - create_ngw.subnet_id == subnet_id
- - '"tags" in create_ngw'
- - '"vpc_id" in create_ngw'
- - create_ngw.vpc_id == vpc_id
-
- - name: Trying this again for idempotency - create new NAT gateway with eip allocation-id
- ec2_vpc_nat_gateway:
- subnet_id: "{{ subnet_id }}"
- allocation_id: "{{ allocation_id }}"
- wait: yes
- register: create_ngw
-
- - name: Assert recreation would do nothing (expected changed=false)
- assert:
- that:
- - not create_ngw.changed
- - '"create_time" in create_ngw'
- - '"nat_gateway_addresses" in create_ngw'
- - '"nat_gateway_id" in create_ngw'
- - create_ngw.nat_gateway_addresses[0].allocation_id == allocation_id
- - create_ngw.nat_gateway_id.startswith("nat-")
- - '"state" in create_ngw'
- - create_ngw.state == 'available'
- - '"subnet_id" in create_ngw'
- - create_ngw.subnet_id == subnet_id
- - '"tags" in create_ngw'
- - '"vpc_id" in create_ngw'
- - create_ngw.vpc_id == vpc_id
-
-
- # ============================================================
- - name: Create new NAT gateway only if one does not exist already - CHECK_MODE
- ec2_vpc_nat_gateway:
- if_exist_do_not_create: yes
- subnet_id: "{{ subnet_id }}"
- wait: yes
- register: create_ngw
- check_mode: yes
-
- - name: Assert recreation would do nothing (expected changed=false) - CHECK_MODE
- assert:
- that:
- - not create_ngw.changed
- - '"create_time" in create_ngw'
- - '"nat_gateway_addresses" in create_ngw'
- - '"nat_gateway_id" in create_ngw'
- - create_ngw.nat_gateway_addresses[0].allocation_id == allocation_id
- - create_ngw.nat_gateway_id.startswith("nat-")
- - '"state" in create_ngw'
- - create_ngw.state == 'available'
- - '"subnet_id" in create_ngw'
- - create_ngw.subnet_id == subnet_id
- - '"tags" in create_ngw'
- - '"vpc_id" in create_ngw'
- - create_ngw.vpc_id == vpc_id
-
- - name: Create new NAT gateway only if one does not exist already
- ec2_vpc_nat_gateway:
- if_exist_do_not_create: yes
- subnet_id: "{{ subnet_id }}"
- wait: yes
- register: create_ngw
-
- - name: Assert recreation would do nothing (expected changed=false)
- assert:
- that:
- - not create_ngw.changed
- - '"create_time" in create_ngw'
- - '"nat_gateway_addresses" in create_ngw'
- - '"nat_gateway_id" in create_ngw'
- - create_ngw.nat_gateway_addresses[0].allocation_id == allocation_id
- - create_ngw.nat_gateway_id.startswith("nat-")
- - '"state" in create_ngw'
- - create_ngw.state == 'available'
- - '"subnet_id" in create_ngw'
- - create_ngw.subnet_id == subnet_id
- - '"tags" in create_ngw'
- - '"vpc_id" in create_ngw'
- - create_ngw.vpc_id == vpc_id
-
-
- # ============================================================
- - name: Allocate a new EIP
- ec2_eip:
- in_vpc: true
- reuse_existing_ip_allowed: true
- tag_name: FREE
- register: eip_result
-
- - name: Assert success
- assert:
- that:
- - eip_result is successful
- - '"allocation_id" in eip_result'
- - 'eip_result.allocation_id.startswith("eipalloc-")'
- - '"public_ip" in eip_result'
-
- - name: "set fact: EIP allocation ID and EIP public IP"
- set_fact:
- second_eip_address: "{{ eip_result.public_ip }}"
- second_allocation_id: "{{ eip_result.allocation_id }}"
-
-
- # ============================================================
- - name: Create new nat gateway with eip address - CHECK_MODE
- ec2_vpc_nat_gateway:
- subnet_id: "{{ subnet_id }}"
- eip_address: "{{ second_eip_address }}"
- wait: yes
- register: create_ngw
- check_mode: yes
-
- - name: Assert creation happened (expected changed=true) - CHECK_MODE
- assert:
- that:
- - create_ngw.changed
-
- - name: Create new NAT gateway with eip address
- ec2_vpc_nat_gateway:
- subnet_id: "{{ subnet_id }}"
- eip_address: "{{ second_eip_address }}"
- wait: yes
- register: create_ngw
-
- - name: Assert creation happened (expected changed=true)
- assert:
- that:
- - create_ngw.changed
- - '"create_time" in create_ngw'
- - '"nat_gateway_addresses" in create_ngw'
- - '"nat_gateway_id" in create_ngw'
- - create_ngw.nat_gateway_addresses[0].allocation_id == second_allocation_id
- - create_ngw.nat_gateway_id.startswith("nat-")
- - '"state" in create_ngw'
- - create_ngw.state == 'available'
- - '"subnet_id" in create_ngw'
- - create_ngw.subnet_id == subnet_id
- - '"tags" in create_ngw'
- - '"vpc_id" in create_ngw'
- - create_ngw.vpc_id == vpc_id
-
-
- # ============================================================
- - name: Trying this again for idempotency - create new NAT gateway with eip address - CHECK_MODE
- ec2_vpc_nat_gateway:
- subnet_id: "{{ subnet_id }}"
- eip_address: "{{ second_eip_address }}"
- wait: yes
- register: create_ngw
- check_mode: yes
-
- - name: Assert recreation would do nothing (expected changed=false) - CHECK_MODE
- assert:
- that:
- - not create_ngw.changed
- - '"create_time" in create_ngw'
- - '"nat_gateway_addresses" in create_ngw'
- - '"nat_gateway_id" in create_ngw'
- - create_ngw.nat_gateway_addresses[0].allocation_id == second_allocation_id
- - create_ngw.nat_gateway_id.startswith("nat-")
- - '"state" in create_ngw'
- - create_ngw.state == 'available'
- - '"subnet_id" in create_ngw'
- - create_ngw.subnet_id == subnet_id
- - '"tags" in create_ngw'
- - '"vpc_id" in create_ngw'
- - create_ngw.vpc_id == vpc_id
-
- - name: Trying this again for idempotency - create new NAT gateway with eip address
- ec2_vpc_nat_gateway:
- subnet_id: "{{ subnet_id }}"
- eip_address: "{{ second_eip_address }}"
- wait: yes
- register: create_ngw
-
- - name: Assert recreation would do nothing (expected changed=false)
- assert:
- that:
- - not create_ngw.changed
- - '"create_time" in create_ngw'
- - '"nat_gateway_addresses" in create_ngw'
- - '"nat_gateway_id" in create_ngw'
- - create_ngw.nat_gateway_addresses[0].allocation_id == second_allocation_id
- - create_ngw.nat_gateway_id.startswith("nat-")
- - '"state" in create_ngw'
- - create_ngw.state == 'available'
- - '"subnet_id" in create_ngw'
- - create_ngw.subnet_id == subnet_id
- - '"tags" in create_ngw'
- - '"vpc_id" in create_ngw'
- - create_ngw.vpc_id == vpc_id
-
-
- # ============================================================
- - name: Fetch NAT gateway by ID (list)
- ec2_vpc_nat_gateway_info:
- nat_gateway_ids:
- - "{{ nat_gateway_id }}"
- register: ngw_info
-
- - name: Check NAT gateway exists
- assert:
- that:
- - ngw_info is successful
- - ngw_info.result | length == 1
- - '"create_time" in first_ngw'
- - '"nat_gateway_addresses" in first_ngw'
- - '"nat_gateway_id" in first_ngw'
- - first_ngw.nat_gateway_id == nat_gateway_id
- - '"state" in first_ngw'
- - first_ngw.state == 'available'
- - '"subnet_id" in first_ngw'
- - first_ngw.subnet_id == subnet_id
- - '"tags" in first_ngw'
- - '"vpc_id" in first_ngw'
- - first_ngw.vpc_id == vpc_id
- vars:
- first_ngw: '{{ ngw_info.result[0] }}'
-
-
- # ============================================================
- - name: Delete NAT gateway - CHECK_MODE
- ec2_vpc_nat_gateway:
- nat_gateway_id: "{{ nat_gateway_id }}"
- state: absent
- wait: yes
- register: delete_nat_gateway
- check_mode: yes
-
- - name: Assert state=absent (expected changed=true) - CHECK_MODE
- assert:
- that:
- - delete_nat_gateway.changed
-
- - name: Delete NAT gateway
- ec2_vpc_nat_gateway:
- nat_gateway_id: "{{ nat_gateway_id }}"
- state: absent
- wait: yes
- register: delete_nat_gateway
-
- - name: Assert state=absent (expected changed=true)
- assert:
- that:
- - delete_nat_gateway.changed
- - '"delete_time" in delete_nat_gateway'
- - '"nat_gateway_addresses" in delete_nat_gateway'
- - '"nat_gateway_id" in delete_nat_gateway'
- - delete_nat_gateway.nat_gateway_id == nat_gateway_id
- - '"state" in delete_nat_gateway'
- - delete_nat_gateway.state == 'deleted'
- - '"subnet_id" in delete_nat_gateway'
- - delete_nat_gateway.subnet_id == subnet_id
- - '"tags" in delete_nat_gateway'
- - '"vpc_id" in delete_nat_gateway'
- - delete_nat_gateway.vpc_id == vpc_id
-
-
- # ============================================================
- - name: Create new NAT gateway with eip allocation-id and tags - CHECK_MODE
- ec2_vpc_nat_gateway:
- subnet_id: "{{ subnet_id }}"
- allocation_id: "{{ allocation_id }}"
- tags:
- tag_one: '{{ resource_prefix }} One'
- "Tag Two": 'two {{ resource_prefix }}'
- wait: yes
- register: create_ngw
- check_mode: yes
-
- - name: Assert creation happened (expected changed=true) - CHECK_MODE
- assert:
- that:
- - create_ngw.changed
-
- - name: Create new NAT gateway with eip allocation-id and tags
- ec2_vpc_nat_gateway:
- subnet_id: "{{ subnet_id }}"
- allocation_id: "{{ allocation_id }}"
- tags:
- tag_one: '{{ resource_prefix }} One'
- "Tag Two": 'two {{ resource_prefix }}'
- wait: yes
- register: create_ngw
-
- - name: Assert creation happened (expected changed=true)
- assert:
- that:
- - create_ngw.changed
- - '"create_time" in create_ngw'
- - create_ngw.nat_gateway_addresses[0].allocation_id == allocation_id
- - '"nat_gateway_id" in create_ngw'
- - create_ngw.nat_gateway_id.startswith("nat-")
- - '"state" in create_ngw'
- - create_ngw.state == 'available'
- - '"subnet_id" in create_ngw'
- - create_ngw.subnet_id == subnet_id
- - '"tags" in create_ngw'
- - create_ngw.tags | length == 2
- - create_ngw.tags["tag_one"] == '{{ resource_prefix }} One'
- - create_ngw.tags["Tag Two"] == 'two {{ resource_prefix }}'
- - '"vpc_id" in create_ngw'
- - create_ngw.vpc_id == vpc_id
-
- - name: "set facts: NAT gateway ID"
- set_fact:
- ngw_id: "{{ create_ngw.nat_gateway_id }}"
-
-
- # ============================================================
- - name: Update the tags (no change) - CHECK_MODE
- ec2_vpc_nat_gateway:
- subnet_id: "{{ subnet_id }}"
- allocation_id: "{{ allocation_id }}"
- tags:
- tag_one: '{{ resource_prefix }} One'
- "Tag Two": 'two {{ resource_prefix }}'
- wait: yes
- register: update_tags_ngw
- check_mode: yes
-
- - name: assert tag update would do nothing (expected changed=false) - CHECK_MODE
- assert:
- that:
- - not update_tags_ngw.changed
- - '"nat_gateway_id" in update_tags_ngw'
- - update_tags_ngw.nat_gateway_id == ngw_id
- - '"subnet_id" in update_tags_ngw'
- - update_tags_ngw.subnet_id == subnet_id
- - '"tags" in update_tags_ngw'
- - update_tags_ngw.tags | length == 2
- - update_tags_ngw.tags["tag_one"] == '{{ resource_prefix }} One'
- - update_tags_ngw.tags["Tag Two"] == 'two {{ resource_prefix }}'
- - '"vpc_id" in update_tags_ngw'
- - update_tags_ngw.vpc_id == vpc_id
-
- - name: Update the tags (no change)
- ec2_vpc_nat_gateway:
- subnet_id: "{{ subnet_id }}"
- allocation_id: "{{ allocation_id }}"
- tags:
- tag_one: '{{ resource_prefix }} One'
- "Tag Two": 'two {{ resource_prefix }}'
- wait: yes
- register: update_tags_ngw
-
- - name: assert tag update would do nothing (expected changed=false)
- assert:
- that:
- - not update_tags_ngw.changed
- - '"nat_gateway_id" in update_tags_ngw'
- - update_tags_ngw.nat_gateway_id == ngw_id
- - '"subnet_id" in update_tags_ngw'
- - update_tags_ngw.subnet_id == subnet_id
- - '"tags" in update_tags_ngw'
- - update_tags_ngw.tags | length == 2
- - update_tags_ngw.tags["tag_one"] == '{{ resource_prefix }} One'
- - update_tags_ngw.tags["Tag Two"] == 'two {{ resource_prefix }}'
- - '"vpc_id" in update_tags_ngw'
- - update_tags_ngw.vpc_id == vpc_id
-
-
- # ============================================================
- - name: Gather information about a filtered list of NAT Gateways using tags and state - CHECK_MODE
- ec2_vpc_nat_gateway_info:
- filters:
- "tag:Tag Two": 'two {{ resource_prefix }}'
- state: ['available']
- register: ngw_info
- check_mode: yes
-
- - name: Assert success - CHECK_MODE
- assert:
- that:
- - ngw_info is successful
- - ngw_info.result | length == 1
- - '"create_time" in second_ngw'
- - '"nat_gateway_addresses" in second_ngw'
- - '"nat_gateway_id" in second_ngw'
- - second_ngw.nat_gateway_id == ngw_id
- - '"state" in second_ngw'
- - second_ngw.state == 'available'
- - '"subnet_id" in second_ngw'
- - second_ngw.subnet_id == subnet_id
- - '"tags" in second_ngw'
- - second_ngw.tags | length == 2
- - '"tag_one" in second_ngw.tags'
- - '"Tag Two" in second_ngw.tags'
- - second_ngw.tags["tag_one"] == '{{ resource_prefix }} One'
- - second_ngw.tags["Tag Two"] == 'two {{ resource_prefix }}'
- - '"vpc_id" in second_ngw'
- - second_ngw.vpc_id == vpc_id
- vars:
- second_ngw: '{{ ngw_info.result[0] }}'
-
- - name: Gather information about a filtered list of NAT Gateways using tags and state
- ec2_vpc_nat_gateway_info:
- filters:
- "tag:Tag Two": 'two {{ resource_prefix }}'
- state: ['available']
- register: ngw_info
-
- - name: Assert success
- assert:
- that:
- - ngw_info is successful
- - ngw_info.result | length == 1
- - '"create_time" in second_ngw'
- - '"nat_gateway_addresses" in second_ngw'
- - '"nat_gateway_id" in second_ngw'
- - second_ngw.nat_gateway_id == ngw_id
- - '"state" in second_ngw'
- - second_ngw.state == 'available'
- - '"subnet_id" in second_ngw'
- - second_ngw.subnet_id == subnet_id
- - '"tags" in second_ngw'
- - second_ngw.tags | length == 2
- - '"tag_one" in second_ngw.tags'
- - '"Tag Two" in second_ngw.tags'
- - second_ngw.tags["tag_one"] == '{{ resource_prefix }} One'
- - second_ngw.tags["Tag Two"] == 'two {{ resource_prefix }}'
- - '"vpc_id" in second_ngw'
- - second_ngw.vpc_id == vpc_id
- vars:
- second_ngw: '{{ ngw_info.result[0] }}'
-
-
- # ============================================================
- - name: Update the tags - remove and add - CHECK_MODE
- ec2_vpc_nat_gateway:
- subnet_id: "{{ subnet_id }}"
- allocation_id: "{{ allocation_id }}"
- tags:
- tag_three: '{{ resource_prefix }} Three'
- "Tag Two": 'two {{ resource_prefix }}'
- wait: yes
- register: update_tags_ngw
- check_mode: yes
-
- - name: Assert tag update would happen (expected changed=true) - CHECK_MODE
- assert:
- that:
- - update_tags_ngw.changed
- - '"nat_gateway_id" in update_tags_ngw'
- - update_tags_ngw.nat_gateway_id == ngw_id
- - '"subnet_id" in update_tags_ngw'
- - update_tags_ngw.subnet_id == subnet_id
- - '"tags" in update_tags_ngw'
- - update_tags_ngw.tags | length == 2
- - update_tags_ngw.tags["tag_three"] == '{{ resource_prefix }} Three'
- - update_tags_ngw.tags["Tag Two"] == 'two {{ resource_prefix }}'
- - '"vpc_id" in update_tags_ngw'
- - update_tags_ngw.vpc_id == vpc_id
-
- - name: Update the tags - remove and add
- ec2_vpc_nat_gateway:
- subnet_id: "{{ subnet_id }}"
- allocation_id: "{{ allocation_id }}"
- tags:
- tag_three: '{{ resource_prefix }} Three'
- "Tag Two": 'two {{ resource_prefix }}'
- wait: yes
- register: update_tags_ngw
-
- - name: Assert tag update would happen (expected changed=true)
- assert:
- that:
- - update_tags_ngw.changed
- - '"nat_gateway_id" in update_tags_ngw'
- - update_tags_ngw.nat_gateway_id == ngw_id
- - '"subnet_id" in update_tags_ngw'
- - update_tags_ngw.subnet_id == subnet_id
- - '"tags" in update_tags_ngw'
- - update_tags_ngw.tags | length == 2
- - update_tags_ngw.tags["tag_three"] == '{{ resource_prefix }} Three'
- - update_tags_ngw.tags["Tag Two"] == 'two {{ resource_prefix }}'
- - '"vpc_id" in update_tags_ngw'
- - update_tags_ngw.vpc_id == vpc_id
-
-
- # ============================================================
- - name: Gather information about a filtered list of NAT Gateways using tags and state (no match) - CHECK_MODE
- ec2_vpc_nat_gateway_info:
- filters:
- "tag:tag_one": '{{ resource_prefix }} One'
- state: ['available']
- register: ngw_info
- check_mode: yes
-
- - name: Assert success - CHECK_MODE
- assert:
- that:
- - ngw_info is successful
- - ngw_info.result | length == 0
-
- - name: Gather information about a filtered list of NAT Gateways using tags and state (no match)
- ec2_vpc_nat_gateway_info:
- filters:
- "tag:tag_one": '{{ resource_prefix }} One'
- state: ['available']
- register: ngw_info
-
- - name: Assert success
- assert:
- that:
- - ngw_info is successful
- - ngw_info.result | length == 0
-
-
- # ============================================================
- - name: Update the tags add without purge - CHECK_MODE
- ec2_vpc_nat_gateway:
- if_exist_do_not_create: yes
- subnet_id: "{{ subnet_id }}"
- allocation_id: "{{ allocation_id }}"
- purge_tags: no
- tags:
- tag_one: '{{ resource_prefix }} One'
- wait: yes
- register: update_tags_ngw
- check_mode: yes
-
- - name: Assert tags would be added - CHECK_MODE
- assert:
- that:
- - update_tags_ngw.changed
- - '"nat_gateway_id" in update_tags_ngw'
- - update_tags_ngw.nat_gateway_id == ngw_id
- - '"subnet_id" in update_tags_ngw'
- - update_tags_ngw.subnet_id == subnet_id
- - '"tags" in update_tags_ngw'
- - update_tags_ngw.tags | length == 3
- - update_tags_ngw.tags["tag_one"] == '{{ resource_prefix }} One'
- - update_tags_ngw.tags["tag_three"] == '{{ resource_prefix }} Three'
- - update_tags_ngw.tags["Tag Two"] == 'two {{ resource_prefix }}'
- - '"vpc_id" in update_tags_ngw'
- - update_tags_ngw.vpc_id == vpc_id
-
- - name: Update the tags add without purge
- ec2_vpc_nat_gateway:
- if_exist_do_not_create: yes
- subnet_id: "{{ subnet_id }}"
- allocation_id: "{{ allocation_id }}"
- purge_tags: no
- tags:
- tag_one: '{{ resource_prefix }} One'
- wait: yes
- register: update_tags_ngw
-
- - name: Assert tags would be added
- assert:
- that:
- - update_tags_ngw.changed
- - '"nat_gateway_id" in update_tags_ngw'
- - update_tags_ngw.nat_gateway_id == ngw_id
- - '"subnet_id" in update_tags_ngw'
- - update_tags_ngw.subnet_id == subnet_id
- - '"tags" in update_tags_ngw'
- - update_tags_ngw.tags | length == 3
- - update_tags_ngw.tags["tag_one"] == '{{ resource_prefix }} One'
- - update_tags_ngw.tags["tag_three"] == '{{ resource_prefix }} Three'
- - update_tags_ngw.tags["Tag Two"] == 'two {{ resource_prefix }}'
- - '"vpc_id" in update_tags_ngw'
- - update_tags_ngw.vpc_id == vpc_id
-
-
- # ============================================================
- - name: Remove all tags - CHECK_MODE
- ec2_vpc_nat_gateway:
- subnet_id: "{{ subnet_id }}"
- allocation_id: "{{ allocation_id }}"
- tags: {}
- register: delete_tags_ngw
- check_mode: yes
-
- - name: assert tags would be removed - CHECK_MODE
- assert:
- that:
- - delete_tags_ngw.changed
- - '"nat_gateway_id" in delete_tags_ngw'
- - delete_tags_ngw.nat_gateway_id == ngw_id
- - '"subnet_id" in delete_tags_ngw'
- - delete_tags_ngw.subnet_id == subnet_id
- - '"tags" in delete_tags_ngw'
- - delete_tags_ngw.tags | length == 0
- - '"vpc_id" in delete_tags_ngw'
- - delete_tags_ngw.vpc_id == vpc_id
-
- - name: Remove all tags
- ec2_vpc_nat_gateway:
- subnet_id: "{{ subnet_id }}"
- allocation_id: "{{ allocation_id }}"
- tags: {}
- register: delete_tags_ngw
-
- - name: assert tags would be removed
- assert:
- that:
- - delete_tags_ngw.changed
- - '"nat_gateway_id" in delete_tags_ngw'
- - delete_tags_ngw.nat_gateway_id == ngw_id
- - '"subnet_id" in delete_tags_ngw'
- - delete_tags_ngw.subnet_id == subnet_id
- - '"tags" in delete_tags_ngw'
- - delete_tags_ngw.tags | length == 0
- - '"vpc_id" in delete_tags_ngw'
- - delete_tags_ngw.vpc_id == vpc_id
-
-
- # ============================================================
- - name: Update with CamelCase tags - CHECK_MODE
- ec2_vpc_nat_gateway:
- if_exist_do_not_create: yes
- subnet_id: "{{ subnet_id }}"
- allocation_id: "{{ allocation_id }}"
- purge_tags: no
- tags:
- "lowercase spaced": 'hello cruel world ❤️'
- "Title Case": 'Hello Cruel World ❤️'
- CamelCase: 'SimpleCamelCase ❤️'
- snake_case: 'simple_snake_case ❤️'
- wait: yes
- register: update_tags_ngw
- check_mode: yes
-
- - name: Assert tags would be added - CHECK_MODE
- assert:
- that:
- - update_tags_ngw.changed
- - '"nat_gateway_id" in update_tags_ngw'
- - update_tags_ngw.nat_gateway_id == ngw_id
- - '"subnet_id" in update_tags_ngw'
- - update_tags_ngw.subnet_id == subnet_id
- - '"tags" in update_tags_ngw'
- - update_tags_ngw.tags | length == 4
- - update_tags_ngw.tags["lowercase spaced"] == 'hello cruel world ❤️'
- - update_tags_ngw.tags["Title Case"] == 'Hello Cruel World ❤️'
- - update_tags_ngw.tags["CamelCase"] == 'SimpleCamelCase ❤️'
- - update_tags_ngw.tags["snake_case"] == 'simple_snake_case ❤️'
- - '"vpc_id" in update_tags_ngw'
- - update_tags_ngw.vpc_id == vpc_id
-
- - name: Update with CamelCase tags
- ec2_vpc_nat_gateway:
- if_exist_do_not_create: yes
- subnet_id: "{{ subnet_id }}"
- allocation_id: "{{ allocation_id }}"
- purge_tags: no
- tags:
- "lowercase spaced": 'hello cruel world ❤️'
- "Title Case": 'Hello Cruel World ❤️'
- CamelCase: 'SimpleCamelCase ❤️'
- snake_case: 'simple_snake_case ❤️'
- wait: yes
- register: update_tags_ngw
-
- - name: Assert tags would be added
- assert:
- that:
- - update_tags_ngw.changed
- - '"nat_gateway_id" in update_tags_ngw'
- - update_tags_ngw.nat_gateway_id == ngw_id
- - '"subnet_id" in update_tags_ngw'
- - update_tags_ngw.subnet_id == subnet_id
- - '"tags" in update_tags_ngw'
- - update_tags_ngw.tags | length == 4
- - update_tags_ngw.tags["lowercase spaced"] == 'hello cruel world ❤️'
- - update_tags_ngw.tags["Title Case"] == 'Hello Cruel World ❤️'
- - update_tags_ngw.tags["CamelCase"] == 'SimpleCamelCase ❤️'
- - update_tags_ngw.tags["snake_case"] == 'simple_snake_case ❤️'
- - '"vpc_id" in update_tags_ngw'
- - update_tags_ngw.vpc_id == vpc_id
-
-
- # ============================================================
- always:
- - name: Get NAT gateways
- ec2_vpc_nat_gateway_info:
- filters:
- vpc-id: "{{ vpc_id }}"
- state: ['available']
- register: existing_ngws
- ignore_errors: true
-
- - name: Tidy up NAT gateway
- ec2_vpc_nat_gateway:
- subnet_id: "{{ item.subnet_id }}"
- nat_gateway_id: "{{ item.nat_gateway_id }}"
- release_eip: yes
- state: absent
- wait: yes
- with_items: "{{ existing_ngws.result }}"
- ignore_errors: true
-
- - name: Delete IGW
- ec2_vpc_igw:
- vpc_id: "{{ vpc_id }}"
- state: absent
- ignore_errors: true
-
- - name: Remove subnet
- ec2_vpc_subnet:
- state: absent
- cidr: "{{ subnet_cidr }}"
- vpc_id: "{{ vpc_id }}"
- ignore_errors: true
-
- - name: Ensure EIP is actually released
- ec2_eip:
- state: absent
- device_id: "{{ item.nat_gateway_addresses[0].network_interface_id }}"
- in_vpc: yes
- with_items: "{{ existing_ngws.result }}"
- ignore_errors: yes
-
- - name: Delete VPC
- ec2_vpc_net:
- name: "{{ vpc_name }}"
- cidr_block: "{{ vpc_cidr }}"
- state: absent
- purge_cidrs: yes
- ignore_errors: yes
diff --git a/tests/integration/targets/ecs_cluster/defaults/main.yml b/tests/integration/targets/ecs_cluster/defaults/main.yml
index 20e010e366d..b909b2977af 100644
--- a/tests/integration/targets/ecs_cluster/defaults/main.yml
+++ b/tests/integration/targets/ecs_cluster/defaults/main.yml
@@ -7,6 +7,8 @@ ecs_service_name: "{{ resource_prefix }}-service"
ecs_task_image_path: nginx
ecs_task_name: "{{ resource_prefix }}-task"
ecs_task_memory: 128
+target_swap_mb: 0
+target_swappiness: 80
ecs_task_containers:
- name: "{{ ecs_task_name }}"
image: "{{ ecs_task_image_path }}"
@@ -15,6 +17,9 @@ ecs_task_containers:
portMappings:
- containerPort: "{{ ecs_task_container_port }}"
hostPort: "{{ ecs_task_host_port|default(0) }}"
+ linuxParameters:
+ maxSwap: "{{ target_swap_mb }}"
+ swappiness: "{{ target_swappiness }}"
mountPoints: "{{ ecs_task_mount_points|default([]) }}"
ecs_service_deployment_configuration:
minimum_healthy_percent: 0
@@ -36,3 +41,6 @@ ecs_fargate_task_containers:
- containerPort: "{{ ecs_task_container_port }}"
hostPort: "{{ ecs_task_host_port|default(0) }}"
#mountPoints: "{{ ecs_task_mount_points|default([]) }}"
+ecs_taskdefinition_placement_constraints:
+ - type: memberOf
+ expression: 'attribute:ecs.instance-type == t3.micro'
diff --git a/tests/integration/targets/ecs_cluster/tasks/full_test.yml b/tests/integration/targets/ecs_cluster/tasks/full_test.yml
index a463fa5de0d..cb58ecc74ed 100644
--- a/tests/integration/targets/ecs_cluster/tasks/full_test.yml
+++ b/tests/integration/targets/ecs_cluster/tasks/full_test.yml
@@ -72,7 +72,7 @@
- name: create subnets
ec2_vpc_subnet:
- az: '{{ ec2_region }}{{ item.zone }}'
+ az: '{{ aws_region }}{{ item.zone }}'
tags:
Name: '{{ resource_prefix }}_ecs_cluster-subnet-{{ item.zone }}'
vpc_id: '{{ setup_vpc.vpc.id }}'
@@ -116,7 +116,7 @@
- name: provision ec2 instance to create an image
ec2_instance:
key_name: '{{ ec2_keypair|default(setup_key.key.name) }}'
- instance_type: t2.micro
+ instance_type: t3.micro
state: present
image_id: '{{ ecs_image_id }}'
wait: yes
@@ -156,7 +156,7 @@
state: present
scheme: internal
security_groups: '{{ setup_sg.group_id }}'
- subnets: "{{ setup_subnet.results | community.general.json_query('[].subnet.id') }}"
+ subnets: "{{ setup_subnet.results | map(attribute='subnet.id') | list }}"
listeners:
- Protocol: HTTP
Port: 80
@@ -187,8 +187,6 @@
assert:
that:
- not ecs_task_definition_again.changed
- # FIXME: task definition should not change, will need #26752 or equivalent
- ignore_errors: yes
- name: obtain ECS task definition facts
ecs_taskdefinition_info:
@@ -281,7 +279,7 @@
containerName: "{{ ecs_task_name }}"
containerPort: "{{ ecs_task_container_port }}"
network_configuration:
- subnets: "{{ setup_subnet.results | community.general.json_query('[].subnet.id') }}"
+ subnets: "{{ setup_subnet.results | map(attribute='subnet.id') | list }}"
security_groups:
- '{{ setup_sg.group_id }}'
register: ecs_service_network_without_awsvpc_task
@@ -389,7 +387,7 @@
containerName: "{{ ecs_task_name }}"
containerPort: "{{ ecs_task_container_port }}"
network_configuration:
- subnets: "{{ setup_subnet.results | community.general.json_query('[].subnet.id') }}"
+ subnets: "{{ setup_subnet.results | map(attribute='subnet.id') | list }}"
security_groups:
- '{{ setup_sg.group_id }}'
register: create_ecs_service_with_vpc
@@ -423,7 +421,7 @@
containerName: "{{ ecs_task_name }}"
containerPort: "{{ ecs_task_container_port }}"
network_configuration:
- subnets: "{{ setup_subnet.results | community.general.json_query('[].subnet.id') }}"
+ subnets: "{{ setup_subnet.results | map(attribute='subnet.id') | list }}"
security_groups:
- "{{ resource_prefix }}-ecs-vpc-test-sg"
register: update_ecs_service_with_vpc
@@ -578,6 +576,35 @@
- name: attempt to get facts from missing task definition
ecs_taskdefinition_info:
task_definition: "{{ ecs_task_name }}-vpc:{{ ecs_task_definition.taskdefinition.revision + 1}}"
+
+ - name: Create another task definition with placement constraints
+ ecs_taskdefinition:
+ containers: "{{ ecs_task_containers }}"
+ family: "{{ ecs_task_name }}-constraints"
+ state: present
+ placement_constraints: "{{ ecs_taskdefinition_placement_constraints }}"
+ register: ecs_task_definition_constraints
+
+ - name: Check that task definition has been created
+ assert:
+ that:
+ - ecs_task_definition_constraints is changed
+ - ecs_task_definition_constraints.taskdefinition.placementConstraints[0].type == "{{ ecs_taskdefinition_placement_constraints[0].type }}"
+ - ecs_task_definition_constraints.taskdefinition.placementConstraints[0].expression == "{{ ecs_taskdefinition_placement_constraints[0].expression }}"
+
+ - name: Remove ecs task definition with placement constraints
+ ecs_taskdefinition:
+ containers: "{{ ecs_task_containers }}"
+ family: "{{ ecs_task_name }}-constraints"
+ revision: "{{ ecs_task_definition.taskdefinition.revision }}"
+ state: absent
+ register: ecs_task_definition_constraints_delete
+
+ - name: Check that task definition has been deleted
+ assert:
+ that:
+ - ecs_task_definition_constraints_delete is changed
+
# ============================================================
# Begin tests for Fargate
@@ -674,7 +701,7 @@
deployment_configuration: "{{ ecs_service_deployment_configuration }}"
launch_type: FARGATE
network_configuration:
- subnets: "{{ setup_subnet.results | community.general.json_query('[].subnet.id') }}"
+ subnets: "{{ setup_subnet.results | map(attribute='subnet.id') | list }}"
security_groups:
- '{{ setup_sg.group_id }}'
assign_public_ip: true
@@ -693,7 +720,7 @@
launch_type: FARGATE
count: 1
network_configuration:
- subnets: "{{ setup_subnet.results | community.general.json_query('[].subnet.id') }}"
+ subnets: "{{ setup_subnet.results | map(attribute='subnet.id') | list }}"
security_groups:
- '{{ setup_sg.group_id }}'
assign_public_ip: true
@@ -725,7 +752,7 @@
tag_key: tag_value
tag_key2: tag_value2
network_configuration:
- subnets: "{{ setup_subnet.results | community.general.json_query('[].subnet.id') }}"
+ subnets: "{{ setup_subnet.results | map(attribute='subnet.id') | list }}"
security_groups:
- '{{ setup_sg.group_id }}'
assign_public_ip: true
@@ -752,7 +779,7 @@
tag_key: tag_value
tag_key2: tag_value2
network_configuration:
- subnets: "{{ setup_subnet.results | community.general.json_query('[].subnet.id') }}"
+ subnets: "{{ setup_subnet.results | map(attribute='subnet.id') | list }}"
security_groups:
- '{{ setup_sg.group_id }}'
assign_public_ip: true
@@ -767,7 +794,7 @@
launch_type: FARGATE
count: 1
network_configuration:
- subnets: "{{ setup_subnet.results | community.general.json_query('[].subnet.id') }}"
+ subnets: "{{ setup_subnet.results | map(attribute='subnet.id') | list }}"
security_groups:
- '{{ setup_sg.group_id }}'
assign_public_ip: false
@@ -857,8 +884,6 @@
ignore_errors: yes
register: ecs_service_scale_down
-
-
- name: scale down scheduling_strategy service
ecs_service:
name: "{{ ecs_service_name }}-replica"
diff --git a/tests/integration/targets/ecs_cluster/tasks/main.yml b/tests/integration/targets/ecs_cluster/tasks/main.yml
index bd727cca3a4..fdcdd16a669 100644
--- a/tests/integration/targets/ecs_cluster/tasks/main.yml
+++ b/tests/integration/targets/ecs_cluster/tasks/main.yml
@@ -10,58 +10,5 @@
region: '{{ aws_region }}'
block:
- - set_fact:
- virtualenv: "{{ remote_tmp_dir }}/virtualenv"
- virtualenv_command: "{{ ansible_python_interpreter }} -m virtualenv"
-
- - set_fact:
- virtualenv_interpreter: "{{ virtualenv }}/bin/python"
-
- - pip:
- name: virtualenv
-
- # Test graceful failures when botocore<1.8.4
-
- - pip:
- name:
- - 'botocore<1.8.4'
- - boto3
- - coverage<5
- virtualenv: "{{ virtualenv }}"
- virtualenv_command: "{{ virtualenv_command }}"
- virtualenv_site_packages: no
-
- - include_tasks: network_assign_public_ip_fail.yml
- vars:
- ansible_python_interpreter: "{{ virtualenv_interpreter }}"
-
- - include_tasks: network_force_new_deployment_fail.yml
- vars:
- ansible_python_interpreter: "{{ virtualenv_interpreter }}"
-
- - file:
- path: "{{ virtualenv }}"
- state: absent
-
- # Test graceful failures when botocore<1.12.38
-
- - pip:
- name:
- - 'botocore>=1.12.60'
- - 'boto3>=1.16.57'
- - coverage<5
- virtualenv: "{{ virtualenv }}"
- virtualenv_command: "{{ virtualenv_command }}"
- virtualenv_site_packages: no
-
- include_tasks: network_force_new_deployment.yml
- vars:
- ansible_python_interpreter: "{{ virtualenv_interpreter }}"
-
- include_tasks: full_test.yml
- vars:
- ansible_python_interpreter: "{{ virtualenv_interpreter }}"
-
- - file:
- path: "{{ virtualenv }}"
- state: absent
diff --git a/tests/integration/targets/ecs_cluster/tasks/network_assign_public_ip_fail.yml b/tests/integration/targets/ecs_cluster/tasks/network_assign_public_ip_fail.yml
deleted file mode 100644
index 46999fe0f4c..00000000000
--- a/tests/integration/targets/ecs_cluster/tasks/network_assign_public_ip_fail.yml
+++ /dev/null
@@ -1,106 +0,0 @@
----
-- block:
- - name: create ecs cluster
- ecs_cluster:
- name: "{{ resource_prefix }}"
- state: present
-
- - name: create ecs_taskdefinition with bridged network
- ecs_taskdefinition:
- containers:
- - name: my_container
- image: ubuntu
- memory: 128
- family: "{{ resource_prefix }}"
- state: present
- network_mode: bridge
- register: ecs_taskdefinition_creation
-
- - name: create ecs_taskdefinition with awsvpc network
- ecs_taskdefinition:
- containers:
- - name: my_container
- image: ubuntu
- memory: 128
- family: "{{ resource_prefix }}-vpc"
- state: present
- network_mode: awsvpc
- register: ecs_taskdefinition_creation_vpc
-
- - name: ecs_taskdefinition works fine even when older botocore is used
- assert:
- that:
- - ecs_taskdefinition_creation_vpc.changed
-
- - name: create ecs_service using awsvpc network_configuration
- ecs_service:
- name: "{{ resource_prefix }}-vpc"
- cluster: "{{ resource_prefix }}"
- task_definition: "{{ resource_prefix }}-vpc"
- desired_count: 1
- network_configuration:
- subnets:
- - subnet-abcd1234
- security_groups:
- - sg-abcd1234
- assign_public_ip: true
- state: present
- register: ecs_service_creation_vpc
- ignore_errors: yes
-
- - name: check that graceful failure message is returned from ecs_service
- assert:
- that:
- - ecs_service_creation_vpc.failed
- - 'ecs_service_creation_vpc.msg == "botocore needs to be version 1.8.4 or higher to use assign_public_ip in network_configuration"'
-
- always:
- - name: scale down ecs service
- ecs_service:
- name: "{{ resource_prefix }}"
- cluster: "{{ resource_prefix }}"
- task_definition: "{{ resource_prefix }}"
- desired_count: 0
- state: present
- ignore_errors: yes
-
- - name: pause to wait for scale down
- pause:
- seconds: 30
-
- - name: remove ecs service
- ecs_service:
- name: "{{ resource_prefix }}"
- cluster: "{{ resource_prefix }}"
- task_definition: "{{ resource_prefix }}"
- desired_count: 1
- state: absent
- ignore_errors: yes
-
- - name: remove ecs task definition
- ecs_taskdefinition:
- containers:
- - name: my_container
- image: ubuntu
- memory: 128
- family: "{{ resource_prefix }}"
- revision: "{{ ecs_taskdefinition_creation.taskdefinition.revision }}"
- state: absent
- ignore_errors: yes
-
- - name: remove ecs task definition vpc
- ecs_taskdefinition:
- containers:
- - name: my_container
- image: ubuntu
- memory: 128
- family: "{{ resource_prefix }}-vpc"
- revision: "{{ ecs_taskdefinition_creation_vpc.taskdefinition.revision }}"
- state: absent
- ignore_errors: yes
-
- - name: remove ecs cluster
- ecs_cluster:
- name: "{{ resource_prefix }}"
- state: absent
- ignore_errors: yes
diff --git a/tests/integration/targets/ecs_cluster/tasks/network_fail.yml b/tests/integration/targets/ecs_cluster/tasks/network_fail.yml
deleted file mode 100644
index d21eba22a0b..00000000000
--- a/tests/integration/targets/ecs_cluster/tasks/network_fail.yml
+++ /dev/null
@@ -1,194 +0,0 @@
----
-- block:
- - name: create ecs cluster
- ecs_cluster:
- name: "{{ resource_prefix }}"
- state: present
-
- - name: create ecs_taskdefinition with bridged network
- ecs_taskdefinition:
- containers:
- - name: my_container
- image: ubuntu
- memory: 128
- family: "{{ resource_prefix }}"
- state: present
- network_mode: bridge
- register: ecs_taskdefinition_creation
-
- - name: create ecs_taskdefinition with awsvpc network
- ecs_taskdefinition:
- containers:
- - name: my_container
- image: ubuntu
- memory: 128
- family: "{{ resource_prefix }}-vpc"
- state: present
- network_mode: awsvpc
- register: ecs_taskdefinition_creation_vpc
-
- - name: create ecs_taskdefinition and execution_role_arn (expected to fail)
- ecs_taskdefinition:
- containers:
- - name: my_container
- image: ubuntu
- memory: 128
- family: "{{ resource_prefix }}-vpc"
- execution_role_arn: not_a_real_arn
- state: present
- network_mode: awsvpc
- ignore_errors: yes
- register: ecs_taskdefinition_arn
-
- - name: check that graceful failure message is returned from ecs_taskdefinition_arn
- assert:
- that:
- - ecs_taskdefinition_arn.failed
- - 'ecs_taskdefinition_arn.msg == "botocore needs to be version 1.10.44 or higher to use execution_role_arn"'
-
- - name: ecs_taskdefinition works fine even when older botocore is used
- assert:
- that:
- - ecs_taskdefinition_creation_vpc.changed
-
- - name: create ecs_service using bridged network
- ecs_service:
- name: "{{ resource_prefix }}"
- cluster: "{{ resource_prefix }}"
- task_definition: "{{ resource_prefix }}"
- desired_count: 1
- state: present
- register: ecs_service_creation
-
- - name: create ecs_service using awsvpc network_configuration
- ecs_service:
- name: "{{ resource_prefix }}-vpc"
- cluster: "{{ resource_prefix }}"
- task_definition: "{{ resource_prefix }}-vpc"
- desired_count: 1
- network_configuration:
- subnets:
- - subnet-abcd1234
- security_groups:
- - sg-abcd1234
- state: present
- register: ecs_service_creation_vpc
- ignore_errors: yes
-
- - name: check that graceful failure message is returned from ecs_service
- assert:
- that:
- - ecs_service_creation_vpc.failed
- - 'ecs_service_creation_vpc.msg == "botocore needs to be version 1.7.44 or higher to use network configuration"'
-
- - name: create ecs_service using awsvpc network_configuration and launch_type
- ecs_service:
- name: "{{ resource_prefix }}-vpc"
- cluster: "{{ resource_prefix }}"
- task_definition: "{{ resource_prefix }}-vpc"
- desired_count: 1
- network_configuration:
- subnets:
- - subnet-abcd1234
- security_groups:
- - sg-abcd1234
- launch_type: FARGATE
- state: present
- register: ecs_service_creation_vpc_launchtype
- ignore_errors: yes
-
- - name: check that graceful failure message is returned from ecs_service
- assert:
- that:
- - ecs_service_creation_vpc_launchtype.failed
- - 'ecs_service_creation_vpc_launchtype.msg == "botocore needs to be version 1.7.44 or higher to use network configuration"'
-
- - name: create ecs_service with launchtype and missing network_configuration
- ecs_service:
- name: "{{ resource_prefix }}-vpc"
- cluster: "{{ resource_prefix }}"
- task_definition: "{{ resource_prefix }}-vpc"
- desired_count: 1
- launch_type: FARGATE
- state: present
- register: ecs_service_creation_vpc_launchtype_nonet
- ignore_errors: yes
-
- - name: check that graceful failure message is returned from ecs_service
- assert:
- that:
- - ecs_service_creation_vpc_launchtype_nonet.failed
- - 'ecs_service_creation_vpc_launchtype_nonet.msg == "launch_type is FARGATE but all of the following are missing: network_configuration"'
-
- - name: create ecs_task using awsvpc network_configuration
- ecs_task:
- cluster: "{{ resource_prefix }}-vpc"
- task_definition: "{{ resource_prefix }}"
- operation: run
- count: 1
- started_by: me
- network_configuration:
- subnets:
- - subnet-abcd1234
- security_groups:
- - sg-abcd1234
- register: ecs_task_creation_vpc
- ignore_errors: yes
-
- - name: check that graceful failure message is returned from ecs_task
- assert:
- that:
- - ecs_task_creation_vpc.failed
- - 'ecs_task_creation_vpc.msg == "botocore needs to be version 1.7.44 or higher to use network configuration"'
-
-
- always:
- - name: scale down ecs service
- ecs_service:
- name: "{{ resource_prefix }}"
- cluster: "{{ resource_prefix }}"
- task_definition: "{{ resource_prefix }}"
- desired_count: 0
- state: present
- ignore_errors: yes
-
- - name: pause to wait for scale down
- pause:
- seconds: 30
-
- - name: remove ecs service
- ecs_service:
- name: "{{ resource_prefix }}"
- cluster: "{{ resource_prefix }}"
- task_definition: "{{ resource_prefix }}"
- desired_count: 1
- state: absent
- ignore_errors: yes
-
- - name: remove ecs task definition
- ecs_taskdefinition:
- containers:
- - name: my_container
- image: ubuntu
- memory: 128
- family: "{{ resource_prefix }}"
- revision: "{{ ecs_taskdefinition_creation.taskdefinition.revision }}"
- state: absent
- ignore_errors: yes
-
- - name: remove ecs task definition vpc
- ecs_taskdefinition:
- containers:
- - name: my_container
- image: ubuntu
- memory: 128
- family: "{{ resource_prefix }}-vpc"
- revision: "{{ ecs_taskdefinition_creation_vpc.taskdefinition.revision }}"
- state: absent
- ignore_errors: yes
-
- - name: remove ecs cluster
- ecs_cluster:
- name: "{{ resource_prefix }}"
- state: absent
- ignore_errors: yes
diff --git a/tests/integration/targets/ecs_cluster/tasks/network_force_new_deployment_fail.yml b/tests/integration/targets/ecs_cluster/tasks/network_force_new_deployment_fail.yml
deleted file mode 100644
index f65c20850c5..00000000000
--- a/tests/integration/targets/ecs_cluster/tasks/network_force_new_deployment_fail.yml
+++ /dev/null
@@ -1,108 +0,0 @@
----
-- block:
- - name: create ecs cluster
- ecs_cluster:
- name: "{{ resource_prefix }}"
- state: present
-
- - name: create ecs_taskdefinition
- ecs_taskdefinition:
- containers:
- - name: my_container
- image: ubuntu
- memory: 128
- family: "{{ resource_prefix }}"
- state: present
- register: ecs_taskdefinition_creation
-
- # even after deleting the cluster and recreating with a different name
- # the previous service can prevent the current service from starting
- # while it's in a draining state. Check the service info and sleep
- # if the service does not report as inactive.
-
- - name: check if service is still running from a previous task
- ecs_service_info:
- service: "{{ resource_prefix }}"
- cluster: "{{ resource_prefix }}"
- details: yes
- register: ecs_service_info_results
- - name: delay if the service was not inactive
- debug: var=ecs_service_info_results
-
- - name: delay if the service was not inactive
- pause:
- seconds: 30
- when:
- - ecs_service_info_results.services|length >0
- - ecs_service_info_results.services[0]['status'] != 'INACTIVE'
-
- - name: create ecs_service
- ecs_service:
- name: "{{ resource_prefix }}"
- cluster: "{{ resource_prefix }}"
- task_definition: "{{ resource_prefix }}"
- desired_count: 1
- state: present
- register: ecs_service_creation
-
- - name: ecs_service works fine even when older botocore is used
- assert:
- that:
- - ecs_service_creation.changed
-
- - name: create ecs_service using force_new_deployment
- ecs_service:
- name: "{{ resource_prefix }}"
- cluster: "{{ resource_prefix }}"
- task_definition: "{{ resource_prefix }}"
- desired_count: 1
- force_new_deployment: true
- state: present
- register: ecs_service_creation_force_new_deploy
- ignore_errors: yes
-
- - name: check that graceful failure message is returned from ecs_service
- assert:
- that:
- - ecs_service_creation_force_new_deploy.failed
- - 'ecs_service_creation_force_new_deploy.msg == "botocore needs to be version 1.8.4 or higher to use force_new_deployment"'
-
- always:
- - name: scale down ecs service
- ecs_service:
- name: "{{ resource_prefix }}"
- cluster: "{{ resource_prefix }}"
- task_definition: "{{ resource_prefix }}"
- desired_count: 0
- state: present
- ignore_errors: yes
-
- - name: pause to wait for scale down
- pause:
- seconds: 30
-
- - name: remove ecs service
- ecs_service:
- name: "{{ resource_prefix }}"
- cluster: "{{ resource_prefix }}"
- task_definition: "{{ resource_prefix }}"
- desired_count: 1
- state: absent
- ignore_errors: yes
-
- - name: remove ecs task definition
- ecs_taskdefinition:
- containers:
- - name: my_container
- image: ubuntu
- memory: 128
- family: "{{ resource_prefix }}"
- revision: "{{ ecs_taskdefinition_creation.taskdefinition.revision }}"
- state: absent
- ignore_errors: yes
-
- - name: remove ecs cluster
- ecs_cluster:
- name: "{{ resource_prefix }}"
- state: absent
- ignore_errors: yes
diff --git a/tests/integration/targets/efs/aliases b/tests/integration/targets/efs/aliases
index d0d7616f534..60c7f1ac7a6 100644
--- a/tests/integration/targets/efs/aliases
+++ b/tests/integration/targets/efs/aliases
@@ -1,7 +1,4 @@
-# reason: missing-policy
-# ansible/ansible#36520 - attempts were made to get it running in CI but were unsuccessful
-unsupported
-
cloud/aws
efs_info
+efs_tag
diff --git a/tests/integration/targets/efs/defaults/main.yml b/tests/integration/targets/efs/defaults/main.yml
new file mode 100644
index 00000000000..11df6135096
--- /dev/null
+++ b/tests/integration/targets/efs/defaults/main.yml
@@ -0,0 +1 @@
+efs_name: "ansible-test-{{ tiny_prefix }}"
\ No newline at end of file
diff --git a/tests/integration/targets/efs/playbooks/full_test.yml b/tests/integration/targets/efs/playbooks/full_test.yml
deleted file mode 100644
index e15e5aa4e90..00000000000
--- a/tests/integration/targets/efs/playbooks/full_test.yml
+++ /dev/null
@@ -1,9 +0,0 @@
-- hosts: localhost
- connection: local
-# environment: "{{ ansible_test.environment }}"
-
- vars:
- resource_prefix: 'ansible-testing'
-
- roles:
- - efs
diff --git a/tests/integration/targets/efs/playbooks/version_fail.yml b/tests/integration/targets/efs/playbooks/version_fail.yml
deleted file mode 100644
index 6d73b75867e..00000000000
--- a/tests/integration/targets/efs/playbooks/version_fail.yml
+++ /dev/null
@@ -1,32 +0,0 @@
-- hosts: localhost
- connection: local
- environment: "{{ ansible_test.environment }}"
- vars:
- resource_prefix: 'ansible-testing'
-
- tasks:
- - name: 'efs graceful failure tests'
- collections:
- - amazon.aws
- module_defaults:
- group/aws:
- aws_access_key: '{{ aws_access_key }}'
- aws_secret_key: '{{ aws_secret_key }}'
- security_token: '{{ security_token | default(omit) }}'
- region: '{{ aws_region }}'
- block:
-
- - name: create efs with provisioned_throughput options (fails gracefully)
- efs:
- state: present
- name: "{{ resource_prefix }}-efs"
- throughput_mode: 'provisioned'
- provisioned_throughput_in_mibps: 8.0
- register: efs_provisioned_throughput_creation
- ignore_errors: yes
-
- - name: check that graceful error message is returned when creation with throughput_mode and old botocore
- assert:
- that:
- - efs_provisioned_throughput_creation.failed
- - 'efs_provisioned_throughput_creation.msg == "throughput_mode parameter requires botocore >= 1.10.57"'
diff --git a/tests/integration/targets/efs/runme.sh b/tests/integration/targets/efs/runme.sh
deleted file mode 100755
index e4f214b8e85..00000000000
--- a/tests/integration/targets/efs/runme.sh
+++ /dev/null
@@ -1,15 +0,0 @@
-#!/usr/bin/env bash
-
-set -eux
-
-export ANSIBLE_ROLES_PATH=../
-
-# Test graceful failure for older versions of botocore
-source virtualenv.sh
-pip install 'botocore<1.10.57' boto3
-ansible-playbook -i ../../inventory -v playbooks/version_fail.yml "$@"
-
-# Run full test suite
-source virtualenv.sh
-pip install 'botocore>=1.10.57' boto3
-ansible-playbook -i ../../inventory -v playbooks/full_test.yml "$@"
diff --git a/tests/integration/targets/efs/playbooks/roles/efs/tasks/main.yml b/tests/integration/targets/efs/tasks/main.yml
similarity index 52%
rename from tests/integration/targets/efs/playbooks/roles/efs/tasks/main.yml
rename to tests/integration/targets/efs/tasks/main.yml
index 094ac782628..dc8e064dbb2 100644
--- a/tests/integration/targets/efs/playbooks/roles/efs/tasks/main.yml
+++ b/tests/integration/targets/efs/tasks/main.yml
@@ -13,7 +13,7 @@
# ============================================================
- name: Create VPC for testing
ec2_vpc_net:
- name: "{{ resource_prefix }}-vpc"
+ name: "{{ efs_name }}-vpc"
cidr_block: 10.22.32.0/23
tags:
Name: Ansible ec2_instance Testing VPC
@@ -27,7 +27,7 @@
cidr: 10.22.32.0/24
az: "{{ aws_region }}a"
resource_tags:
- Name: "{{ resource_prefix }}-subnet-a"
+ Name: "{{ efs_name }}-subnet-a"
register: testing_subnet_a
- name: Create subnet in zone B for testing
@@ -37,7 +37,7 @@
cidr: 10.22.33.0/24
az: "{{ aws_region }}b"
resource_tags:
- Name: "{{ resource_prefix }}-subnet-b"
+ Name: "{{ efs_name }}-subnet-b"
register: testing_subnet_b
- name: Get default security group id for vpc
@@ -54,9 +54,9 @@
- name: Create Efs for testing
efs:
state: present
- name: "{{ resource_prefix }}-test-efs"
+ name: "{{ efs_name }}-test-efs"
tags:
- Name: "{{ resource_prefix }}-test-tag"
+ Name: "{{ efs_name }}-test-tag"
Purpose: file-storage
targets:
- subnet_id: "{{testing_subnet_a.subnet.id}}"
@@ -76,19 +76,19 @@
# ============================================================
- name: Get EFS by creation token
efs_info:
- name: "{{ resource_prefix }}-test-efs"
+ name: "{{ efs_name }}-test-efs"
register: efs_result
- set_fact:
efs_result_assertions:
- efs_result is not changed
- (efs_result.efs | length) == 1
- - efs_result.efs[0].creation_token == "{{ resource_prefix }}-test-efs"
+ - efs_result.efs[0].creation_token == "{{ efs_name }}-test-efs"
- efs_result.efs[0].file_system_id == created_efs.efs.file_system_id
- efs_result.efs[0].number_of_mount_targets == 2
- (efs_result.efs[0].mount_targets | length) == 2
- - efs_result.efs[0].name == "{{ resource_prefix }}-test-tag"
- - efs_result.efs[0].tags.Name == "{{ resource_prefix }}-test-tag"
+ - efs_result.efs[0].name == "{{ efs_name }}-test-tag"
+ - efs_result.efs[0].tags.Name == "{{ efs_name }}-test-tag"
- efs_result.efs[0].tags.Purpose == "file-storage"
- efs_result.efs[0].encrypted == false
- efs_result.efs[0].life_cycle_state == "available"
@@ -113,7 +113,7 @@
- name: Get EFS by tag
efs_info:
tags:
- Name: "{{ resource_prefix }}-test-tag"
+ Name: "{{ efs_name }}-test-tag"
register: efs_result
- assert:
@@ -143,7 +143,7 @@
- name: Get EFS by tag and target
efs_info:
tags:
- Name: "{{ resource_prefix }}-test-tag"
+ Name: "{{ efs_name }}-test-tag"
targets:
- "{{testing_subnet_a.subnet.id}}"
register: efs_result
@@ -157,9 +157,9 @@
- name: Update Efs to use provisioned throughput_mode
efs:
state: present
- name: "{{ resource_prefix }}-test-efs"
+ name: "{{ efs_name }}-test-efs"
tags:
- Name: "{{ resource_prefix }}-test-tag"
+ Name: "{{ efs_name }}-test-tag"
Purpose: file-storage
targets:
- subnet_id: "{{testing_subnet_a.subnet.id}}"
@@ -168,17 +168,17 @@
provisioned_throughput_in_mibps: 5.0
register: efs_result
- - assert:
- that:
+ - assert:
+ that:
- efs_result is changed
# ============================================================
- name: Efs same value for provisioned_throughput_in_mibps
efs:
state: present
- name: "{{ resource_prefix }}-test-efs"
+ name: "{{ efs_name }}-test-efs"
tags:
- Name: "{{ resource_prefix }}-test-tag"
+ Name: "{{ efs_name }}-test-tag"
Purpose: file-storage
targets:
- subnet_id: "{{testing_subnet_a.subnet.id}}"
@@ -186,9 +186,9 @@
throughput_mode: 'provisioned'
provisioned_throughput_in_mibps: 5.0
register: efs_result
-
+
- assert:
- that:
+ that:
- efs_result is not changed
- efs_result.efs["throughput_mode"] == "provisioned"
- efs_result.efs["provisioned_throughput_in_mibps"] == 5.0
@@ -197,9 +197,9 @@
- name: Efs new value for provisioned_throughput_in_mibps
efs:
state: present
- name: "{{ resource_prefix }}-test-efs"
+ name: "{{ efs_name }}-test-efs"
tags:
- Name: "{{ resource_prefix }}-test-tag"
+ Name: "{{ efs_name }}-test-tag"
Purpose: file-storage
targets:
- subnet_id: "{{testing_subnet_a.subnet.id}}"
@@ -211,12 +211,14 @@
- assert:
that:
- efs_result is changed
- - efs_result.efs["provisioned_throughput_in_mibps"] == 8.0
+ # Change of provisioned_throughput_in_mibps takes time
+ - pause:
+ seconds: 15
# ============================================================
- name: Check new facts with provisioned mode
efs_info:
- name: "{{ resource_prefix }}-test-efs"
+ name: "{{ efs_name }}-test-efs"
register: efs_result
- set_fact:
@@ -225,7 +227,7 @@
- efs_result.efs[0].throughput_mode == "provisioned"
- efs_result.efs[0].provisioned_throughput_in_mibps == 8.0
- (efs_result.efs | length) == 1
- - efs_result.efs[0].creation_token == "{{ resource_prefix }}-test-efs"
+ - efs_result.efs[0].creation_token == "{{ efs_name }}-test-efs"
- efs_result.efs[0].file_system_id == created_efs.efs.file_system_id
- assert:
@@ -235,7 +237,7 @@
- name: Query unknown EFS by tag
efs_info:
tags:
- Name: "{{ resource_prefix }}-unknown"
+ Name: "{{ efs_name }}-unknown"
register: efs_result
- assert:
@@ -254,14 +256,190 @@
- efs_result is not changed
- (efs_result.efs | length) == 0
+ # ============================================================
+ # efs_tag module tests
+ - name: Add tags to EFS filesystem in check mode
+ efs_tag:
+ state: present
+ resource: "{{ created_efs.efs.file_system_id }}"
+ aws_access_key: '{{ aws_access_key }}'
+ aws_secret_key: '{{ aws_secret_key }}'
+ security_token: '{{ security_token | default(omit) }}'
+ region: "{{ aws_region }}"
+ tags:
+ check_mode_tag: 'this tag should not be applied'
+ check_mode: yes
+ register: efs_tag_result
+
+ - assert:
+ that:
+ - not efs_tag_result.tags.check_mode_tag is defined
+
+ - name: Add tags to EFS filesystem
+ efs_tag:
+ state: present
+ resource: "{{ created_efs.efs.file_system_id }}"
+ aws_access_key: '{{ aws_access_key }}'
+ aws_secret_key: '{{ aws_secret_key }}'
+ security_token: '{{ security_token | default(omit) }}'
+ region: "{{ aws_region }}"
+ tags:
+ "Title Case": 'Hello Cruel World'
+ "lowercase spaced": 'hello cruel world'
+ CamelCase: 'SimpleCamelCase'
+ Env: IntegrationTests
+ snake_case: 'simple_snake_case'
+ register: efs_tag_result
+
+ - assert:
+ that:
+ - efs_tag_result.tags.Env is defined
+ - efs_tag_result.tags.Env is search("IntegrationTests")
+ - efs_tag_result.tags.Name is defined
+ - efs_tag_result.tags.Name is search("{{ efs_name }}-test-tag")
+ - efs_tag_result.tags["CamelCase"] == 'SimpleCamelCase'
+ - efs_tag_result.tags["Title Case"] == 'Hello Cruel World'
+ - efs_tag_result.tags["lowercase spaced"] == 'hello cruel world'
+ - efs_tag_result.tags["snake_case"] == 'simple_snake_case'
+ - efs_tag_result is changed
+
+ - name: Add/Change tags on EFS filesystem - idempotency
+ efs_tag:
+ state: present
+ resource: "{{ created_efs.efs.file_system_id }}"
+ aws_access_key: '{{ aws_access_key }}'
+ aws_secret_key: '{{ aws_secret_key }}'
+ security_token: '{{ security_token | default(omit) }}'
+ region: "{{ aws_region }}"
+ tags:
+ Env: IntegrationTests
+ snake_case: 'simple_snake_case'
+ register: efs_tag_result
+
+ - assert:
+ that:
+ - not efs_tag_result is changed
+
+ - name: Remove specific EFS filesystem tag in check mode
+ efs_tag:
+ state: absent
+ resource: "{{ created_efs.efs.file_system_id }}"
+ aws_access_key: '{{ aws_access_key }}'
+ aws_secret_key: '{{ aws_secret_key }}'
+ security_token: '{{ security_token | default(omit) }}'
+ region: "{{ aws_region }}"
+ tags:
+ snake_case: 'simple_snake_case'
+ check_mode: yes
+ register: efs_tag_result
+
+ - assert:
+ that:
+ - efs_tag_result.tags["snake_case"] is defined
+ - efs_tag_result.tags["snake_case"] == 'simple_snake_case'
+
+ - name: Change tags on EFS filesystem
+ efs_tag:
+ state: present
+ resource: "{{ created_efs.efs.file_system_id }}"
+ aws_access_key: '{{ aws_access_key }}'
+ aws_secret_key: '{{ aws_secret_key }}'
+ security_token: '{{ security_token | default(omit) }}'
+ region: "{{ aws_region }}"
+ tags:
+ Env: OtherIntegrationTests
+ register: efs_tag_result
+
+ - assert:
+ that:
+ - efs_tag_result.tags.Env is defined
+ - efs_tag_result.tags.Env is search("OtherIntegrationTests")
+ - efs_tag_result is changed
+
+ - name: Change tags on EFS filesystem - idempotency
+ efs_tag:
+ state: present
+ resource: "{{ created_efs.efs.file_system_id }}"
+ aws_access_key: '{{ aws_access_key }}'
+ aws_secret_key: '{{ aws_secret_key }}'
+ security_token: '{{ security_token | default(omit) }}'
+ region: "{{ aws_region }}"
+ tags:
+ Env: OtherIntegrationTests
+ register: efs_tag_result
+
+ - assert:
+ that:
+ - efs_tag_result.tags.Env is defined
+ - efs_tag_result.tags.Env is search("OtherIntegrationTests")
+ - not efs_tag_result is changed
+
+ - name: Remove specific EFS filesystem tags
+ efs_tag:
+ state: absent
+ resource: "{{ created_efs.efs.file_system_id }}"
+ aws_access_key: '{{ aws_access_key }}'
+ aws_secret_key: '{{ aws_secret_key }}'
+ security_token: '{{ security_token | default(omit) }}'
+ region: "{{ aws_region }}"
+ tags:
+ "Title Case": 'Hello Cruel World'
+ "lowercase spaced": 'hello cruel world'
+ CamelCase: 'SimpleCamelCase'
+ snake_case: 'simple_snake_case'
+ register: efs_tag_result
+
+ - assert:
+ that:
+ - efs_tag_result.tags.Env is defined
+ - efs_tag_result.tags.Env is search("IntegrationTests")
+ - efs_tag_result.tags.Name is defined
+ - efs_tag_result.tags.Name is search("{{ efs_name }}-test-tag")
+ - not efs_tag_result.tags["CamelCase"] is defined
+ - not efs_tag_result.tags["Title Case"] is defined
+ - not efs_tag_result.tags["lowercase spaced"] is defined
+ - not efs_tag_result.tags["snake_case"] is defined
+
+ - name: Remove specific EFS filesystem tag - idempotency
+ efs_tag:
+ state: absent
+ resource: "{{ created_efs.efs.file_system_id }}"
+ aws_access_key: '{{ aws_access_key }}'
+ aws_secret_key: '{{ aws_secret_key }}'
+ security_token: '{{ security_token | default(omit) }}'
+ region: "{{ aws_region }}"
+ tags:
+ snake_case: 'simple_snake_case'
+ register: efs_tag_result
+
+ - assert:
+ that:
+ - not efs_tag_result is changed
+
+ - name: Remove all tag on EFS filesystem
+ efs_tag:
+ state: absent
+ resource: "{{ created_efs.efs.file_system_id }}"
+ region: "{{ aws_region }}"
+ aws_access_key: '{{ aws_access_key }}'
+ aws_secret_key: '{{ aws_secret_key }}'
+ security_token: '{{ security_token | default(omit) }}'
+ tags: {}
+ purge_tags: true
+ register: efs_tag_result
+
+ - assert:
+ that:
+ - efs_tag_result.tags == {}
+
# ============================================================
always:
- name: Delete EFS used for tests
efs:
state: absent
- name: "{{ resource_prefix }}-test-efs"
+ name: "{{ efs_name }}-test-efs"
tags:
- Name: "{{ resource_prefix }}-test-tag"
+ Name: "{{ efs_name }}-test-tag"
Purpose: file-storage
register: removed
until: removed is not failed
@@ -275,7 +453,7 @@
cidr: 10.22.32.0/24
az: "{{ aws_region }}a"
resource_tags:
- Name: "{{ resource_prefix }}-subnet-a"
+ Name: "{{ efs_name }}-subnet-a"
register: removed
until: removed is not failed
ignore_errors: yes
@@ -288,7 +466,7 @@
cidr: 10.22.33.0/24
az: "{{ aws_region }}b"
resource_tags:
- Name: "{{ resource_prefix }}-subnet-b"
+ Name: "{{ efs_name }}-subnet-b"
register: removed
until: removed is not failed
ignore_errors: yes
@@ -296,7 +474,7 @@
- name: remove the VPC
ec2_vpc_net:
- name: "{{ resource_prefix }}-vpc"
+ name: "{{ efs_name }}-vpc"
cidr_block: 10.22.32.0/23
state: absent
register: removed
diff --git a/tests/integration/targets/elasticache/aliases b/tests/integration/targets/elasticache/aliases
index 88ef7754817..5ee1d22add8 100644
--- a/tests/integration/targets/elasticache/aliases
+++ b/tests/integration/targets/elasticache/aliases
@@ -3,5 +3,3 @@
unstable
cloud/aws
-
-elasticache_subnet_group
diff --git a/tests/integration/targets/elasticache_subnet_group/aliases b/tests/integration/targets/elasticache_subnet_group/aliases
new file mode 100644
index 00000000000..4ef4b2067d0
--- /dev/null
+++ b/tests/integration/targets/elasticache_subnet_group/aliases
@@ -0,0 +1 @@
+cloud/aws
diff --git a/tests/integration/targets/elasticache_subnet_group/defaults/main.yml b/tests/integration/targets/elasticache_subnet_group/defaults/main.yml
new file mode 100644
index 00000000000..ea8921880a9
--- /dev/null
+++ b/tests/integration/targets/elasticache_subnet_group/defaults/main.yml
@@ -0,0 +1,42 @@
+---
+availability_zone: '{{ ec2_availability_zone_names[0] }}'
+
+vpc_name: '{{ resource_prefix }}'
+subnet_name_a: '{{ resource_prefix }}-a'
+subnet_name_b: '{{ resource_prefix }}-b'
+subnet_name_c: '{{ resource_prefix }}-c'
+subnet_name_d: '{{ resource_prefix }}-d'
+
+vpc_cidr: '10.{{ 256 | random(seed=resource_prefix) }}.0.0/16'
+subnet_cidr_a: '10.{{ 256 | random(seed=resource_prefix) }}.1.0/24'
+subnet_cidr_b: '10.{{ 256 | random(seed=resource_prefix) }}.2.0/24'
+subnet_cidr_c: '10.{{ 256 | random(seed=resource_prefix) }}.3.0/24'
+subnet_cidr_d: '10.{{ 256 | random(seed=resource_prefix) }}.4.0/24'
+
+subnet_zone_a: '{{ ec2_availability_zone_names[0] }}'
+subnet_zone_b: '{{ ec2_availability_zone_names[1] }}'
+subnet_zone_c: '{{ ec2_availability_zone_names[0] }}'
+subnet_zone_d: '{{ ec2_availability_zone_names[1] }}'
+
+group_name: '{{ resource_prefix }}'
+description_default: 'Subnet Description'
+description_updated: 'updated subnet description'
+
+# Tagging not currently supported, planned with boto3 upgrade
+tags_default:
+ snake_case_key: snake_case_value
+ camelCaseKey: camelCaseValue
+ PascalCaseKey: PascalCaseValue
+ 'key with spaces': value with spaces
+ 'Upper With Spaces': Upper With Spaces
+
+partial_tags:
+ snake_case_key: snake_case_value
+ camelCaseKey: camelCaseValue
+
+updated_tags:
+ updated_snake_case_key: updated_snake_case_value
+ updatedCamelCaseKey: updatedCamelCaseValue
+ UpdatedPascalCaseKey: UpdatedPascalCaseValue
+ 'updated key with spaces': updated value with spaces
+ 'updated Upper With Spaces': Updated Upper With Spaces
diff --git a/tests/integration/targets/elasticache_subnet_group/meta/main.yml b/tests/integration/targets/elasticache_subnet_group/meta/main.yml
new file mode 100644
index 00000000000..930e8622824
--- /dev/null
+++ b/tests/integration/targets/elasticache_subnet_group/meta/main.yml
@@ -0,0 +1,3 @@
+dependencies:
+ - prepare_tests
+ - setup_ec2_facts
diff --git a/tests/integration/targets/elasticache_subnet_group/tasks/main.yml b/tests/integration/targets/elasticache_subnet_group/tasks/main.yml
new file mode 100644
index 00000000000..5814f9dc90d
--- /dev/null
+++ b/tests/integration/targets/elasticache_subnet_group/tasks/main.yml
@@ -0,0 +1,681 @@
+---
+# elasticache_subnet_group integration tests
+#
+# Current module limitations:
+# - check_mode not supported
+# - Tagging not supported
+# - Returned values *very* limited (almost none)
+#
+- module_defaults:
+ group/aws:
+ aws_access_key: '{{ aws_access_key }}'
+ aws_secret_key: '{{ aws_secret_key }}'
+ security_token: '{{ security_token | default(omit) }}'
+ region: '{{ aws_region }}'
+ block:
+
+ # ============================================================
+
+ - name: Create Subnet Group with no subnets - check_mode
+ elasticache_subnet_group:
+ state: present
+ name: '{{ group_name }}'
+ check_mode: True
+ register: create_group
+ ignore_errors: True
+
+ - name: Check result - Create Subnet Group with no subnets - check_mode
+ assert:
+ that:
+ - create_group is failed
+ # Check we caught the issue before trying to create
+ - '"CreateCacheSubnetGroup" not in create_group.resource_actions'
+ # Check that we don't refer to the boto3 parameter
+ - '"SubnetIds" not in create_group.msg'
+ # Loosely check the message
+ - '"subnet" in create_group.msg'
+ - '"At least" in create_group.msg'
+
+ - name: Create Subnet Group with no subnets
+ elasticache_subnet_group:
+ state: present
+ name: '{{ group_name }}'
+ register: create_group
+ ignore_errors: True
+
+ - name: Check result - Create Subnet Group with no subnets
+ assert:
+ that:
+ - create_group is failed
+ # Check we caught the issue before trying to create
+ - '"CreateCacheSubnetGroup" not in create_group.resource_actions'
+ # Check that we don't refer to the boto3 parameter
+ - '"SubnetIds" not in create_group.msg'
+ # Loosely check the message
+ - '"subnet" in create_group.msg'
+ - '"At least" in create_group.msg'
+
+ # ============================================================
+ # Setup infra needed for tests
+ - name: create a VPC
+ ec2_vpc_net:
+ state: present
+ name: '{{ vpc_name }}'
+ cidr_block: '{{ vpc_cidr }}'
+ tags:
+ TestPrefix: '{{ resource_prefix }}'
+ register: vpc_result
+
+ - name: create subnets
+ ec2_vpc_subnet:
+ state: present
+ cidr: '{{ item.cidr }}'
+ az: '{{ item.zone }}'
+ vpc_id: '{{ vpc_result.vpc.id }}'
+ tags:
+ Name: '{{ item.name }}'
+ TestPrefix: '{{ resource_prefix }}'
+ register: vpc_subnet_create
+ loop:
+ - name: '{{ subnet_name_a }}'
+ cidr: '{{ subnet_cidr_a }}'
+ zone: '{{ subnet_zone_a }}'
+ - name: '{{ subnet_name_b }}'
+ cidr: '{{ subnet_cidr_b }}'
+ zone: '{{ subnet_zone_b }}'
+ - name: '{{ subnet_name_c }}'
+ cidr: '{{ subnet_cidr_c }}'
+ zone: '{{ subnet_zone_c }}'
+ - name: '{{ subnet_name_d }}'
+ cidr: '{{ subnet_cidr_d }}'
+ zone: '{{ subnet_zone_d }}'
+
+ - name: Store IDs of subnets and VPC
+ set_fact:
+ vpc_id: '{{ vpc_result.vpc.id }}'
+ subnet_id_a: '{{ vpc_subnet_create.results[0].subnet.id }}'
+ subnet_id_b: '{{ vpc_subnet_create.results[1].subnet.id }}'
+ subnet_id_c: '{{ vpc_subnet_create.results[2].subnet.id }}'
+ subnet_id_d: '{{ vpc_subnet_create.results[3].subnet.id }}'
+
+ # ============================================================
+
+ - name: Create Subnet Group - check_mode
+ elasticache_subnet_group:
+ state: present
+ name: '{{ group_name }}'
+ description: '{{ description_default }}'
+ subnets:
+ - '{{ subnet_id_a }}'
+ - '{{ subnet_id_b }}'
+ check_mode: True
+ register: create_group
+
+ - name: Check result - Create Subnet Group - check_mode
+ assert:
+ that:
+ - create_group is successful
+ - create_group is changed
+
+ - name: Create Subnet Group
+ elasticache_subnet_group:
+ state: present
+ name: '{{ group_name }}'
+ description: '{{ description_default }}'
+ subnets:
+ - '{{ subnet_id_a }}'
+ - '{{ subnet_id_b }}'
+ register: create_group
+
+ - name: Check result - Create Subnet Group
+ assert:
+ that:
+ - create_group is successful
+ - create_group is changed
+ - '"cache_subnet_group" in create_group'
+ - '"arn" in create_group.cache_subnet_group'
+ - '"description" in create_group.cache_subnet_group'
+ - '"name" in create_group.cache_subnet_group'
+ - '"subnet_ids" in create_group.cache_subnet_group'
+ - '"vpc_id" in create_group.cache_subnet_group'
+ - create_group.cache_subnet_group.description == description_default
+ - create_group.cache_subnet_group.name == group_name
+ - subnet_id_a in create_group.cache_subnet_group.subnet_ids
+ - subnet_id_b in create_group.cache_subnet_group.subnet_ids
+ - subnet_id_c not in create_group.cache_subnet_group.subnet_ids
+ - subnet_id_d not in create_group.cache_subnet_group.subnet_ids
+ - create_group.cache_subnet_group.vpc_id == vpc_id
+ - create_group.cache_subnet_group.arn.startswith('arn:')
+ - create_group.cache_subnet_group.arn.endswith(group_name)
+
+ - name: Create Subnet Group - idempotency - check_mode
+ elasticache_subnet_group:
+ state: present
+ name: '{{ group_name }}'
+ description: '{{ description_default }}'
+ subnets:
+ - '{{ subnet_id_a }}'
+ - '{{ subnet_id_b }}'
+ check_mode: True
+ register: create_group
+
+ - name: Check result - Create Subnet Group - idempotency - check_mode
+ assert:
+ that:
+ - create_group is successful
+ - create_group is not changed
+
+ - name: Create Subnet Group - idempotency
+ elasticache_subnet_group:
+ state: present
+ name: '{{ group_name }}'
+ description: '{{ description_default }}'
+ subnets:
+ - '{{ subnet_id_a }}'
+ - '{{ subnet_id_b }}'
+ register: create_group
+
+ - name: Check result - Create Subnet Group - idempotency
+ assert:
+ that:
+ - create_group is successful
+ - create_group is not changed
+ - '"cache_subnet_group" in create_group'
+ - '"arn" in create_group.cache_subnet_group'
+ - '"description" in create_group.cache_subnet_group'
+ - '"name" in create_group.cache_subnet_group'
+ - '"subnet_ids" in create_group.cache_subnet_group'
+ - '"vpc_id" in create_group.cache_subnet_group'
+ - create_group.cache_subnet_group.description == description_default
+ - create_group.cache_subnet_group.name == group_name
+ - subnet_id_a in create_group.cache_subnet_group.subnet_ids
+ - subnet_id_b in create_group.cache_subnet_group.subnet_ids
+ - subnet_id_c not in create_group.cache_subnet_group.subnet_ids
+ - subnet_id_d not in create_group.cache_subnet_group.subnet_ids
+ - create_group.cache_subnet_group.vpc_id == vpc_id
+ - create_group.cache_subnet_group.arn.startswith('arn:')
+ - create_group.cache_subnet_group.arn.endswith(group_name)
+
+ # ============================================================
+
+ - name: Update Subnet Group Description - check_mode
+ elasticache_subnet_group:
+ state: present
+ name: '{{ group_name }}'
+ description: '{{ description_updated }}'
+ ## No longer mandatory
+ # subnets:
+ # - '{{ subnet_id_a }}'
+ # - '{{ subnet_id_b }}'
+ check_mode: True
+ register: update_description
+
+ - name: Check result - Update Subnet Group Description - check_mode
+ assert:
+ that:
+ - update_description is successful
+ - update_description is changed
+
+ - name: Update Subnet Group Description
+ elasticache_subnet_group:
+ state: present
+ name: '{{ group_name }}'
+ description: '{{ description_updated }}'
+ ## No longer mandatory
+ # subnets:
+ # - '{{ subnet_id_a }}'
+ # - '{{ subnet_id_b }}'
+ register: update_description
+
+ - name: Check result - Update Subnet Group Description
+ assert:
+ that:
+ - update_description is successful
+ - update_description is changed
+ - '"cache_subnet_group" in update_description'
+ - '"arn" in update_description.cache_subnet_group'
+ - '"description" in update_description.cache_subnet_group'
+ - '"name" in update_description.cache_subnet_group'
+ - '"subnet_ids" in update_description.cache_subnet_group'
+ - '"vpc_id" in update_description.cache_subnet_group'
+ - update_description.cache_subnet_group.description == description_updated
+ - update_description.cache_subnet_group.name == group_name
+ - subnet_id_a in update_description.cache_subnet_group.subnet_ids
+ - subnet_id_b in update_description.cache_subnet_group.subnet_ids
+ - subnet_id_c not in update_description.cache_subnet_group.subnet_ids
+ - subnet_id_d not in update_description.cache_subnet_group.subnet_ids
+ - update_description.cache_subnet_group.vpc_id == vpc_id
+ - update_description.cache_subnet_group.arn.startswith('arn:')
+ - update_description.cache_subnet_group.arn.endswith(group_name)
+
+ - name: Update Subnet Group Description - idempotency - check_mode
+ elasticache_subnet_group:
+ state: present
+ name: '{{ group_name }}'
+ description: '{{ description_updated }}'
+ ## No longer mandatory
+ # subnets:
+ # - '{{ subnet_id_a }}'
+ # - '{{ subnet_id_b }}'
+ check_mode: True
+ register: update_description
+
+ - name: Check result - Update Subnet Group Description - idempotency - check_mode
+ assert:
+ that:
+ - update_description is successful
+ - update_description is not changed
+
+ - name: Update Subnet Group Description - idempotency
+ elasticache_subnet_group:
+ state: present
+ name: '{{ group_name }}'
+ description: '{{ description_updated }}'
+ ## No longer mandatory
+ # subnets:
+ # - '{{ subnet_id_a }}'
+ # - '{{ subnet_id_b }}'
+ register: update_description
+
+ - name: Check result - Update Subnet Group Description - idempotency
+ assert:
+ that:
+ - update_description is successful
+ - update_description is not changed
+ - '"cache_subnet_group" in update_description'
+ - '"arn" in update_description.cache_subnet_group'
+ - '"description" in update_description.cache_subnet_group'
+ - '"name" in update_description.cache_subnet_group'
+ - '"subnet_ids" in update_description.cache_subnet_group'
+ - '"vpc_id" in update_description.cache_subnet_group'
+ - update_description.cache_subnet_group.description == description_updated
+ - update_description.cache_subnet_group.name == group_name
+ - subnet_id_a in update_description.cache_subnet_group.subnet_ids
+ - subnet_id_b in update_description.cache_subnet_group.subnet_ids
+ - subnet_id_c not in update_description.cache_subnet_group.subnet_ids
+ - subnet_id_d not in update_description.cache_subnet_group.subnet_ids
+ - update_description.cache_subnet_group.vpc_id == vpc_id
+ - update_description.cache_subnet_group.arn.startswith('arn:')
+ - update_description.cache_subnet_group.arn.endswith(group_name)
+
+ # ============================================================
+
+ - name: Update Subnet Group subnets - check_mode
+ elasticache_subnet_group:
+ state: present
+ name: '{{ group_name }}'
+ ## No longer mandatory
+ # description: '{{ description_updated }}'
+ subnets:
+ - '{{ subnet_id_c }}'
+ - '{{ subnet_id_d }}'
+ check_mode: True
+ register: update_subnets
+
+ - name: Check result - Update Subnet Group subnets - check_mode
+ assert:
+ that:
+ - update_subnets is successful
+ - update_subnets is changed
+
+ - name: Update Subnet Group subnets
+ elasticache_subnet_group:
+ state: present
+ name: '{{ group_name }}'
+ ## No longer mandatory
+ # description: '{{ description_updated }}'
+ subnets:
+ - '{{ subnet_id_c }}'
+ - '{{ subnet_id_d }}'
+ register: update_subnets
+
+ - name: Check result - Update Subnet Group subnets
+ assert:
+ that:
+ - update_subnets is successful
+ - update_subnets is changed
+ - '"cache_subnet_group" in update_subnets'
+ - '"arn" in update_subnets.cache_subnet_group'
+ - '"description" in update_subnets.cache_subnet_group'
+ - '"name" in update_subnets.cache_subnet_group'
+ - '"subnet_ids" in update_subnets.cache_subnet_group'
+ - '"vpc_id" in update_subnets.cache_subnet_group'
+ - update_subnets.cache_subnet_group.description == description_updated
+ - update_subnets.cache_subnet_group.name == group_name
+ - subnet_id_a not in update_subnets.cache_subnet_group.subnet_ids
+ - subnet_id_b not in update_subnets.cache_subnet_group.subnet_ids
+ - subnet_id_c in update_subnets.cache_subnet_group.subnet_ids
+ - subnet_id_d in update_subnets.cache_subnet_group.subnet_ids
+ - update_subnets.cache_subnet_group.vpc_id == vpc_id
+ - update_subnets.cache_subnet_group.arn.startswith('arn:')
+ - update_subnets.cache_subnet_group.arn.endswith(group_name)
+
+ - name: Update Subnet Group subnets - idempotency - check_mode
+ elasticache_subnet_group:
+ state: present
+ name: '{{ group_name }}'
+ ## No longer mandatory
+ # description: '{{ description_updated }}'
+ subnets:
+ - '{{ subnet_id_c }}'
+ - '{{ subnet_id_d }}'
+ check_mode: True
+ register: update_subnets
+
+ - name: Check result - Update Subnet Group subnets - idempotency - check_mode
+ assert:
+ that:
+ - update_subnets is successful
+ - update_subnets is not changed
+
+ - name: Update Subnet Group subnets - idempotency
+ elasticache_subnet_group:
+ state: present
+ name: '{{ group_name }}'
+ ## No longer mandatory
+ # description: '{{ description_updated }}'
+ subnets:
+ - '{{ subnet_id_c }}'
+ - '{{ subnet_id_d }}'
+ register: update_subnets
+
+ - name: Check result - Update Subnet Group subnets - idempotency
+ assert:
+ that:
+ - update_subnets is successful
+ - update_subnets is not changed
+ - '"cache_subnet_group" in update_subnets'
+ - '"arn" in update_subnets.cache_subnet_group'
+ - '"description" in update_subnets.cache_subnet_group'
+ - '"name" in update_subnets.cache_subnet_group'
+ - '"subnet_ids" in update_subnets.cache_subnet_group'
+ - '"vpc_id" in update_subnets.cache_subnet_group'
+ - update_subnets.cache_subnet_group.description == description_updated
+ - update_subnets.cache_subnet_group.name == group_name
+ - subnet_id_a not in update_subnets.cache_subnet_group.subnet_ids
+ - subnet_id_b not in update_subnets.cache_subnet_group.subnet_ids
+ - subnet_id_c in update_subnets.cache_subnet_group.subnet_ids
+ - subnet_id_d in update_subnets.cache_subnet_group.subnet_ids
+ - update_subnets.cache_subnet_group.vpc_id == vpc_id
+ - update_subnets.cache_subnet_group.arn.startswith('arn:')
+ - update_subnets.cache_subnet_group.arn.endswith(group_name)
+
+ # ============================================================
+
+ - name: Delete Subnet Group - check_mode
+ elasticache_subnet_group:
+ state: absent
+ name: '{{ group_name }}'
+ check_mode: True
+ register: delete_group
+
+ - name: Check result - Delete Subnet Group - check_mode
+ assert:
+ that:
+ - delete_group is changed
+
+ - name: Delete Subnet Group
+ elasticache_subnet_group:
+ state: absent
+ name: '{{ group_name }}'
+ register: delete_group
+
+ - name: Check result - Delete Subnet Group
+ assert:
+ that:
+ - delete_group is changed
+
+ - name: Delete Subnet Group - idempotency - check_mode
+ elasticache_subnet_group:
+ state: absent
+ name: '{{ group_name }}'
+ check_mode: True
+ register: delete_group
+
+ - name: Check result - Delete Subnet Group - idempotency - check_mode
+ assert:
+ that:
+ - delete_group is not changed
+
+ - name: Delete Subnet Group - idempotency
+ elasticache_subnet_group:
+ state: absent
+ name: '{{ group_name }}'
+ register: delete_group
+
+ - name: Check result - Delete Subnet Group - idempotency
+ assert:
+ that:
+ - delete_group is not changed
+
+ # ============================================================
+
+ - name: Create minimal Subnet Group - check_mode
+ elasticache_subnet_group:
+ state: present
+ name: '{{ group_name }}'
+ subnets:
+ - '{{ subnet_id_a }}'
+ check_mode: True
+ register: create_group
+
+ - name: Check result - Create minimal Subnet Group - check_mode
+ assert:
+ that:
+ - create_group is successful
+ - create_group is changed
+
+ - name: Create minimal Subnet Group
+ elasticache_subnet_group:
+ state: present
+ name: '{{ group_name }}'
+ subnets:
+ - '{{ subnet_id_a }}'
+ register: create_group
+
+ - name: Check result - Create minimal Subnet Group
+ assert:
+ that:
+ - create_group is successful
+ - create_group is changed
+ - '"cache_subnet_group" in create_group'
+ - '"arn" in create_group.cache_subnet_group'
+ - '"description" in create_group.cache_subnet_group'
+ - '"name" in create_group.cache_subnet_group'
+ - '"subnet_ids" in create_group.cache_subnet_group'
+ - '"vpc_id" in create_group.cache_subnet_group'
+ - create_group.cache_subnet_group.description == group_name
+ - create_group.cache_subnet_group.name == group_name
+ - subnet_id_a in create_group.cache_subnet_group.subnet_ids
+ - subnet_id_b not in create_group.cache_subnet_group.subnet_ids
+ - subnet_id_c not in create_group.cache_subnet_group.subnet_ids
+ - subnet_id_d not in create_group.cache_subnet_group.subnet_ids
+ - create_group.cache_subnet_group.vpc_id == vpc_id
+ - create_group.cache_subnet_group.arn.startswith('arn:')
+ - create_group.cache_subnet_group.arn.endswith(group_name)
+
+ - name: Create minimal Subnet Group - idempotency - check_mode
+ elasticache_subnet_group:
+ state: present
+ name: '{{ group_name }}'
+ subnets:
+ - '{{ subnet_id_a }}'
+ check_mode: True
+ register: create_group
+
+ - name: Check result - Create minimal Subnet Group - idempotency - check_mode
+ assert:
+ that:
+ - create_group is successful
+ - create_group is not changed
+
+ - name: Create minimal Subnet Group - idempotency
+ elasticache_subnet_group:
+ state: present
+ name: '{{ group_name }}'
+ subnets:
+ - '{{ subnet_id_a }}'
+ register: create_group
+
+ - name: Check result - Create minimal Subnet Group - idempotency
+ assert:
+ that:
+ - create_group is successful
+ - create_group is not changed
+ - '"cache_subnet_group" in create_group'
+ - '"arn" in create_group.cache_subnet_group'
+ - '"description" in create_group.cache_subnet_group'
+ - '"name" in create_group.cache_subnet_group'
+ - '"subnet_ids" in create_group.cache_subnet_group'
+ - '"vpc_id" in create_group.cache_subnet_group'
+ - create_group.cache_subnet_group.description == group_name
+ - create_group.cache_subnet_group.name == group_name
+ - subnet_id_a in create_group.cache_subnet_group.subnet_ids
+ - subnet_id_b not in create_group.cache_subnet_group.subnet_ids
+ - subnet_id_c not in create_group.cache_subnet_group.subnet_ids
+ - subnet_id_d not in create_group.cache_subnet_group.subnet_ids
+ - create_group.cache_subnet_group.vpc_id == vpc_id
+ - create_group.cache_subnet_group.arn.startswith('arn:')
+ - create_group.cache_subnet_group.arn.endswith(group_name)
+
+ # ============================================================
+
+ - name: Full Update Subnet Group - check_mode
+ elasticache_subnet_group:
+ state: present
+ name: '{{ group_name }}'
+ description: '{{ description_updated }}'
+ subnets:
+ - '{{ subnet_id_a }}'
+ - '{{ subnet_id_b }}'
+ check_mode: True
+ register: update_complex
+
+ - name: Check result - Full Update Subnet Group - check_mode
+ assert:
+ that:
+ - update_complex is successful
+ - update_complex is changed
+
+ - name: Update Subnet Group
+ elasticache_subnet_group:
+ state: present
+ name: '{{ group_name }}'
+ description: '{{ description_updated }}'
+ subnets:
+ - '{{ subnet_id_a }}'
+ - '{{ subnet_id_b }}'
+ register: update_complex
+
+ - name: Check result - Full Update Subnet Group
+ assert:
+ that:
+ - update_complex is successful
+ - update_complex is changed
+ - '"cache_subnet_group" in update_complex'
+ - '"arn" in update_complex.cache_subnet_group'
+ - '"description" in update_complex.cache_subnet_group'
+ - '"name" in update_complex.cache_subnet_group'
+ - '"subnet_ids" in update_complex.cache_subnet_group'
+ - '"vpc_id" in update_complex.cache_subnet_group'
+ - update_complex.cache_subnet_group.description == description_updated
+ - update_complex.cache_subnet_group.name == group_name
+ - subnet_id_a in update_complex.cache_subnet_group.subnet_ids
+ - subnet_id_b in update_complex.cache_subnet_group.subnet_ids
+ - subnet_id_c not in update_complex.cache_subnet_group.subnet_ids
+ - subnet_id_d not in update_complex.cache_subnet_group.subnet_ids
+ - update_complex.cache_subnet_group.vpc_id == vpc_id
+ - update_complex.cache_subnet_group.arn.startswith('arn:')
+ - update_complex.cache_subnet_group.arn.endswith(group_name)
+
+ - name: Full Update Subnet Group - idempotency - check_mode
+ elasticache_subnet_group:
+ state: present
+ name: '{{ group_name }}'
+ description: '{{ description_updated }}'
+ subnets:
+ - '{{ subnet_id_a }}'
+ - '{{ subnet_id_b }}'
+ check_mode: True
+ register: update_complex
+
+ - name: Check result - Full Update Subnet Group - idempotency - check_mode
+ assert:
+ that:
+ - update_complex is successful
+ - update_complex is not changed
+
+ - name: Full Update Subnet Group - idempotency
+ elasticache_subnet_group:
+ state: present
+ name: '{{ group_name }}'
+ description: '{{ description_updated }}'
+ subnets:
+ - '{{ subnet_id_a }}'
+ - '{{ subnet_id_b }}'
+ register: update_complex
+
+ - name: Check result - Full Update Subnet Group - idempotency
+ assert:
+ that:
+ - update_complex is successful
+ - update_complex is not changed
+ - '"cache_subnet_group" in update_complex'
+ - '"arn" in update_complex.cache_subnet_group'
+ - '"description" in update_complex.cache_subnet_group'
+ - '"name" in update_complex.cache_subnet_group'
+ - '"subnet_ids" in update_complex.cache_subnet_group'
+ - '"vpc_id" in update_complex.cache_subnet_group'
+ - update_complex.cache_subnet_group.description == description_updated
+ - update_complex.cache_subnet_group.name == group_name
+ - subnet_id_a in update_complex.cache_subnet_group.subnet_ids
+ - subnet_id_b in update_complex.cache_subnet_group.subnet_ids
+ - subnet_id_c not in update_complex.cache_subnet_group.subnet_ids
+ - subnet_id_d not in update_complex.cache_subnet_group.subnet_ids
+ - update_complex.cache_subnet_group.vpc_id == vpc_id
+ - update_complex.cache_subnet_group.arn.startswith('arn:')
+ - update_complex.cache_subnet_group.arn.endswith(group_name)
+
+ # ============================================================
+
+ - name: Delete Subnet Group
+ elasticache_subnet_group:
+ state: absent
+ name: '{{ group_name }}'
+ register: delete_group
+
+ - name: Check result - Delete Subnet Group
+ assert:
+ that:
+ - delete_group is changed
+
+ always:
+
+ ################################################
+ # TEARDOWN STARTS HERE
+ ################################################
+
+ - name: Delete Subnet Group
+ elasticache_subnet_group:
+ state: absent
+ name: '{{ group_name }}'
+ ignore_errors: True
+
+ - name: tidy up subnet
+ ec2_vpc_subnet:
+ state: absent
+ cidr: '{{ item }}'
+ vpc_id: '{{ vpc_result.vpc.id }}'
+ loop:
+ - '{{ subnet_cidr_a }}'
+ - '{{ subnet_cidr_b }}'
+ - '{{ subnet_cidr_c }}'
+ - '{{ subnet_cidr_d }}'
+ ignore_errors: True
+
+ - name: tidy up VPC
+ ec2_vpc_net:
+ state: absent
+ name: '{{ vpc_name }}'
+ cidr_block: '{{ vpc_cidr }}'
+ ignore_errors: True
diff --git a/tests/integration/targets/elb_application_lb/tasks/full_test.yml b/tests/integration/targets/elb_application_lb/tasks/full_test.yml
index bf68f93aefa..e260d0f7f5c 100644
--- a/tests/integration/targets/elb_application_lb/tasks/full_test.yml
+++ b/tests/integration/targets/elb_application_lb/tasks/full_test.yml
@@ -91,11 +91,6 @@
state: present
register: tg
- # Run tests for graceful failure with an old version of botocore
- - include_tasks: test_multiple_actions_fail.yml
- vars:
- ansible_python_interpreter: "{{ virtualenv_interpreter }}"
-
# Run main tests
- include_tasks: test_alb_bad_listener_options.yml
- include_tasks: test_alb_ip_address_type_options.yml
diff --git a/tests/integration/targets/elb_application_lb/tasks/main.yml b/tests/integration/targets/elb_application_lb/tasks/main.yml
index 5bf26c54fd5..90914288d88 100644
--- a/tests/integration/targets/elb_application_lb/tasks/main.yml
+++ b/tests/integration/targets/elb_application_lb/tasks/main.yml
@@ -9,32 +9,4 @@
region: '{{ aws_region }}'
block:
- # Prepare a virtual environment for multiple_actions_fail.yml
- - set_fact:
- virtualenv: "{{ remote_tmp_dir }}/virtualenv"
- virtualenv_command: "{{ ansible_python_interpreter }} -m virtualenv"
-
- - set_fact:
- virtualenv_interpreter: "{{ virtualenv }}/bin/python"
-
- - pip:
- name: virtualenv
-
- - pip:
- name:
- - 'botocore<1.10.30'
- - boto3
- - boto
- - coverage<5
- - cryptography
- virtualenv: "{{ virtualenv }}"
- virtualenv_command: "{{ virtualenv_command }}"
- virtualenv_site_packages: no
-
- include_tasks: full_test.yml
-
- always:
-
- - file:
- path: "{{ virtualenv }}"
- state: absent
diff --git a/tests/integration/targets/elb_application_lb/tasks/test_multiple_actions_fail.yml b/tests/integration/targets/elb_application_lb/tasks/test_multiple_actions_fail.yml
deleted file mode 100644
index 2e0d0700825..00000000000
--- a/tests/integration/targets/elb_application_lb/tasks/test_multiple_actions_fail.yml
+++ /dev/null
@@ -1,50 +0,0 @@
-- block:
-
- - name: register dummy OIDC config
- set_fact:
- AuthenticateOidcActionConfig:
- AuthorizationEndpoint: "https://www.example.com/auth"
- ClientId: "eeeeeeeeeeeeeeeeeeeeeeeeee"
- ClientSecret: "eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee"
- Issuer: "https://www.example.com/issuer"
- OnUnauthenticatedRequest: "authenticate"
- Scope: "openid"
- SessionCookieName: "AWSELBAuthSessionCookie"
- SessionTimeout: 604800
- TokenEndpoint: "https://www.example.com/token"
- UserInfoEndpoint: "https://www.example.com/userinfo"
-
- - name: create ALB with multiple DefaultActions
- elb_application_lb:
- name: "{{ alb_name }}"
- subnets: "{{ alb_subnets }}"
- security_groups: "{{ sec_group.group_id }}"
- state: present
- listeners:
- - Protocol: HTTP
- Port: 80
- DefaultActions:
- - Type: forward
- TargetGroupName: "{{ tg_name }}"
- Order: 2
- - Type: authenticate-oidc
- AuthenticateOidcConfig: "{{ AuthenticateOidcActionConfig }}"
- Order: 1
- register: alb
- ignore_errors: yes
-
- - name: check for a graceful failure message
- assert:
- that:
- - alb.failed
- - 'alb.msg == "installed version of botocore does not support multiple actions, please upgrade botocore to version 1.10.30 or higher"'
-
- always:
- # Cleanup
- - name: destroy ALB if created
- elb_application_lb:
- name: '{{ alb_name }}'
- state: absent
- wait: true
- wait_timeout: 600
- ignore_errors: true
diff --git a/tests/integration/targets/elb_application_lb_info/tasks/main.yml b/tests/integration/targets/elb_application_lb_info/tasks/main.yml
index 4ec0660c237..5d9eb4fe73f 100644
--- a/tests/integration/targets/elb_application_lb_info/tasks/main.yml
+++ b/tests/integration/targets/elb_application_lb_info/tasks/main.yml
@@ -8,33 +8,4 @@
security_token: '{{ security_token | default(omit) }}'
region: '{{ aws_region }}'
block:
-
- # Prepare a virtual environment for multiple_actions_fail.yml
- - set_fact:
- virtualenv: "{{ remote_tmp_dir }}/virtualenv"
- virtualenv_command: "{{ ansible_python_interpreter }} -m virtualenv"
-
- - set_fact:
- virtualenv_interpreter: "{{ virtualenv }}/bin/python"
-
- - pip:
- name: virtualenv
-
- - pip:
- name:
- - 'botocore<1.10.30'
- - boto3
- - boto
- - coverage<5
- - cryptography
- virtualenv: "{{ virtualenv }}"
- virtualenv_command: "{{ virtualenv_command }}"
- virtualenv_site_packages: no
-
- include_tasks: full_test.yml
-
- always:
-
- - file:
- path: "{{ virtualenv }}"
- state: absent
diff --git a/tests/integration/targets/elb_instance/aliases b/tests/integration/targets/elb_instance/aliases
new file mode 100644
index 00000000000..4ef4b2067d0
--- /dev/null
+++ b/tests/integration/targets/elb_instance/aliases
@@ -0,0 +1 @@
+cloud/aws
diff --git a/tests/integration/targets/elb_instance/defaults/main.yml b/tests/integration/targets/elb_instance/defaults/main.yml
new file mode 100644
index 00000000000..65b75091b6b
--- /dev/null
+++ b/tests/integration/targets/elb_instance/defaults/main.yml
@@ -0,0 +1,17 @@
+---
+# defaults file for ec2_elb_lb
+elb_name_1: 'ansible-test-{{ tiny_prefix }}-1'
+elb_name_2: 'ansible-test-{{ tiny_prefix }}-2'
+
+vpc_cidr: '10.{{ 256 | random(seed=resource_prefix) }}.0.0/16'
+subnet_cidr_1: '10.{{ 256 | random(seed=resource_prefix) }}.1.0/24'
+subnet_cidr_2: '10.{{ 256 | random(seed=resource_prefix) }}.2.0/24'
+
+availability_zone_a: '{{ ec2_availability_zone_names[0] }}'
+availability_zone_b: '{{ ec2_availability_zone_names[1] }}'
+
+elb_listeners:
+ - protocol: tcp
+ load_balancer_port: 80
+ instance_port: 80
+ instance_protocol: tcp
diff --git a/tests/integration/targets/elb_instance/meta/main.yml b/tests/integration/targets/elb_instance/meta/main.yml
new file mode 100644
index 00000000000..a0c556a5cb1
--- /dev/null
+++ b/tests/integration/targets/elb_instance/meta/main.yml
@@ -0,0 +1,4 @@
+dependencies:
+ - prepare_tests
+ - setup_ec2
+ - setup_ec2_facts
diff --git a/tests/integration/targets/elb_instance/tasks/cleanup_elbs.yml b/tests/integration/targets/elb_instance/tasks/cleanup_elbs.yml
new file mode 100644
index 00000000000..92f7e31ae6b
--- /dev/null
+++ b/tests/integration/targets/elb_instance/tasks/cleanup_elbs.yml
@@ -0,0 +1,16 @@
+---
+- name: remove the public load balancer
+ elb_classic_lb:
+ name: "{{ elb_name_1 }}"
+ state: absent
+ wait: true
+ register: result
+ ignore_errors: true
+
+- name: remove the private load balancer
+ elb_classic_lb:
+ name: "{{ elb_name_2 }}"
+ state: absent
+ wait: true
+ register: result
+ ignore_errors: true
diff --git a/tests/integration/targets/elb_instance/tasks/cleanup_instances.yml b/tests/integration/targets/elb_instance/tasks/cleanup_instances.yml
new file mode 100644
index 00000000000..5ad09127084
--- /dev/null
+++ b/tests/integration/targets/elb_instance/tasks/cleanup_instances.yml
@@ -0,0 +1,23 @@
+---
+- name: Delete instance
+ ec2_instance:
+ instance_ids:
+ - '{{ instance_a }}'
+ - '{{ instance_b }}'
+ state: absent
+ wait: true
+ ignore_errors: true
+
+- name: Delete ASG
+ ec2_asg:
+ name: "ansible-test-{{ tiny_prefix }}-elb"
+ state: absent
+ ignore_errors: true
+ register: ec2_asg_a
+
+- name: Delete Launch Template
+ ec2_lc:
+ name: "ansible-test-{{ tiny_prefix }}-elb"
+ state: absent
+ ignore_errors: true
+ register: ec2_lc_a
diff --git a/tests/integration/targets/elb_instance/tasks/cleanup_vpc.yml b/tests/integration/targets/elb_instance/tasks/cleanup_vpc.yml
new file mode 100644
index 00000000000..5c79f7adfbe
--- /dev/null
+++ b/tests/integration/targets/elb_instance/tasks/cleanup_vpc.yml
@@ -0,0 +1,26 @@
+---
+- name: delete security groups
+ ec2_group:
+ name: '{{ item }}'
+ state: absent
+ ignore_errors: true
+ loop:
+ - '{{ resource_prefix }}-a'
+ - '{{ resource_prefix }}-b'
+
+- name: delete subnets
+ ec2_vpc_subnet:
+ vpc_id: '{{ setup_vpc.vpc.id }}'
+ cidr: '{{ item }}'
+ state: absent
+ ignore_errors: true
+ loop:
+ - '{{ subnet_cidr_1 }}'
+ - '{{ subnet_cidr_2 }}'
+
+- name: delete VPC
+ ec2_vpc_net:
+ cidr_block: '{{ vpc_cidr }}'
+ state: absent
+ name: '{{ resource_prefix }}'
+ ignore_errors: true
diff --git a/tests/integration/targets/elb_instance/tasks/main.yml b/tests/integration/targets/elb_instance/tasks/main.yml
new file mode 100644
index 00000000000..247b6f6b6c1
--- /dev/null
+++ b/tests/integration/targets/elb_instance/tasks/main.yml
@@ -0,0 +1,29 @@
+---
+- module_defaults:
+ group/aws:
+ region: "{{ aws_region }}"
+ aws_access_key: "{{ aws_access_key }}"
+ aws_secret_key: "{{ aws_secret_key }}"
+ security_token: "{{ security_token | default(omit) }}"
+ collections:
+ - community.aws
+ - amazon.aws
+ block:
+ # ============================================================
+
+ - include_tasks: setup_vpc.yml
+ - include_tasks: setup_elbs.yml
+ - include_tasks: setup_instances.yml
+
+ # ============================================================
+
+ - include_tasks: manage_instances.yml
+ - include_tasks: manage_asgs.yml
+
+ always:
+
+ # ============================================================
+
+ - include_tasks: cleanup_elbs.yml
+ - include_tasks: cleanup_instances.yml
+ - include_tasks: cleanup_vpc.yml
diff --git a/tests/integration/targets/elb_instance/tasks/manage_asgs.yml b/tests/integration/targets/elb_instance/tasks/manage_asgs.yml
new file mode 100644
index 00000000000..b4e246ef08c
--- /dev/null
+++ b/tests/integration/targets/elb_instance/tasks/manage_asgs.yml
@@ -0,0 +1,110 @@
+---
+- name: Get ASG info
+ ec2_asg_info:
+ name: "ansible-test-{{ tiny_prefix }}-elb$"
+ register: asg_info
+
+- name: Store Instance ID from ASG
+ set_fact:
+ instance_asg: '{{ asg_info.results[0].instances[0].instance_id }}'
+
+- name: 'Remove an instance from ELB (check_mode)'
+ elb_instance:
+ instance_id: '{{ instance_asg }}'
+ state: 'absent'
+ wait_timeout: 60
+ register: remove_instance
+ check_mode: true
+
+- elb_classic_lb_info:
+ names: '{{ elb_name_1 }}'
+ register: elb_info_1
+- elb_classic_lb_info:
+ names: '{{ elb_name_2 }}'
+ register: elb_info_2
+
+- assert:
+ that:
+ - remove_instance is successful
+ # - remove_instance is changed
+ # It really shouldn't be returning a fact here
+ - '"ansible_facts" in remove_instance'
+ - '"ec2_elbs" in remove_instance.ansible_facts'
+ - elb_name_1 in remove_instance.ansible_facts.ec2_elbs
+ - elb_name_2 in remove_instance.ansible_facts.ec2_elbs
+ # Check the real state didn't change
+ - instance_asg in elb_info_1.elbs[0].instances_inservice
+ - instance_asg in elb_info_2.elbs[0].instances_inservice
+
+- name: 'Remove an instance from ELB'
+ elb_instance:
+ instance_id: '{{ instance_asg }}'
+ state: 'absent'
+ wait_timeout: 60
+ register: remove_instance
+
+- elb_classic_lb_info:
+ names: '{{ elb_name_1 }}'
+ register: elb_info_1
+- elb_classic_lb_info:
+ names: '{{ elb_name_2 }}'
+ register: elb_info_2
+
+- assert:
+ that:
+ - remove_instance is successful
+ - remove_instance is changed
+ # It really shouldn't be returning a fact here
+ - '"ansible_facts" in remove_instance'
+ - '"ec2_elbs" in remove_instance.ansible_facts'
+ - elb_name_1 in remove_instance.ansible_facts.ec2_elbs
+ - elb_name_2 in remove_instance.ansible_facts.ec2_elbs
+ # Check the real state
+ - instance_asg not in elb_info_1.elbs[0].instances_inservice
+ - instance_asg not in elb_info_2.elbs[0].instances_inservice
+
+- name: 'Remove an instance from ELB - idempotency (check_mode)'
+ elb_instance:
+ instance_id: '{{ instance_asg }}'
+ state: 'absent'
+ wait_timeout: 60
+ register: remove_instance
+ check_mode: true
+
+- elb_classic_lb_info:
+ names: '{{ elb_name_1 }}'
+ register: elb_info_1
+- elb_classic_lb_info:
+ names: '{{ elb_name_2 }}'
+ register: elb_info_2
+
+- assert:
+ that:
+ - remove_instance is successful
+ - remove_instance is not changed
+ # Check the real state
+ - instance_asg not in elb_info_1.elbs[0].instances_inservice
+ - instance_asg not in elb_info_2.elbs[0].instances_inservice
+
+- name: 'Remove an instance from ELB - idempotency'
+ elb_instance:
+ instance_id: '{{ instance_asg }}'
+ state: 'absent'
+ wait_timeout: 60
+ register: remove_instance
+
+- elb_classic_lb_info:
+ names: '{{ elb_name_1 }}'
+ register: elb_info_1
+- elb_classic_lb_info:
+ names: '{{ elb_name_2 }}'
+ register: elb_info_2
+
+- assert:
+ that:
+ - remove_instance is successful
+ # XXX always returns the ELBs the ASG belongs to
+ # - remove_instance is not changed
+ # Check the real state
+ - instance_asg not in elb_info_1.elbs[0].instances_inservice
+ - instance_asg not in elb_info_2.elbs[0].instances_inservice
diff --git a/tests/integration/targets/elb_instance/tasks/manage_instances.yml b/tests/integration/targets/elb_instance/tasks/manage_instances.yml
new file mode 100644
index 00000000000..4530b371ede
--- /dev/null
+++ b/tests/integration/targets/elb_instance/tasks/manage_instances.yml
@@ -0,0 +1,357 @@
+---
+- name: 'Wait for instances to be OK'
+ ec2_instance:
+ instance_ids:
+ - '{{ instance_a }}'
+ - '{{ instance_b }}'
+ state: 'started'
+
+- name: 'Add an instance to two ELBs (check_mode)'
+ elb_instance:
+ instance_id: '{{ instance_a }}'
+ state: 'present'
+ ec2_elbs:
+ - '{{ elb_name_1 }}'
+ - '{{ elb_name_2 }}'
+ wait_timeout: 60
+ register: add_instance
+ check_mode: true
+
+- elb_classic_lb_info:
+ names: '{{ elb_name_1 }}'
+ register: elb_info_1
+- elb_classic_lb_info:
+ names: '{{ elb_name_2 }}'
+ register: elb_info_2
+
+- assert:
+ that:
+ - add_instance is successful
+ # - add_instance is changed
+ # It really shouldn't be returning a fact here
+ - '"ansible_facts" in add_instance'
+ - '"ec2_elbs" in add_instance.ansible_facts'
+ - elb_name_1 in add_instance.ansible_facts.ec2_elbs
+ - elb_name_2 in add_instance.ansible_facts.ec2_elbs
+ # Check the real state didn't change
+ - instance_a not in elb_info_1.elbs[0].instances_inservice
+ - instance_a not in elb_info_2.elbs[0].instances_inservice
+
+- name: 'Add an instance to two ELBs'
+ elb_instance:
+ instance_id: '{{ instance_a }}'
+ state: 'present'
+ ec2_elbs:
+ - '{{ elb_name_1 }}'
+ - '{{ elb_name_2 }}'
+ wait_timeout: 60
+ register: add_instance
+
+- elb_classic_lb_info:
+ names: '{{ elb_name_1 }}'
+ register: elb_info_1
+- elb_classic_lb_info:
+ names: '{{ elb_name_2 }}'
+ register: elb_info_2
+
+- assert:
+ that:
+ - add_instance is successful
+ - add_instance is changed
+ # It really shouldn't be returning a fact here
+ - '"ansible_facts" in add_instance'
+ - '"ec2_elbs" in add_instance.ansible_facts'
+ - elb_name_1 in add_instance.ansible_facts.ec2_elbs
+ - elb_name_2 in add_instance.ansible_facts.ec2_elbs
+ # Check the real state
+ - instance_a in elb_info_1.elbs[0].instances_inservice
+ - instance_a in elb_info_2.elbs[0].instances_inservice
+
+- name: 'Add an instance to two ELBs - idempotency (check_mode)'
+ elb_instance:
+ instance_id: '{{ instance_a }}'
+ state: 'present'
+ ec2_elbs:
+ - '{{ elb_name_1 }}'
+ - '{{ elb_name_2 }}'
+ wait_timeout: 60
+ register: add_instance
+ check_mode: true
+
+- elb_classic_lb_info:
+ names: '{{ elb_name_1 }}'
+ register: elb_info_1
+- elb_classic_lb_info:
+ names: '{{ elb_name_2 }}'
+ register: elb_info_2
+
+- assert:
+ that:
+ - add_instance is successful
+ - add_instance is not changed
+ # Check the real state didn't change
+ - instance_a in elb_info_1.elbs[0].instances_inservice
+ - instance_a in elb_info_2.elbs[0].instances_inservice
+
+- name: 'Add an instance to two ELBs - idempotency'
+ elb_instance:
+ instance_id: '{{ instance_a }}'
+ state: 'present'
+ ec2_elbs:
+ - '{{ elb_name_1 }}'
+ - '{{ elb_name_2 }}'
+ wait_timeout: 60
+ register: add_instance
+
+- elb_classic_lb_info:
+ names: '{{ elb_name_1 }}'
+ register: elb_info_1
+- elb_classic_lb_info:
+ names: '{{ elb_name_2 }}'
+ register: elb_info_2
+
+- assert:
+ that:
+ - add_instance is successful
+ - add_instance is not changed
+ # Check the real state didn't change
+ - instance_a in elb_info_1.elbs[0].instances_inservice
+ - instance_a in elb_info_2.elbs[0].instances_inservice
+
+###############################################################################
+
+- name: 'Add an instance to an ELB in wrong AZ (check_mode)'
+ elb_instance:
+ instance_id: '{{ instance_b }}'
+ state: 'present'
+ ec2_elbs:
+ - '{{ elb_name_1 }}'
+ wait_timeout: 60
+ register: add_instance
+ check_mode: true
+ ignore_errors: true
+
+- elb_classic_lb_info:
+ names: '{{ elb_name_1 }}'
+ register: elb_info_1
+
+- assert:
+ that:
+ # - add_instance is failed
+ # Check the real state didn't change
+ - instance_b not in elb_info_1.elbs[0].instances_inservice
+
+- name: 'Add an instance to an ELB in wrong AZ'
+ elb_instance:
+ instance_id: '{{ instance_b }}'
+ state: 'present'
+ ec2_elbs:
+ - '{{ elb_name_1 }}'
+ wait_timeout: 60
+ register: add_instance
+ ignore_errors: true
+
+- elb_classic_lb_info:
+ names: '{{ elb_name_1 }}'
+ register: elb_info_1
+
+- assert:
+ that:
+ - add_instance is failed
+ - instance_b not in elb_info_1.elbs[0].instances_inservice
+
+################################################################################
+# Currently doesn't support adding an AZ if you're not using the default VPC
+#
+# - name: 'Add an instance to an ELB with enable_availability_zone (check_mode)'
+# elb_instance:
+# instance_id: '{{ instance_b }}'
+# state: 'present'
+# ec2_elbs:
+# - '{{ elb_name_1 }}'
+# wait_timeout: 60
+# register: add_instance
+# check_mode: true
+# ignore_errors: true
+#
+# - elb_classic_lb_info:
+# names: '{{ elb_name_1 }}'
+# register: elb_info_1
+#
+# - assert:
+# that:
+# - add_instance is successful
+# # - add_instance is changed
+#
+# - name: 'Add an instance to an ELB with enable_availability_zone'
+# elb_instance:
+# instance_id: '{{ instance_b }}'
+# state: 'present'
+# ec2_elbs:
+# - '{{ elb_name_1 }}'
+# wait_timeout: 60
+# register: add_instance
+# ignore_errors: true
+#
+# - elb_classic_lb_info:
+# names: '{{ elb_name_1 }}'
+# register: elb_info_1
+#
+# - assert:
+# that:
+# - add_instance is successful
+# - add_instance is changed
+#
+# - name: 'Add an instance to an ELB with enable_availability_zone - idempotency (check_mode)'
+# elb_instance:
+# instance_id: '{{ instance_b }}'
+# state: 'present'
+# ec2_elbs:
+# - '{{ elb_name_1 }}'
+# wait_timeout: 60
+# register: add_instance
+# check_mode: true
+# ignore_errors: true
+#
+# - elb_classic_lb_info:
+# names: '{{ elb_name_2 }}'
+# register: elb_info_1
+#
+# - assert:
+# that:
+# - add_instance is successful
+# - add_instance is not changed
+#
+# - name: 'Add an instance to an ELB with enable_availability_zone - idempotency'
+# elb_instance:
+# instance_id: '{{ instance_b }}'
+# state: 'present'
+# ec2_elbs:
+# - '{{ elb_name_1 }}'
+# wait_timeout: 60
+# register: add_instance
+# ignore_errors: true
+#
+# - elb_classic_lb_info:
+# names: '{{ elb_name_1 }}'
+# register: elb_info_1
+#
+# - assert:
+# that:
+# - add_instance is successful
+# - add_instance is not changed
+#
+################################################################################
+
+
+- name: 'Remove an instance from two ELBs (check_mode)'
+ elb_instance:
+ instance_id: '{{ instance_a }}'
+ state: 'absent'
+ ec2_elbs:
+ - '{{ elb_name_1 }}'
+ - '{{ elb_name_2 }}'
+ wait_timeout: 60
+ register: remove_instance
+ check_mode: true
+
+- elb_classic_lb_info:
+ names: '{{ elb_name_1 }}'
+ register: elb_info_1
+- elb_classic_lb_info:
+ names: '{{ elb_name_2 }}'
+ register: elb_info_2
+
+- assert:
+ that:
+ - remove_instance is successful
+ # - remove_instance is changed
+ # It really shouldn't be returning a fact here
+ - '"ansible_facts" in remove_instance'
+ - '"ec2_elbs" in remove_instance.ansible_facts'
+ - elb_name_1 in remove_instance.ansible_facts.ec2_elbs
+ - elb_name_2 in remove_instance.ansible_facts.ec2_elbs
+ # Check the real state didn't change
+ - instance_a in elb_info_1.elbs[0].instances_inservice
+ - instance_a in elb_info_2.elbs[0].instances_inservice
+
+- name: 'Remove an instance from two ELBs'
+ elb_instance:
+ instance_id: '{{ instance_a }}'
+ state: 'absent'
+ ec2_elbs:
+ - '{{ elb_name_1 }}'
+ - '{{ elb_name_2 }}'
+ wait_timeout: 60
+ register: remove_instance
+
+- elb_classic_lb_info:
+ names: '{{ elb_name_1 }}'
+ register: elb_info_1
+- elb_classic_lb_info:
+ names: '{{ elb_name_2 }}'
+ register: elb_info_2
+
+- assert:
+ that:
+ - remove_instance is successful
+ - remove_instance is changed
+ # It really shouldn't be returning a fact here
+ - '"ansible_facts" in remove_instance'
+ - '"ec2_elbs" in remove_instance.ansible_facts'
+ - elb_name_1 in remove_instance.ansible_facts.ec2_elbs
+ - elb_name_2 in remove_instance.ansible_facts.ec2_elbs
+ # Check the real state
+ - instance_a not in elb_info_1.elbs[0].instances_inservice
+ - instance_a not in elb_info_2.elbs[0].instances_inservice
+
+- name: 'Remove an instance from two ELBs - idempotency (check_mode)'
+ elb_instance:
+ instance_id: '{{ instance_a }}'
+ state: 'absent'
+ ec2_elbs:
+ - '{{ elb_name_1 }}'
+ - '{{ elb_name_2 }}'
+ wait_timeout: 60
+ register: remove_instance
+ check_mode: true
+
+- elb_classic_lb_info:
+ names: '{{ elb_name_1 }}'
+ register: elb_info_1
+- elb_classic_lb_info:
+ names: '{{ elb_name_2 }}'
+ register: elb_info_2
+
+- assert:
+ that:
+ - remove_instance is successful
+ - remove_instance is not changed
+ # Check the real state didn't change
+ - instance_a not in elb_info_1.elbs[0].instances_inservice
+ - instance_a not in elb_info_2.elbs[0].instances_inservice
+
+- name: 'Remove an instance from two ELBs - idempotency'
+ elb_instance:
+ instance_id: '{{ instance_a }}'
+ state: 'absent'
+ ec2_elbs:
+ - '{{ elb_name_1 }}'
+ - '{{ elb_name_2 }}'
+ wait_timeout: 60
+ register: remove_instance
+
+- elb_classic_lb_info:
+ names: '{{ elb_name_1 }}'
+ register: elb_info_1
+- elb_classic_lb_info:
+ names: '{{ elb_name_2 }}'
+ register: elb_info_2
+
+- assert:
+ that:
+ - remove_instance is successful
+ - remove_instance is not changed
+ # Check the real state didn't change
+ - instance_a not in elb_info_1.elbs[0].instances_inservice
+ - instance_a not in elb_info_2.elbs[0].instances_inservice
diff --git a/tests/integration/targets/elb_instance/tasks/setup_elbs.yml b/tests/integration/targets/elb_instance/tasks/setup_elbs.yml
new file mode 100644
index 00000000000..835c7a03600
--- /dev/null
+++ b/tests/integration/targets/elb_instance/tasks/setup_elbs.yml
@@ -0,0 +1,45 @@
+---
+
+- name: Create a private load balancer with 1 AZ enabled
+ elb_classic_lb:
+ name: "{{ elb_name_1 }}"
+ state: present
+ scheme: 'internal'
+ subnets: ['{{ subnet_a }}']
+ listeners: '{{ elb_listeners }}'
+ wait: true
+ health_check:
+ ping_protocol: TCP
+ ping_port: 22
+ healthy_threshold: 2
+ unhealthy_threshold: 2
+ interval: 5
+ timeout: 2
+ register: result
+
+- assert:
+ that:
+ - result is changed
+ - result.elb.status == "created"
+
+- name: Create a private load balancer with 2 AZs enabled
+ elb_classic_lb:
+ name: "{{ elb_name_2 }}"
+ state: present
+ scheme: 'internal'
+ subnets: ['{{ subnet_a }}', '{{ subnet_b }}']
+ listeners: '{{ elb_listeners }}'
+ wait: true
+ health_check:
+ ping_protocol: TCP
+ ping_port: 22
+ healthy_threshold: 2
+ unhealthy_threshold: 2
+ interval: 5
+ timeout: 2
+ register: result
+
+- assert:
+ that:
+ - result is changed
+ - result.elb.status == "created"
diff --git a/tests/integration/targets/elb_instance/tasks/setup_instances.yml b/tests/integration/targets/elb_instance/tasks/setup_instances.yml
new file mode 100644
index 00000000000..2abc348dfca
--- /dev/null
+++ b/tests/integration/targets/elb_instance/tasks/setup_instances.yml
@@ -0,0 +1,52 @@
+---
+- name: Create instance a
+ ec2_instance:
+ name: "ansible-test-{{ tiny_prefix }}-elb-a"
+ image_id: "{{ ec2_ami_id }}"
+ vpc_subnet_id: "{{ subnet_a }}"
+ instance_type: t3.micro
+ wait: false
+ security_group: "{{ sg_a }}"
+ register: ec2_instance_a
+
+- name: Create instance b
+ ec2_instance:
+ name: "ansible-test-{{ tiny_prefix }}-elb-b"
+ image_id: "{{ ec2_ami_id }}"
+ vpc_subnet_id: "{{ subnet_b }}"
+ instance_type: t3.micro
+ wait: false
+ security_group: "{{ sg_a }}"
+ register: ec2_instance_b
+
+- name: store the Instance IDs
+ set_fact:
+ instance_a: "{{ ec2_instance_a.instance_ids[0] }}"
+ instance_b: "{{ ec2_instance_b.instance_ids[0] }}"
+
+- name: Create a Launch Template
+ ec2_lc:
+ name: "ansible-test-{{ tiny_prefix }}-elb"
+ image_id: "{{ ec2_ami_id }}"
+ security_groups: "{{ sg_a }}"
+ instance_type: t3.micro
+ assign_public_ip: no
+ register: ec2_lc_a
+
+- name: Create an ASG
+ ec2_asg:
+ name: "ansible-test-{{ tiny_prefix }}-elb"
+ load_balancers:
+ - "{{ elb_name_1 }}"
+ - "{{ elb_name_2 }}"
+ launch_config_name: "ansible-test-{{ tiny_prefix }}-elb"
+ availability_zones:
+ - "{{ availability_zone_a }}"
+ min_size: 0
+ max_size: 1
+ desired_capacity: 1
+ wait_timeout: 600
+ health_check_period: 60
+ vpc_zone_identifier:
+ - "{{ subnet_a }}"
+ register: ec2_asg_a
diff --git a/tests/integration/targets/elb_instance/tasks/setup_vpc.yml b/tests/integration/targets/elb_instance/tasks/setup_vpc.yml
new file mode 100644
index 00000000000..6edbe7e2c9b
--- /dev/null
+++ b/tests/integration/targets/elb_instance/tasks/setup_vpc.yml
@@ -0,0 +1,65 @@
+---
+# SETUP: vpc, subnet, security group
+- name: create a VPC to work in
+ ec2_vpc_net:
+ cidr_block: '{{ vpc_cidr }}'
+ state: present
+ name: '{{ resource_prefix }}'
+ resource_tags:
+ Name: '{{ resource_prefix }}'
+ register: setup_vpc
+
+- name: create a subnet
+ ec2_vpc_subnet:
+ az: '{{ availability_zone_a }}'
+ tags: '{{ resource_prefix }}'
+ vpc_id: '{{ setup_vpc.vpc.id }}'
+ cidr: '{{ subnet_cidr_1 }}'
+ state: present
+ resource_tags:
+ Name: '{{ resource_prefix }}-a'
+ register: setup_subnet_1
+
+- name: create a subnet
+ ec2_vpc_subnet:
+ az: '{{ availability_zone_b }}'
+ tags: '{{ resource_prefix }}'
+ vpc_id: '{{ setup_vpc.vpc.id }}'
+ cidr: '{{ subnet_cidr_2 }}'
+ state: present
+ resource_tags:
+ Name: '{{ resource_prefix }}-b'
+ register: setup_subnet_2
+
+- name: create a security group
+ ec2_group:
+ name: '{{ resource_prefix }}-a'
+ description: 'created by Ansible integration tests'
+ state: present
+ vpc_id: '{{ setup_vpc.vpc.id }}'
+ rules:
+ - proto: tcp
+ from_port: 22
+ to_port: 22
+ cidr_ip: '{{ vpc_cidr }}'
+ register: setup_sg_1
+
+- name: create a security group
+ ec2_group:
+ name: '{{ resource_prefix }}-b'
+ description: 'created by Ansible integration tests'
+ state: present
+ vpc_id: '{{ setup_vpc.vpc.id }}'
+ rules:
+ - proto: tcp
+ from_port: 22
+ to_port: 22
+ cidr_ip: '{{ vpc_cidr }}'
+ register: setup_sg_2
+
+- name: store the IDs
+ set_fact:
+ subnet_a: "{{ setup_subnet_1.subnet.id }}"
+ subnet_b: "{{ setup_subnet_2.subnet.id }}"
+ sg_a: "{{ setup_sg_1.group_id }}"
+ sg_b: "{{ setup_sg_2.group_id }}"
diff --git a/tests/integration/targets/elb_instance/vars/main.yml b/tests/integration/targets/elb_instance/vars/main.yml
new file mode 100644
index 00000000000..ed97d539c09
--- /dev/null
+++ b/tests/integration/targets/elb_instance/vars/main.yml
@@ -0,0 +1 @@
+---
diff --git a/tests/integration/targets/elb_target/defaults/main.yml b/tests/integration/targets/elb_target/defaults/main.yml
new file mode 100644
index 00000000000..14068f1e5c0
--- /dev/null
+++ b/tests/integration/targets/elb_target/defaults/main.yml
@@ -0,0 +1,15 @@
+unique_id: "ansible-test-{{ tiny_prefix }}"
+
+# Defaults used by the lambda based test
+
+lambda_role_name: '{{ unique_id }}-elb-target'
+lambda_name: '{{ unique_id }}-elb-target'
+elb_target_group_name: "{{ unique_id }}-elb-tg"
+
+# Defaults used by the EC2 based test
+ec2_ami_name: 'amzn2-ami-hvm-2.0.20190612-x86_64-gp2'
+tg_name: "{{ unique_id }}-tg"
+tg_tcpudp_name: "{{ unique_id }}-tgtcpudp"
+lb_name: "{{ unique_id }}-lb"
+healthy_state:
+ state: 'healthy'
diff --git a/tests/integration/targets/elb_target/playbooks/roles/elb_lambda_target/files/ansible_lambda_target.py b/tests/integration/targets/elb_target/files/ansible_lambda_target.py
similarity index 100%
rename from tests/integration/targets/elb_target/playbooks/roles/elb_lambda_target/files/ansible_lambda_target.py
rename to tests/integration/targets/elb_target/files/ansible_lambda_target.py
diff --git a/tests/integration/targets/elb_target/playbooks/roles/elb_lambda_target/files/assume-role.json b/tests/integration/targets/elb_target/files/assume-role.json
similarity index 100%
rename from tests/integration/targets/elb_target/playbooks/roles/elb_lambda_target/files/assume-role.json
rename to tests/integration/targets/elb_target/files/assume-role.json
diff --git a/tests/integration/targets/elb_target/playbooks/full_test.yml b/tests/integration/targets/elb_target/playbooks/full_test.yml
deleted file mode 100644
index ac95c66f3de..00000000000
--- a/tests/integration/targets/elb_target/playbooks/full_test.yml
+++ /dev/null
@@ -1,7 +0,0 @@
-- hosts: localhost
- connection: local
-# environment: "{{ ansible_test.environment }}"
-
- roles:
- - elb_lambda_target
- - elb_target
diff --git a/tests/integration/targets/elb_target/playbooks/roles/elb_lambda_target/defaults/main.yml b/tests/integration/targets/elb_target/playbooks/roles/elb_lambda_target/defaults/main.yml
deleted file mode 100644
index 911e2080e8b..00000000000
--- a/tests/integration/targets/elb_target/playbooks/roles/elb_lambda_target/defaults/main.yml
+++ /dev/null
@@ -1,5 +0,0 @@
-unique_id: "ansible-test-{{ resource_prefix | hash('md5') }}"
-lambda_role_name: '{{ unique_id }}-elb-target'
-#lambda_role_name: '{{ resource_prefix }}-elb-target'
-lambda_name: '{{ unique_id }}-elb-target'
-elb_target_group_name: "{{ unique_id | truncate(8, True, '') }}-elb-tg"
diff --git a/tests/integration/targets/elb_target/playbooks/roles/elb_target/defaults/main.yml b/tests/integration/targets/elb_target/playbooks/roles/elb_target/defaults/main.yml
deleted file mode 100644
index 75204ee0b02..00000000000
--- a/tests/integration/targets/elb_target/playbooks/roles/elb_target/defaults/main.yml
+++ /dev/null
@@ -1,10 +0,0 @@
----
-ec2_ami_name: 'amzn2-ami-hvm-2.0.20190612-x86_64-gp2'
-
-unique_id: "ansible-test-{{ resource_prefix | hash('md5') | truncate(8, True, '') }}"
-tg_name: "{{ unique_id }}-tg"
-tg_tcpudp_name: "{{ unique_id }}-tgtcpudp"
-lb_name: "{{ unique_id }}-lb"
-
-healthy_state:
- state: 'healthy'
diff --git a/tests/integration/targets/elb_target/playbooks/version_fail.yml b/tests/integration/targets/elb_target/playbooks/version_fail.yml
deleted file mode 100644
index 9149f593048..00000000000
--- a/tests/integration/targets/elb_target/playbooks/version_fail.yml
+++ /dev/null
@@ -1,41 +0,0 @@
-- hosts: localhost
- connection: local
- environment: "{{ ansible_test.environment }}"
-
- tasks:
- - name: set up aws connection info
- module_defaults:
- group/aws:
- aws_access_key: "{{ aws_access_key }}"
- aws_secret_key: "{{ aws_secret_key }}"
- security_token: "{{ security_token | default(omit) }}"
- region: "{{ aws_region }}"
- block:
- - name: set up testing target group (type=ip)
- elb_target_group:
- state: present
- #name: "{{ unique_id }}-tg"
- name: "ansible-test-{{ resource_prefix | regex_search('([0-9]+)$') }}-tg"
- health_check_port: 80
- protocol: http
- port: 80
- vpc_id: 'vpc-abcd1234'
- target_type: ip
- tags:
- Description: "Created by {{ resource_prefix }}"
- register: elb_target_group_type_ip
- ignore_errors: yes
-
- - name: check that setting up target group with type=ip fails with friendly message
- assert:
- that:
- - elb_target_group_type_ip is failed
- - "'msg' in elb_target_group_type_ip"
-
- # In the off-chance that this went (partially) through when it shouldn't...
- always:
- - name: Remove testing target group (type=ip)
- elb_target_group:
- state: absent
- #name: "{{ unique_id }}-tg"
- name: "ansible-test-{{ resource_prefix | regex_search('([0-9]+)$') }}-tg"
diff --git a/tests/integration/targets/elb_target/runme.sh b/tests/integration/targets/elb_target/runme.sh
deleted file mode 100755
index fe0850e46c9..00000000000
--- a/tests/integration/targets/elb_target/runme.sh
+++ /dev/null
@@ -1,13 +0,0 @@
-#!/usr/bin/env bash
-
-set -eux
-
-# Test graceful failure for older versions of botocore
-source virtualenv.sh
-pip install 'botocore<=1.7.1' boto3
-ansible-playbook -i ../../inventory -v playbooks/version_fail.yml "$@"
-
-# Run full test suite
-source virtualenv.sh
-pip install 'botocore' 'boto3>=1.16.57'
-ansible-playbook -i ../../inventory -v playbooks/full_test.yml "$@"
diff --git a/tests/integration/targets/elb_target/playbooks/roles/elb_target/tasks/main.yml b/tests/integration/targets/elb_target/tasks/ec2_target.yml
similarity index 71%
rename from tests/integration/targets/elb_target/playbooks/roles/elb_target/tasks/main.yml
rename to tests/integration/targets/elb_target/tasks/ec2_target.yml
index 30a67cef93c..f350672cafe 100644
--- a/tests/integration/targets/elb_target/playbooks/roles/elb_target/tasks/main.yml
+++ b/tests/integration/targets/elb_target/tasks/ec2_target.yml
@@ -1,20 +1,11 @@
---
- - name: set up elb_target test prerequisites
- module_defaults:
- group/aws:
- aws_access_key: "{{ aws_access_key }}"
- aws_secret_key: "{{ aws_secret_key }}"
- security_token: "{{ security_token | default(omit) }}"
- region: "{{ aws_region }}"
- collections:
- - amazon.aws
-
+ - name: set up ec2 based test prerequisites
block:
# ============================================================
- name:
- debug: msg="********** Setting up elb_target test dependencies **********"
+ debug: msg="********** Setting up elb_target EC2 test dependencies **********"
# ============================================================
- name: Find AMI to use
@@ -26,7 +17,6 @@
- set_fact:
ec2_ami_image: '{{ ec2_amis.images[0].image_id }}'
-
- name: set up testing VPC
ec2_vpc_net:
name: "{{ resource_prefix }}-vpc"
@@ -128,6 +118,33 @@
tags:
Description: "Created by {{ resource_prefix }}"
+ - name: set up testing target group for NLB (type=instance)
+ elb_target_group:
+ name: "{{ tg_name }}-nlb"
+ health_check_port: 80
+ protocol: tcp
+ port: 80
+ vpc_id: '{{ vpc.vpc.id }}'
+ state: present
+ target_type: instance
+ tags:
+ Description: "Created by {{ resource_prefix }}"
+ register: result
+
+ - name: set up testing target group for NLB (type=instance)
+ assert:
+ that:
+ - result.changed
+ - '"health_check_port" in result'
+ - result.port == 80
+ - '"health_check_protocol" in result'
+ - result.health_check_protocol == 'TCP'
+ - '"tags" in result'
+ - '"target_group_arn" in result'
+ - result.target_group_name == "{{ tg_name }}-nlb"
+ - result.target_type == 'instance'
+ - result.vpc_id == '{{ vpc.vpc.id }}'
+
- name: set up ec2 instance to use as a target
ec2_instance:
name: "{{ resource_prefix }}-inst"
@@ -170,6 +187,98 @@
TargetGroupName: "{{ tg_name }}-used"
state: present
+ - name: create a network load balancer
+ elb_network_lb:
+ name: "{{ lb_name }}-nlb"
+ subnets:
+ - "{{ subnet_1.subnet.id }}"
+ - "{{ subnet_2.subnet.id }}"
+ listeners:
+ - Protocol: TCP
+ Port: 80
+ DefaultActions:
+ - Type: forward
+ TargetGroupName: "{{ tg_name }}-nlb"
+ state: present
+ register: result
+
+ - name: create a netwok load balancer
+ assert:
+ that:
+ - result.changed
+ - '"created_time" in result'
+ - '"load_balancer_arn" in result'
+ - '"tags" in result'
+ - result.type == 'network'
+ - result.vpc_id == '{{ vpc.vpc.id }}'
+
+ - name: modify up testing target group for NLB (preserve_client_ip_enabled=false)
+ elb_target_group:
+ name: "{{ tg_name }}-nlb"
+ health_check_port: 80
+ protocol: tcp
+ port: 80
+ vpc_id: '{{ vpc.vpc.id }}'
+ state: present
+ target_type: instance
+ modify_targets: true
+ preserve_client_ip_enabled: false
+ tags:
+ Description: "Created by {{ resource_prefix }}"
+ register: result
+
+ - name: modify up testing target group for NLB (preserve_client_ip_enabled=false)
+ assert:
+ that:
+ - result.changed
+ - result.preserve_client_ip_enabled == 'false'
+ - result.proxy_protocol_v2_enabled == 'false'
+
+ - name: modify up testing target group for NLB (proxy_protocol_v2_enabled=true)
+ elb_target_group:
+ name: "{{ tg_name }}-nlb"
+ health_check_port: 80
+ protocol: tcp
+ port: 80
+ vpc_id: '{{ vpc.vpc.id }}'
+ state: present
+ target_type: instance
+ modify_targets: true
+ proxy_protocol_v2_enabled: true
+ tags:
+ Description: "Created by {{ resource_prefix }}"
+ register: result
+
+ - name: modify up testing target group for NLB (proxy_protocol_v2_enabled=true)
+ assert:
+ that:
+ - result.changed
+ - result.proxy_protocol_v2_enabled == 'true'
+ - result.preserve_client_ip_enabled == 'false'
+
+ - name: (idempotence) modify up testing target group for NLB (preserve_client_ip_enabled=false and proxy_protocol_v2_enabled=true)
+ elb_target_group:
+ name: "{{ tg_name }}-nlb"
+ health_check_port: 80
+ protocol: tcp
+ port: 80
+ vpc_id: '{{ vpc.vpc.id }}'
+ state: present
+ target_type: instance
+ modify_targets: true
+ preserve_client_ip_enabled: false
+ proxy_protocol_v2_enabled: true
+ tags:
+ Description: "Created by {{ resource_prefix }}"
+ register: result
+
+ - name: (idempotence) modify up testing target group for NLB (preserve_client_ip_enabled=false and proxy_protocol_v2_enabled=true)
+ assert:
+ that:
+ - not result.changed
+ - result.proxy_protocol_v2_enabled == 'true'
+ - result.preserve_client_ip_enabled == 'false'
+
# ============================================================
- name:
@@ -372,6 +481,26 @@
- "{{ tg_tcpudp_name }}"
ignore_errors: true
+ - name: remove tcp testing target groups
+ elb_target_group:
+ name: "{{ item }}"
+ protocol: tcp
+ port: 80
+ vpc_id: '{{ vpc.vpc.id }}'
+ state: absent
+ target_type: instance
+ tags:
+ Description: "Created by {{ resource_prefix }}"
+ Protocol: "UDP"
+ wait: true
+ wait_timeout: 400
+ register: removed
+ retries: 10
+ until: removed is not failed
+ with_items:
+ - "{{ tg_name }}-nlb"
+ ignore_errors: true
+
- name: remove application load balancer
elb_application_lb:
name: "{{ lb_name }}"
@@ -394,6 +523,26 @@
until: removed is not failed
ignore_errors: true
+ - name: remove network load balancer
+ elb_network_lb:
+ name: "{{ lb_name }}-nlb"
+ subnets:
+ - "{{ subnet_1.subnet.id }}"
+ - "{{ subnet_2.subnet.id }}"
+ listeners:
+ - Protocol: TCP
+ Port: 80
+ DefaultActions:
+ - Type: forward
+ TargetGroupName: "{{ tg_name }}-nlb"
+ state: absent
+ wait: true
+ wait_timeout: 400
+ register: removed
+ retries: 10
+ until: removed is not failed
+ ignore_errors: true
+
- name: remove testing security group
ec2_group:
state: absent
diff --git a/tests/integration/targets/elb_target/playbooks/roles/elb_lambda_target/tasks/main.yml b/tests/integration/targets/elb_target/tasks/lambda_target.yml
similarity index 92%
rename from tests/integration/targets/elb_target/playbooks/roles/elb_lambda_target/tasks/main.yml
rename to tests/integration/targets/elb_target/tasks/lambda_target.yml
index fb310b848c5..8b7955ddbe3 100644
--- a/tests/integration/targets/elb_target/playbooks/roles/elb_lambda_target/tasks/main.yml
+++ b/tests/integration/targets/elb_target/tasks/lambda_target.yml
@@ -1,13 +1,6 @@
- name: set up lambda as elb_target
- module_defaults:
- group/aws:
- aws_access_key: '{{ aws_access_key }}'
- aws_secret_key: '{{ aws_secret_key }}'
- security_token: '{{ security_token | default(omit) }}'
- region: '{{ aws_region }}'
- collections:
- - community.general
block:
+
- name: create zip to deploy lambda code
archive:
path: '{{ role_path }}/files/ansible_lambda_target.py'
@@ -23,6 +16,7 @@
- name: when it is too fast, the role is not usable.
pause:
seconds: 10
+
- name: deploy lambda.zip to ansible_lambda_target function
lambda:
name: '{{ lambda_name }}'
@@ -36,6 +30,7 @@
retries: 3
delay: 15
until: lambda_function.changed
+
- name: create empty target group
elb_target_group:
name: '{{ elb_target_group_name }}'
@@ -43,10 +38,12 @@
state: present
modify_targets: false
register: elb_target_group
+
- name: tg is created, state must be changed
assert:
that:
- elb_target_group.changed
+
- name: allow elb to invoke the lambda function
lambda_policy:
state: present
@@ -56,6 +53,7 @@
action: lambda:InvokeFunction
principal: elasticloadbalancing.amazonaws.com
source_arn: '{{ elb_target_group.target_group_arn }}'
+
- name: add lambda to elb target
elb_target_group:
name: '{{ elb_target_group_name }}'
@@ -64,10 +62,12 @@
targets:
- Id: '{{ lambda_function.configuration.function_arn }}'
register: elb_target_group
+
- name: target is updated, state must be changed
assert:
that:
- elb_target_group.changed
+
- name: re-add lambda to elb target (idempotency)
elb_target_group:
name: '{{ elb_target_group_name }}'
@@ -76,10 +76,12 @@
targets:
- Id: '{{ lambda_function.configuration.function_arn }}'
register: elb_target_group
+
- name: target is still the same, state must not be changed (idempotency)
assert:
that:
- not elb_target_group.changed
+
- name: remove lambda target from target group
elb_target_group:
name: '{{ elb_target_group_name }}'
@@ -87,10 +89,12 @@
state: absent
targets: []
register: elb_target_group
+
- name: target is still the same, state must not be changed (idempotency)
assert:
that:
- elb_target_group.changed
+
always:
- name: remove elb target group
elb_target_group:
@@ -98,11 +102,13 @@
target_type: lambda
state: absent
ignore_errors: true
+
- name: remove lambda function
lambda:
name: '{{ lambda_name }}'
state: absent
ignore_errors: true
+
- name: remove iam role for lambda
iam_role:
name: '{{ lambda_role_name }}'
diff --git a/tests/integration/targets/elb_target/tasks/main.yml b/tests/integration/targets/elb_target/tasks/main.yml
new file mode 100644
index 00000000000..e6c62f922d3
--- /dev/null
+++ b/tests/integration/targets/elb_target/tasks/main.yml
@@ -0,0 +1,13 @@
+---
+- name: set up elb_target test prerequisites
+ module_defaults:
+ group/aws:
+ aws_access_key: "{{ aws_access_key }}"
+ aws_secret_key: "{{ aws_secret_key }}"
+ security_token: "{{ security_token | default(omit) }}"
+ region: "{{ aws_region }}"
+ collections:
+ - amazon.aws
+ block:
+ - include_tasks: lambda_target.yml
+ - include_tasks: ec2_target.yml
diff --git a/tests/integration/targets/iam_access_key/aliases b/tests/integration/targets/iam_access_key/aliases
new file mode 100644
index 00000000000..ffceccfcc41
--- /dev/null
+++ b/tests/integration/targets/iam_access_key/aliases
@@ -0,0 +1,9 @@
+# reason: missing-policy
+# It should be possible to test iam_user by limiting which policies can be
+# attached to the users.
+# Careful review is needed prior to adding this to the main CI.
+unsupported
+
+cloud/aws
+
+iam_access_key_info
diff --git a/tests/integration/targets/iam_access_key/defaults/main.yml b/tests/integration/targets/iam_access_key/defaults/main.yml
new file mode 100644
index 00000000000..eaaa3523e19
--- /dev/null
+++ b/tests/integration/targets/iam_access_key/defaults/main.yml
@@ -0,0 +1,2 @@
+---
+test_user: '{{ resource_prefix }}'
diff --git a/tests/integration/targets/iam_access_key/meta/main.yml b/tests/integration/targets/iam_access_key/meta/main.yml
new file mode 100644
index 00000000000..1f64f1169a9
--- /dev/null
+++ b/tests/integration/targets/iam_access_key/meta/main.yml
@@ -0,0 +1,3 @@
+dependencies:
+ - prepare_tests
+ - setup_ec2
diff --git a/tests/integration/targets/iam_access_key/tasks/main.yml b/tests/integration/targets/iam_access_key/tasks/main.yml
new file mode 100644
index 00000000000..a7fcc633ce9
--- /dev/null
+++ b/tests/integration/targets/iam_access_key/tasks/main.yml
@@ -0,0 +1,808 @@
+---
+- name: AWS AuthN details
+ module_defaults:
+ group/aws:
+ aws_access_key: "{{ aws_access_key }}"
+ aws_secret_key: "{{ aws_secret_key }}"
+ security_token: "{{ security_token | default(omit) }}"
+ region: "{{ aws_region }}"
+ collections:
+ - amazon.aws
+ - community.aws
+ block:
+ # ==================================================================================
+ # Preparation
+ # ==================================================================================
+ # We create an IAM user with no attached permissions. The *only* thing the
+ # user will be able to do is call sts.get_caller_identity
+ # https://docs.aws.amazon.com/STS/latest/APIReference/API_GetCallerIdentity.html
+ - name: Create test user
+ iam_user:
+ name: '{{ test_user }}'
+ state: present
+ register: iam_user
+
+ - assert:
+ that:
+ - iam_user is successful
+ - iam_user is changed
+
+ # ==================================================================================
+
+ - name: Fetch IAM key info (no keys)
+ iam_access_key_info:
+ user_name: '{{ test_user }}'
+ register: access_key_info
+
+ - assert:
+ that:
+ - access_key_info is successful
+ - '"access_keys" in access_key_info'
+ - access_key_info.access_keys | length == 0
+
+ # ==================================================================================
+
+ - name: Create a key (check_mode)
+ iam_access_key:
+ user_name: '{{ test_user }}'
+ state: present
+ register: create_key_1
+ check_mode: true
+
+ - assert:
+ that:
+ - create_key_1 is successful
+ - create_key_1 is changed
+
+ - name: Create a key
+ iam_access_key:
+ user_name: '{{ test_user }}'
+ state: present
+ register: create_key_1
+
+ - assert:
+ that:
+ - create_key_1 is successful
+ - create_key_1 is changed
+ - '"access_key" in create_key_1'
+ - '"secret_access_key" in create_key_1'
+ - '"deleted_access_key_id" not in create_key_1'
+ - '"access_key_id" in create_key_1.access_key'
+ - '"create_date" in create_key_1.access_key'
+ - '"user_name" in create_key_1.access_key'
+ - '"status" in create_key_1.access_key'
+ - create_key_1.access_key.user_name == test_user
+ - create_key_1.access_key.status == 'Active'
+
+ - name: Fetch IAM key info (1 key)
+ iam_access_key_info:
+ user_name: '{{ test_user }}'
+ register: access_key_info
+
+ - assert:
+ that:
+ - access_key_info is successful
+ - '"access_keys" in access_key_info'
+ - access_key_info.access_keys | length == 1
+ - '"access_key_id" in access_key_1'
+ - '"create_date" in access_key_1'
+ - '"user_name" in access_key_1'
+ - '"status" in access_key_1'
+ - access_key_1.user_name == test_user
+ - access_key_1.access_key_id == create_key_1.access_key.access_key_id
+ - access_key_1.create_date == create_key_1.access_key.create_date
+ - access_key_1.status == 'Active'
+ vars:
+ access_key_1: '{{ access_key_info.access_keys[0] }}'
+
+ # ==================================================================================
+
+ - name: Create a second key (check_mode)
+ iam_access_key:
+ user_name: '{{ test_user }}'
+ state: present
+ register: create_key_2
+ check_mode: true
+
+ - assert:
+ that:
+ - create_key_2 is successful
+ - create_key_2 is changed
+
+ - name: Create a second key
+ iam_access_key:
+ user_name: '{{ test_user }}'
+ state: present
+ register: create_key_2
+
+ - assert:
+ that:
+ - create_key_2 is successful
+ - create_key_2 is changed
+ - '"access_key" in create_key_2'
+ - '"secret_access_key" in create_key_2'
+ - '"deleted_access_key_id" not in create_key_2'
+ - '"access_key_id" in create_key_2.access_key'
+ - '"create_date" in create_key_2.access_key'
+ - '"user_name" in create_key_2.access_key'
+ - '"status" in create_key_2.access_key'
+ - create_key_2.access_key.user_name == test_user
+ - create_key_2.access_key.status == 'Active'
+
+ - name: Fetch IAM key info (2 keys)
+ iam_access_key_info:
+ user_name: '{{ test_user }}'
+ register: access_key_info
+
+ - assert:
+ that:
+ - access_key_info is successful
+ - '"access_keys" in access_key_info'
+ - access_key_info.access_keys | length == 2
+ - '"access_key_id" in access_key_1'
+ - '"create_date" in access_key_1'
+ - '"user_name" in access_key_1'
+ - '"status" in access_key_1'
+ - access_key_1.user_name == test_user
+ - access_key_1.access_key_id == create_key_1.access_key.access_key_id
+ - access_key_1.create_date == create_key_1.access_key.create_date
+ - access_key_1.status == 'Active'
+ - '"access_key_id" in access_key_2'
+ - '"create_date" in access_key_2'
+ - '"user_name" in access_key_2'
+ - '"status" in access_key_2'
+ - access_key_2.user_name == test_user
+ - access_key_2.access_key_id == create_key_2.access_key.access_key_id
+ - access_key_2.create_date == create_key_2.access_key.create_date
+ - access_key_2.status == 'Active'
+ vars:
+ access_key_1: '{{ access_key_info.access_keys[0] }}'
+ access_key_2: '{{ access_key_info.access_keys[1] }}'
+
+ # ==================================================================================
+
+ # We don't block the attempt to create a third access key - should AWS change
+ # the limits this will "JustWork".
+
+ # - name: Create a third key (check_mode)
+ # iam_access_key:
+ # user_name: '{{ test_user }}'
+ # state: present
+ # register: create_key_3
+ # ignore_errors: True
+ # check_mode: true
+
+ # - assert:
+ # that:
+ # - create_key_3 is successful
+ # - create_key_3 is changed
+
+ - name: Create a third key without rotation
+ iam_access_key:
+ user_name: '{{ test_user }}'
+ state: present
+ register: create_key_3
+ ignore_errors: True
+
+ - assert:
+ that:
+ # If Amazon update the limits we may need to change the expectation here.
+ - create_key_3 is failed
+
+ - name: Fetch IAM key info (2 keys - not changed)
+ iam_access_key_info:
+ user_name: '{{ test_user }}'
+ register: access_key_info
+
+ - assert:
+ that:
+ - access_key_info is successful
+ - '"access_keys" in access_key_info'
+ - access_key_info.access_keys | length == 2
+ - '"access_key_id" in access_key_1'
+ - '"create_date" in access_key_1'
+ - '"user_name" in access_key_1'
+ - '"status" in access_key_1'
+ - access_key_1.user_name == test_user
+ - access_key_1.access_key_id == create_key_1.access_key.access_key_id
+ - access_key_1.create_date == create_key_1.access_key.create_date
+ - access_key_1.status == 'Active'
+ - '"access_key_id" in access_key_2'
+ - '"create_date" in access_key_2'
+ - '"user_name" in access_key_2'
+ - '"status" in access_key_2'
+ - access_key_2.user_name == test_user
+ - access_key_2.access_key_id == create_key_2.access_key.access_key_id
+ - access_key_2.create_date == create_key_2.access_key.create_date
+ - access_key_2.status == 'Active'
+ vars:
+ access_key_1: '{{ access_key_info.access_keys[0] }}'
+ access_key_2: '{{ access_key_info.access_keys[1] }}'
+
+ # ==================================================================================
+
+ - name: Create a third key - rotation enabled (check_mode)
+ iam_access_key:
+ user_name: '{{ test_user }}'
+ state: present
+ rotate_keys: true
+ register: create_key_3
+ check_mode: true
+
+ - assert:
+ that:
+ - create_key_3 is successful
+ - create_key_3 is changed
+ - '"deleted_access_key_id" in create_key_3'
+ - create_key_3.deleted_access_key_id == create_key_1.access_key.access_key_id
+
+ - name: Create a second key
+ iam_access_key:
+ user_name: '{{ test_user }}'
+ state: present
+ rotate_keys: true
+ register: create_key_3
+
+ - assert:
+ that:
+ - create_key_3 is successful
+ - create_key_3 is changed
+ - '"access_key" in create_key_3'
+ - '"secret_access_key" in create_key_3'
+ - '"deleted_access_key_id" in create_key_3'
+ - create_key_3.deleted_access_key_id == create_key_1.access_key.access_key_id
+ - '"access_key_id" in create_key_3.access_key'
+ - '"create_date" in create_key_3.access_key'
+ - '"user_name" in create_key_3.access_key'
+ - '"status" in create_key_3.access_key'
+ - create_key_3.access_key.user_name == test_user
+ - create_key_3.access_key.status == 'Active'
+
+ - name: Fetch IAM key info (2 keys - oldest rotated)
+ iam_access_key_info:
+ user_name: '{{ test_user }}'
+ register: access_key_info
+
+ - assert:
+ that:
+ - access_key_info is successful
+ - '"access_keys" in access_key_info'
+ - access_key_info.access_keys | length == 2
+ - '"access_key_id" in access_key_1'
+ - '"create_date" in access_key_1'
+ - '"user_name" in access_key_1'
+ - '"status" in access_key_1'
+ - access_key_1.user_name == test_user
+ - access_key_1.access_key_id == create_key_2.access_key.access_key_id
+ - access_key_1.create_date == create_key_2.access_key.create_date
+ - access_key_1.status == 'Active'
+ - '"access_key_id" in access_key_2'
+ - '"create_date" in access_key_2'
+ - '"user_name" in access_key_2'
+ - '"status" in access_key_2'
+ - access_key_2.user_name == test_user
+ - access_key_2.access_key_id == create_key_3.access_key.access_key_id
+ - access_key_2.create_date == create_key_3.access_key.create_date
+ - access_key_2.status == 'Active'
+ vars:
+ access_key_1: '{{ access_key_info.access_keys[0] }}'
+ access_key_2: '{{ access_key_info.access_keys[1] }}'
+
+ # ==================================================================================
+
+ - name: Disable third key (check_mode)
+ iam_access_key:
+ user_name: '{{ test_user }}'
+ id: '{{ create_key_3.access_key.access_key_id }}'
+ enabled: False
+ register: disable_key
+ check_mode: true
+
+ - assert:
+ that:
+ - disable_key is successful
+ - disable_key is changed
+
+ - name: Disable third key
+ iam_access_key:
+ user_name: '{{ test_user }}'
+ id: '{{ create_key_3.access_key.access_key_id }}'
+ enabled: False
+ register: disable_key
+
+ - assert:
+ that:
+ - disable_key is successful
+ - disable_key is changed
+ - '"access_key" in disable_key'
+ - '"secret_access_key" not in disable_key'
+ - '"deleted_access_key_id" not in disable_key'
+ - '"access_key_id" in disable_key.access_key'
+ - '"create_date" in disable_key.access_key'
+ - '"user_name" in disable_key.access_key'
+ - '"status" in disable_key.access_key'
+ - disable_key.access_key.user_name == test_user
+ - disable_key.access_key.status == 'Inactive'
+
+ - name: Disable third key - idempotency (check_mode)
+ iam_access_key:
+ user_name: '{{ test_user }}'
+ id: '{{ create_key_3.access_key.access_key_id }}'
+ enabled: False
+ register: disable_key
+ check_mode: true
+
+ - assert:
+ that:
+ - disable_key is successful
+ - disable_key is not changed
+
+ - name: Disable third key - idempotency
+ iam_access_key:
+ user_name: '{{ test_user }}'
+ id: '{{ create_key_3.access_key.access_key_id }}'
+ enabled: False
+ register: disable_key
+
+ - assert:
+ that:
+ - disable_key is successful
+ - disable_key is not changed
+ - '"access_key" in disable_key'
+ - '"secret_access_key" not in disable_key'
+ - '"deleted_access_key_id" not in disable_key'
+ - '"access_key_id" in disable_key.access_key'
+ - '"create_date" in disable_key.access_key'
+ - '"user_name" in disable_key.access_key'
+ - '"status" in disable_key.access_key'
+ - disable_key.access_key.user_name == test_user
+ - disable_key.access_key.status == 'Inactive'
+
+ - name: Fetch IAM key info (2 keys - 1 disabled)
+ iam_access_key_info:
+ user_name: '{{ test_user }}'
+ register: access_key_info
+
+ - assert:
+ that:
+ - access_key_info is successful
+ - '"access_keys" in access_key_info'
+ - access_key_info.access_keys | length == 2
+ - '"access_key_id" in access_key_1'
+ - '"create_date" in access_key_1'
+ - '"user_name" in access_key_1'
+ - '"status" in access_key_1'
+ - access_key_1.user_name == test_user
+ - access_key_1.access_key_id == create_key_2.access_key.access_key_id
+ - access_key_1.create_date == create_key_2.access_key.create_date
+ - access_key_1.status == 'Active'
+ - '"access_key_id" in access_key_2'
+ - '"create_date" in access_key_2'
+ - '"user_name" in access_key_2'
+ - '"status" in access_key_2'
+ - access_key_2.user_name == test_user
+ - access_key_2.access_key_id == create_key_3.access_key.access_key_id
+ - access_key_2.create_date == create_key_3.access_key.create_date
+ - access_key_2.status == 'Inactive'
+ vars:
+ access_key_1: '{{ access_key_info.access_keys[0] }}'
+ access_key_2: '{{ access_key_info.access_keys[1] }}'
+
+ # ==================================================================================
+
+ - name: Touch third key - no change (check_mode)
+ iam_access_key:
+ user_name: '{{ test_user }}'
+ id: '{{ create_key_3.access_key.access_key_id }}'
+ register: touch_key
+ check_mode: true
+
+ - assert:
+ that:
+ - touch_key is successful
+ - touch_key is not changed
+
+ - name: Touch third key - no change
+ iam_access_key:
+ user_name: '{{ test_user }}'
+ id: '{{ create_key_3.access_key.access_key_id }}'
+ register: touch_key
+
+ - assert:
+ that:
+ - touch_key is successful
+ - touch_key is not changed
+ - '"access_key" in touch_key'
+ - '"secret_access_key" not in touch_key'
+ - '"deleted_access_key_id" not in touch_key'
+ - '"access_key_id" in touch_key.access_key'
+ - '"create_date" in touch_key.access_key'
+ - '"user_name" in touch_key.access_key'
+ - '"status" in touch_key.access_key'
+ - touch_key.access_key.user_name == test_user
+ - touch_key.access_key.status == 'Inactive'
+
+ # ==================================================================================
+
+ - name: Enable third key (check_mode)
+ iam_access_key:
+ user_name: '{{ test_user }}'
+ id: '{{ create_key_3.access_key.access_key_id }}'
+ enabled: True
+ register: enable_key
+ check_mode: true
+
+ - assert:
+ that:
+ - enable_key is successful
+ - enable_key is changed
+
+ - name: Enable third key
+ iam_access_key:
+ user_name: '{{ test_user }}'
+ id: '{{ create_key_3.access_key.access_key_id }}'
+ enabled: True
+ register: enable_key
+
+ - assert:
+ that:
+ - enable_key is successful
+ - enable_key is changed
+ - '"access_key" in enable_key'
+ - '"secret_access_key" not in enable_key'
+ - '"deleted_access_key_id" not in enable_key'
+ - '"access_key_id" in enable_key.access_key'
+ - '"create_date" in enable_key.access_key'
+ - '"user_name" in enable_key.access_key'
+ - '"status" in enable_key.access_key'
+ - enable_key.access_key.user_name == test_user
+ - enable_key.access_key.status == 'Active'
+
+ - name: Enable third key - idempotency (check_mode)
+ iam_access_key:
+ user_name: '{{ test_user }}'
+ id: '{{ create_key_3.access_key.access_key_id }}'
+ enabled: True
+ register: enable_key
+ check_mode: true
+
+ - assert:
+ that:
+ - enable_key is successful
+ - enable_key is not changed
+
+ - name: Enable third key - idempotency
+ iam_access_key:
+ user_name: '{{ test_user }}'
+ id: '{{ create_key_3.access_key.access_key_id }}'
+ enabled: True
+ register: enable_key
+
+ - assert:
+ that:
+ - enable_key is successful
+ - enable_key is not changed
+ - '"access_key" in enable_key'
+ - '"secret_access_key" not in enable_key'
+ - '"deleted_access_key_id" not in enable_key'
+ - '"access_key_id" in enable_key.access_key'
+ - '"create_date" in enable_key.access_key'
+ - '"user_name" in enable_key.access_key'
+ - '"status" in enable_key.access_key'
+ - enable_key.access_key.user_name == test_user
+ - enable_key.access_key.status == 'Active'
+
+ # ==================================================================================
+
+ - name: Touch third key again - no change (check_mode)
+ iam_access_key:
+ user_name: '{{ test_user }}'
+ id: '{{ create_key_3.access_key.access_key_id }}'
+ register: touch_key
+ check_mode: true
+
+ - assert:
+ that:
+ - touch_key is successful
+ - touch_key is not changed
+
+ - name: Touch third key again - no change
+ iam_access_key:
+ user_name: '{{ test_user }}'
+ id: '{{ create_key_3.access_key.access_key_id }}'
+ register: touch_key
+
+ - assert:
+ that:
+ - touch_key is successful
+ - touch_key is not changed
+ - '"access_key" in touch_key'
+ - '"secret_access_key" not in touch_key'
+ - '"deleted_access_key_id" not in touch_key'
+ - '"access_key_id" in touch_key.access_key'
+ - '"create_date" in touch_key.access_key'
+ - '"user_name" in touch_key.access_key'
+ - '"status" in touch_key.access_key'
+ - touch_key.access_key.user_name == test_user
+ - touch_key.access_key.status == 'Active'
+
+ # ==================================================================================
+
+ - name: Re-Disable third key
+ iam_access_key:
+ user_name: '{{ test_user }}'
+ id: '{{ create_key_3.access_key.access_key_id }}'
+ enabled: False
+ register: redisable_key
+
+ - assert:
+ that:
+ - redisable_key is successful
+ - redisable_key is changed
+ - redisable_key.access_key.status == 'Inactive'
+
+ - pause:
+ seconds: 10
+
+ # ==================================================================================
+
+ - name: Test GetCallerIdentity - Key 2
+ aws_caller_info:
+ aws_access_key: "{{ create_key_2.access_key.access_key_id }}"
+ aws_secret_key: "{{ create_key_2.secret_access_key }}"
+ security_token: "{{ omit }}"
+ register: caller_identity_2
+
+ - assert:
+ that:
+ - caller_identity_2 is successful
+ - caller_identity_2.arn == iam_user.iam_user.user.arn
+
+ - name: Test GetCallerIdentity - Key 1 (gone)
+ aws_caller_info:
+ aws_access_key: "{{ create_key_1.access_key.access_key_id }}"
+ aws_secret_key: "{{ create_key_1.secret_access_key }}"
+ security_token: "{{ omit }}"
+ register: caller_identity_1
+ ignore_errors: true
+
+ - assert:
+ that:
+ - caller_identity_1 is failed
+ - caller_identity_1.error.code == 'InvalidClientTokenId'
+
+ - name: Test GetCallerIdentity - Key 3 (disabled)
+ aws_caller_info:
+ aws_access_key: "{{ create_key_3.access_key.access_key_id }}"
+ aws_secret_key: "{{ create_key_3.secret_access_key }}"
+ security_token: "{{ omit }}"
+ register: caller_identity_3
+ ignore_errors: true
+
+ - assert:
+ that:
+ - caller_identity_3 is failed
+ - caller_identity_3.error.code == 'InvalidClientTokenId'
+
+ # ==================================================================================
+
+ - name: Delete active key (check_mode)
+ iam_access_key:
+ user_name: '{{ test_user }}'
+ id: '{{ create_key_2.access_key.access_key_id }}'
+ state: absent
+ register: delete_active_key
+ check_mode: true
+
+ - assert:
+ that:
+ - delete_active_key is successful
+ - delete_active_key is changed
+
+ - name: Delete active key
+ iam_access_key:
+ user_name: '{{ test_user }}'
+ id: '{{ create_key_2.access_key.access_key_id }}'
+ state: absent
+ register: delete_active_key
+
+ - assert:
+ that:
+ - delete_active_key is successful
+ - delete_active_key is changed
+
+ - name: Delete active key - idempotency (check_mode)
+ iam_access_key:
+ user_name: '{{ test_user }}'
+ id: '{{ create_key_2.access_key.access_key_id }}'
+ state: absent
+ register: delete_active_key
+ check_mode: true
+
+ - assert:
+ that:
+ - delete_active_key is successful
+ - delete_active_key is not changed
+
+ - name: Delete active key - idempotency
+ iam_access_key:
+ user_name: '{{ test_user }}'
+ id: '{{ create_key_2.access_key.access_key_id }}'
+ state: absent
+ register: delete_active_key
+
+ - assert:
+ that:
+ - delete_active_key is successful
+ - delete_active_key is not changed
+
+ # ==================================================================================
+
+ - name: Delete inactive key (check_mode)
+ iam_access_key:
+ user_name: '{{ test_user }}'
+ id: '{{ create_key_3.access_key.access_key_id }}'
+ state: absent
+ register: delete_inactive_key
+ check_mode: true
+
+ - assert:
+ that:
+ - delete_inactive_key is successful
+ - delete_inactive_key is changed
+
+ - name: Delete inactive key
+ iam_access_key:
+ user_name: '{{ test_user }}'
+ id: '{{ create_key_3.access_key.access_key_id }}'
+ state: absent
+ register: delete_inactive_key
+
+ - assert:
+ that:
+ - delete_inactive_key is successful
+ - delete_inactive_key is changed
+
+ - name: Delete inactive key - idempotency (check_mode)
+ iam_access_key:
+ user_name: '{{ test_user }}'
+ id: '{{ create_key_3.access_key.access_key_id }}'
+ state: absent
+ register: delete_inactive_key
+ check_mode: true
+
+ - assert:
+ that:
+ - delete_inactive_key is successful
+ - delete_inactive_key is not changed
+
+ - name: Delete inactive key - idempotency
+ iam_access_key:
+ user_name: '{{ test_user }}'
+ id: '{{ create_key_3.access_key.access_key_id }}'
+ state: absent
+ register: delete_inactive_key
+
+ - assert:
+ that:
+ - delete_inactive_key is successful
+ - delete_inactive_key is not changed
+
+ # ==================================================================================
+
+ - name: Fetch IAM key info (no keys)
+ iam_access_key_info:
+ user_name: '{{ test_user }}'
+ register: access_key_info
+
+ - assert:
+ that:
+ - access_key_info is successful
+ - '"access_keys" in access_key_info'
+ - access_key_info.access_keys | length == 0
+
+ # ==================================================================================
+
+ - name: Create an inactive key (check_mode)
+ iam_access_key:
+ user_name: '{{ test_user }}'
+ state: present
+ enabled: false
+ register: create_key_4
+ check_mode: true
+
+ - assert:
+ that:
+ - create_key_4 is successful
+ - create_key_4 is changed
+
+ - name: Create a key
+ iam_access_key:
+ user_name: '{{ test_user }}'
+ state: present
+ enabled: false
+ register: create_key_4
+
+ - assert:
+ that:
+ - create_key_4 is successful
+ - create_key_4 is changed
+ - '"access_key" in create_key_4'
+ - '"secret_access_key" in create_key_4'
+ - '"deleted_access_key_id" not in create_key_4'
+ - '"access_key_id" in create_key_4.access_key'
+ - '"create_date" in create_key_4.access_key'
+ - '"user_name" in create_key_4.access_key'
+ - '"status" in create_key_4.access_key'
+ - create_key_4.access_key.user_name == test_user
+ - create_key_4.access_key.status == 'Inactive'
+
+ - name: Fetch IAM key info (1 inactive key)
+ iam_access_key_info:
+ user_name: '{{ test_user }}'
+ register: access_key_info
+
+ - assert:
+ that:
+ - access_key_info is successful
+ - '"access_keys" in access_key_info'
+ - access_key_info.access_keys | length == 1
+ - '"access_key_id" in access_key_1'
+ - '"create_date" in access_key_1'
+ - '"user_name" in access_key_1'
+ - '"status" in access_key_1'
+ - access_key_1.user_name == test_user
+ - access_key_1.access_key_id == create_key_4.access_key.access_key_id
+ - access_key_1.create_date == create_key_4.access_key.create_date
+ - access_key_1.status == 'Inactive'
+ vars:
+ access_key_1: '{{ access_key_info.access_keys[0] }}'
+
+ # We already tested the idempotency of disabling keys, use this to verify that
+ # the key is disabled
+ - name: Disable new key
+ iam_access_key:
+ user_name: '{{ test_user }}'
+ id: '{{ create_key_4.access_key.access_key_id }}'
+ enabled: False
+ register: disable_new_key
+
+ - assert:
+ that:
+ - disable_new_key is successful
+ - disable_new_key is not changed
+ - '"access_key" in disable_new_key'
+
+ # ==================================================================================
+ # Cleanup
+
+ - name: Delete new key
+ iam_access_key:
+ user_name: '{{ test_user }}'
+ id: '{{ create_key_4.access_key.access_key_id }}'
+ state: absent
+ register: delete_new_key
+
+ - assert:
+ that:
+ - delete_new_key is successful
+ - delete_new_key is changed
+
+ - name: Remove test user
+ iam_user:
+ name: '{{ test_user }}'
+ state: absent
+ register: delete_user
+
+ - assert:
+ that:
+ - delete_user is successful
+ - delete_user is changed
+
+ always:
+
+ - name: Remove test user
+ iam_user:
+ name: '{{ test_user }}'
+ state: absent
+ ignore_errors: yes
diff --git a/tests/integration/targets/iam_role/defaults/main.yml b/tests/integration/targets/iam_role/defaults/main.yml
index 46db605072e..d496c421636 100644
--- a/tests/integration/targets/iam_role/defaults/main.yml
+++ b/tests/integration/targets/iam_role/defaults/main.yml
@@ -4,5 +4,3 @@ test_path: '/{{ resource_prefix }}/'
safe_managed_policy: 'AWSDenyAll'
custom_policy_name: '{{ resource_prefix }}-denyall'
boundary_policy: 'arn:aws:iam::aws:policy/AWSDenyAll'
-paranoid_pauses: no
-standard_pauses: no
diff --git a/tests/integration/targets/iam_role/tasks/boundary_policy.yml b/tests/integration/targets/iam_role/tasks/boundary_policy.yml
new file mode 100644
index 00000000000..9f4684d150d
--- /dev/null
+++ b/tests/integration/targets/iam_role/tasks/boundary_policy.yml
@@ -0,0 +1,82 @@
+---
+- name: "Create minimal role with no boundary policy"
+ iam_role:
+ name: "{{ test_role }}"
+ create_instance_profile: no
+ register: iam_role
+
+- assert:
+ that:
+ - iam_role is changed
+ - iam_role.iam_role.role_name == test_role
+
+- name: "Configure Boundary Policy (CHECK MODE)"
+ iam_role:
+ name: "{{ test_role }}"
+ create_instance_profile: no
+ boundary: "{{ boundary_policy }}"
+ check_mode: yes
+ register: iam_role
+
+- assert:
+ that:
+ - iam_role is changed
+
+- name: "Configure Boundary Policy"
+ iam_role:
+ name: "{{ test_role }}"
+ create_instance_profile: no
+ boundary: "{{ boundary_policy }}"
+ register: iam_role
+
+- assert:
+ that:
+ - iam_role is changed
+ - iam_role.iam_role.role_name == test_role
+
+- name: "Configure Boundary Policy (no change)"
+ iam_role:
+ name: "{{ test_role }}"
+ create_instance_profile: no
+ boundary: "{{ boundary_policy }}"
+ register: iam_role
+
+- assert:
+ that:
+ - iam_role is not changed
+ - iam_role.iam_role.role_name == test_role
+
+- name: "iam_role_info after adding boundary policy"
+ iam_role_info:
+ name: "{{ test_role }}"
+ register: role_info
+
+- assert:
+ that:
+ - role_info is succeeded
+ - role_info.iam_roles | length == 1
+ - 'role_info.iam_roles[0].arn.startswith("arn")'
+ - 'role_info.iam_roles[0].arn.endswith("role/" + test_role )'
+ - '"assume_role_policy_document" in role_info.iam_roles[0]'
+ - '"create_date" in role_info.iam_roles[0]'
+ - '"description" not in role_info.iam_roles[0]'
+ - role_info.iam_roles[0].inline_policies | length == 0
+ - role_info.iam_roles[0].instance_profiles | length == 0
+ - role_info.iam_roles[0].managed_policies | length == 0
+ - role_info.iam_roles[0].max_session_duration == 3600
+ - role_info.iam_roles[0].path == '/'
+ - role_info.iam_roles[0].permissions_boundary.permissions_boundary_arn == boundary_policy
+ - role_info.iam_roles[0].permissions_boundary.permissions_boundary_type == 'Policy'
+ - role_info.iam_roles[0].role_id == iam_role.iam_role.role_id
+ - role_info.iam_roles[0].role_name == test_role
+
+- name: "Remove IAM Role"
+ iam_role:
+ state: absent
+ name: "{{ test_role }}"
+ delete_instance_profile: yes
+ register: iam_role
+
+- assert:
+ that:
+ - iam_role is changed
\ No newline at end of file
diff --git a/tests/integration/targets/iam_role/tasks/complex_role_creation.yml b/tests/integration/targets/iam_role/tasks/complex_role_creation.yml
new file mode 100644
index 00000000000..93a7b7d8342
--- /dev/null
+++ b/tests/integration/targets/iam_role/tasks/complex_role_creation.yml
@@ -0,0 +1,110 @@
+---
+- name: "Complex IAM Role (CHECK MODE)"
+ iam_role:
+ name: "{{ test_role }}"
+ assume_role_policy_document: '{{ lookup("file", "deny-assume.json") }}'
+ boundary: "{{ boundary_policy }}"
+ create_instance_profile: no
+ description: "Ansible Test Role {{ resource_prefix }}"
+ managed_policy:
+ - "{{ safe_managed_policy }}"
+ - "{{ custom_policy_name }}"
+ max_session_duration: 43200
+ path: "{{ test_path }}"
+ tags:
+ TagA: "ValueA"
+ check_mode: yes
+ register: iam_role
+
+- assert:
+ that:
+ - iam_role is changed
+
+- name: "iam_role_info after Complex Role creation in check_mode"
+ iam_role_info:
+ name: "{{ test_role }}"
+ register: role_info
+- assert:
+ that:
+ - role_info is succeeded
+ - role_info.iam_roles | length == 0
+
+- name: "Complex IAM Role"
+ iam_role:
+ name: "{{ test_role }}"
+ assume_role_policy_document: '{{ lookup("file", "deny-assume.json") }}'
+ boundary: "{{ boundary_policy }}"
+ create_instance_profile: no
+ description: "Ansible Test Role {{ resource_prefix }}"
+ managed_policy:
+ - "{{ safe_managed_policy }}"
+ - "{{ custom_policy_name }}"
+ max_session_duration: 43200
+ path: "{{ test_path }}"
+ tags:
+ TagA: "ValueA"
+ register: iam_role
+
+- assert:
+ that:
+ - iam_role is changed
+ - iam_role.iam_role.role_name == test_role
+ - 'iam_role.iam_role.arn.startswith("arn")'
+ - 'iam_role.iam_role.arn.endswith("role" + test_path + test_role )'
+ # Would be nice to test the contents...
+ - '"assume_role_policy_document" in iam_role.iam_role'
+ - iam_role.iam_role.attached_policies | length == 2
+ - iam_role.iam_role.max_session_duration == 43200
+ - iam_role.iam_role.path == test_path
+ - iam_role.iam_role.role_name == test_role
+ - '"create_date" in iam_role.iam_role'
+ - '"role_id" in iam_role.iam_role'
+
+- name: "Complex IAM role (no change)"
+ iam_role:
+ name: "{{ test_role }}"
+ assume_role_policy_document: '{{ lookup("file", "deny-assume.json") }}'
+ boundary: "{{ boundary_policy }}"
+ create_instance_profile: no
+ description: "Ansible Test Role {{ resource_prefix }}"
+ managed_policy:
+ - "{{ safe_managed_policy }}"
+ - "{{ custom_policy_name }}"
+ max_session_duration: 43200
+ path: "{{ test_path }}"
+ tags:
+ TagA: "ValueA"
+ register: iam_role
+
+- assert:
+ that:
+ - iam_role is not changed
+ - iam_role.iam_role.role_name == test_role
+
+- name: "iam_role_info after Role creation"
+ iam_role_info:
+ name: "{{ test_role }}"
+ register: role_info
+
+- assert:
+ that:
+ - role_info is succeeded
+ - role_info.iam_roles | length == 1
+ - 'role_info.iam_roles[0].arn.startswith("arn")'
+ - 'role_info.iam_roles[0].arn.endswith("role" + test_path + test_role )'
+ - '"assume_role_policy_document" in role_info.iam_roles[0]'
+ - '"create_date" in role_info.iam_roles[0]'
+ - 'role_info.iam_roles[0].description == "Ansible Test Role {{ resource_prefix }}"'
+ - role_info.iam_roles[0].inline_policies | length == 0
+ - role_info.iam_roles[0].instance_profiles | length == 0
+ - role_info.iam_roles[0].managed_policies | length == 2
+ - safe_managed_policy in ( role_info | community.general.json_query("iam_roles[*].managed_policies[*].policy_name") | list | flatten )
+ - custom_policy_name in ( role_info | community.general.json_query("iam_roles[*].managed_policies[*].policy_name") | list | flatten )
+ - role_info.iam_roles[0].max_session_duration == 43200
+ - role_info.iam_roles[0].path == test_path
+ - role_info.iam_roles[0].permissions_boundary.permissions_boundary_arn == boundary_policy
+ - role_info.iam_roles[0].permissions_boundary.permissions_boundary_type == 'Policy'
+ - role_info.iam_roles[0].role_id == iam_role.iam_role.role_id
+ - role_info.iam_roles[0].role_name == test_role
+ - '"TagA" in role_info.iam_roles[0].tags'
+ - role_info.iam_roles[0].tags.TagA == "ValueA"
diff --git a/tests/integration/targets/iam_role/tasks/creation_deletion.yml b/tests/integration/targets/iam_role/tasks/creation_deletion.yml
new file mode 100644
index 00000000000..88fc79f977c
--- /dev/null
+++ b/tests/integration/targets/iam_role/tasks/creation_deletion.yml
@@ -0,0 +1,353 @@
+---
+- name: Try running some rapid fire create/delete tests
+ block:
+ - name: "Minimal IAM Role without instance profile (rapid)"
+ iam_role:
+ name: "{{ test_role }}"
+ create_instance_profile: no
+ register: iam_role
+
+ - name: "Minimal IAM Role without instance profile (rapid)"
+ iam_role:
+ name: "{{ test_role }}"
+ create_instance_profile: no
+ register: iam_role_again
+
+ - assert:
+ that:
+ - iam_role is changed
+ - iam_role_again is not changed
+
+ - name: "Remove IAM Role (rapid)"
+ iam_role:
+ state: absent
+ name: "{{ test_role }}"
+ register: iam_role
+
+ - name: "Remove IAM Role (rapid)"
+ iam_role:
+ state: absent
+ name: "{{ test_role }}"
+ register: iam_role_again
+
+ - assert:
+ that:
+ - iam_role is changed
+ - iam_role_again is not changed
+
+ - name: "Minimal IAM Role without instance profile (rapid)"
+ iam_role:
+ name: "{{ test_role }}"
+ create_instance_profile: no
+ register: iam_role
+
+ - name: "Remove IAM Role (rapid)"
+ iam_role:
+ state: absent
+ name: "{{ test_role }}"
+
+ register: iam_role_again
+ - assert:
+ that:
+ - iam_role is changed
+ - iam_role_again is changed
+
+# ===================================================================
+# Role Creation
+# (without Instance profile)
+- name: "iam_role_info before Role creation (no args)"
+ iam_role_info:
+ register: role_info
+
+- assert:
+ that:
+ - role_info is succeeded
+
+- name: "iam_role_info before Role creation (search for test role)"
+ iam_role_info:
+ name: "{{ test_role }}"
+ register: role_info
+
+- assert:
+ that:
+ - role_info is succeeded
+ - role_info.iam_roles | length == 0
+
+- name: "Minimal IAM Role (CHECK MODE)"
+ iam_role:
+ name: "{{ test_role }}"
+ create_instance_profile: no
+ check_mode: yes
+ register: iam_role
+
+- assert:
+ that:
+ - iam_role is changed
+
+- name: "iam_role_info after Role creation in check_mode"
+ iam_role_info:
+ name: "{{ test_role }}"
+ register: role_info
+- assert:
+ that:
+ - role_info is succeeded
+ - role_info.iam_roles | length == 0
+
+- name: "Minimal IAM Role without instance profile"
+ iam_role:
+ name: "{{ test_role }}"
+ create_instance_profile: no
+ register: iam_role
+
+- assert:
+ that:
+ - iam_role is changed
+ - iam_role.iam_role.role_name == test_role
+ - 'iam_role.iam_role.arn.startswith("arn")'
+ - 'iam_role.iam_role.arn.endswith("role/" + test_role )'
+ # Would be nice to test the contents...
+ - '"assume_role_policy_document" in iam_role.iam_role'
+ - iam_role.iam_role.attached_policies | length == 0
+ - iam_role.iam_role.max_session_duration == 3600
+ - iam_role.iam_role.path == '/'
+ - iam_role.iam_role.role_name == test_role
+ - '"create_date" in iam_role.iam_role'
+ - '"role_id" in iam_role.iam_role'
+
+- name: "Minimal IAM Role without instance profile (no change)"
+ iam_role:
+ name: "{{ test_role }}"
+ create_instance_profile: no
+ register: iam_role
+
+- assert:
+ that:
+ - iam_role is not changed
+ - iam_role.iam_role.role_name == test_role
+
+- name: "iam_role_info after Role creation"
+ iam_role_info:
+ name: "{{ test_role }}"
+ register: role_info
+
+- assert:
+ that:
+ - role_info is succeeded
+ - role_info.iam_roles | length == 1
+ - 'role_info.iam_roles[0].arn.startswith("arn")'
+ - 'role_info.iam_roles[0].arn.endswith("role/" + test_role )'
+ - '"assume_role_policy_document" in role_info.iam_roles[0]'
+ - '"create_date" in role_info.iam_roles[0]'
+ - '"description" not in role_info.iam_roles[0]'
+ - role_info.iam_roles[0].inline_policies | length == 0
+ - role_info.iam_roles[0].instance_profiles | length == 0
+ - role_info.iam_roles[0].managed_policies | length == 0
+ - role_info.iam_roles[0].max_session_duration == 3600
+ - role_info.iam_roles[0].path == '/'
+ - '"permissions_boundary" not in role_info.iam_roles[0]'
+ - role_info.iam_roles[0].role_id == iam_role.iam_role.role_id
+ - role_info.iam_roles[0].role_name == test_role
+ - role_info.iam_roles[0].tags | length == 0
+
+- name: "Remove IAM Role"
+ iam_role:
+ state: absent
+ name: "{{ test_role }}"
+ delete_instance_profile: yes
+ register: iam_role
+
+- assert:
+ that:
+ - iam_role is changed
+
+- name: "iam_role_info after Role deletion"
+ iam_role_info:
+ name: "{{ test_role }}"
+ register: role_info
+
+- assert:
+ that:
+ - role_info is succeeded
+ - role_info.iam_roles | length == 0
+
+# (with path)
+- name: "Minimal IAM Role with path (CHECK MODE)"
+ iam_role:
+ name: "{{ test_role }}"
+ path: "{{ test_path }}"
+ register: iam_role
+ check_mode: yes
+
+- assert:
+ that:
+ - iam_role is changed
+
+- name: "Minimal IAM Role with path"
+ iam_role:
+ name: "{{ test_role }}"
+ path: "{{ test_path }}"
+ register: iam_role
+
+- assert:
+ that:
+ - iam_role is changed
+ - iam_role.iam_role.role_name == test_role
+ - 'iam_role.iam_role.arn.startswith("arn")'
+ - 'iam_role.iam_role.arn.endswith("role" + test_path + test_role )'
+ # Would be nice to test the contents...
+ - '"assume_role_policy_document" in iam_role.iam_role'
+ - iam_role.iam_role.attached_policies | length == 0
+ - iam_role.iam_role.max_session_duration == 3600
+ - iam_role.iam_role.path == '{{ test_path }}'
+ - iam_role.iam_role.role_name == test_role
+ - '"create_date" in iam_role.iam_role'
+ - '"role_id" in iam_role.iam_role'
+
+- name: "Minimal IAM Role with path (no change)"
+ iam_role:
+ name: "{{ test_role }}"
+ path: "{{ test_path }}"
+ register: iam_role
+
+- assert:
+ that:
+ - iam_role is not changed
+ - iam_role.iam_role.role_name == test_role
+
+- name: "iam_role_info after Role creation"
+ iam_role_info:
+ name: "{{ test_role }}"
+ register: role_info
+
+- assert:
+ that:
+ - role_info is succeeded
+ - role_info.iam_roles | length == 1
+ - 'role_info.iam_roles[0].arn.startswith("arn")'
+ - 'role_info.iam_roles[0].arn.endswith("role" + test_path + test_role )'
+ - '"assume_role_policy_document" in role_info.iam_roles[0]'
+ - '"create_date" in role_info.iam_roles[0]'
+ - '"description" not in role_info.iam_roles[0]'
+ - role_info.iam_roles[0].inline_policies | length == 0
+ - role_info.iam_roles[0].instance_profiles | length == 1
+ - role_info.iam_roles[0].instance_profiles[0].instance_profile_name == test_role
+ - 'role_info.iam_roles[0].instance_profiles[0].arn.startswith("arn")'
+ - 'role_info.iam_roles[0].instance_profiles[0].arn.endswith("instance-profile" + test_path + test_role)'
+ - role_info.iam_roles[0].managed_policies | length == 0
+ - role_info.iam_roles[0].max_session_duration == 3600
+ - role_info.iam_roles[0].path == '{{ test_path }}'
+ - '"permissions_boundary" not in role_info.iam_roles[0]'
+ - role_info.iam_roles[0].role_id == iam_role.iam_role.role_id
+ - role_info.iam_roles[0].role_name == test_role
+ - role_info.iam_roles[0].tags | length == 0
+
+- name: "iam_role_info after Role creation (searching a path)"
+ iam_role_info:
+ path_prefix: "{{ test_path }}"
+ register: role_info
+
+- assert:
+ that:
+ - role_info is succeeded
+ - role_info.iam_roles | length == 1
+ - 'role_info.iam_roles[0].arn.startswith("arn")'
+ - 'role_info.iam_roles[0].arn.endswith("role" + test_path + test_role )'
+ - '"assume_role_policy_document" in role_info.iam_roles[0]'
+ - '"create_date" in role_info.iam_roles[0]'
+ - '"description" not in role_info.iam_roles[0]'
+ - role_info.iam_roles[0].inline_policies | length == 0
+ - role_info.iam_roles[0].instance_profiles | length == 1
+ - role_info.iam_roles[0].instance_profiles[0].instance_profile_name == test_role
+ - 'role_info.iam_roles[0].instance_profiles[0].arn.startswith("arn")'
+ - 'role_info.iam_roles[0].instance_profiles[0].arn.endswith("instance-profile" + test_path + test_role)'
+ - role_info.iam_roles[0].managed_policies | length == 0
+ - role_info.iam_roles[0].max_session_duration == 3600
+ - '"permissions_boundary" not in role_info.iam_roles[0]'
+ - role_info.iam_roles[0].path == '{{ test_path }}'
+ - role_info.iam_roles[0].role_id == iam_role.iam_role.role_id
+ - role_info.iam_roles[0].role_name == test_role
+ - role_info.iam_roles[0].tags | length == 0
+
+- name: "Remove IAM Role"
+ iam_role:
+ state: absent
+ name: "{{ test_role }}"
+ path: "{{ test_path }}"
+ # If we don't delete the existing profile it'll be reused (with the path)
+ # by the test below.
+ delete_instance_profile: yes
+ register: iam_role
+
+- assert:
+ that:
+ - iam_role is changed
+
+- name: "iam_role_info after Role deletion"
+ iam_role_info:
+ name: "{{ test_role }}"
+ register: role_info
+
+- assert:
+ that:
+ - role_info is succeeded
+ - role_info.iam_roles | length == 0
+
+# (with Instance profile)
+- name: "Minimal IAM Role with instance profile"
+ iam_role:
+ name: "{{ test_role }}"
+ create_instance_profile: yes
+ register: iam_role
+
+- assert:
+ that:
+ - iam_role is changed
+ - iam_role.iam_role.role_name == test_role
+ - 'iam_role.iam_role.arn.startswith("arn")'
+ - 'iam_role.iam_role.arn.endswith("role/" + test_role )'
+ # Would be nice to test the contents...
+ - '"assume_role_policy_document" in iam_role.iam_role'
+ - iam_role.iam_role.attached_policies | length == 0
+ - iam_role.iam_role.max_session_duration == 3600
+ - iam_role.iam_role.path == '/'
+ - iam_role.iam_role.role_name == test_role
+ - '"create_date" in iam_role.iam_role'
+ - '"role_id" in iam_role.iam_role'
+
+- name: "Minimal IAM Role wth instance profile (no change)"
+ iam_role:
+ name: "{{ test_role }}"
+ create_instance_profile: yes
+ register: iam_role
+
+- assert:
+ that:
+ - iam_role is not changed
+ - iam_role.iam_role.role_name == test_role
+
+- name: "iam_role_info after Role creation"
+ iam_role_info:
+ name: "{{ test_role }}"
+ register: role_info
+
+- assert:
+ that:
+ - role_info is succeeded
+ - role_info.iam_roles | length == 1
+ - 'role_info.iam_roles[0].arn.startswith("arn")'
+ - 'role_info.iam_roles[0].arn.endswith("role/" + test_role )'
+ - '"assume_role_policy_document" in role_info.iam_roles[0]'
+ - '"create_date" in role_info.iam_roles[0]'
+ - '"description" not in role_info.iam_roles[0]'
+ - role_info.iam_roles[0].inline_policies | length == 0
+ - role_info.iam_roles[0].instance_profiles | length == 1
+ - role_info.iam_roles[0].instance_profiles[0].instance_profile_name == test_role
+ - 'role_info.iam_roles[0].instance_profiles[0].arn.startswith("arn")'
+ - 'role_info.iam_roles[0].instance_profiles[0].arn.endswith("instance-profile/" + test_role)'
+ - role_info.iam_roles[0].managed_policies | length == 0
+ - role_info.iam_roles[0].max_session_duration == 3600
+ - role_info.iam_roles[0].path == '/'
+ - '"permissions_boundary" not in role_info.iam_roles[0]'
+ - role_info.iam_roles[0].role_id == iam_role.iam_role.role_id
+ - role_info.iam_roles[0].role_name == test_role
+ - role_info.iam_roles[0].tags | length == 0
\ No newline at end of file
diff --git a/tests/integration/targets/iam_role/tasks/description_update.yml b/tests/integration/targets/iam_role/tasks/description_update.yml
new file mode 100644
index 00000000000..d4ee520147f
--- /dev/null
+++ b/tests/integration/targets/iam_role/tasks/description_update.yml
@@ -0,0 +1,124 @@
+---
+- name: "Add Description (CHECK MODE)"
+ iam_role:
+ name: "{{ test_role }}"
+ description: "Ansible Test Role {{ resource_prefix }}"
+ check_mode: yes
+ register: iam_role
+
+- assert:
+ that:
+ - iam_role is changed
+
+- name: "Add Description"
+ iam_role:
+ name: "{{ test_role }}"
+ description: "Ansible Test Role {{ resource_prefix }}"
+ register: iam_role
+
+- assert:
+ that:
+ - iam_role is changed
+ - iam_role.iam_role.role_name == test_role
+ - iam_role.iam_role.description == 'Ansible Test Role {{ resource_prefix }}'
+
+- name: "Add Description (no change)"
+ iam_role:
+ name: "{{ test_role }}"
+ description: "Ansible Test Role {{ resource_prefix }}"
+ register: iam_role
+
+- assert:
+ that:
+ - iam_role is not changed
+ - iam_role.iam_role.role_name == test_role
+ - iam_role.iam_role.description == 'Ansible Test Role {{ resource_prefix }}'
+
+- name: "iam_role_info after adding Description"
+ iam_role_info:
+ name: "{{ test_role }}"
+ register: role_info
+
+- assert:
+ that:
+ - role_info is succeeded
+ - role_info.iam_roles | length == 1
+ - 'role_info.iam_roles[0].arn.startswith("arn")'
+ - 'role_info.iam_roles[0].arn.endswith("role/" + test_role )'
+ - '"assume_role_policy_document" in role_info.iam_roles[0]'
+ - '"create_date" in role_info.iam_roles[0]'
+ - 'role_info.iam_roles[0].description == "Ansible Test Role {{ resource_prefix }}"'
+ - role_info.iam_roles[0].inline_policies | length == 0
+ - role_info.iam_roles[0].instance_profiles | length == 1
+ - role_info.iam_roles[0].instance_profiles[0].instance_profile_name == test_role
+ - 'role_info.iam_roles[0].instance_profiles[0].arn.startswith("arn")'
+ - 'role_info.iam_roles[0].instance_profiles[0].arn.endswith("instance-profile/" + test_role)'
+ - role_info.iam_roles[0].managed_policies | length == 0
+ - role_info.iam_roles[0].max_session_duration == 43200
+ - role_info.iam_roles[0].path == '/'
+ - '"permissions_boundary" not in role_info.iam_roles[0]'
+ - role_info.iam_roles[0].role_id == iam_role.iam_role.role_id
+ - role_info.iam_roles[0].role_name == test_role
+ - role_info.iam_roles[0].tags | length == 0
+
+- name: "Update Description (CHECK MODE)"
+ iam_role:
+ name: "{{ test_role }}"
+ description: "Ansible Test Role (updated) {{ resource_prefix }}"
+ check_mode: yes
+ register: iam_role
+
+- assert:
+ that:
+ - iam_role is changed
+
+- name: "Update Description"
+ iam_role:
+ name: "{{ test_role }}"
+ description: "Ansible Test Role (updated) {{ resource_prefix }}"
+ register: iam_role
+
+- assert:
+ that:
+ - iam_role is changed
+ - iam_role.iam_role.role_name == test_role
+ - iam_role.iam_role.description == 'Ansible Test Role (updated) {{ resource_prefix }}'
+
+- name: "Update Description (no change)"
+ iam_role:
+ name: "{{ test_role }}"
+ description: "Ansible Test Role (updated) {{ resource_prefix }}"
+ register: iam_role
+
+- assert:
+ that:
+ - iam_role is not changed
+ - iam_role.iam_role.role_name == test_role
+ - iam_role.iam_role.description == 'Ansible Test Role (updated) {{ resource_prefix }}'
+
+- name: "iam_role_info after updating Description"
+ iam_role_info:
+ name: "{{ test_role }}"
+ register: role_info
+
+- assert:
+ that:
+ - role_info is succeeded
+ - role_info.iam_roles | length == 1
+ - 'role_info.iam_roles[0].arn.startswith("arn")'
+ - 'role_info.iam_roles[0].arn.endswith("role/" + test_role )'
+ - '"assume_role_policy_document" in role_info.iam_roles[0]'
+ - '"create_date" in role_info.iam_roles[0]'
+ - 'role_info.iam_roles[0].description == "Ansible Test Role (updated) {{ resource_prefix }}"'
+ - role_info.iam_roles[0].inline_policies | length == 0
+ - role_info.iam_roles[0].instance_profiles | length == 1
+ - role_info.iam_roles[0].instance_profiles[0].instance_profile_name == test_role
+ - 'role_info.iam_roles[0].instance_profiles[0].arn.startswith("arn")'
+ - 'role_info.iam_roles[0].instance_profiles[0].arn.endswith("instance-profile/" + test_role)'
+ - role_info.iam_roles[0].managed_policies | length == 0
+ - role_info.iam_roles[0].max_session_duration == 43200
+ - role_info.iam_roles[0].path == '/'
+ - '"permissions_boundary" not in role_info.iam_roles[0]'
+ - role_info.iam_roles[0].role_id == iam_role.iam_role.role_id
+ - role_info.iam_roles[0].role_name == test_role
+ - role_info.iam_roles[0].tags | length == 0
diff --git a/tests/integration/targets/iam_role/tasks/inline_policy_update.yml b/tests/integration/targets/iam_role/tasks/inline_policy_update.yml
new file mode 100644
index 00000000000..7fb5eef3e37
--- /dev/null
+++ b/tests/integration/targets/iam_role/tasks/inline_policy_update.yml
@@ -0,0 +1,63 @@
+---
+- name: "Attach inline policy a"
+ iam_policy:
+ state: present
+ iam_type: "role"
+ iam_name: "{{ test_role }}"
+ policy_name: "inline-policy-a"
+ policy_json: '{{ lookup("file", "deny-all-a.json") }}'
+
+- name: "Attach inline policy b"
+ iam_policy:
+ state: present
+ iam_type: "role"
+ iam_name: "{{ test_role }}"
+ policy_name: "inline-policy-b"
+ policy_json: '{{ lookup("file", "deny-all-b.json") }}'
+
+- name: "iam_role_info after attaching inline policies (using iam_policy)"
+ iam_role_info:
+ name: "{{ test_role }}"
+ register: role_info
+- assert:
+ that:
+ - role_info is succeeded
+ - role_info.iam_roles | length == 1
+ - 'role_info.iam_roles[0].arn.startswith("arn")'
+ - 'role_info.iam_roles[0].arn.endswith("role/" + test_role )'
+ - '"assume_role_policy_document" in role_info.iam_roles[0]'
+ - '"create_date" in role_info.iam_roles[0]'
+ - 'role_info.iam_roles[0].description == "Ansible Test Role (updated) {{ resource_prefix }}"'
+ - role_info.iam_roles[0].inline_policies | length == 2
+ - '"inline-policy-a" in role_info.iam_roles[0].inline_policies'
+ - '"inline-policy-b" in role_info.iam_roles[0].inline_policies'
+ - role_info.iam_roles[0].instance_profiles | length == 1
+ - role_info.iam_roles[0].instance_profiles[0].instance_profile_name == test_role
+ - 'role_info.iam_roles[0].instance_profiles[0].arn.startswith("arn")'
+ - 'role_info.iam_roles[0].instance_profiles[0].arn.endswith("instance-profile/" + test_role)'
+ - role_info.iam_roles[0].managed_policies | length == 1
+ - safe_managed_policy not in ( role_info | community.general.json_query("iam_roles[*].managed_policies[*].policy_name") | list | flatten )
+ - custom_policy_name in ( role_info | community.general.json_query("iam_roles[*].managed_policies[*].policy_name") | list | flatten )
+ - role_info.iam_roles[0].max_session_duration == 43200
+ - role_info.iam_roles[0].path == '/'
+ - '"permissions_boundary" not in role_info.iam_roles[0]'
+ - role_info.iam_roles[0].role_id == iam_role.iam_role.role_id
+ - role_info.iam_roles[0].role_name == test_role
+ - role_info.iam_roles[0].tags | length == 1
+ - '"TagB" in role_info.iam_roles[0].tags'
+ - role_info.iam_roles[0].tags.TagB == "ValueB"
+
+# XXX iam_role fails to remove inline policies before deleting the role
+- name: "Detach inline policy a"
+ iam_policy:
+ state: absent
+ iam_type: "role"
+ iam_name: "{{ test_role }}"
+ policy_name: "inline-policy-a"
+
+- name: "Detach inline policy b"
+ iam_policy:
+ state: absent
+ iam_type: "role"
+ iam_name: "{{ test_role }}"
+ policy_name: "inline-policy-b"
diff --git a/tests/integration/targets/iam_role/tasks/main.yml b/tests/integration/targets/iam_role/tasks/main.yml
index 34c17af3369..b4132c60c2a 100644
--- a/tests/integration/targets/iam_role/tasks/main.yml
+++ b/tests/integration/targets/iam_role/tasks/main.yml
@@ -22,1500 +22,115 @@
# Possible Bugs:
# - Fails to delete role if inline policies not removed first
-- name: 'Setup AWS connection info'
+- name: "Setup AWS connection info"
module_defaults:
group/aws:
- aws_access_key: '{{ aws_access_key }}'
- aws_secret_key: '{{ aws_secret_key }}'
- security_token: '{{ security_token | default(omit) }}'
- region: '{{ aws_region }}'
+ aws_access_key: "{{ aws_access_key }}"
+ aws_secret_key: "{{ aws_secret_key }}"
+ security_token: "{{ security_token | default(omit) }}"
+ region: "{{ aws_region }}"
iam_role:
assume_role_policy_document: '{{ lookup("file", "deny-assume.json") }}'
collections:
- amazon.aws
+ - community.general
block:
- # ===================================================================
- # Parameter Checks
- - name: 'Friendly message when creating an instance profile and adding a boundary profile'
- iam_role:
- name: '{{ test_role }}'
- boundary: '{{ boundary_policy }}'
- register: iam_role
- ignore_errors: yes
- - assert:
- that:
- - iam_role is failed
- - '"boundary policy" in iam_role.msg'
- - '"create_instance_profile" in iam_role.msg'
- - '"false" in iam_role.msg'
-
- - name: 'Friendly message when boundary profile is not an ARN'
- iam_role:
- name: '{{ test_role }}'
- boundary: 'AWSDenyAll'
- create_instance_profile: no
- register: iam_role
- ignore_errors: yes
- - assert:
- that:
- - iam_role is failed
- - '"Boundary policy" in iam_role.msg'
- - '"ARN" in iam_role.msg'
-
- - name: 'Friendly message when "present" without assume_role_policy_document'
- module_defaults: { iam_role: {} }
- iam_role:
- name: '{{ test_role }}'
- register: iam_role
- ignore_errors: yes
- - assert:
- that:
- - iam_role is failed
- - 'iam_role.msg.startswith("state is present but all of the following are missing")'
- - '"assume_role_policy_document" in iam_role.msg'
-
- - name: 'Maximum Session Duration needs to be between 1 and 12 hours'
- iam_role:
- name: '{{ test_role }}'
- max_session_duration: 3599
- register: iam_role
- ignore_errors: yes
- - assert:
- that:
- - iam_role is failed
- - '"max_session_duration must be between" in iam_role.msg'
-
- - name: 'Maximum Session Duration needs to be between 1 and 12 hours'
- iam_role:
- name: '{{ test_role }}'
- max_session_duration: 43201
- register: iam_role
- ignore_errors: yes
- - assert:
- that:
- - iam_role is failed
- - '"max_session_duration must be between" in iam_role.msg'
-
- - name: 'Role Paths must start with /'
- iam_role:
- name: '{{ test_role }}'
- path: 'test/'
- register: iam_role
- ignore_errors: yes
- - assert:
- that:
- - iam_role is failed
- - '"path must begin and end with /" in iam_role.msg'
+ # ===================================================================
+ # Parameter Checks
+ - include_tasks: parameter_checks.yml
+
+ # ===================================================================
+ # Supplemental resource pre-creation
+ - name: "Create Safe IAM Managed Policy"
+ iam_managed_policy:
+ state: present
+ policy_name: "{{ custom_policy_name }}"
+ policy_description: "A safe (deny-all) managed policy"
+ policy: "{{ lookup('file', 'deny-all.json') }}"
+ register: create_managed_policy
- - name: 'Role Paths must end with /'
- iam_role:
- name: '{{ test_role }}'
- path: '/test'
- register: iam_role
- ignore_errors: yes
- - assert:
- that:
- - iam_role is failed
- - '"path must begin and end with /" in iam_role.msg'
-
- # ===================================================================
- # Supplemental resource pre-creation
- - name: 'Create Safe IAM Managed Policy'
- iam_managed_policy:
- state: present
- policy_name: '{{ custom_policy_name }}'
- policy_description: "A safe (deny-all) managed policy"
- policy: "{{ lookup('file', 'deny-all.json') }}"
- register: create_managed_policy
- - assert:
- that:
- - create_managed_policy is succeeded
-
- # ===================================================================
- # Rapid Role Creation and deletion
- - name: Try running some rapid fire create/delete tests
- # We've previously seen issues with iam_role returning before creation's
- # actually complete, if we think the issue's gone, let's try creating and
- # deleting things in quick succession
- when: not (standard_pauses | bool)
- block:
- - name: 'Minimal IAM Role without instance profile (rapid)'
- iam_role:
- name: '{{ test_role }}'
- create_instance_profile: no
- register: iam_role
- - name: 'Minimal IAM Role without instance profile (rapid)'
- iam_role:
- name: '{{ test_role }}'
- create_instance_profile: no
- register: iam_role_again
- - assert:
- that:
- - iam_role is changed
- - iam_role_again is not changed
- - name: 'Remove IAM Role (rapid)'
- iam_role:
- state: absent
- name: '{{ test_role }}'
- register: iam_role
- - name: 'Remove IAM Role (rapid)'
- iam_role:
- state: absent
- name: '{{ test_role }}'
- register: iam_role_again
- assert:
that:
- - iam_role is changed
- - iam_role_again is not changed
-
- - name: 'Minimal IAM Role without instance profile (rapid)'
- iam_role:
- name: '{{ test_role }}'
- create_instance_profile: no
- register: iam_role
- - name: 'Remove IAM Role (rapid)'
- iam_role:
- state: absent
- name: '{{ test_role }}'
- register: iam_role_again
- - assert:
- that:
- - iam_role is changed
- - iam_role_again is changed
-
- # ===================================================================
- # Role Creation
- # (without Instance profile)
- - name: 'iam_role_info before Role creation (no args)'
- iam_role_info:
- register: role_info
- - assert:
- that:
- - role_info is succeeded
-
- - name: 'iam_role_info before Role creation (search for test role)'
- iam_role_info:
- name: '{{ test_role }}'
- register: role_info
- - assert:
- that:
- - role_info is succeeded
- - role_info.iam_roles | length == 0
-
- - name: 'Minimal IAM Role (CHECK MODE)'
- iam_role:
- name: '{{ test_role }}'
- create_instance_profile: no
- check_mode: yes
- register: iam_role
- - assert:
- that:
- - iam_role is changed
- # Pause this first time, just in case we actually created something...
- - name: Short pause for role creation to finish
- pause:
- seconds: 10
- when: standard_pauses | bool
-
- - name: 'iam_role_info after Role creation in check_mode'
- iam_role_info:
- name: '{{ test_role }}'
- register: role_info
- - assert:
- that:
- - role_info is succeeded
- - role_info.iam_roles | length == 0
-
- - name: 'Minimal IAM Role without instance profile'
- iam_role:
- name: '{{ test_role }}'
- create_instance_profile: no
- register: iam_role
- - assert:
- that:
- - iam_role is changed
- - iam_role.iam_role.role_name == test_role
- - 'iam_role.iam_role.arn.startswith("arn")'
- - 'iam_role.iam_role.arn.endswith("role/" + test_role )'
- # Would be nice to test the contents...
- - '"assume_role_policy_document" in iam_role.iam_role'
- - iam_role.iam_role.attached_policies | length == 0
- - iam_role.iam_role.max_session_duration == 3600
- - iam_role.iam_role.path == '/'
- - iam_role.iam_role.role_name == test_role
- - '"create_date" in iam_role.iam_role'
- - '"role_id" in iam_role.iam_role'
- - name: Short pause for role creation to finish
- pause:
- seconds: 10
- when: standard_pauses | bool
-
- - name: 'Minimal IAM Role without instance profile (no change)'
- iam_role:
- name: '{{ test_role }}'
- create_instance_profile: no
- register: iam_role
- - assert:
- that:
- - iam_role is not changed
- - iam_role.iam_role.role_name == test_role
-
- - name: 'iam_role_info after Role creation'
- iam_role_info:
- name: '{{ test_role }}'
- register: role_info
- - assert:
- that:
- - role_info is succeeded
- - role_info.iam_roles | length == 1
- - 'role_info.iam_roles[0].arn.startswith("arn")'
- - 'role_info.iam_roles[0].arn.endswith("role/" + test_role )'
- - '"assume_role_policy_document" in role_info.iam_roles[0]'
- - '"create_date" in role_info.iam_roles[0]'
- - '"description" not in role_info.iam_roles[0]'
- - role_info.iam_roles[0].inline_policies | length == 0
- - role_info.iam_roles[0].instance_profiles | length == 0
- - role_info.iam_roles[0].managed_policies | length == 0
- - role_info.iam_roles[0].max_session_duration == 3600
- - role_info.iam_roles[0].path == '/'
- - '"permissions_boundary" not in role_info.iam_roles[0]'
- - role_info.iam_roles[0].role_id == iam_role.iam_role.role_id
- - role_info.iam_roles[0].role_name == test_role
- - role_info.iam_roles[0].tags | length == 0
-
- - name: 'Remove IAM Role'
- iam_role:
- state: absent
- name: '{{ test_role }}'
- delete_instance_profile: yes
- register: iam_role
- - assert:
- that:
- - iam_role is changed
- - name: Short pause for role removal to finish
- pause:
- seconds: 10
- when: paranoid_pauses | bool
-
- - name: 'iam_role_info after Role deletion'
- iam_role_info:
- name: '{{ test_role }}'
- register: role_info
- - assert:
- that:
- - role_info is succeeded
- - role_info.iam_roles | length == 0
-
- # (with path)
- - name: 'Minimal IAM Role with path (CHECK MODE)'
- iam_role:
- name: '{{ test_role }}'
- path: '{{ test_path }}'
- register: iam_role
- check_mode: yes
- - assert:
- that:
- - iam_role is changed
-
- - name: 'Minimal IAM Role with path'
- iam_role:
- name: '{{ test_role }}'
- path: '{{ test_path }}'
- register: iam_role
- - assert:
- that:
- - iam_role is changed
- - iam_role.iam_role.role_name == test_role
- - 'iam_role.iam_role.arn.startswith("arn")'
- - 'iam_role.iam_role.arn.endswith("role" + test_path + test_role )'
- # Would be nice to test the contents...
- - '"assume_role_policy_document" in iam_role.iam_role'
- - iam_role.iam_role.attached_policies | length == 0
- - iam_role.iam_role.max_session_duration == 3600
- - iam_role.iam_role.path == '{{ test_path }}'
- - iam_role.iam_role.role_name == test_role
- - '"create_date" in iam_role.iam_role'
- - '"role_id" in iam_role.iam_role'
- - name: Short pause for role creation to finish
- pause:
- seconds: 10
- when: standard_pauses | bool
-
- - name: 'Minimal IAM Role with path (no change)'
- iam_role:
- name: '{{ test_role }}'
- path: '{{ test_path }}'
- register: iam_role
- - assert:
- that:
- - iam_role is not changed
- - iam_role.iam_role.role_name == test_role
-
- - name: 'iam_role_info after Role creation'
- iam_role_info:
- name: '{{ test_role }}'
- register: role_info
- - assert:
- that:
- - role_info is succeeded
- - role_info.iam_roles | length == 1
- - 'role_info.iam_roles[0].arn.startswith("arn")'
- - 'role_info.iam_roles[0].arn.endswith("role" + test_path + test_role )'
- - '"assume_role_policy_document" in role_info.iam_roles[0]'
- - '"create_date" in role_info.iam_roles[0]'
- - '"description" not in role_info.iam_roles[0]'
- - role_info.iam_roles[0].inline_policies | length == 0
- - role_info.iam_roles[0].instance_profiles | length == 1
- - role_info.iam_roles[0].instance_profiles[0].instance_profile_name == test_role
- - 'role_info.iam_roles[0].instance_profiles[0].arn.startswith("arn")'
- - 'role_info.iam_roles[0].instance_profiles[0].arn.endswith("instance-profile" + test_path + test_role)'
- - role_info.iam_roles[0].managed_policies | length == 0
- - role_info.iam_roles[0].max_session_duration == 3600
- - role_info.iam_roles[0].path == '{{ test_path }}'
- - '"permissions_boundary" not in role_info.iam_roles[0]'
- - role_info.iam_roles[0].role_id == iam_role.iam_role.role_id
- - role_info.iam_roles[0].role_name == test_role
- - role_info.iam_roles[0].tags | length == 0
-
- - name: 'iam_role_info after Role creation (searching a path)'
- iam_role_info:
- path_prefix: '{{ test_path }}'
- register: role_info
- - assert:
- that:
- - role_info is succeeded
- - role_info.iam_roles | length == 1
- - 'role_info.iam_roles[0].arn.startswith("arn")'
- - 'role_info.iam_roles[0].arn.endswith("role" + test_path + test_role )'
- - '"assume_role_policy_document" in role_info.iam_roles[0]'
- - '"create_date" in role_info.iam_roles[0]'
- - '"description" not in role_info.iam_roles[0]'
- - role_info.iam_roles[0].inline_policies | length == 0
- - role_info.iam_roles[0].instance_profiles | length == 1
- - role_info.iam_roles[0].instance_profiles[0].instance_profile_name == test_role
- - 'role_info.iam_roles[0].instance_profiles[0].arn.startswith("arn")'
- - 'role_info.iam_roles[0].instance_profiles[0].arn.endswith("instance-profile" + test_path + test_role)'
- - role_info.iam_roles[0].managed_policies | length == 0
- - role_info.iam_roles[0].max_session_duration == 3600
- - '"permissions_boundary" not in role_info.iam_roles[0]'
- - role_info.iam_roles[0].path == '{{ test_path }}'
- - role_info.iam_roles[0].role_id == iam_role.iam_role.role_id
- - role_info.iam_roles[0].role_name == test_role
- - role_info.iam_roles[0].tags | length == 0
-
- - name: 'Remove IAM Role'
- iam_role:
- state: absent
- name: '{{ test_role }}'
- path: '{{ test_path }}'
- # If we don't delete the existing profile it'll be reused (with the path)
- # by the test below.
- delete_instance_profile: yes
- register: iam_role
- - assert:
- that:
- - iam_role is changed
- - name: Short pause for role removal to finish
- pause:
- seconds: 10
- when: paranoid_pauses | bool
-
- - name: 'iam_role_info after Role deletion'
- iam_role_info:
- name: '{{ test_role }}'
- register: role_info
- - assert:
- that:
- - role_info is succeeded
- - role_info.iam_roles | length == 0
-
- # (with Instance profile)
- - name: 'Minimal IAM Role with instance profile'
- iam_role:
- name: '{{ test_role }}'
- create_instance_profile: yes
- register: iam_role
- - assert:
- that:
- - iam_role is changed
- - iam_role.iam_role.role_name == test_role
- - 'iam_role.iam_role.arn.startswith("arn")'
- - 'iam_role.iam_role.arn.endswith("role/" + test_role )'
- # Would be nice to test the contents...
- - '"assume_role_policy_document" in iam_role.iam_role'
- - iam_role.iam_role.attached_policies | length == 0
- - iam_role.iam_role.max_session_duration == 3600
- - iam_role.iam_role.path == '/'
- - iam_role.iam_role.role_name == test_role
- - '"create_date" in iam_role.iam_role'
- - '"role_id" in iam_role.iam_role'
- - name: Short pause for role creation to finish
- pause:
- seconds: 10
- when: standard_pauses | bool
-
- - name: 'Minimal IAM Role wth instance profile (no change)'
- iam_role:
- name: '{{ test_role }}'
- create_instance_profile: yes
- register: iam_role
- - assert:
- that:
- - iam_role is not changed
- - iam_role.iam_role.role_name == test_role
-
- - name: 'iam_role_info after Role creation'
- iam_role_info:
- name: '{{ test_role }}'
- register: role_info
- - assert:
- that:
- - role_info is succeeded
- - role_info.iam_roles | length == 1
- - 'role_info.iam_roles[0].arn.startswith("arn")'
- - 'role_info.iam_roles[0].arn.endswith("role/" + test_role )'
- - '"assume_role_policy_document" in role_info.iam_roles[0]'
- - '"create_date" in role_info.iam_roles[0]'
- - '"description" not in role_info.iam_roles[0]'
- - role_info.iam_roles[0].inline_policies | length == 0
- - role_info.iam_roles[0].instance_profiles | length == 1
- - role_info.iam_roles[0].instance_profiles[0].instance_profile_name == test_role
- - 'role_info.iam_roles[0].instance_profiles[0].arn.startswith("arn")'
- - 'role_info.iam_roles[0].instance_profiles[0].arn.endswith("instance-profile/" + test_role)'
- - role_info.iam_roles[0].managed_policies | length == 0
- - role_info.iam_roles[0].max_session_duration == 3600
- - role_info.iam_roles[0].path == '/'
- - '"permissions_boundary" not in role_info.iam_roles[0]'
- - role_info.iam_roles[0].role_id == iam_role.iam_role.role_id
- - role_info.iam_roles[0].role_name == test_role
- - role_info.iam_roles[0].tags | length == 0
-
- # ===================================================================
- # Max Session Duration Manipulation
-
- - name: 'Update Max Session Duration (CHECK MODE)'
- iam_role:
- name: '{{ test_role }}'
- max_session_duration: 43200
- check_mode: yes
- register: iam_role
- - assert:
- that:
- - iam_role is changed
-
- - name: 'Update Max Session Duration'
- iam_role:
- name: '{{ test_role }}'
- max_session_duration: 43200
- register: iam_role
- - assert:
- that:
- - iam_role is changed
- - iam_role.iam_role.role_name == test_role
- - iam_role.iam_role.max_session_duration == 43200
-
- - name: 'Update Max Session Duration (no change)'
- iam_role:
- name: '{{ test_role }}'
- max_session_duration: 43200
- register: iam_role
- - assert:
- that:
- - iam_role is not changed
- - iam_role.iam_role.role_name == test_role
-
- - name: 'iam_role_info after updating Max Session Duration'
- iam_role_info:
- name: '{{ test_role }}'
- register: role_info
- - assert:
- that:
- - role_info is succeeded
- - role_info.iam_roles | length == 1
- - 'role_info.iam_roles[0].arn.startswith("arn")'
- - 'role_info.iam_roles[0].arn.endswith("role/" + test_role )'
- - '"assume_role_policy_document" in role_info.iam_roles[0]'
- - '"create_date" in role_info.iam_roles[0]'
- - '"description" not in role_info.iam_roles[0]'
- - role_info.iam_roles[0].inline_policies | length == 0
- - role_info.iam_roles[0].instance_profiles | length == 1
- - role_info.iam_roles[0].instance_profiles[0].instance_profile_name == test_role
- - 'role_info.iam_roles[0].instance_profiles[0].arn.startswith("arn")'
- - 'role_info.iam_roles[0].instance_profiles[0].arn.endswith("instance-profile/" + test_role)'
- - role_info.iam_roles[0].managed_policies | length == 0
- - role_info.iam_roles[0].max_session_duration == 43200
- - role_info.iam_roles[0].path == '/'
- - '"permissions_boundary" not in role_info.iam_roles[0]'
- - role_info.iam_roles[0].role_id == iam_role.iam_role.role_id
- - role_info.iam_roles[0].role_name == test_role
- - role_info.iam_roles[0].tags | length == 0
-
- # ===================================================================
- # Description Manipulation
-
- - name: 'Add Description (CHECK MODE)'
- iam_role:
- name: '{{ test_role }}'
- description: 'Ansible Test Role {{ resource_prefix }}'
- check_mode: yes
- register: iam_role
- - assert:
- that:
- - iam_role is changed
-
- - name: 'Add Description'
- iam_role:
- name: '{{ test_role }}'
- description: 'Ansible Test Role {{ resource_prefix }}'
- register: iam_role
- - assert:
- that:
- - iam_role is changed
- - iam_role.iam_role.role_name == test_role
- - iam_role.iam_role.description == 'Ansible Test Role {{ resource_prefix }}'
-
- - name: 'Add Description (no change)'
- iam_role:
- name: '{{ test_role }}'
- description: 'Ansible Test Role {{ resource_prefix }}'
- register: iam_role
- - assert:
- that:
- - iam_role is not changed
- - iam_role.iam_role.role_name == test_role
- - iam_role.iam_role.description == 'Ansible Test Role {{ resource_prefix }}'
-
- - name: 'iam_role_info after adding Description'
- iam_role_info:
- name: '{{ test_role }}'
- register: role_info
- - assert:
- that:
- - role_info is succeeded
- - role_info.iam_roles | length == 1
- - 'role_info.iam_roles[0].arn.startswith("arn")'
- - 'role_info.iam_roles[0].arn.endswith("role/" + test_role )'
- - '"assume_role_policy_document" in role_info.iam_roles[0]'
- - '"create_date" in role_info.iam_roles[0]'
- - 'role_info.iam_roles[0].description == "Ansible Test Role {{ resource_prefix }}"'
- - role_info.iam_roles[0].inline_policies | length == 0
- - role_info.iam_roles[0].instance_profiles | length == 1
- - role_info.iam_roles[0].instance_profiles[0].instance_profile_name == test_role
- - 'role_info.iam_roles[0].instance_profiles[0].arn.startswith("arn")'
- - 'role_info.iam_roles[0].instance_profiles[0].arn.endswith("instance-profile/" + test_role)'
- - role_info.iam_roles[0].managed_policies | length == 0
- - role_info.iam_roles[0].max_session_duration == 43200
- - role_info.iam_roles[0].path == '/'
- - '"permissions_boundary" not in role_info.iam_roles[0]'
- - role_info.iam_roles[0].role_id == iam_role.iam_role.role_id
- - role_info.iam_roles[0].role_name == test_role
- - role_info.iam_roles[0].tags | length == 0
-
- - name: 'Update Description (CHECK MODE)'
- iam_role:
- name: '{{ test_role }}'
- description: 'Ansible Test Role (updated) {{ resource_prefix }}'
- check_mode: yes
- register: iam_role
- - assert:
- that:
- - iam_role is changed
-
- - name: 'Update Description'
- iam_role:
- name: '{{ test_role }}'
- description: 'Ansible Test Role (updated) {{ resource_prefix }}'
- register: iam_role
- - assert:
- that:
- - iam_role is changed
- - iam_role.iam_role.role_name == test_role
- - iam_role.iam_role.description == 'Ansible Test Role (updated) {{ resource_prefix }}'
-
- - name: 'Update Description (no change)'
- iam_role:
- name: '{{ test_role }}'
- description: 'Ansible Test Role (updated) {{ resource_prefix }}'
- register: iam_role
- - assert:
- that:
- - iam_role is not changed
- - iam_role.iam_role.role_name == test_role
- - iam_role.iam_role.description == 'Ansible Test Role (updated) {{ resource_prefix }}'
-
- - name: 'iam_role_info after updating Description'
- iam_role_info:
- name: '{{ test_role }}'
- register: role_info
- - assert:
- that:
- - role_info is succeeded
- - role_info.iam_roles | length == 1
- - 'role_info.iam_roles[0].arn.startswith("arn")'
- - 'role_info.iam_roles[0].arn.endswith("role/" + test_role )'
- - '"assume_role_policy_document" in role_info.iam_roles[0]'
- - '"create_date" in role_info.iam_roles[0]'
- - 'role_info.iam_roles[0].description == "Ansible Test Role (updated) {{ resource_prefix }}"'
- - role_info.iam_roles[0].inline_policies | length == 0
- - role_info.iam_roles[0].instance_profiles | length == 1
- - role_info.iam_roles[0].instance_profiles[0].instance_profile_name == test_role
- - 'role_info.iam_roles[0].instance_profiles[0].arn.startswith("arn")'
- - 'role_info.iam_roles[0].instance_profiles[0].arn.endswith("instance-profile/" + test_role)'
- - role_info.iam_roles[0].managed_policies | length == 0
- - role_info.iam_roles[0].max_session_duration == 43200
- - role_info.iam_roles[0].path == '/'
- - '"permissions_boundary" not in role_info.iam_roles[0]'
- - role_info.iam_roles[0].role_id == iam_role.iam_role.role_id
- - role_info.iam_roles[0].role_name == test_role
- - role_info.iam_roles[0].tags | length == 0
-
-
- # ===================================================================
- # Tag Manipulation
-
- - name: 'Add Tag (CHECK MODE)'
- iam_role:
- name: '{{ test_role }}'
- tags:
- TagA: ValueA
- check_mode: yes
- register: iam_role
- - assert:
- that:
- - iam_role is changed
-
- - name: 'Add Tag'
- iam_role:
- name: '{{ test_role }}'
- tags:
- TagA: ValueA
- register: iam_role
- - assert:
- that:
- - iam_role is changed
- - iam_role.iam_role.role_name == test_role
- - iam_role.iam_role.tags | length == 1
- - '"TagA" in iam_role.iam_role.tags'
- - iam_role.iam_role.tags.TagA == "ValueA"
+ - create_managed_policy is succeeded
- - name: 'Add Tag (no change)'
- iam_role:
- name: '{{ test_role }}'
- tags:
- TagA: ValueA
- register: iam_role
- - assert:
- that:
- - iam_role is not changed
- - iam_role.iam_role.role_name == test_role
- - '"TagA" in iam_role.iam_role.tags'
- - iam_role.iam_role.tags.TagA == "ValueA"
-
- - name: 'iam_role_info after adding Tags'
- iam_role_info:
- name: '{{ test_role }}'
- register: role_info
- - assert:
- that:
- - role_info is succeeded
- - role_info.iam_roles | length == 1
- - 'role_info.iam_roles[0].arn.startswith("arn")'
- - 'role_info.iam_roles[0].arn.endswith("role/" + test_role )'
- - '"assume_role_policy_document" in role_info.iam_roles[0]'
- - '"create_date" in role_info.iam_roles[0]'
- - 'role_info.iam_roles[0].description == "Ansible Test Role (updated) {{ resource_prefix }}"'
- - role_info.iam_roles[0].inline_policies | length == 0
- - role_info.iam_roles[0].instance_profiles | length == 1
- - role_info.iam_roles[0].instance_profiles[0].instance_profile_name == test_role
- - 'role_info.iam_roles[0].instance_profiles[0].arn.startswith("arn")'
- - 'role_info.iam_roles[0].instance_profiles[0].arn.endswith("instance-profile/" + test_role)'
- - role_info.iam_roles[0].managed_policies | length == 0
- - role_info.iam_roles[0].max_session_duration == 43200
- - role_info.iam_roles[0].path == '/'
- - '"permissions_boundary" not in role_info.iam_roles[0]'
- - role_info.iam_roles[0].role_id == iam_role.iam_role.role_id
- - role_info.iam_roles[0].role_name == test_role
- - role_info.iam_roles[0].tags | length == 1
- - '"TagA" in role_info.iam_roles[0].tags'
- - role_info.iam_roles[0].tags.TagA == "ValueA"
-
- - name: 'Update Tag (CHECK MODE)'
- iam_role:
- name: '{{ test_role }}'
- tags:
- TagA: AValue
- check_mode: yes
- register: iam_role
- - assert:
- that:
- - iam_role is changed
-
- - name: 'Update Tag'
- iam_role:
- name: '{{ test_role }}'
- tags:
- TagA: AValue
- register: iam_role
- - assert:
- that:
- - iam_role is changed
- - iam_role.iam_role.role_name == test_role
- - '"TagA" in iam_role.iam_role.tags'
- - iam_role.iam_role.tags.TagA == "AValue"
-
- - name: 'Update Tag (no change)'
- iam_role:
- name: '{{ test_role }}'
- tags:
- TagA: AValue
- register: iam_role
- - assert:
- that:
- - iam_role is not changed
- - iam_role.iam_role.role_name == test_role
- - '"TagA" in iam_role.iam_role.tags'
- - iam_role.iam_role.tags.TagA == "AValue"
-
- - name: 'iam_role_info after updating Tag'
- iam_role_info:
- name: '{{ test_role }}'
- register: role_info
- - assert:
- that:
- - role_info is succeeded
- - role_info.iam_roles | length == 1
- - 'role_info.iam_roles[0].arn.startswith("arn")'
- - 'role_info.iam_roles[0].arn.endswith("role/" + test_role )'
- - '"assume_role_policy_document" in role_info.iam_roles[0]'
- - '"create_date" in role_info.iam_roles[0]'
- - 'role_info.iam_roles[0].description == "Ansible Test Role (updated) {{ resource_prefix }}"'
- - role_info.iam_roles[0].inline_policies | length == 0
- - role_info.iam_roles[0].instance_profiles | length == 1
- - role_info.iam_roles[0].instance_profiles[0].instance_profile_name == test_role
- - 'role_info.iam_roles[0].instance_profiles[0].arn.startswith("arn")'
- - 'role_info.iam_roles[0].instance_profiles[0].arn.endswith("instance-profile/" + test_role)'
- - role_info.iam_roles[0].managed_policies | length == 0
- - role_info.iam_roles[0].max_session_duration == 43200
- - role_info.iam_roles[0].path == '/'
- - '"permissions_boundary" not in role_info.iam_roles[0]'
- - role_info.iam_roles[0].role_id == iam_role.iam_role.role_id
- - role_info.iam_roles[0].role_name == test_role
- - role_info.iam_roles[0].tags | length == 1
- - '"TagA" in role_info.iam_roles[0].tags'
- - role_info.iam_roles[0].tags.TagA == "AValue"
-
- - name: 'Add second Tag without purge (CHECK MODE)'
- iam_role:
- name: '{{ test_role }}'
- purge_tags: no
- tags:
- TagB: ValueB
- check_mode: yes
- register: iam_role
- - assert:
- that:
- - iam_role is changed
-
- - name: 'Add second Tag without purge'
- iam_role:
- name: '{{ test_role }}'
- purge_tags: no
- tags:
- TagB: ValueB
- register: iam_role
- - assert:
- that:
- - iam_role is changed
- - iam_role.iam_role.role_name == test_role
- - '"TagB" in iam_role.iam_role.tags'
- - iam_role.iam_role.tags.TagB == "ValueB"
-
- - name: 'Add second Tag without purge (no change)'
- iam_role:
- name: '{{ test_role }}'
- purge_tags: no
- tags:
- TagB: ValueB
- register: iam_role
- - assert:
- that:
- - iam_role is not changed
- - iam_role.iam_role.role_name == test_role
- - '"TagB" in iam_role.iam_role.tags'
- - iam_role.iam_role.tags.TagB == "ValueB"
-
- - name: 'iam_role_info after adding second Tag without purge'
- iam_role_info:
- name: '{{ test_role }}'
- register: role_info
- - assert:
- that:
- - role_info is succeeded
- - role_info.iam_roles | length == 1
- - 'role_info.iam_roles[0].arn.startswith("arn")'
- - 'role_info.iam_roles[0].arn.endswith("role/" + test_role )'
- - '"assume_role_policy_document" in role_info.iam_roles[0]'
- - '"create_date" in role_info.iam_roles[0]'
- - 'role_info.iam_roles[0].description == "Ansible Test Role (updated) {{ resource_prefix }}"'
- - role_info.iam_roles[0].inline_policies | length == 0
- - role_info.iam_roles[0].instance_profiles | length == 1
- - role_info.iam_roles[0].instance_profiles[0].instance_profile_name == test_role
- - 'role_info.iam_roles[0].instance_profiles[0].arn.startswith("arn")'
- - 'role_info.iam_roles[0].instance_profiles[0].arn.endswith("instance-profile/" + test_role)'
- - role_info.iam_roles[0].managed_policies | length == 0
- - role_info.iam_roles[0].max_session_duration == 43200
- - role_info.iam_roles[0].path == '/'
- - '"permissions_boundary" not in role_info.iam_roles[0]'
- - role_info.iam_roles[0].role_id == iam_role.iam_role.role_id
- - role_info.iam_roles[0].role_name == test_role
- - role_info.iam_roles[0].tags | length == 2
- - '"TagA" in role_info.iam_roles[0].tags'
- - role_info.iam_roles[0].tags.TagA == "AValue"
- - '"TagB" in role_info.iam_roles[0].tags'
- - role_info.iam_roles[0].tags.TagB == "ValueB"
-
- - name: 'Purge first tag (CHECK MODE)'
- iam_role:
- name: '{{ test_role }}'
- purge_tags: yes
- tags:
- TagB: ValueB
- check_mode: yes
- register: iam_role
- - assert:
- that:
- - iam_role is changed
-
- - name: 'Purge first tag'
- iam_role:
- name: '{{ test_role }}'
- purge_tags: yes
- tags:
- TagB: ValueB
- register: iam_role
- - assert:
- that:
- - iam_role is changed
- - iam_role.iam_role.role_name == test_role
- - '"TagB" in iam_role.iam_role.tags'
- - iam_role.iam_role.tags.TagB == "ValueB"
-
- - name: 'Purge first tag (no change)'
- iam_role:
- name: '{{ test_role }}'
- purge_tags: yes
- tags:
- TagB: ValueB
- register: iam_role
- - assert:
- that:
- - iam_role is not changed
- - iam_role.iam_role.role_name == test_role
- - '"TagB" in iam_role.iam_role.tags'
- - iam_role.iam_role.tags.TagB == "ValueB"
-
- - name: 'iam_role_info after purging first Tag'
- iam_role_info:
- name: '{{ test_role }}'
- register: role_info
- - assert:
- that:
- - role_info is succeeded
- - role_info.iam_roles | length == 1
- - 'role_info.iam_roles[0].arn.startswith("arn")'
- - 'role_info.iam_roles[0].arn.endswith("role/" + test_role )'
- - '"assume_role_policy_document" in role_info.iam_roles[0]'
- - '"create_date" in role_info.iam_roles[0]'
- - 'role_info.iam_roles[0].description == "Ansible Test Role (updated) {{ resource_prefix }}"'
- - role_info.iam_roles[0].inline_policies | length == 0
- - role_info.iam_roles[0].instance_profiles | length == 1
- - role_info.iam_roles[0].instance_profiles[0].instance_profile_name == test_role
- - 'role_info.iam_roles[0].instance_profiles[0].arn.startswith("arn")'
- - 'role_info.iam_roles[0].instance_profiles[0].arn.endswith("instance-profile/" + test_role)'
- - role_info.iam_roles[0].managed_policies | length == 0
- - role_info.iam_roles[0].max_session_duration == 43200
- - role_info.iam_roles[0].path == '/'
- - '"permissions_boundary" not in role_info.iam_roles[0]'
- - role_info.iam_roles[0].role_id == iam_role.iam_role.role_id
- - role_info.iam_roles[0].role_name == test_role
- - role_info.iam_roles[0].tags | length == 1
- - '"TagA" not in role_info.iam_roles[0].tags'
- - '"TagB" in role_info.iam_roles[0].tags'
- - role_info.iam_roles[0].tags.TagB == "ValueB"
-
-
- # ===================================================================
- # Policy Manipulation
-
- - name: 'Add Managed Policy (CHECK MODE)'
- iam_role:
- name: '{{ test_role }}'
- purge_policies: no
- managed_policy:
- - '{{ safe_managed_policy }}'
- check_mode: yes
- register: iam_role
- - assert:
- that:
- - iam_role is changed
-
- - name: 'Add Managed Policy'
- iam_role:
- name: '{{ test_role }}'
- purge_policies: no
- managed_policy:
- - '{{ safe_managed_policy }}'
- register: iam_role
- - assert:
- that:
- - iam_role is changed
- - iam_role.iam_role.role_name == test_role
-
- - name: 'Add Managed Policy (no change)'
- iam_role:
- name: '{{ test_role }}'
- purge_policies: no
- managed_policy:
- - '{{ safe_managed_policy }}'
- register: iam_role
- - assert:
- that:
- - iam_role is not changed
- - iam_role.iam_role.role_name == test_role
-
- - name: 'iam_role_info after adding Managed Policy'
- iam_role_info:
- name: '{{ test_role }}'
- register: role_info
- - assert:
- that:
- - role_info is succeeded
- - role_info.iam_roles | length == 1
- - 'role_info.iam_roles[0].arn.startswith("arn")'
- - 'role_info.iam_roles[0].arn.endswith("role/" + test_role )'
- - '"assume_role_policy_document" in role_info.iam_roles[0]'
- - '"create_date" in role_info.iam_roles[0]'
- - 'role_info.iam_roles[0].description == "Ansible Test Role (updated) {{ resource_prefix }}"'
- - role_info.iam_roles[0].inline_policies | length == 0
- - role_info.iam_roles[0].instance_profiles | length == 1
- - role_info.iam_roles[0].instance_profiles[0].instance_profile_name == test_role
- - 'role_info.iam_roles[0].instance_profiles[0].arn.startswith("arn")'
- - 'role_info.iam_roles[0].instance_profiles[0].arn.endswith("instance-profile/" + test_role)'
- - role_info.iam_roles[0].managed_policies | length == 1
- - safe_managed_policy in ( role_info | community.general.json_query("iam_roles[*].managed_policies[*].policy_name") | list | flatten )
- - custom_policy_name not in ( role_info | community.general.json_query("iam_roles[*].managed_policies[*].policy_name") | list | flatten )
- - role_info.iam_roles[0].max_session_duration == 43200
- - role_info.iam_roles[0].path == '/'
- - '"permissions_boundary" not in role_info.iam_roles[0]'
- - role_info.iam_roles[0].role_id == iam_role.iam_role.role_id
- - role_info.iam_roles[0].role_name == test_role
- - role_info.iam_roles[0].tags | length == 1
- - '"TagB" in role_info.iam_roles[0].tags'
- - role_info.iam_roles[0].tags.TagB == "ValueB"
-
- - name: 'Update Managed Policy without purge (CHECK MODE)'
- iam_role:
- name: '{{ test_role }}'
- purge_policies: no
- managed_policy:
- - '{{ custom_policy_name }}'
- check_mode: yes
- register: iam_role
- - assert:
- that:
- - iam_role is changed
-
- - name: 'Update Managed Policy without purge'
- iam_role:
- name: '{{ test_role }}'
- purge_policies: no
- managed_policy:
- - '{{ custom_policy_name }}'
- register: iam_role
- - assert:
- that:
- - iam_role is changed
- - iam_role.iam_role.role_name == test_role
-
- - name: 'Update Managed Policy without purge (no change)'
- iam_role:
- name: '{{ test_role }}'
- purge_policies: no
- managed_policy:
- - '{{ custom_policy_name }}'
- register: iam_role
- - assert:
- that:
- - iam_role is not changed
- - iam_role.iam_role.role_name == test_role
-
- - name: 'iam_role_info after updating Managed Policy without purge'
- iam_role_info:
- name: '{{ test_role }}'
- register: role_info
- - assert:
- that:
- - role_info is succeeded
- - role_info.iam_roles | length == 1
- - 'role_info.iam_roles[0].arn.startswith("arn")'
- - 'role_info.iam_roles[0].arn.endswith("role/" + test_role )'
- - '"assume_role_policy_document" in role_info.iam_roles[0]'
- - '"create_date" in role_info.iam_roles[0]'
- - 'role_info.iam_roles[0].description == "Ansible Test Role (updated) {{ resource_prefix }}"'
- - role_info.iam_roles[0].inline_policies | length == 0
- - role_info.iam_roles[0].instance_profiles | length == 1
- - role_info.iam_roles[0].instance_profiles[0].instance_profile_name == test_role
- - 'role_info.iam_roles[0].instance_profiles[0].arn.startswith("arn")'
- - 'role_info.iam_roles[0].instance_profiles[0].arn.endswith("instance-profile/" + test_role)'
- - role_info.iam_roles[0].managed_policies | length == 2
- - safe_managed_policy in ( role_info | community.general.json_query("iam_roles[*].managed_policies[*].policy_name") | list | flatten )
- - custom_policy_name in ( role_info | community.general.json_query("iam_roles[*].managed_policies[*].policy_name") | list | flatten )
- - role_info.iam_roles[0].max_session_duration == 43200
- - role_info.iam_roles[0].path == '/'
- - '"permissions_boundary" not in role_info.iam_roles[0]'
- - role_info.iam_roles[0].role_id == iam_role.iam_role.role_id
- - role_info.iam_roles[0].role_name == test_role
- - role_info.iam_roles[0].tags | length == 1
- - '"TagB" in role_info.iam_roles[0].tags'
- - role_info.iam_roles[0].tags.TagB == "ValueB"
-
- # Managed Policies are purged by default
- - name: 'Update Managed Policy with purge (CHECK MODE)'
- iam_role:
- name: '{{ test_role }}'
- managed_policy:
- - '{{ custom_policy_name }}'
- check_mode: yes
- register: iam_role
- - assert:
- that:
- - iam_role is changed
-
- - name: 'Update Managed Policy with purge'
- iam_role:
- name: '{{ test_role }}'
- managed_policy:
- - '{{ custom_policy_name }}'
- register: iam_role
- - assert:
- that:
- - iam_role is changed
- - iam_role.iam_role.role_name == test_role
+ # ===================================================================
+ # Rapid Role Creation and deletion
+ - include_tasks: creation_deletion.yml
- - name: 'Update Managed Policy with purge (no change)'
- iam_role:
- name: '{{ test_role }}'
- managed_policy:
- - '{{ custom_policy_name }}'
- register: iam_role
- - assert:
- that:
- - iam_role is not changed
- - iam_role.iam_role.role_name == test_role
-
- - name: 'iam_role_info after updating Managed Policy with purge'
- iam_role_info:
- name: '{{ test_role }}'
- register: role_info
- - assert:
- that:
- - role_info is succeeded
- - role_info.iam_roles | length == 1
- - 'role_info.iam_roles[0].arn.startswith("arn")'
- - 'role_info.iam_roles[0].arn.endswith("role/" + test_role )'
- - '"assume_role_policy_document" in role_info.iam_roles[0]'
- - '"create_date" in role_info.iam_roles[0]'
- - 'role_info.iam_roles[0].description == "Ansible Test Role (updated) {{ resource_prefix }}"'
- - role_info.iam_roles[0].inline_policies | length == 0
- - role_info.iam_roles[0].instance_profiles | length == 1
- - role_info.iam_roles[0].instance_profiles[0].instance_profile_name == test_role
- - 'role_info.iam_roles[0].instance_profiles[0].arn.startswith("arn")'
- - 'role_info.iam_roles[0].instance_profiles[0].arn.endswith("instance-profile/" + test_role)'
- - role_info.iam_roles[0].managed_policies | length == 1
- - safe_managed_policy not in ( role_info | community.general.json_query("iam_roles[*].managed_policies[*].policy_name") | list | flatten )
- - custom_policy_name in ( role_info | community.general.json_query("iam_roles[*].managed_policies[*].policy_name") | list | flatten )
- - role_info.iam_roles[0].max_session_duration == 43200
- - role_info.iam_roles[0].path == '/'
- - '"permissions_boundary" not in role_info.iam_roles[0]'
- - role_info.iam_roles[0].role_id == iam_role.iam_role.role_id
- - role_info.iam_roles[0].role_name == test_role
- - role_info.iam_roles[0].tags | length == 1
- - '"TagB" in role_info.iam_roles[0].tags'
- - role_info.iam_roles[0].tags.TagB == "ValueB"
-
- # ===================================================================
- # Inline Policy (test _info behaviour)
-
- # XXX Not sure if it's a bug in Ansible or a "quirk" of AWS, but these two
- # policies need to have at least different Sids or the second doesn't show
- # up...
-
- - name: 'Attach inline policy a'
- iam_policy:
- state: present
- iam_type: 'role'
- iam_name: '{{ test_role }}'
- policy_name: 'inline-policy-a'
- policy_json: '{{ lookup("file", "deny-all-a.json") }}'
-
- - name: 'Attach inline policy b'
- iam_policy:
- state: present
- iam_type: 'role'
- iam_name: '{{ test_role }}'
- policy_name: 'inline-policy-b'
- policy_json: '{{ lookup("file", "deny-all-b.json") }}'
-
- - name: 'iam_role_info after attaching inline policies (using iam_policy)'
- iam_role_info:
- name: '{{ test_role }}'
- register: role_info
- - assert:
- that:
- - role_info is succeeded
- - role_info.iam_roles | length == 1
- - 'role_info.iam_roles[0].arn.startswith("arn")'
- - 'role_info.iam_roles[0].arn.endswith("role/" + test_role )'
- - '"assume_role_policy_document" in role_info.iam_roles[0]'
- - '"create_date" in role_info.iam_roles[0]'
- - 'role_info.iam_roles[0].description == "Ansible Test Role (updated) {{ resource_prefix }}"'
- - role_info.iam_roles[0].inline_policies | length == 2
- - '"inline-policy-a" in role_info.iam_roles[0].inline_policies'
- - '"inline-policy-b" in role_info.iam_roles[0].inline_policies'
- - role_info.iam_roles[0].instance_profiles | length == 1
- - role_info.iam_roles[0].instance_profiles[0].instance_profile_name == test_role
- - 'role_info.iam_roles[0].instance_profiles[0].arn.startswith("arn")'
- - 'role_info.iam_roles[0].instance_profiles[0].arn.endswith("instance-profile/" + test_role)'
- - role_info.iam_roles[0].managed_policies | length == 1
- - safe_managed_policy not in ( role_info | community.general.json_query("iam_roles[*].managed_policies[*].policy_name") | list | flatten )
- - custom_policy_name in ( role_info | community.general.json_query("iam_roles[*].managed_policies[*].policy_name") | list | flatten )
- - role_info.iam_roles[0].max_session_duration == 43200
- - role_info.iam_roles[0].path == '/'
- - '"permissions_boundary" not in role_info.iam_roles[0]'
- - role_info.iam_roles[0].role_id == iam_role.iam_role.role_id
- - role_info.iam_roles[0].role_name == test_role
- - role_info.iam_roles[0].tags | length == 1
- - '"TagB" in role_info.iam_roles[0].tags'
- - role_info.iam_roles[0].tags.TagB == "ValueB"
-
- # XXX iam_role fails to remove inline policies before deleting the role
- - name: 'Detach inline policy a'
- iam_policy:
- state: absent
- iam_type: 'role'
- iam_name: '{{ test_role }}'
- policy_name: 'inline-policy-a'
-
- - name: 'Detach inline policy b'
- iam_policy:
- state: absent
- iam_type: 'role'
- iam_name: '{{ test_role }}'
- policy_name: 'inline-policy-b'
-
- # ===================================================================
- # Role Removal
- - name: 'Remove IAM Role (CHECK MODE)'
- iam_role:
- state: absent
- name: '{{ test_role }}'
- delete_instance_profile: yes
- check_mode: yes
- register: iam_role
- - assert:
- that:
- - iam_role is changed
- - name: 'Short pause for role removal to finish'
- pause:
- seconds: 10
- when: paranoid_pauses | bool
+ # ===================================================================
+ # Max Session Duration Manipulation
+ - include_tasks: max_session_update.yml
- - name: 'iam_role_info after deleting role in check mode'
- iam_role_info:
- name: '{{ test_role }}'
- register: role_info
- - assert:
- that:
- - role_info is succeeded
- - role_info.iam_roles | length == 1
+ # ===================================================================
+ # Description Manipulation
+ - include_tasks: description_update.yml
- - name: 'Remove IAM Role'
- iam_role:
- state: absent
- name: '{{ test_role }}'
- delete_instance_profile: yes
- register: iam_role
- - assert:
- that:
- - iam_role is changed
- - name: 'Short pause for role removal to finish'
- pause:
- seconds: 10
- when: paranoid_pauses | bool
+ # ===================================================================
+ # Tag Manipulation
+ - include_tasks: tags_update.yml
- - name: 'iam_role_info after deleting role'
- iam_role_info:
- name: '{{ test_role }}'
- register: role_info
- - assert:
- that:
- - role_info is succeeded
- - role_info.iam_roles | length == 0
+ # ===================================================================
+ # Policy Manipulation
+ - include_tasks: policy_update.yml
- - name: 'Remove IAM Role (should be gone already)'
- iam_role:
- state: absent
- name: '{{ test_role }}'
- delete_instance_profile: yes
- register: iam_role
- - assert:
- that:
- - iam_role is not changed
- - name: 'Short pause for role removal to finish'
- pause:
- seconds: 10
- when: paranoid_pauses | bool
+ # ===================================================================
+ # Inline Policy (test _info behavior)
+ - include_tasks: inline_policy_update.yml
- # ===================================================================
- # Boundary Policy (requires create_instance_profile: no)
- - name: 'Create minimal role with no boundary policy'
- iam_role:
- name: '{{ test_role }}'
- create_instance_profile: no
- register: iam_role
- - assert:
- that:
- - iam_role is changed
- - iam_role.iam_role.role_name == test_role
+ # ===================================================================
+ # Role Removal
+ - include_tasks: role_removal.yml
- - name: 'Configure Boundary Policy (CHECK MODE)'
- iam_role:
- name: '{{ test_role }}'
- create_instance_profile: no
- boundary: '{{ boundary_policy }}'
- check_mode: yes
- register: iam_role
- - assert:
- that:
- - iam_role is changed
+ # ===================================================================
+ # Boundary Policy (requires create_instance_profile: no)
+ - include_tasks: boundary_policy.yml
- - name: 'Configure Boundary Policy'
- iam_role:
- name: '{{ test_role }}'
- create_instance_profile: no
- boundary: '{{ boundary_policy }}'
- register: iam_role
- - assert:
- that:
- - iam_role is changed
- - iam_role.iam_role.role_name == test_role
-
- - name: 'Configure Boundary Policy (no change)'
- iam_role:
- name: '{{ test_role }}'
- create_instance_profile: no
- boundary: '{{ boundary_policy }}'
- register: iam_role
- - assert:
- that:
- - iam_role is not changed
- - iam_role.iam_role.role_name == test_role
-
- - name: 'iam_role_info after adding boundary policy'
- iam_role_info:
- name: '{{ test_role }}'
- register: role_info
- - assert:
- that:
- - role_info is succeeded
- - role_info.iam_roles | length == 1
- - 'role_info.iam_roles[0].arn.startswith("arn")'
- - 'role_info.iam_roles[0].arn.endswith("role/" + test_role )'
- - '"assume_role_policy_document" in role_info.iam_roles[0]'
- - '"create_date" in role_info.iam_roles[0]'
- - '"description" not in role_info.iam_roles[0]'
- - role_info.iam_roles[0].inline_policies | length == 0
- - role_info.iam_roles[0].instance_profiles | length == 0
- - role_info.iam_roles[0].managed_policies | length == 0
- - role_info.iam_roles[0].max_session_duration == 3600
- - role_info.iam_roles[0].path == '/'
- - role_info.iam_roles[0].permissions_boundary.permissions_boundary_arn == boundary_policy
- - role_info.iam_roles[0].permissions_boundary.permissions_boundary_type == 'Policy'
- - role_info.iam_roles[0].role_id == iam_role.iam_role.role_id
- - role_info.iam_roles[0].role_name == test_role
-
- - name: 'Remove IAM Role'
- iam_role:
- state: absent
- name: '{{ test_role }}'
- delete_instance_profile: yes
- register: iam_role
- - assert:
- that:
- - iam_role is changed
- - name: Short pause for role removal to finish
- pause:
- seconds: 10
- when: paranoid_pauses | bool
-
- # ===================================================================
- # Complex role Creation
- - name: 'Complex IAM Role (CHECK MODE)'
- iam_role:
- name: '{{ test_role }}'
- assume_role_policy_document: '{{ lookup("file", "deny-assume.json") }}'
- boundary: '{{ boundary_policy }}'
- create_instance_profile: no
- description: 'Ansible Test Role {{ resource_prefix }}'
- managed_policy:
- - '{{ safe_managed_policy }}'
- - '{{ custom_policy_name }}'
- max_session_duration: 43200
- path: '{{ test_path }}'
- tags:
- TagA: 'ValueA'
- check_mode: yes
- register: iam_role
- - assert:
- that:
- - iam_role is changed
- - name: Short pause for role creation to finish
- pause:
- seconds: 10
- when: standard_pauses | bool
-
- - name: 'iam_role_info after Complex Role creation in check_mode'
- iam_role_info:
- name: '{{ test_role }}'
- register: role_info
- - assert:
- that:
- - role_info is succeeded
- - role_info.iam_roles | length == 0
-
- - name: 'Complex IAM Role'
- iam_role:
- name: '{{ test_role }}'
- assume_role_policy_document: '{{ lookup("file", "deny-assume.json") }}'
- boundary: '{{ boundary_policy }}'
- create_instance_profile: no
- description: 'Ansible Test Role {{ resource_prefix }}'
- managed_policy:
- - '{{ safe_managed_policy }}'
- - '{{ custom_policy_name }}'
- max_session_duration: 43200
- path: '{{ test_path }}'
- tags:
- TagA: 'ValueA'
- register: iam_role
- - assert:
- that:
- - iam_role is changed
- - iam_role.iam_role.role_name == test_role
- - 'iam_role.iam_role.arn.startswith("arn")'
- - 'iam_role.iam_role.arn.endswith("role" + test_path + test_role )'
- # Would be nice to test the contents...
- - '"assume_role_policy_document" in iam_role.iam_role'
- - iam_role.iam_role.attached_policies | length == 2
- - iam_role.iam_role.max_session_duration == 43200
- - iam_role.iam_role.path == test_path
- - iam_role.iam_role.role_name == test_role
- - '"create_date" in iam_role.iam_role'
- - '"role_id" in iam_role.iam_role'
- - name: Short pause for role creation to finish
- pause:
- seconds: 10
- when: standard_pauses | bool
-
- - name: 'Complex IAM role (no change)'
- iam_role:
- name: '{{ test_role }}'
- assume_role_policy_document: '{{ lookup("file", "deny-assume.json") }}'
- boundary: '{{ boundary_policy }}'
- create_instance_profile: no
- description: 'Ansible Test Role {{ resource_prefix }}'
- managed_policy:
- - '{{ safe_managed_policy }}'
- - '{{ custom_policy_name }}'
- max_session_duration: 43200
- path: '{{ test_path }}'
- tags:
- TagA: 'ValueA'
- register: iam_role
- - assert:
- that:
- - iam_role is not changed
- - iam_role.iam_role.role_name == test_role
-
- - name: 'iam_role_info after Role creation'
- iam_role_info:
- name: '{{ test_role }}'
- register: role_info
- - assert:
- that:
- - role_info is succeeded
- - role_info.iam_roles | length == 1
- - 'role_info.iam_roles[0].arn.startswith("arn")'
- - 'role_info.iam_roles[0].arn.endswith("role" + test_path + test_role )'
- - '"assume_role_policy_document" in role_info.iam_roles[0]'
- - '"create_date" in role_info.iam_roles[0]'
- - 'role_info.iam_roles[0].description == "Ansible Test Role {{ resource_prefix }}"'
- - role_info.iam_roles[0].inline_policies | length == 0
- - role_info.iam_roles[0].instance_profiles | length == 0
- - role_info.iam_roles[0].managed_policies | length == 2
- - safe_managed_policy in ( role_info | community.general.json_query("iam_roles[*].managed_policies[*].policy_name") | list | flatten )
- - custom_policy_name in ( role_info | community.general.json_query("iam_roles[*].managed_policies[*].policy_name") | list | flatten )
- - role_info.iam_roles[0].max_session_duration == 43200
- - role_info.iam_roles[0].path == test_path
- - role_info.iam_roles[0].permissions_boundary.permissions_boundary_arn == boundary_policy
- - role_info.iam_roles[0].permissions_boundary.permissions_boundary_type == 'Policy'
- - role_info.iam_roles[0].role_id == iam_role.iam_role.role_id
- - role_info.iam_roles[0].role_name == test_role
- - '"TagA" in role_info.iam_roles[0].tags'
- - role_info.iam_roles[0].tags.TagA == "ValueA"
+ # ===================================================================
+ # Complex role Creation
+ - include_tasks: complex_role_creation.yml
always:
- # ===================================================================
- # Cleanup
-
- # XXX iam_role fails to remove inline policies before deleting the role
- - name: 'Detach inline policy a'
- iam_policy:
- state: absent
- iam_type: 'role'
- iam_name: '{{ test_role }}'
- policy_name: 'inline-policy-a'
- ignore_errors: true
+ # ===================================================================
+ # Cleanup
- - name: 'Detach inline policy b'
- iam_policy:
- state: absent
- iam_type: 'role'
- iam_name: '{{ test_role }}'
- policy_name: 'inline-policy-b'
- ignore_errors: true
-
- - name: 'Remove IAM Role'
- iam_role:
- state: absent
- name: '{{ test_role }}'
- delete_instance_profile: yes
- ignore_errors: true
+ # XXX iam_role fails to remove inline policies before deleting the role
+ - name: "Detach inline policy a"
+ iam_policy:
+ state: absent
+ iam_type: "role"
+ iam_name: "{{ test_role }}"
+ policy_name: "inline-policy-a"
+ ignore_errors: true
- - name: 'Remove IAM Role (with path)'
- iam_role:
- state: absent
- name: '{{ test_role }}'
- path: '{{ test_path }}'
- delete_instance_profile: yes
- ignore_errors: true
+ - name: "Detach inline policy b"
+ iam_policy:
+ state: absent
+ iam_type: "role"
+ iam_name: "{{ test_role }}"
+ policy_name: "inline-policy-b"
+ ignore_errors: true
- - name: 'iam_role_info after Role deletion'
- iam_role_info:
- name: '{{ test_role }}'
- ignore_errors: true
+ - name: "Remove IAM Role"
+ iam_role:
+ state: absent
+ name: "{{ test_role }}"
+ delete_instance_profile: yes
+ ignore_errors: true
- - name: 'Remove test managed policy'
- iam_managed_policy:
- state: absent
- policy_name: '{{ custom_policy_name }}'
+ - name: "Remove IAM Role (with path)"
+ iam_role:
+ state: absent
+ name: "{{ test_role }}"
+ path: "{{ test_path }}"
+ delete_instance_profile: yes
+ ignore_errors: true
+
+ - name: "iam_role_info after Role deletion"
+ iam_role_info:
+ name: "{{ test_role }}"
+ ignore_errors: true
+
+ - name: "Remove test managed policy"
+ iam_managed_policy:
+ state: absent
+ policy_name: "{{ custom_policy_name }}"
diff --git a/tests/integration/targets/iam_role/tasks/max_session_update.yml b/tests/integration/targets/iam_role/tasks/max_session_update.yml
new file mode 100644
index 00000000000..cbe64df684e
--- /dev/null
+++ b/tests/integration/targets/iam_role/tasks/max_session_update.yml
@@ -0,0 +1,61 @@
+---
+- name: "Update Max Session Duration (CHECK MODE)"
+ iam_role:
+ name: "{{ test_role }}"
+ max_session_duration: 43200
+ check_mode: yes
+ register: iam_role
+
+- assert:
+ that:
+ - iam_role is changed
+
+- name: "Update Max Session Duration"
+ iam_role:
+ name: "{{ test_role }}"
+ max_session_duration: 43200
+ register: iam_role
+
+- assert:
+ that:
+ - iam_role is changed
+ - iam_role.iam_role.role_name == test_role
+ - iam_role.iam_role.max_session_duration == 43200
+
+- name: "Update Max Session Duration (no change)"
+ iam_role:
+ name: "{{ test_role }}"
+ max_session_duration: 43200
+ register: iam_role
+
+- assert:
+ that:
+ - iam_role is not changed
+ - iam_role.iam_role.role_name == test_role
+
+- name: "iam_role_info after updating Max Session Duration"
+ iam_role_info:
+ name: "{{ test_role }}"
+ register: role_info
+
+- assert:
+ that:
+ - role_info is succeeded
+ - role_info.iam_roles | length == 1
+ - 'role_info.iam_roles[0].arn.startswith("arn")'
+ - 'role_info.iam_roles[0].arn.endswith("role/" + test_role )'
+ - '"assume_role_policy_document" in role_info.iam_roles[0]'
+ - '"create_date" in role_info.iam_roles[0]'
+ - '"description" not in role_info.iam_roles[0]'
+ - role_info.iam_roles[0].inline_policies | length == 0
+ - role_info.iam_roles[0].instance_profiles | length == 1
+ - role_info.iam_roles[0].instance_profiles[0].instance_profile_name == test_role
+ - 'role_info.iam_roles[0].instance_profiles[0].arn.startswith("arn")'
+ - 'role_info.iam_roles[0].instance_profiles[0].arn.endswith("instance-profile/" + test_role)'
+ - role_info.iam_roles[0].managed_policies | length == 0
+ - role_info.iam_roles[0].max_session_duration == 43200
+ - role_info.iam_roles[0].path == '/'
+ - '"permissions_boundary" not in role_info.iam_roles[0]'
+ - role_info.iam_roles[0].role_id == iam_role.iam_role.role_id
+ - role_info.iam_roles[0].role_name == test_role
+ - role_info.iam_roles[0].tags | length == 0
diff --git a/tests/integration/targets/iam_role/tasks/parameter_checks.yml b/tests/integration/targets/iam_role/tasks/parameter_checks.yml
new file mode 100644
index 00000000000..57df5436afc
--- /dev/null
+++ b/tests/integration/targets/iam_role/tasks/parameter_checks.yml
@@ -0,0 +1,90 @@
+---
+# Parameter Checks
+- name: "Friendly message when creating an instance profile and adding a boundary profile"
+ iam_role:
+ name: "{{ test_role }}"
+ boundary: "{{ boundary_policy }}"
+ register: iam_role
+ ignore_errors: yes
+
+- assert:
+ that:
+ - iam_role is failed
+ - '"boundary policy" in iam_role.msg'
+ - '"create_instance_profile" in iam_role.msg'
+ - '"false" in iam_role.msg'
+
+- name: "Friendly message when boundary profile is not an ARN"
+ iam_role:
+ name: "{{ test_role }}"
+ boundary: "AWSDenyAll"
+ create_instance_profile: no
+ register: iam_role
+ ignore_errors: yes
+
+- assert:
+ that:
+ - iam_role is failed
+ - '"Boundary policy" in iam_role.msg'
+ - '"ARN" in iam_role.msg'
+
+- name: 'Friendly message when "present" without assume_role_policy_document'
+ module_defaults: { iam_role: {} }
+ iam_role:
+ name: "{{ test_role }}"
+ register: iam_role
+ ignore_errors: yes
+
+- assert:
+ that:
+ - iam_role is failed
+ - 'iam_role.msg.startswith("state is present but all of the following are missing")'
+ - '"assume_role_policy_document" in iam_role.msg'
+
+- name: "Maximum Session Duration needs to be between 1 and 12 hours"
+ iam_role:
+ name: "{{ test_role }}"
+ max_session_duration: 3599
+ register: iam_role
+ ignore_errors: yes
+
+- assert:
+ that:
+ - iam_role is failed
+ - '"max_session_duration must be between" in iam_role.msg'
+
+- name: "Maximum Session Duration needs to be between 1 and 12 hours"
+ iam_role:
+ name: "{{ test_role }}"
+ max_session_duration: 43201
+ register: iam_role
+ ignore_errors: yes
+
+- assert:
+ that:
+ - iam_role is failed
+ - '"max_session_duration must be between" in iam_role.msg'
+
+- name: "Role Paths must start with /"
+ iam_role:
+ name: "{{ test_role }}"
+ path: "test/"
+ register: iam_role
+ ignore_errors: yes
+
+- assert:
+ that:
+ - iam_role is failed
+ - '"path must begin and end with /" in iam_role.msg'
+
+- name: "Role Paths must end with /"
+ iam_role:
+ name: "{{ test_role }}"
+ path: "/test"
+ register: iam_role
+ ignore_errors: yes
+
+- assert:
+ that:
+ - iam_role is failed
+ - '"path must begin and end with /" in iam_role.msg'
diff --git a/tests/integration/targets/iam_role/tasks/policy_update.yml b/tests/integration/targets/iam_role/tasks/policy_update.yml
new file mode 100644
index 00000000000..a34f2a0ad30
--- /dev/null
+++ b/tests/integration/targets/iam_role/tasks/policy_update.yml
@@ -0,0 +1,208 @@
+---
+- name: "Add Managed Policy (CHECK MODE)"
+ iam_role:
+ name: "{{ test_role }}"
+ purge_policies: no
+ managed_policy:
+ - "{{ safe_managed_policy }}"
+ check_mode: yes
+ register: iam_role
+
+- assert:
+ that:
+ - iam_role is changed
+
+- name: "Add Managed Policy"
+ iam_role:
+ name: "{{ test_role }}"
+ purge_policies: no
+ managed_policy:
+ - "{{ safe_managed_policy }}"
+ register: iam_role
+
+- assert:
+ that:
+ - iam_role is changed
+ - iam_role.iam_role.role_name == test_role
+
+- name: "Add Managed Policy (no change)"
+ iam_role:
+ name: "{{ test_role }}"
+ purge_policies: no
+ managed_policy:
+ - "{{ safe_managed_policy }}"
+ register: iam_role
+
+- assert:
+ that:
+ - iam_role is not changed
+ - iam_role.iam_role.role_name == test_role
+
+- name: "iam_role_info after adding Managed Policy"
+ iam_role_info:
+ name: "{{ test_role }}"
+ register: role_info
+
+- assert:
+ that:
+ - role_info is succeeded
+ - role_info.iam_roles | length == 1
+ - 'role_info.iam_roles[0].arn.startswith("arn")'
+ - 'role_info.iam_roles[0].arn.endswith("role/" + test_role )'
+ - '"assume_role_policy_document" in role_info.iam_roles[0]'
+ - '"create_date" in role_info.iam_roles[0]'
+ - 'role_info.iam_roles[0].description == "Ansible Test Role (updated) {{ resource_prefix }}"'
+ - role_info.iam_roles[0].inline_policies | length == 0
+ - role_info.iam_roles[0].instance_profiles | length == 1
+ - role_info.iam_roles[0].instance_profiles[0].instance_profile_name == test_role
+ - 'role_info.iam_roles[0].instance_profiles[0].arn.startswith("arn")'
+ - 'role_info.iam_roles[0].instance_profiles[0].arn.endswith("instance-profile/" + test_role)'
+ - role_info.iam_roles[0].managed_policies | length == 1
+ - safe_managed_policy in ( role_info | community.general.json_query("iam_roles[*].managed_policies[*].policy_name") | list | flatten )
+ - custom_policy_name not in ( role_info | community.general.json_query("iam_roles[*].managed_policies[*].policy_name") | list | flatten )
+ - role_info.iam_roles[0].max_session_duration == 43200
+ - role_info.iam_roles[0].path == '/'
+ - '"permissions_boundary" not in role_info.iam_roles[0]'
+ - role_info.iam_roles[0].role_id == iam_role.iam_role.role_id
+ - role_info.iam_roles[0].role_name == test_role
+ - role_info.iam_roles[0].tags | length == 1
+ - '"TagB" in role_info.iam_roles[0].tags'
+ - role_info.iam_roles[0].tags.TagB == "ValueB"
+
+- name: "Update Managed Policy without purge (CHECK MODE)"
+ iam_role:
+ name: "{{ test_role }}"
+ purge_policies: no
+ managed_policy:
+ - "{{ custom_policy_name }}"
+ check_mode: yes
+ register: iam_role
+
+- assert:
+ that:
+ - iam_role is changed
+
+- name: "Update Managed Policy without purge"
+ iam_role:
+ name: "{{ test_role }}"
+ purge_policies: no
+ managed_policy:
+ - "{{ custom_policy_name }}"
+ register: iam_role
+
+- assert:
+ that:
+ - iam_role is changed
+ - iam_role.iam_role.role_name == test_role
+
+- name: "Update Managed Policy without purge (no change)"
+ iam_role:
+ name: "{{ test_role }}"
+ purge_policies: no
+ managed_policy:
+ - "{{ custom_policy_name }}"
+ register: iam_role
+
+- assert:
+ that:
+ - iam_role is not changed
+ - iam_role.iam_role.role_name == test_role
+
+- name: "iam_role_info after updating Managed Policy without purge"
+ iam_role_info:
+ name: "{{ test_role }}"
+ register: role_info
+
+- assert:
+ that:
+ - role_info is succeeded
+ - role_info.iam_roles | length == 1
+ - 'role_info.iam_roles[0].arn.startswith("arn")'
+ - 'role_info.iam_roles[0].arn.endswith("role/" + test_role )'
+ - '"assume_role_policy_document" in role_info.iam_roles[0]'
+ - '"create_date" in role_info.iam_roles[0]'
+ - 'role_info.iam_roles[0].description == "Ansible Test Role (updated) {{ resource_prefix }}"'
+ - role_info.iam_roles[0].inline_policies | length == 0
+ - role_info.iam_roles[0].instance_profiles | length == 1
+ - role_info.iam_roles[0].instance_profiles[0].instance_profile_name == test_role
+ - 'role_info.iam_roles[0].instance_profiles[0].arn.startswith("arn")'
+ - 'role_info.iam_roles[0].instance_profiles[0].arn.endswith("instance-profile/" + test_role)'
+ - role_info.iam_roles[0].managed_policies | length == 2
+ - safe_managed_policy in ( role_info | community.general.json_query("iam_roles[*].managed_policies[*].policy_name") | list | flatten )
+ - custom_policy_name in ( role_info | community.general.json_query("iam_roles[*].managed_policies[*].policy_name") | list | flatten )
+ - role_info.iam_roles[0].max_session_duration == 43200
+ - role_info.iam_roles[0].path == '/'
+ - '"permissions_boundary" not in role_info.iam_roles[0]'
+ - role_info.iam_roles[0].role_id == iam_role.iam_role.role_id
+ - role_info.iam_roles[0].role_name == test_role
+ - role_info.iam_roles[0].tags | length == 1
+ - '"TagB" in role_info.iam_roles[0].tags'
+ - role_info.iam_roles[0].tags.TagB == "ValueB"
+
+# Managed Policies are purged by default
+- name: "Update Managed Policy with purge (CHECK MODE)"
+ iam_role:
+ name: "{{ test_role }}"
+ managed_policy:
+ - "{{ custom_policy_name }}"
+ check_mode: yes
+ register: iam_role
+
+- assert:
+ that:
+ - iam_role is changed
+
+- name: "Update Managed Policy with purge"
+ iam_role:
+ name: "{{ test_role }}"
+ managed_policy:
+ - "{{ custom_policy_name }}"
+ register: iam_role
+
+- assert:
+ that:
+ - iam_role is changed
+ - iam_role.iam_role.role_name == test_role
+
+- name: "Update Managed Policy with purge (no change)"
+ iam_role:
+ name: "{{ test_role }}"
+ managed_policy:
+ - "{{ custom_policy_name }}"
+ register: iam_role
+
+- assert:
+ that:
+ - iam_role is not changed
+ - iam_role.iam_role.role_name == test_role
+
+- name: "iam_role_info after updating Managed Policy with purge"
+ iam_role_info:
+ name: "{{ test_role }}"
+ register: role_info
+
+- assert:
+ that:
+ - role_info is succeeded
+ - role_info.iam_roles | length == 1
+ - 'role_info.iam_roles[0].arn.startswith("arn")'
+ - 'role_info.iam_roles[0].arn.endswith("role/" + test_role )'
+ - '"assume_role_policy_document" in role_info.iam_roles[0]'
+ - '"create_date" in role_info.iam_roles[0]'
+ - 'role_info.iam_roles[0].description == "Ansible Test Role (updated) {{ resource_prefix }}"'
+ - role_info.iam_roles[0].inline_policies | length == 0
+ - role_info.iam_roles[0].instance_profiles | length == 1
+ - role_info.iam_roles[0].instance_profiles[0].instance_profile_name == test_role
+ - 'role_info.iam_roles[0].instance_profiles[0].arn.startswith("arn")'
+ - 'role_info.iam_roles[0].instance_profiles[0].arn.endswith("instance-profile/" + test_role)'
+ - role_info.iam_roles[0].managed_policies | length == 1
+ - safe_managed_policy not in ( role_info | community.general.json_query("iam_roles[*].managed_policies[*].policy_name") | list | flatten )
+ - custom_policy_name in ( role_info | community.general.json_query("iam_roles[*].managed_policies[*].policy_name") | list | flatten )
+ - role_info.iam_roles[0].max_session_duration == 43200
+ - role_info.iam_roles[0].path == '/'
+ - '"permissions_boundary" not in role_info.iam_roles[0]'
+ - role_info.iam_roles[0].role_id == iam_role.iam_role.role_id
+ - role_info.iam_roles[0].role_name == test_role
+ - role_info.iam_roles[0].tags | length == 1
+ - '"TagB" in role_info.iam_roles[0].tags'
+ - role_info.iam_roles[0].tags.TagB == "ValueB"
diff --git a/tests/integration/targets/iam_role/tasks/role_removal.yml b/tests/integration/targets/iam_role/tasks/role_removal.yml
new file mode 100644
index 00000000000..1b8d10710a9
--- /dev/null
+++ b/tests/integration/targets/iam_role/tasks/role_removal.yml
@@ -0,0 +1,53 @@
+---
+- name: "Remove IAM Role (CHECK MODE)"
+ iam_role:
+ state: absent
+ name: "{{ test_role }}"
+ delete_instance_profile: yes
+ check_mode: yes
+ register: iam_role
+
+- assert:
+ that:
+ - iam_role is changed
+
+- name: "iam_role_info after deleting role in check mode"
+ iam_role_info:
+ name: "{{ test_role }}"
+ register: role_info
+
+- assert:
+ that:
+ - role_info is succeeded
+ - role_info.iam_roles | length == 1
+
+- name: "Remove IAM Role"
+ iam_role:
+ state: absent
+ name: "{{ test_role }}"
+ delete_instance_profile: yes
+ register: iam_role
+
+- assert:
+ that:
+ - iam_role is changed
+
+- name: "iam_role_info after deleting role"
+ iam_role_info:
+ name: "{{ test_role }}"
+ register: role_info
+- assert:
+ that:
+ - role_info is succeeded
+ - role_info.iam_roles | length == 0
+
+- name: "Remove IAM Role (should be gone already)"
+ iam_role:
+ state: absent
+ name: "{{ test_role }}"
+ delete_instance_profile: yes
+ register: iam_role
+
+- assert:
+ that:
+ - iam_role is not changed
diff --git a/tests/integration/targets/iam_role/tasks/tags_update.yml b/tests/integration/targets/iam_role/tasks/tags_update.yml
new file mode 100644
index 00000000000..617fb9a1331
--- /dev/null
+++ b/tests/integration/targets/iam_role/tasks/tags_update.yml
@@ -0,0 +1,286 @@
+---
+- name: "Add Tag (CHECK MODE)"
+ iam_role:
+ name: "{{ test_role }}"
+ tags:
+ TagA: ValueA
+ check_mode: yes
+ register: iam_role
+
+- assert:
+ that:
+ - iam_role is changed
+
+- name: "Add Tag"
+ iam_role:
+ name: "{{ test_role }}"
+ tags:
+ TagA: ValueA
+ register: iam_role
+
+- assert:
+ that:
+ - iam_role is changed
+ - iam_role.iam_role.role_name == test_role
+ - iam_role.iam_role.tags | length == 1
+ - '"TagA" in iam_role.iam_role.tags'
+ - iam_role.iam_role.tags.TagA == "ValueA"
+
+- name: "Add Tag (no change)"
+ iam_role:
+ name: "{{ test_role }}"
+ tags:
+ TagA: ValueA
+ register: iam_role
+
+- assert:
+ that:
+ - iam_role is not changed
+ - iam_role.iam_role.role_name == test_role
+ - '"TagA" in iam_role.iam_role.tags'
+ - iam_role.iam_role.tags.TagA == "ValueA"
+
+- name: "iam_role_info after adding Tags"
+ iam_role_info:
+ name: "{{ test_role }}"
+ register: role_info
+
+- assert:
+ that:
+ - role_info is succeeded
+ - role_info.iam_roles | length == 1
+ - 'role_info.iam_roles[0].arn.startswith("arn")'
+ - 'role_info.iam_roles[0].arn.endswith("role/" + test_role )'
+ - '"assume_role_policy_document" in role_info.iam_roles[0]'
+ - '"create_date" in role_info.iam_roles[0]'
+ - 'role_info.iam_roles[0].description == "Ansible Test Role (updated) {{ resource_prefix }}"'
+ - role_info.iam_roles[0].inline_policies | length == 0
+ - role_info.iam_roles[0].instance_profiles | length == 1
+ - role_info.iam_roles[0].instance_profiles[0].instance_profile_name == test_role
+ - 'role_info.iam_roles[0].instance_profiles[0].arn.startswith("arn")'
+ - 'role_info.iam_roles[0].instance_profiles[0].arn.endswith("instance-profile/" + test_role)'
+ - role_info.iam_roles[0].managed_policies | length == 0
+ - role_info.iam_roles[0].max_session_duration == 43200
+ - role_info.iam_roles[0].path == '/'
+ - '"permissions_boundary" not in role_info.iam_roles[0]'
+ - role_info.iam_roles[0].role_id == iam_role.iam_role.role_id
+ - role_info.iam_roles[0].role_name == test_role
+ - role_info.iam_roles[0].tags | length == 1
+ - '"TagA" in role_info.iam_roles[0].tags'
+ - role_info.iam_roles[0].tags.TagA == "ValueA"
+
+- name: "Update Tag (CHECK MODE)"
+ iam_role:
+ name: "{{ test_role }}"
+ tags:
+ TagA: AValue
+ check_mode: yes
+ register: iam_role
+
+- assert:
+ that:
+ - iam_role is changed
+
+- name: "Update Tag"
+ iam_role:
+ name: "{{ test_role }}"
+ tags:
+ TagA: AValue
+ register: iam_role
+
+- assert:
+ that:
+ - iam_role is changed
+ - iam_role.iam_role.role_name == test_role
+ - '"TagA" in iam_role.iam_role.tags'
+ - iam_role.iam_role.tags.TagA == "AValue"
+
+- name: "Update Tag (no change)"
+ iam_role:
+ name: "{{ test_role }}"
+ tags:
+ TagA: AValue
+ register: iam_role
+
+- assert:
+ that:
+ - iam_role is not changed
+ - iam_role.iam_role.role_name == test_role
+ - '"TagA" in iam_role.iam_role.tags'
+ - iam_role.iam_role.tags.TagA == "AValue"
+
+- name: "iam_role_info after updating Tag"
+ iam_role_info:
+ name: "{{ test_role }}"
+ register: role_info
+
+- assert:
+ that:
+ - role_info is succeeded
+ - role_info.iam_roles | length == 1
+ - 'role_info.iam_roles[0].arn.startswith("arn")'
+ - 'role_info.iam_roles[0].arn.endswith("role/" + test_role )'
+ - '"assume_role_policy_document" in role_info.iam_roles[0]'
+ - '"create_date" in role_info.iam_roles[0]'
+ - 'role_info.iam_roles[0].description == "Ansible Test Role (updated) {{ resource_prefix }}"'
+ - role_info.iam_roles[0].inline_policies | length == 0
+ - role_info.iam_roles[0].instance_profiles | length == 1
+ - role_info.iam_roles[0].instance_profiles[0].instance_profile_name == test_role
+ - 'role_info.iam_roles[0].instance_profiles[0].arn.startswith("arn")'
+ - 'role_info.iam_roles[0].instance_profiles[0].arn.endswith("instance-profile/" + test_role)'
+ - role_info.iam_roles[0].managed_policies | length == 0
+ - role_info.iam_roles[0].max_session_duration == 43200
+ - role_info.iam_roles[0].path == '/'
+ - '"permissions_boundary" not in role_info.iam_roles[0]'
+ - role_info.iam_roles[0].role_id == iam_role.iam_role.role_id
+ - role_info.iam_roles[0].role_name == test_role
+ - role_info.iam_roles[0].tags | length == 1
+ - '"TagA" in role_info.iam_roles[0].tags'
+ - role_info.iam_roles[0].tags.TagA == "AValue"
+
+- name: "Add second Tag without purge (CHECK MODE)"
+ iam_role:
+ name: "{{ test_role }}"
+ purge_tags: no
+ tags:
+ TagB: ValueB
+ check_mode: yes
+ register: iam_role
+
+- assert:
+ that:
+ - iam_role is changed
+
+- name: "Add second Tag without purge"
+ iam_role:
+ name: "{{ test_role }}"
+ purge_tags: no
+ tags:
+ TagB: ValueB
+ register: iam_role
+
+- assert:
+ that:
+ - iam_role is changed
+ - iam_role.iam_role.role_name == test_role
+ - '"TagB" in iam_role.iam_role.tags'
+ - iam_role.iam_role.tags.TagB == "ValueB"
+
+- name: "Add second Tag without purge (no change)"
+ iam_role:
+ name: "{{ test_role }}"
+ purge_tags: no
+ tags:
+ TagB: ValueB
+ register: iam_role
+
+- assert:
+ that:
+ - iam_role is not changed
+ - iam_role.iam_role.role_name == test_role
+ - '"TagB" in iam_role.iam_role.tags'
+ - iam_role.iam_role.tags.TagB == "ValueB"
+
+- name: "iam_role_info after adding second Tag without purge"
+ iam_role_info:
+ name: "{{ test_role }}"
+ register: role_info
+
+- assert:
+ that:
+ - role_info is succeeded
+ - role_info.iam_roles | length == 1
+ - 'role_info.iam_roles[0].arn.startswith("arn")'
+ - 'role_info.iam_roles[0].arn.endswith("role/" + test_role )'
+ - '"assume_role_policy_document" in role_info.iam_roles[0]'
+ - '"create_date" in role_info.iam_roles[0]'
+ - 'role_info.iam_roles[0].description == "Ansible Test Role (updated) {{ resource_prefix }}"'
+ - role_info.iam_roles[0].inline_policies | length == 0
+ - role_info.iam_roles[0].instance_profiles | length == 1
+ - role_info.iam_roles[0].instance_profiles[0].instance_profile_name == test_role
+ - 'role_info.iam_roles[0].instance_profiles[0].arn.startswith("arn")'
+ - 'role_info.iam_roles[0].instance_profiles[0].arn.endswith("instance-profile/" + test_role)'
+ - role_info.iam_roles[0].managed_policies | length == 0
+ - role_info.iam_roles[0].max_session_duration == 43200
+ - role_info.iam_roles[0].path == '/'
+ - '"permissions_boundary" not in role_info.iam_roles[0]'
+ - role_info.iam_roles[0].role_id == iam_role.iam_role.role_id
+ - role_info.iam_roles[0].role_name == test_role
+ - role_info.iam_roles[0].tags | length == 2
+ - '"TagA" in role_info.iam_roles[0].tags'
+ - role_info.iam_roles[0].tags.TagA == "AValue"
+ - '"TagB" in role_info.iam_roles[0].tags'
+ - role_info.iam_roles[0].tags.TagB == "ValueB"
+
+- name: "Purge first tag (CHECK MODE)"
+ iam_role:
+ name: "{{ test_role }}"
+ purge_tags: yes
+ tags:
+ TagB: ValueB
+ check_mode: yes
+ register: iam_role
+
+- assert:
+ that:
+ - iam_role is changed
+
+- name: "Purge first tag"
+ iam_role:
+ name: "{{ test_role }}"
+ purge_tags: yes
+ tags:
+ TagB: ValueB
+ register: iam_role
+
+- assert:
+ that:
+ - iam_role is changed
+ - iam_role.iam_role.role_name == test_role
+ - '"TagB" in iam_role.iam_role.tags'
+ - iam_role.iam_role.tags.TagB == "ValueB"
+
+- name: "Purge first tag (no change)"
+ iam_role:
+ name: "{{ test_role }}"
+ purge_tags: yes
+ tags:
+ TagB: ValueB
+ register: iam_role
+
+- assert:
+ that:
+ - iam_role is not changed
+ - iam_role.iam_role.role_name == test_role
+ - '"TagB" in iam_role.iam_role.tags'
+ - iam_role.iam_role.tags.TagB == "ValueB"
+
+- name: "iam_role_info after purging first Tag"
+ iam_role_info:
+ name: "{{ test_role }}"
+ register: role_info
+
+- assert:
+ that:
+ - role_info is succeeded
+ - role_info.iam_roles | length == 1
+ - 'role_info.iam_roles[0].arn.startswith("arn")'
+ - 'role_info.iam_roles[0].arn.endswith("role/" + test_role )'
+ - '"assume_role_policy_document" in role_info.iam_roles[0]'
+ - '"create_date" in role_info.iam_roles[0]'
+ - 'role_info.iam_roles[0].description == "Ansible Test Role (updated) {{ resource_prefix }}"'
+ - role_info.iam_roles[0].inline_policies | length == 0
+ - role_info.iam_roles[0].instance_profiles | length == 1
+ - role_info.iam_roles[0].instance_profiles[0].instance_profile_name == test_role
+ - 'role_info.iam_roles[0].instance_profiles[0].arn.startswith("arn")'
+ - 'role_info.iam_roles[0].instance_profiles[0].arn.endswith("instance-profile/" + test_role)'
+ - role_info.iam_roles[0].managed_policies | length == 0
+ - role_info.iam_roles[0].max_session_duration == 43200
+ - role_info.iam_roles[0].path == '/'
+ - '"permissions_boundary" not in role_info.iam_roles[0]'
+ - role_info.iam_roles[0].role_id == iam_role.iam_role.role_id
+ - role_info.iam_roles[0].role_name == test_role
+ - role_info.iam_roles[0].tags | length == 1
+ - '"TagA" not in role_info.iam_roles[0].tags'
+ - '"TagB" in role_info.iam_roles[0].tags'
+ - role_info.iam_roles[0].tags.TagB == "ValueB"
diff --git a/tests/integration/targets/iam_server_certificate/aliases b/tests/integration/targets/iam_server_certificate/aliases
new file mode 100644
index 00000000000..98e604ec4b3
--- /dev/null
+++ b/tests/integration/targets/iam_server_certificate/aliases
@@ -0,0 +1,3 @@
+cloud/aws
+
+iam_server_certificate_info
diff --git a/tests/integration/targets/iam_server_certificate/defaults/main.yml b/tests/integration/targets/iam_server_certificate/defaults/main.yml
new file mode 100644
index 00000000000..1f136642a70
--- /dev/null
+++ b/tests/integration/targets/iam_server_certificate/defaults/main.yml
@@ -0,0 +1,2 @@
+---
+cert_name: 'ansible-test-{{ tiny_prefix }}'
diff --git a/tests/integration/targets/ec2_vpc_endpoint_service_info/meta/main.yml b/tests/integration/targets/iam_server_certificate/meta/main.yml
similarity index 68%
rename from tests/integration/targets/ec2_vpc_endpoint_service_info/meta/main.yml
rename to tests/integration/targets/iam_server_certificate/meta/main.yml
index 1810d4bec98..cb6005d042c 100644
--- a/tests/integration/targets/ec2_vpc_endpoint_service_info/meta/main.yml
+++ b/tests/integration/targets/iam_server_certificate/meta/main.yml
@@ -1,2 +1,3 @@
dependencies:
+ - prepare_tests
- setup_remote_tmp_dir
diff --git a/tests/integration/targets/iam_server_certificate/tasks/generate-certs.yml b/tests/integration/targets/iam_server_certificate/tasks/generate-certs.yml
new file mode 100644
index 00000000000..02d2dac7322
--- /dev/null
+++ b/tests/integration/targets/iam_server_certificate/tasks/generate-certs.yml
@@ -0,0 +1,65 @@
+################################################
+# Setup SSL certs to store in IAM
+################################################
+- name: 'Generate SSL Keys'
+ community.crypto.openssl_privatekey:
+ path: '{{ remote_tmp_dir }}/{{ item }}-key.pem'
+ size: 2048
+ loop:
+ - 'ca'
+ - 'cert1'
+ - 'cert2'
+
+- name: 'Generate CSRs'
+ community.crypto.openssl_csr:
+ path: '{{ remote_tmp_dir }}/{{ item }}.csr'
+ privatekey_path: '{{ remote_tmp_dir }}/{{ item }}-key.pem'
+ common_name: '{{ item }}.ansible.test'
+ subject_alt_name: 'DNS:{{ item }}.ansible.test'
+ basic_constraints:
+ - 'CA:TRUE'
+ loop:
+ - 'ca'
+ - 'cert1'
+ - 'cert2'
+
+- name: 'Self-sign the "root"'
+ community.crypto.x509_certificate:
+ provider: selfsigned
+ path: '{{ remote_tmp_dir }}/ca.pem'
+ privatekey_path: '{{ remote_tmp_dir }}/ca-key.pem'
+ csr_path: '{{ remote_tmp_dir }}/ca.csr'
+
+- name: 'Sign the intermediate cert'
+ community.crypto.x509_certificate:
+ provider: ownca
+ path: '{{ remote_tmp_dir }}/cert1.pem'
+ csr_path: '{{ remote_tmp_dir }}/cert1.csr'
+ ownca_path: '{{ remote_tmp_dir }}/ca.pem'
+ ownca_privatekey_path: '{{ remote_tmp_dir }}/ca-key.pem'
+
+- name: 'Sign the end-cert'
+ community.crypto.x509_certificate:
+ provider: ownca
+ path: '{{ remote_tmp_dir }}/cert2.pem'
+ csr_path: '{{ remote_tmp_dir }}/cert2.csr'
+ ownca_path: '{{ remote_tmp_dir }}/cert1.pem'
+ ownca_privatekey_path: '{{ remote_tmp_dir }}/cert1-key.pem'
+
+- name: 'Re-Sign the end-cert'
+ community.crypto.x509_certificate:
+ provider: ownca
+ path: '{{ remote_tmp_dir }}/cert2-new.pem'
+ csr_path: '{{ remote_tmp_dir }}/cert2.csr'
+ ownca_path: '{{ remote_tmp_dir }}/cert1.pem'
+ ownca_privatekey_path: '{{ remote_tmp_dir }}/cert1-key.pem'
+
+- set_fact:
+ path_ca_cert: '{{ remote_tmp_dir }}/ca.pem'
+ path_ca_key: '{{ remote_tmp_dir }}/ca-key.pem'
+ path_intermediate_cert: '{{ remote_tmp_dir }}/cert1.pem'
+ path_intermediate_key: '{{ remote_tmp_dir }}/cert1-key.pem'
+ # Same key, updated cert
+ path_cert_a: '{{ remote_tmp_dir }}/cert2.pem'
+ path_cert_b: '{{ remote_tmp_dir }}/cert2-new.pem'
+ path_cert_key: '{{ remote_tmp_dir }}/cert2-key.pem'
diff --git a/tests/integration/targets/iam_server_certificate/tasks/main.yml b/tests/integration/targets/iam_server_certificate/tasks/main.yml
new file mode 100644
index 00000000000..02e88d2cade
--- /dev/null
+++ b/tests/integration/targets/iam_server_certificate/tasks/main.yml
@@ -0,0 +1,616 @@
+---
+# iam_server_certificate integration tests
+#
+# Note:
+#
+# AWS APIs only support renaming and/or updating
+# the *path*.
+#
+# It is not possible to update the cert/key/chain
+# without deleting the ceritifate
+#
+- module_defaults:
+ group/aws:
+ aws_access_key: '{{ aws_access_key }}'
+ aws_secret_key: '{{ aws_secret_key }}'
+ security_token: '{{ security_token | default(omit) }}'
+ region: '{{ aws_region }}'
+ block:
+ ################################################
+
+ # Check that the alias works
+ - name: Test deprecated alias
+ iam_cert: {}
+ ignore_errors: true
+ register: iam_cert_alias
+
+ - name: Test with no args
+ iam_server_certificate: {}
+ ignore_errors: true
+ register: no_args
+
+ - assert:
+ that:
+ - iam_cert_alias is failed
+ - no_args is failed
+ - no_args.msg == iam_cert_alias.msg
+ - no_args.msg.startswith('missing required arguments')
+
+ ################################################
+
+ - include_tasks: 'generate-certs.yml'
+
+ ################################################
+
+ - set_fact:
+ cert_a_data: '{{ lookup("file", path_cert_a) }}'
+ cert_b_data: '{{ lookup("file", path_cert_b) }}'
+ chain_cert_data: '{{ lookup("file", path_intermediate_cert) }}'
+
+ - name: Create Certificate - check_mode
+ iam_server_certificate:
+ name: '{{ cert_name }}'
+ state: present
+ cert: '{{ cert_a_data }}'
+ key: '{{ lookup("file", path_cert_key) }}'
+ register: create_cert
+ check_mode: true
+
+ - name: check result - Create Certificate - check_mode
+ assert:
+ that:
+ - create_cert is successful
+ - create_cert is changed
+
+ - name: Create Certificate
+ iam_server_certificate:
+ name: '{{ cert_name }}'
+ state: present
+ cert: '{{ cert_a_data }}'
+ key: '{{ lookup("file", path_cert_key) }}'
+ register: create_cert
+
+ - name: check result - Create Certificate
+ assert:
+ that:
+ - create_cert is successful
+ - create_cert is changed
+ - '"arn" in create_cert'
+ - '"cert_body" in create_cert'
+ - '"cert_path" in create_cert'
+ - '"expiration_date" in create_cert'
+ - '"name" in create_cert'
+ - '"upload_date" in create_cert'
+ - create_cert.arn.startswith('arn:aws')
+ - create_cert.arn.endswith(cert_name)
+ - create_cert.name == cert_name
+ - create_cert.cert_path == '/'
+ - create_cert.cert_body == cert_a_data
+
+ - name: Create Certificate - idempotency - check_mode
+ iam_server_certificate:
+ name: '{{ cert_name }}'
+ state: present
+ cert: '{{ cert_a_data }}'
+ key: '{{ lookup("file", path_cert_key) }}'
+ register: create_cert
+ check_mode: true
+
+ - name: check result - Create Certificate - idempotency
+ assert:
+ that:
+ - create_cert is successful
+ - create_cert is not changed
+
+ - name: Create Certificate - idempotency
+ iam_server_certificate:
+ name: '{{ cert_name }}'
+ state: present
+ cert: '{{ cert_a_data }}'
+ key: '{{ lookup("file", path_cert_key) }}'
+ register: create_cert
+
+ - name: check result - Create Certificate - idempotency
+ assert:
+ that:
+ - create_cert is successful
+ - create_cert is not changed
+ - '"arn" in create_cert'
+ - '"cert_body" in create_cert'
+ - '"cert_path" in create_cert'
+ - '"expiration_date" in create_cert'
+ - '"name" in create_cert'
+ - '"upload_date" in create_cert'
+ - create_cert.arn.startswith('arn:aws')
+ - create_cert.arn.endswith(cert_name)
+ - create_cert.name == cert_name
+ - create_cert.cert_path == '/'
+ - create_cert.cert_body == cert_a_data
+
+ ################################################
+
+ # Module explicitly blocks updating certs
+ - name: Update Certificate - check_mode
+ iam_server_certificate:
+ name: '{{ cert_name }}'
+ state: present
+ cert: '{{ cert_b_data }}'
+ register: update_cert
+ ignore_errors: true
+ check_mode: true
+
+ - name: check result - Update Certificate - check_mode
+ assert:
+ that:
+ - update_cert is failed
+ - '"not supported" in update_cert.msg'
+
+ - name: Update Certificate
+ iam_server_certificate:
+ name: '{{ cert_name }}'
+ state: present
+ cert: '{{ cert_b_data }}'
+ register: update_cert
+ ignore_errors: true
+
+ - name: check result - Update Certificate
+ assert:
+ that:
+ - update_cert is failed
+ - '"not supported" in update_cert.msg'
+
+ - name: Update Chaining Certificate - check_mode
+ iam_server_certificate:
+ name: '{{ cert_name }}'
+ state: present
+ cert_chain: '{{ chain_cert_data }}'
+ register: update_cert
+ ignore_errors: true
+ check_mode: true
+
+ - name: check result - Update Chaining Certificate - check_mode
+ assert:
+ that:
+ - update_cert is failed
+ - '"not supported" in update_cert.msg'
+
+ - name: Update Chaining Certificate
+ iam_server_certificate:
+ name: '{{ cert_name }}'
+ state: present
+ cert_chain: '{{ chain_cert_data }}'
+ register: update_cert
+ ignore_errors: true
+
+ - name: check result - Update Chaining Certificate
+ assert:
+ that:
+ - update_cert is failed
+ - '"not supported" in update_cert.msg'
+
+ # AWS APIs provide no mechanism for accessing
+ # any information about the key, and as such
+ # the module can't tell if a key was updated.
+
+ ################################################
+
+ - name: Delete certificate - check_mode
+ iam_cert:
+ name: '{{ cert_name }}'
+ state: absent
+ register: delete_cert
+ check_mode: true
+
+ - name: check result - Delete certificate - check_mode
+ assert:
+ that:
+ - delete_cert is successful
+ - delete_cert is changed
+
+ - name: Delete certificate
+ iam_cert:
+ name: '{{ cert_name }}'
+ state: absent
+ register: delete_cert
+
+ - name: check result - Delete certificate
+ assert:
+ that:
+ - delete_cert is successful
+ - delete_cert is changed
+
+ - name: Delete certificate - idempotency - check_mode
+ iam_cert:
+ name: '{{ cert_name }}'
+ state: absent
+ register: delete_cert
+ check_mode: true
+
+ - name: check result - Delete certificate - check_mode
+ assert:
+ that:
+ - delete_cert is successful
+ - delete_cert is not changed
+
+ - name: Delete certificate - idempotency
+ iam_cert:
+ name: '{{ cert_name }}'
+ state: absent
+ register: delete_cert
+
+ - name: check result - Delete certificate
+ assert:
+ that:
+ - delete_cert is successful
+ - delete_cert is not changed
+
+ ################################################
+
+ - name: Create Certificate with Chain and path - check_mode
+ iam_server_certificate:
+ name: '{{ cert_name }}'
+ state: present
+ cert: '{{ cert_a_data }}'
+ key: '{{ lookup("file", path_cert_key) }}'
+ cert_chain: '{{ chain_cert_data }}'
+ path: '/example/'
+ register: create_cert
+ check_mode: true
+
+ - name: check result - Create Certificate with Chain and path - check_mode
+ assert:
+ that:
+ - create_cert is successful
+ - create_cert is changed
+
+ - name: Create Certificate with Chain and path
+ iam_server_certificate:
+ name: '{{ cert_name }}'
+ state: present
+ cert: '{{ cert_a_data }}'
+ key: '{{ lookup("file", path_cert_key) }}'
+ cert_chain: '{{ chain_cert_data }}'
+ path: '/example/'
+ register: create_cert
+
+ - name: check result - Create Certificate with Chain and path
+ assert:
+ that:
+ - create_cert is successful
+ - create_cert is changed
+ - '"arn" in create_cert'
+ - '"cert_body" in create_cert'
+ - '"cert_path" in create_cert'
+ - '"expiration_date" in create_cert'
+ - '"name" in create_cert'
+ - '"upload_date" in create_cert'
+ - create_cert.arn.startswith('arn:aws')
+ - create_cert.arn.endswith(cert_name)
+ - create_cert.name == cert_name
+ - create_cert.cert_path == '/example/'
+ - create_cert.cert_body == cert_a_data
+
+ - name: Create Certificate with Chain and path - idempotency - check_mode
+ iam_server_certificate:
+ name: '{{ cert_name }}'
+ state: present
+ cert: '{{ cert_a_data }}'
+ key: '{{ lookup("file", path_cert_key) }}'
+ cert_chain: '{{ chain_cert_data }}'
+ path: '/example/'
+ register: create_cert
+ check_mode: true
+
+ - name: check result - Create Certificate with Chain and path - idempotency - check_mode
+ assert:
+ that:
+ - create_cert is successful
+ - create_cert is not changed
+
+ - name: Create Certificate with Chain and path - idempotency
+ iam_server_certificate:
+ name: '{{ cert_name }}'
+ state: present
+ cert: '{{ cert_a_data }}'
+ key: '{{ lookup("file", path_cert_key) }}'
+ cert_chain: '{{ chain_cert_data }}'
+ path: '/example/'
+ register: create_cert
+
+ - name: check result - Create Certificate with Chain and path - idempotency
+ assert:
+ that:
+ - create_cert is successful
+ - create_cert is not changed
+ - '"arn" in create_cert'
+ - '"cert_body" in create_cert'
+ - '"cert_path" in create_cert'
+ - '"expiration_date" in create_cert'
+ - '"name" in create_cert'
+ - '"upload_date" in create_cert'
+ - create_cert.arn.startswith('arn:aws')
+ - create_cert.arn.endswith(cert_name)
+ - create_cert.name == cert_name
+ - create_cert.cert_path == '/example/'
+ - create_cert.cert_body == cert_a_data
+
+ ################################################
+
+ - name: Create Certificate with identical cert - check_mode
+ iam_server_certificate:
+ name: '{{ cert_name }}-duplicate'
+ state: present
+ cert: '{{ cert_a_data }}'
+ key: '{{ lookup("file", path_cert_key) }}'
+ register: create_duplicate
+ ignore_errors: true
+
+ - name: check result - Create Certificate with identical cert - check_mode
+ assert:
+ that:
+ - create_duplicate is failed
+
+ - name: Create Certificate with identical cert
+ iam_server_certificate:
+ name: '{{ cert_name }}-duplicate'
+ state: present
+ cert: '{{ cert_a_data }}'
+ key: '{{ lookup("file", path_cert_key) }}'
+ register: create_duplicate
+ ignore_errors: true
+
+ - name: check result - Create Certificate with identical cert
+ assert:
+ that:
+ - create_duplicate is failed
+
+ ################################################
+
+ - name: Create Certificate with forced identical cert - check_mode
+ iam_server_certificate:
+ name: '{{ cert_name }}-duplicate'
+ state: present
+ cert: '{{ cert_a_data }}'
+ key: '{{ lookup("file", path_cert_key) }}'
+ dup_ok: true
+ register: create_duplicate
+ check_mode: true
+
+ - name: check result - Create Certificate with forced identical cert - check_mode
+ assert:
+ that:
+ - create_duplicate is successful
+ - create_duplicate is changed
+
+ - name: Create Certificate with forced identical cert
+ iam_server_certificate:
+ name: '{{ cert_name }}-duplicate'
+ state: present
+ cert: '{{ cert_a_data }}'
+ key: '{{ lookup("file", path_cert_key) }}'
+ dup_ok: true
+ register: create_duplicate
+
+ - name: check result - Create Certificate with forced identical cert
+ assert:
+ that:
+ - create_duplicate is successful
+ - create_duplicate is changed
+ - '"arn" in create_duplicate'
+ - '"cert_body" in create_duplicate'
+ - '"cert_path" in create_duplicate'
+ - '"expiration_date" in create_duplicate'
+ - '"name" in create_duplicate'
+ - '"upload_date" in create_duplicate'
+ - create_duplicate.arn.startswith('arn:aws')
+ - create_duplicate.arn.endswith('-duplicate')
+ - create_duplicate.name.endswith('duplicate')
+ - create_duplicate.cert_path == '/'
+ - create_duplicate.cert_body == cert_a_data
+
+ - name: Create Certificate with forced identical cert - idempotency - check_mode
+ iam_server_certificate:
+ name: '{{ cert_name }}-duplicate'
+ state: present
+ cert: '{{ cert_a_data }}'
+ key: '{{ lookup("file", path_cert_key) }}'
+ dup_ok: true
+ register: create_duplicate
+ check_mode: true
+
+ - name: check result - Create Certificate with forced identical cert - idempotency - check_mode
+ assert:
+ that:
+ - create_duplicate is successful
+ - create_duplicate is not changed
+
+ - name: Create Certificate with forced identical cert - idempotency
+ iam_server_certificate:
+ name: '{{ cert_name }}-duplicate'
+ state: present
+ cert: '{{ cert_a_data }}'
+ key: '{{ lookup("file", path_cert_key) }}'
+ dup_ok: true
+ register: create_duplicate
+
+ - name: check result - Create Certificate with forced identical cert - idempotency
+ assert:
+ that:
+ - create_duplicate is successful
+ - create_duplicate is not changed
+ - '"arn" in create_duplicate'
+ - '"cert_body" in create_duplicate'
+ - '"cert_path" in create_duplicate'
+ - '"expiration_date" in create_duplicate'
+ - '"name" in create_duplicate'
+ - '"upload_date" in create_duplicate'
+ - create_duplicate.arn.startswith('arn:aws')
+ - create_duplicate.arn.endswith('-duplicate')
+ - create_duplicate.name.endswith('duplicate')
+ - create_duplicate.cert_path == '/'
+ - create_duplicate.cert_body == cert_a_data
+
+ ################################################
+
+ - name: Update certificate path - check_mode
+ iam_server_certificate:
+ name: '{{ cert_name }}'
+ state: present
+ path: '/example/'
+ new_path: '/path/'
+ register: update_path
+ check_mode: true
+
+ - name: check result - Update certificate path - check_mode
+ assert:
+ that:
+ - update_path is successful
+ - update_path is changed
+
+ - name: Update certificate path
+ iam_server_certificate:
+ name: '{{ cert_name }}'
+ state: present
+ path: '/example/'
+ new_path: '/path/'
+ register: update_path
+
+ - name: check result - Update certificate path
+ assert:
+ that:
+ - update_path is successful
+ - update_path is changed
+ - '"arn" in update_path'
+ - '"cert_body" in update_path'
+ - '"cert_path" in update_path'
+ - '"expiration_date" in update_path'
+ - '"name" in update_path'
+ - '"upload_date" in update_path'
+ - update_path.arn.startswith('arn:aws')
+ - update_path.arn.endswith(cert_name)
+ - update_path.name == cert_name
+ - update_path.cert_path == '/path/'
+ - update_path.cert_body == cert_a_data
+
+ - name: Update certificate path - idempotency - check_mode
+ iam_server_certificate:
+ name: '{{ cert_name }}'
+ state: present
+ path: '/example/'
+ new_path: '/path/'
+ register: update_path
+ check_mode: true
+
+ - name: check result - Update certificate path - idempotency - check_mode
+ assert:
+ that:
+ - update_path is successful
+ - update_path is not changed
+
+ - name: Update certificate path - idempotency
+ iam_server_certificate:
+ name: '{{ cert_name }}'
+ state: present
+ path: '/example/'
+ new_path: '/path/'
+ register: update_path
+
+ - name: check result - Update certificate path - idempotency
+ assert:
+ that:
+ - update_path is successful
+ - update_path is not changed
+
+ ################################################
+
+ - name: Update certificate name - check_mode
+ iam_server_certificate:
+ name: '{{ cert_name }}'
+ new_name: '{{ cert_name }}-renamed'
+ state: present
+ register: update_name
+ check_mode: true
+
+ - name: check result - Update certificate name - check_mode
+ assert:
+ that:
+ - update_name is successful
+ - update_name is changed
+
+ - name: Update certificate name
+ iam_server_certificate:
+ name: '{{ cert_name }}'
+ new_name: '{{ cert_name }}-renamed'
+ state: present
+ register: update_name
+
+ - name: check result - Update certificate name
+ assert:
+ that:
+ - update_name is successful
+ - update_name is changed
+ - '"arn" in update_name'
+ - '"cert_body" in update_name'
+ - '"cert_path" in update_name'
+ - '"expiration_date" in update_name'
+ - '"name" in update_name'
+ - '"upload_date" in update_name'
+ - update_name.arn.startswith('arn:aws')
+ - update_name.arn.endswith('-renamed')
+ - update_name.name.endswith('renamed')
+ - update_name.cert_path == '/path/'
+ - update_name.cert_body == cert_a_data
+
+ - name: Update certificate name - idempotency - check_mode
+ iam_server_certificate:
+ name: '{{ cert_name }}'
+ new_name: '{{ cert_name }}-renamed'
+ state: present
+ register: update_name
+ check_mode: true
+
+ - name: check result - Update certificate name - idempotency - check_mode
+ assert:
+ that:
+ - update_name is successful
+ - update_name is not changed
+
+ - name: Update certificate name - idempotency
+ iam_server_certificate:
+ name: '{{ cert_name }}'
+ new_name: '{{ cert_name }}-renamed'
+ state: present
+ register: update_name
+
+ - name: check result - Update certificate name - idempotency
+ assert:
+ that:
+ - update_name is successful
+ - update_name is not changed
+ - '"arn" in update_name'
+ - '"cert_body" in update_name'
+ - '"cert_path" in update_name'
+ - '"expiration_date" in update_name'
+ - '"name" in update_name'
+ - '"upload_date" in update_name'
+ - update_name.arn.startswith('arn:aws')
+ - update_name.arn.endswith('-renamed')
+ - update_name.name.endswith('renamed')
+ - update_name.cert_path == '/path/'
+ - update_name.cert_body == cert_a_data
+
+ always:
+
+ ################################################
+ # TEARDOWN STARTS HERE
+ ################################################
+
+ - name: Delete certificate
+ iam_cert:
+ name: '{{ item }}'
+ state: absent
+ ignore_errors: true
+ loop:
+ - '{{ cert_name }}'
+ - '{{ cert_name }}-renamed'
+ - '{{ cert_name }}-duplicate'
diff --git a/tests/integration/targets/iam_user/tasks/main.yml b/tests/integration/targets/iam_user/tasks/main.yml
index c5be49ec4c0..76d13e57f19 100644
--- a/tests/integration/targets/iam_user/tasks/main.yml
+++ b/tests/integration/targets/iam_user/tasks/main.yml
@@ -20,38 +20,6 @@
- iam_user_info_path_group is failed
- 'iam_user_info_path_group.msg == "parameters are mutually exclusive: group|path"'
- - name: ensure exception handling fails as expected
- iam_user_info:
- region: 'bogus'
- path: ''
- ignore_errors: yes
- register: iam_user_info
- - assert:
- that:
- - iam_user_info is failed
- - '"user" in iam_user_info.msg'
-
- - name: ensure exception handling fails as expected with group
- iam_user_info:
- region: 'bogus'
- group: '{{ test_group }}'
- ignore_errors: yes
- register: iam_user_info
- - assert:
- that:
- - iam_user_info is failed
- - '"group" in iam_user_info.msg'
-
- - name: ensure exception handling fails as expected with default path
- iam_user_info:
- region: 'bogus'
- ignore_errors: yes
- register: iam_user_info
- - assert:
- that:
- - iam_user_info is failed
- - '"path" in iam_user_info.msg'
-
- name: create test user (check mode)
iam_user:
name: '{{ test_user }}'
@@ -97,6 +65,7 @@
- test_iam_user.path == '{{ test_path }}'
- test_iam_user.user_id is not none
- test_iam_user.user_name == '{{ test_user }}'
+ - test_iam_user.tags | length == 0
- name: get info on IAM user(s)
iam_user_info:
@@ -118,6 +87,7 @@
- iam_user_info.iam_users[0].path == test_iam_user.path
- iam_user_info.iam_users[0].user_id == test_iam_user.user_id
- iam_user_info.iam_users[0].user_name == test_iam_user.user_name
+ - iam_user_info.iam_users[0].tags | length == 0
- name: get info on IAM user(s) on path
iam_user_info:
@@ -132,6 +102,125 @@
- iam_user_info.iam_users[0].path == test_iam_user.path
- iam_user_info.iam_users[0].user_id == test_iam_user.user_id
- iam_user_info.iam_users[0].user_name == test_iam_user.user_name
+ - iam_user_info.iam_users[0].tags | length == 0
+
+ - name: 'Add Tag'
+ iam_user:
+ name: '{{ test_user }}'
+ state: present
+ tags:
+ TagA: ValueA
+ register: iam_user
+ - assert:
+ that:
+ - iam_user is changed
+ - iam_user.iam_user.user.user_name == test_user
+ - iam_user.iam_user.user.tags | length == 1
+ - '"TagA" in iam_user.iam_user.user.tags'
+ - iam_user.iam_user.user.tags.TagA == "ValueA"
+
+ - name: 'Add Tag (no change)'
+ iam_user:
+ name: '{{ test_user }}'
+ state: present
+ tags:
+ TagA: ValueA
+ register: iam_user
+ - assert:
+ that:
+ - iam_user is not changed
+ - iam_user.iam_user.user.user_name == test_user
+ - iam_user.iam_user.user.tags | length == 1
+ - '"TagA" in iam_user.iam_user.user.tags'
+ - iam_user.iam_user.user.tags.TagA == "ValueA"
+
+ - name: 'Extend Tags'
+ iam_user:
+ name: '{{ test_user }}'
+ state: present
+ purge_tags: no
+ tags:
+ tag_b: "value_b"
+ "Tag C": "Value C"
+ "tag d": "value d"
+ register: iam_user
+ - assert:
+ that:
+ - iam_user is changed
+ - iam_user.iam_user.user.user_name == test_user
+ - iam_user.iam_user.user.tags | length == 4
+ - '"TagA" in iam_user.iam_user.user.tags'
+ - '"tag_b" in iam_user.iam_user.user.tags'
+ - '"Tag C" in iam_user.iam_user.user.tags'
+ - '"tag d" in iam_user.iam_user.user.tags'
+ - iam_user.iam_user.user.tags.TagA == "ValueA"
+ - iam_user.iam_user.user.tags.tag_b == "value_b"
+ - iam_user.iam_user.user.tags["Tag C"] == "Value C"
+ - iam_user.iam_user.user.tags["tag d"] == "value d"
+
+ - name: 'Create user without Tag (no change)'
+ iam_user:
+ name: '{{ test_user }}'
+ state: present
+ register: iam_user
+ - assert:
+ that:
+ - iam_user is not changed
+ - iam_user.iam_user.user.user_name == test_user
+ - iam_user.iam_user.user.tags | length == 4
+
+ - name: 'Remove all Tags (check mode)'
+ iam_user:
+ name: '{{ test_user }}'
+ state: present
+ tags: {}
+ check_mode: yes
+ register: iam_user
+ - assert:
+ that:
+ - iam_user is changed
+
+ - name: 'Remove 3 Tags'
+ iam_user:
+ name: '{{ test_user }}'
+ state: present
+ tags:
+ TagA: ValueA
+ register: iam_user
+ - assert:
+ that:
+ - iam_user is changed
+ - iam_user.iam_user.user.user_name == test_user
+ - iam_user.iam_user.user.tags | length == 1
+ - '"TagA" in iam_user.iam_user.user.tags'
+ - iam_user.iam_user.user.tags.TagA == "ValueA"
+
+ - name: 'Change Tag'
+ iam_user:
+ name: '{{ test_user }}'
+ state: present
+ tags:
+ TagA: AnotherValueA
+ register: iam_user
+ - assert:
+ that:
+ - iam_user is changed
+ - iam_user.iam_user.user.user_name == test_user
+ - iam_user.iam_user.user.tags | length == 1
+ - '"TagA" in iam_user.iam_user.user.tags'
+ - iam_user.iam_user.user.tags.TagA == "AnotherValueA"
+
+ - name: 'Remove All Tags'
+ iam_user:
+ name: '{{ test_user }}'
+ state: present
+ tags: {}
+ register: iam_user
+ - assert:
+ that:
+ - iam_user is changed
+ - iam_user.iam_user.user.user_name == test_user
+ - iam_user.iam_user.user.tags | length == 0
# ===========================================
# Test Managed Policy management
@@ -324,6 +413,7 @@
- iam_user_info.iam_users[0].path == test_iam_user.path
- iam_user_info.iam_users[0].user_id == test_iam_user.user_id
- iam_user_info.iam_users[0].user_name == test_iam_user.user_name
+ - iam_user_info.iam_users[0].tags | length == 0
- name: remove user from group
iam_group:
diff --git a/tests/integration/targets/lambda/defaults/main.yml b/tests/integration/targets/lambda/defaults/main.yml
index c48f6972a1f..20e1e5029a7 100644
--- a/tests/integration/targets/lambda/defaults/main.yml
+++ b/tests/integration/targets/lambda/defaults/main.yml
@@ -2,6 +2,5 @@
# defaults file for lambda integration test
# IAM role names have to be less than 64 characters
# we hash the resource_prefix to get a shorter, unique string
-unique_id: "{{ resource_prefix | hash('md5') }}"
-lambda_function_name: '{{ unique_id }}'
-lambda_role_name: 'ansible-test-{{ unique_id }}-lambda'
+lambda_function_name: '{{ tiny_prefix }}'
+lambda_role_name: 'ansible-test-{{ tiny_prefix }}-lambda'
diff --git a/tests/integration/targets/lambda/tasks/main.yml b/tests/integration/targets/lambda/tasks/main.yml
index c48766cd306..0013aec25e0 100644
--- a/tests/integration/targets/lambda/tasks/main.yml
+++ b/tests/integration/targets/lambda/tasks/main.yml
@@ -42,7 +42,8 @@
assert:
that:
- result.failed
- - 'result.msg.startswith("missing required arguments: name")'
+ - 'result.msg.startswith("missing required arguments: ")'
+ - '"name" in result.msg'
- name: test with no parameters except state absent
lambda:
@@ -65,7 +66,9 @@
assert:
that:
- result.failed
- - 'result.msg.startswith("state is present but all of the following are missing: handler")'
+ - 'result.msg.startswith("state is present but all of the following are missing: ")'
+ - '"handler" in result.msg'
+ - '"role" in result.msg'
- name: test state=present with security group but no vpc
lambda:
diff --git a/tests/integration/targets/lambda_alias/defaults/main.yml b/tests/integration/targets/lambda_alias/defaults/main.yml
index ec10501685b..692a4f01536 100644
--- a/tests/integration/targets/lambda_alias/defaults/main.yml
+++ b/tests/integration/targets/lambda_alias/defaults/main.yml
@@ -2,6 +2,5 @@
# defaults file for lambda integration test
# IAM role names have to be less than 64 characters
# we hash the resource_prefix to get a shorter, unique string
-unique_id: "{{ resource_prefix | hash('md5') }}"
-lambda_function_name: 'ansible-test-{{ unique_id }}'
-lambda_role_name: 'ansible-test-{{ unique_id }}-lambda'
+lambda_function_name: 'ansible-test-{{ tiny_prefix }}'
+lambda_role_name: 'ansible-test-{{ tiny_prefix }}-lambda'
diff --git a/tests/integration/targets/lambda_policy/defaults/main.yml b/tests/integration/targets/lambda_policy/defaults/main.yml
index 853bc06fda6..4f4252fa04e 100644
--- a/tests/integration/targets/lambda_policy/defaults/main.yml
+++ b/tests/integration/targets/lambda_policy/defaults/main.yml
@@ -2,6 +2,5 @@
# defaults file for lambda_policy integration test
# IAM role names have to be less than 64 characters
# we hash the resource_prefix to get a shorter, unique string
-unique_id: "{{ resource_prefix | hash('md5') }}"
-lambda_function_name: '{{ unique_id }}-api-endpoint'
-lambda_role_name: 'ansible-test-{{ unique_id }}-lambda-policy'
+lambda_function_name: '{{ tiny_prefix }}-api-endpoint'
+lambda_role_name: 'ansible-test-{{ tiny_prefix }}-lambda-policy'
diff --git a/tests/integration/targets/lambda_policy/tasks/main.yml b/tests/integration/targets/lambda_policy/tasks/main.yml
index 855e9fba994..2b0e3d38f9f 100644
--- a/tests/integration/targets/lambda_policy/tasks/main.yml
+++ b/tests/integration/targets/lambda_policy/tasks/main.yml
@@ -24,7 +24,6 @@
when: iam_role.changed
- name: test with no parameters
- module_defaults: { group/aws: {} }
lambda_policy: null
register: result
ignore_errors: true
@@ -33,42 +32,11 @@
that:
- result.failed
- 'result.msg.startswith("missing required arguments: ")'
- - name: test with all required dummy parameters but no region
- module_defaults: { group/aws: {} }
- lambda_policy:
- statement_id: dummy
- principal: api_fakeway
- action: fake:do_something_fake
- function_name: dummy_fake_function
- ignore_errors: true
- register: result
- - name: assert failure and appropriate message when called without region
- assert:
- that:
- - result.failed
- - '"requires a region and none was found" in result.msg'
- - name: test exceptions generated by forcing bad ec2 url
- module_defaults: { group/aws: {} }
- lambda_policy:
- function_name: '{{ lambda_function_name }}'
- state: present
- statement_id: api-gateway-invoke-lambdas
- action: lambda:InvokeFunction
- principal: apigateway.amazonaws.com
- source_arn: arn:aws:execute-api:no-north-0:1234567:*/*
- ec2_url: https://noexist.example.com
- ec2_region: no-north-0
- ec2_access_key: iamnotreallyanaccesskey
- ec2_secret_key: thisisabadsecretkey
- security_token: andthisisabadsecuritytoken
- register: result
- ignore_errors: true
- - name: assert lambda manages to respond as expected
- assert:
- that:
- - result is failed
- - result.msg != "MODULE FAILURE"
- - result.changed == False
+ - '"action" in result.msg'
+ - '"function_name" in result.msg'
+ - '"principal" in result.msg'
+ - '"statement_id" in result.msg'
+
- name: move lambda into place for archive module
copy:
src: mini_http_lambda.py
diff --git a/tests/integration/targets/rds_instance/aliases b/tests/integration/targets/rds_instance/aliases
index 283523234b9..e30a1801b1e 100644
--- a/tests/integration/targets/rds_instance/aliases
+++ b/tests/integration/targets/rds_instance/aliases
@@ -1,5 +1,3 @@
-# reason: missing-policy
-# reason: slow
-unsupported
+slow
cloud/aws
diff --git a/tests/integration/targets/rds_instance/inventory b/tests/integration/targets/rds_instance/inventory
index 8ae740d0181..9daf5db1e07 100644
--- a/tests/integration/targets/rds_instance/inventory
+++ b/tests/integration/targets/rds_instance/inventory
@@ -1,16 +1,12 @@
[tests]
-credentials
states
-tags
-modification
-bad_options
+modify
+modify_complex
processor_features
-encryption
-final_snapshot
read_replica
vpc_security_groups
restore_instance
-snapshot
+tagging
# TODO: uncomment after adding rds_cluster module
# aurora
diff --git a/tests/integration/targets/rds_instance/main.yml b/tests/integration/targets/rds_instance/main.yml
index fc2c909ec11..1b33dab5076 100644
--- a/tests/integration/targets/rds_instance/main.yml
+++ b/tests/integration/targets/rds_instance/main.yml
@@ -6,6 +6,6 @@
- hosts: all
gather_facts: no
strategy: free
- serial: 5
+ serial: 8
roles:
- rds_instance
diff --git a/tests/integration/targets/rds_instance/roles/rds_instance/defaults/main.yml b/tests/integration/targets/rds_instance/roles/rds_instance/defaults/main.yml
index 33760c64660..e32df5478cd 100644
--- a/tests/integration/targets/rds_instance/roles/rds_instance/defaults/main.yml
+++ b/tests/integration/targets/rds_instance/roles/rds_instance/defaults/main.yml
@@ -8,6 +8,8 @@ storage_encrypted_db_instance_class: db.t3.small
modified_db_instance_class: db.t3.medium
allocated_storage: 20
modified_allocated_storage: 30
+monitoring_interval: 60
+preferred_maintenance_window: "mon:06:20-mon:06:50"
# For aurora tests
cluster_id: "{{ resource_prefix }}-cluster"
@@ -16,13 +18,10 @@ aurora_db_instance_class: db.t3.medium
# For oracle tests
# Smallest instance that permits modification of the coreCount
oracle_ee_db_instance_class: db.r5.2xlarge
-processor_features:
- coreCount: 2
- threadsPerCore: 1
modified_processor_features:
coreCount: 4
threadsPerCore: 2
# For mariadb tests
-mariadb_engine_version: 10.3.20
-mariadb_engine_version_2: 10.4.8
+mariadb_engine_version: 10.3.31
+mariadb_engine_version_2: 10.4.21
diff --git a/tests/integration/targets/rds_instance/roles/rds_instance/files/enhanced_monitoring_assume_policy.json b/tests/integration/targets/rds_instance/roles/rds_instance/files/enhanced_monitoring_assume_policy.json
new file mode 100644
index 00000000000..29acf369fc9
--- /dev/null
+++ b/tests/integration/targets/rds_instance/roles/rds_instance/files/enhanced_monitoring_assume_policy.json
@@ -0,0 +1,13 @@
+{
+ "Version": "2012-10-17",
+ "Statement": [
+ {
+ "Sid": "",
+ "Effect": "Allow",
+ "Principal": {
+ "Service": "monitoring.rds.amazonaws.com"
+ },
+ "Action": "sts:AssumeRole"
+ }
+ ]
+}
diff --git a/tests/integration/targets/rds_instance/roles/rds_instance/tasks/test_aurora.yml b/tests/integration/targets/rds_instance/roles/rds_instance/tasks/test_aurora.yml
index c3a880d6bb1..031d0b8464e 100644
--- a/tests/integration/targets/rds_instance/roles/rds_instance/tasks/test_aurora.yml
+++ b/tests/integration/targets/rds_instance/roles/rds_instance/tasks/test_aurora.yml
@@ -113,6 +113,7 @@
id: "{{ item }}"
state: absent
skip_final_snapshot: True
+ wait: false
loop:
- "{{ instance_id }}"
- "{{ modified_instance_id }}"
@@ -123,4 +124,5 @@
cluster_id: "{{ cluster_id }}"
state: absent
skip_final_snapshot: True
+ wait: false
ignore_errors: yes
diff --git a/tests/integration/targets/rds_instance/roles/rds_instance/tasks/test_bad_options.yml b/tests/integration/targets/rds_instance/roles/rds_instance/tasks/test_bad_options.yml
deleted file mode 100644
index 9fd2f4fa6e4..00000000000
--- a/tests/integration/targets/rds_instance/roles/rds_instance/tasks/test_bad_options.yml
+++ /dev/null
@@ -1,31 +0,0 @@
----
- - block:
-
- - name: Ensure the resource doesn't exist
- rds_instance:
- id: "{{ instance_id }}"
- state: absent
- skip_final_snapshot: True
- register: result
-
- - assert:
- that:
- - not result.changed
- ignore_errors: yes
-
- - name: Create a DB instance with an invalid engine
- rds_instance:
- id: "{{ instance_id }}"
- state: present
- engine: thisisnotavalidengine
- username: "{{ username }}"
- password: "{{ password }}"
- db_instance_class: "{{ db_instance_class }}"
- allocated_storage: "{{ allocated_storage }}"
- register: result
- ignore_errors: True
-
- - assert:
- that:
- - result.failed
- - '"DB engine thisisnotavalidengine should be one of" in result.msg'
diff --git a/tests/integration/targets/rds_instance/roles/rds_instance/tasks/test_credentials.yml b/tests/integration/targets/rds_instance/roles/rds_instance/tasks/test_credentials.yml
deleted file mode 100644
index 36b5a96170c..00000000000
--- a/tests/integration/targets/rds_instance/roles/rds_instance/tasks/test_credentials.yml
+++ /dev/null
@@ -1,46 +0,0 @@
----
-- name: test without credentials
- rds_instance:
- db_instance_identifier: test-rds-instance
- region: '{{ omit }}'
- aws_access_key: '{{ omit }}'
- aws_secret_key: '{{ omit }}'
- security_token: '{{ omit }}'
- register: result
- ignore_errors: yes
-
-- assert:
- that:
- - result.failed
- - 'result.msg == "The rds_instance module requires a region and none was found in configuration, environment variables or module parameters"'
-
-- name: test without credentials
- rds_instance:
- db_instance_identifier: test-rds-instance
- region: us-east-1
- aws_access_key: '{{ omit }}'
- aws_secret_key: '{{ omit }}'
- security_token: '{{ omit }}'
- register: result
- ignore_errors: yes
-
-- assert:
- that:
- - result.failed
- - '"Unable to locate credentials" in result.msg'
-
-- name: test with invalid credentials
- rds_instance:
- db_instance_identifier: test-rds-instance
- region: us-east-1
- profile: doesnotexist
- aws_access_key: '{{ omit }}'
- aws_secret_key: '{{ omit }}'
- security_token: '{{ omit }}'
- register: result
- ignore_errors: yes
-
-- assert:
- that:
- - result.failed
- - 'result.msg == "The config profile (doesnotexist) could not be found"'
diff --git a/tests/integration/targets/rds_instance/roles/rds_instance/tasks/test_encryption.yml b/tests/integration/targets/rds_instance/roles/rds_instance/tasks/test_encryption.yml
deleted file mode 100644
index 6c3e81494e5..00000000000
--- a/tests/integration/targets/rds_instance/roles/rds_instance/tasks/test_encryption.yml
+++ /dev/null
@@ -1,42 +0,0 @@
----
- - block:
-
- - name: Ensure the resource doesn't exist
- rds_instance:
- id: "{{ instance_id }}"
- state: absent
- skip_final_snapshot: True
- register: result
-
- - assert:
- that:
- - not result.changed
- ignore_errors: yes
-
- - name: Create a mariadb instance
- rds_instance:
- id: "{{ instance_id }}"
- state: present
- engine: mariadb
- username: "{{ username }}"
- password: "{{ password }}"
- db_instance_class: "{{ storage_encrypted_db_instance_class }}"
- allocated_storage: "{{ allocated_storage }}"
- storage_encrypted: True
- register: result
-
- - assert:
- that:
- - result.changed
- - "result.db_instance_identifier == '{{ instance_id }}'"
- - result.kms_key_id
- - result.storage_encrypted == true
-
- always:
-
- - name: Delete DB instance
- rds_instance:
- id: "{{ instance_id }}"
- state: absent
- skip_final_snapshot: True
- register: result
diff --git a/tests/integration/targets/rds_instance/roles/rds_instance/tasks/test_final_snapshot.yml b/tests/integration/targets/rds_instance/roles/rds_instance/tasks/test_final_snapshot.yml
deleted file mode 100644
index 922a008c353..00000000000
--- a/tests/integration/targets/rds_instance/roles/rds_instance/tasks/test_final_snapshot.yml
+++ /dev/null
@@ -1,61 +0,0 @@
----
- - block:
-
- - name: Ensure the resource doesn't exist
- rds_instance:
- id: "{{ instance_id }}"
- state: absent
- skip_final_snapshot: True
- register: result
-
- - assert:
- that:
- - not result.changed
- ignore_errors: yes
-
- - name: Create a mariadb instance
- rds_instance:
- id: "{{ instance_id }}"
- state: present
- engine: mariadb
- username: "{{ username }}"
- password: "{{ password }}"
- db_instance_class: "{{ db_instance_class }}"
- allocated_storage: "{{ allocated_storage }}"
- register: result
-
- - name: Delete the DB instance
- rds_instance:
- id: "{{ instance_id }}"
- state: absent
- final_snapshot_identifier: "{{ instance_id }}"
- register: result
-
- - assert:
- that:
- - result.changed
- - "result.final_snapshot.db_instance_identifier == '{{ instance_id }}'"
-
- - name: Check that snapshot exists
- rds_snapshot_info:
- db_snapshot_identifier: "{{ instance_id }}"
- register: result
-
- - assert:
- that:
- - "result.snapshots | length == 1"
- - "result.snapshots.0.engine == 'mariadb'"
-
- always:
- - name: Remove the snapshot
- rds_snapshot:
- db_snapshot_identifier: "{{ instance_id }}"
- state: absent
- ignore_errors: yes
-
- - name: Remove the DB instance
- rds_instance:
- id: "{{ instance_id }}"
- state: absent
- skip_final_snapshot: True
- ignore_errors: yes
diff --git a/tests/integration/targets/rds_instance/roles/rds_instance/tasks/test_modification.yml b/tests/integration/targets/rds_instance/roles/rds_instance/tasks/test_modification.yml
deleted file mode 100644
index 03e49967cae..00000000000
--- a/tests/integration/targets/rds_instance/roles/rds_instance/tasks/test_modification.yml
+++ /dev/null
@@ -1,205 +0,0 @@
----
- #TODO: test availability_zone and multi_az
- - block:
-
- - name: Ensure the resource doesn't exist
- rds_instance:
- id: "{{ instance_id }}"
- state: absent
- skip_final_snapshot: True
- register: result
-
- - assert:
- that:
- - not result.changed
- ignore_errors: yes
-
- - name: Create a mariadb instance
- rds_instance:
- id: "{{ instance_id }}"
- state: present
- engine: mariadb
- engine_version: "{{ mariadb_engine_version }}"
- username: "{{ username }}"
- password: "{{ password }}"
- db_instance_class: "{{ db_instance_class }}"
- allocated_storage: "{{ allocated_storage }}"
- register: result
-
- - assert:
- that:
- - result.changed
- - "result.db_instance_identifier == '{{ instance_id }}'"
-
- - name: Modify the instance name without immediate application
- rds_instance:
- id: "{{ instance_id }}"
- state: present
- new_id: "{{ modified_instance_id }}"
- apply_immediately: False
- register: result
-
- - assert:
- that:
- - result.changed
- - 'result.db_instance_identifier == "{{ instance_id }}"'
-
- - name: Immediately apply the pending update
- rds_instance:
- id: "{{ instance_id }}"
- state: present
- new_id: "{{ modified_instance_id }}"
- apply_immediately: True
- register: result
-
- - assert:
- that:
- - result.changed
- - 'result.db_instance_identifier == "{{ modified_instance_id }}"'
-
- - name: Modify the instance immediately
- rds_instance:
- id: '{{ modified_instance_id }}'
- state: present
- new_id: '{{ instance_id }}'
- apply_immediately: True
- register: result
-
- - assert:
- that:
- - result.changed
- - 'result.db_instance_identifier == "{{ instance_id }}"'
-
- - name: Check mode - modify the password
- rds_instance:
- id: '{{ instance_id }}'
- state: present
- password: '{{ password }}'
- force_update_password: True
- apply_immediately: True
- register: result
- check_mode: True
-
- - assert:
- that:
- - result.changed
-
- - name: Modify the password
- rds_instance:
- id: '{{ instance_id }}'
- state: present
- password: '{{ password }}'
- force_update_password: True
- apply_immediately: True
- register: result
-
- - assert:
- that:
- - result.changed
-
- # TODO: test modifying db_subnet_group_name, db_security_groups, db_parameter_group_name, option_group_name,
- # monitoring_role_arn, monitoring_interval, domain, domain_iam_role_name, cloudwatch_logs_export_configuration
-
- - name: Modify several attributes
- rds_instance:
- id: '{{ instance_id }}'
- state: present
- allocated_storage: 30
- db_instance_class: "{{ modified_db_instance_class }}"
- backup_retention_period: 2
- preferred_backup_window: "05:00-06:00"
- preferred_maintenance_window: "mon:06:20-mon:06:50"
- engine_version: "{{ mariadb_engine_version_2 }}"
- allow_major_version_upgrade: true
- auto_minor_version_upgrade: false
- port: 1150
- max_allocated_storage: 100
- apply_immediately: True
- register: result
-
- - assert:
- that:
- - result.changed
- - '"allocated_storage" in result.pending_modified_values or result.allocated_storage == 30'
- - '"max_allocated_storage" in result.pending_modified_values or result.max_allocated_storage == 100'
- - '"port" in result.pending_modified_values or result.endpoint.port == 1150'
- - '"db_instance_class" in result.pending_modified_values or result.db_instance_class == modified_db_instance_class'
- - '"engine_version" in result.pending_modified_values or result.engine_version == mariadb_engine_version_2'
-
- - name: Idempotence modifying several pending attributes
- rds_instance:
- id: '{{ instance_id }}'
- state: present
- allocated_storage: 30
- db_instance_class: "{{ modified_db_instance_class }}"
- backup_retention_period: 2
- preferred_backup_window: "05:00-06:00"
- preferred_maintenance_window: "mon:06:20-mon:06:50"
- engine_version: "{{ mariadb_engine_version_2 }}"
- allow_major_version_upgrade: true
- auto_minor_version_upgrade: false
- port: 1150
- max_allocated_storage: 100
- register: result
- retries: 30
- delay: 10
- until: result is not failed
-
- - assert:
- that:
- - not result.changed
- - '"allocated_storage" in result.pending_modified_values or result.allocated_storage == 30'
- - '"max_allocated_storage" in result.pending_modified_values or result.max_allocated_storage == 100'
- - '"port" in result.pending_modified_values or result.endpoint.port == 1150'
- - '"db_instance_class" in result.pending_modified_values or result.db_instance_class == modified_db_instance_class'
- - '"engine_version" in result.pending_modified_values or result.engine_version == mariadb_engine_version_2'
-
- - name: Idempotence modifying several pending attributes - preferred_maintenance_window not lowercase
- rds_instance:
- id: '{{ instance_id }}'
- state: present
- allocated_storage: 30
- db_instance_class: "{{ modified_db_instance_class }}"
- backup_retention_period: 2
- preferred_backup_window: "05:00-06:00"
- preferred_maintenance_window: "Mon:06:20-Mon:06:50"
- engine_version: "10.2.21"
- allow_major_version_upgrade: true
- auto_minor_version_upgrade: false
- port: 1150
- max_allocated_storage: 100
- register: result
- retries: 30
- delay: 10
- until: result is not failed
-
- - assert:
- that:
- - not result.changed
- - '"allocated_storage" in result.pending_modified_values or result.allocated_storage == 30'
- - '"max_allocated_storage" in result.pending_modified_values or result.max_allocated_storage == 100'
- - '"port" in result.pending_modified_values or result.endpoint.port == 1150'
- - '"db_instance_class" in result.pending_modified_values or result.db_instance_class == "db.t2.medium"'
- - '"engine_version" in result.pending_modified_values or result.engine_version == "10.2.21"'
-
- - name: Delete the instance
- rds_instance:
- id: '{{ instance_id }}'
- state: absent
- skip_final_snapshot: True
- register: result
-
- - assert:
- that:
- - result.changed
- - '"pending_modified_values" not in result'
-
- always:
-
- - name: Delete the instance
- rds_instance:
- id: '{{ item }}'
- state: absent
- skip_final_snapshot: True
- loop: ['{{ instance_id }}', '{{ modified_instance_id }}']
- ignore_errors: yes
diff --git a/tests/integration/targets/rds_instance/roles/rds_instance/tasks/test_modify.yml b/tests/integration/targets/rds_instance/roles/rds_instance/tasks/test_modify.yml
new file mode 100644
index 00000000000..bfe04be2fbe
--- /dev/null
+++ b/tests/integration/targets/rds_instance/roles/rds_instance/tasks/test_modify.yml
@@ -0,0 +1,77 @@
+---
+#TODO: test availability_zone and multi_az
+- block:
+ - name: Ensure the resource doesn't exist
+ rds_instance:
+ id: "{{ instance_id }}"
+ state: absent
+ skip_final_snapshot: True
+ register: result
+
+ - assert:
+ that:
+ - not result.changed
+ ignore_errors: yes
+
+ - name: Create an enhanced monitoring role
+ iam_role:
+ assume_role_policy_document: "{{ lookup('file','files/enhanced_monitoring_assume_policy.json') }}"
+ name: "{{ instance_id }}-role"
+ state: present
+ managed_policy: "arn:aws:iam::aws:policy/service-role/AmazonRDSEnhancedMonitoringRole"
+ register: enhanced_monitoring_role
+
+ - name: Create a mariadb instance
+ rds_instance:
+ id: "{{ instance_id }}"
+ state: present
+ engine: mariadb
+ engine_version: "{{ mariadb_engine_version }}"
+ allow_major_version_upgrade: true
+ username: "{{ username }}"
+ password: "{{ password }}"
+ db_instance_class: "{{ db_instance_class }}"
+ allocated_storage: "{{ allocated_storage }}"
+ register: result
+
+ - assert:
+ that:
+ - result.changed
+ - "result.db_instance_identifier == '{{ instance_id }}'"
+
+ - name: Modify the instance name without immediate application
+ rds_instance:
+ id: "{{ instance_id }}"
+ state: present
+ new_id: "{{ modified_instance_id }}"
+ password: "{{ password }}"
+ apply_immediately: False
+ register: result
+
+ - assert:
+ that:
+ - result.changed
+ - 'result.db_instance_identifier == "{{ instance_id }}"'
+
+ - name: Immediately apply the pending update
+ rds_instance:
+ id: "{{ instance_id }}"
+ state: present
+ new_id: "{{ modified_instance_id }}"
+ apply_immediately: True
+ register: result
+
+ - assert:
+ that:
+ - result.changed
+ - 'result.db_instance_identifier == "{{ modified_instance_id }}"'
+
+ always:
+ - name: Delete the instance
+ rds_instance:
+ id: "{{ item }}"
+ state: absent
+ skip_final_snapshot: True
+ wait: false
+ loop: ["{{ instance_id }}", "{{ modified_instance_id }}"]
+ ignore_errors: yes
diff --git a/tests/integration/targets/rds_instance/roles/rds_instance/tasks/test_modify_complex.yml b/tests/integration/targets/rds_instance/roles/rds_instance/tasks/test_modify_complex.yml
new file mode 100644
index 00000000000..066d35c11d9
--- /dev/null
+++ b/tests/integration/targets/rds_instance/roles/rds_instance/tasks/test_modify_complex.yml
@@ -0,0 +1,113 @@
+---
+#TODO: test availability_zone and multi_az
+- block:
+ - name: Ensure the resource doesn't exist
+ rds_instance:
+ id: "{{ instance_id }}"
+ state: absent
+ skip_final_snapshot: True
+ register: result
+
+ - assert:
+ that:
+ - not result.changed
+ ignore_errors: yes
+
+ - name: Create an enhanced monitoring role
+ iam_role:
+ assume_role_policy_document: "{{ lookup('file','files/enhanced_monitoring_assume_policy.json') }}"
+ name: "{{ instance_id }}-role"
+ state: present
+ managed_policy: "arn:aws:iam::aws:policy/service-role/AmazonRDSEnhancedMonitoringRole"
+ register: enhanced_monitoring_role
+
+ - name: Create a mariadb instance
+ rds_instance:
+ id: "{{ instance_id }}"
+ state: present
+ engine: mariadb
+ engine_version: "{{ mariadb_engine_version }}"
+ allow_major_version_upgrade: true
+ username: "{{ username }}"
+ password: "{{ password }}"
+ db_instance_class: "{{ db_instance_class }}"
+ allocated_storage: "{{ allocated_storage }}"
+ register: result
+
+ - assert:
+ that:
+ - result.changed
+ - "result.db_instance_identifier == '{{ instance_id }}'"
+
+ # TODO: test modifying db_subnet_group_name, db_security_groups, db_parameter_group_name, option_group_name,
+ # monitoring_role_arn, monitoring_interval, domain, domain_iam_role_name, cloudwatch_logs_export_configuration
+
+ # Test multiple modifications including enabling enhanced monitoring
+
+ - name: Modify several attributes
+ rds_instance:
+ id: "{{ instance_id }}"
+ state: present
+ allocated_storage: 30
+ db_instance_class: "{{ modified_db_instance_class }}"
+ backup_retention_period: 2
+ preferred_backup_window: "05:00-06:00"
+ preferred_maintenance_window: "{{ preferred_maintenance_window }}"
+ engine_version: "{{ mariadb_engine_version_2 }}"
+ allow_major_version_upgrade: true
+ auto_minor_version_upgrade: false
+ monitoring_interval: "{{ monitoring_interval }}"
+ monitoring_role_arn: "{{ enhanced_monitoring_role.arn }}"
+ port: 1150
+ max_allocated_storage: 100
+ apply_immediately: True
+ register: result
+
+ - assert:
+ that:
+ - result.changed
+ - '"allocated_storage" in result.pending_modified_values or result.allocated_storage == 30'
+ - '"max_allocated_storage" in result.pending_modified_values or result.max_allocated_storage == 100'
+ - '"port" in result.pending_modified_values or result.endpoint.port == 1150'
+ - '"db_instance_class" in result.pending_modified_values or result.db_instance_class == modified_db_instance_class'
+ - '"engine_version" in result.pending_modified_values or result.engine_version == mariadb_engine_version_2'
+ - '"monitoring_interval" in result.pending_modified_values or result.monitoring_interval == monitoring_interval'
+
+ - name: Idempotence modifying several pending attributes
+ rds_instance:
+ id: "{{ instance_id }}"
+ state: present
+ allocated_storage: 30
+ db_instance_class: "{{ modified_db_instance_class }}"
+ backup_retention_period: 2
+ preferred_backup_window: "05:00-06:00"
+ preferred_maintenance_window: "{{ preferred_maintenance_window }}"
+ engine_version: "{{ mariadb_engine_version_2 }}"
+ allow_major_version_upgrade: true
+ auto_minor_version_upgrade: false
+ monitoring_interval: "{{ monitoring_interval }}"
+ monitoring_role_arn: "{{ enhanced_monitoring_role.arn }}"
+ port: 1150
+ max_allocated_storage: 100
+ register: result
+ retries: 30
+ delay: 10
+ until: result is not failed
+
+ - assert:
+ that:
+ - not result.changed
+ - '"allocated_storage" in result.pending_modified_values or result.allocated_storage == 30'
+ - '"max_allocated_storage" in result.pending_modified_values or result.max_allocated_storage == 100'
+ - '"port" in result.pending_modified_values or result.endpoint.port == 1150'
+ - '"db_instance_class" in result.pending_modified_values or result.db_instance_class == modified_db_instance_class'
+ - '"engine_version" in result.pending_modified_values or result.engine_version == mariadb_engine_version_2'
+
+ always:
+ - name: Delete the instance
+ rds_instance:
+ id: "{{ instance_id }}"
+ state: absent
+ skip_final_snapshot: True
+ wait: false
+ ignore_errors: yes
diff --git a/tests/integration/targets/rds_instance/roles/rds_instance/tasks/test_processor_features.yml b/tests/integration/targets/rds_instance/roles/rds_instance/tasks/test_processor_features.yml
index 78dd44be4f0..c0ba221cf34 100644
--- a/tests/integration/targets/rds_instance/roles/rds_instance/tasks/test_processor_features.yml
+++ b/tests/integration/targets/rds_instance/roles/rds_instance/tasks/test_processor_features.yml
@@ -23,14 +23,12 @@
db_instance_class: "{{ oracle_ee_db_instance_class }}"
allocated_storage: "{{ allocated_storage }}"
storage_encrypted: True
- processor_features: "{{ processor_features }}"
+ processor_features: {}
register: result
- assert:
that:
- result.changed
- - 'result.processor_features.coreCount == "{{ processor_features.coreCount }}"'
- - 'result.processor_features.threadsPerCore == "{{ processor_features.threadsPerCore }}"'
- name: Check mode - modify the processor features
rds_instance:
@@ -71,32 +69,6 @@
- 'result.pending_modified_values.processor_features.coreCount == "{{ modified_processor_features.coreCount }}"'
- 'result.pending_modified_values.processor_features.threadsPerCore == "{{ modified_processor_features.threadsPerCore }}"'
- - name: Check mode - use the default processor features
- rds_instance:
- id: "{{ instance_id }}"
- state: present
- processor_features: {}
- apply_immediately: True
- register: result
-
- - assert:
- that:
- - result.changed
-
- - name: Use the default processor features
- rds_instance:
- id: "{{ instance_id }}"
- state: present
- processor_features: {}
- apply_immediately: True
- register: result
-
- - assert:
- that:
- - result.changed
- - 'result.pending_modified_values.processor_features.coreCount == "DEFAULT"'
- - 'result.pending_modified_values.processor_features.threadsPerCore == "DEFAULT"'
-
always:
- name: Delete the DB instance
@@ -104,6 +76,7 @@
id: "{{ instance_id }}"
state: absent
skip_final_snapshot: True
+ wait: false
register: result
- assert:
diff --git a/tests/integration/targets/rds_instance/roles/rds_instance/tasks/test_read_replica.yml b/tests/integration/targets/rds_instance/roles/rds_instance/tasks/test_read_replica.yml
index 4aee2687d31..7ca19747dde 100644
--- a/tests/integration/targets/rds_instance/roles/rds_instance/tasks/test_read_replica.yml
+++ b/tests/integration/targets/rds_instance/roles/rds_instance/tasks/test_read_replica.yml
@@ -137,6 +137,7 @@
state: absent
skip_final_snapshot: True
region: "{{ region_src }}"
+ wait: false
ignore_errors: yes
- name: Remove the DB replica
@@ -145,4 +146,5 @@
state: absent
skip_final_snapshot: True
region: "{{ region_dest }}"
+ wait: false
ignore_errors: yes
diff --git a/tests/integration/targets/rds_instance/roles/rds_instance/tasks/test_restore_instance.yml b/tests/integration/targets/rds_instance/roles/rds_instance/tasks/test_restore_instance.yml
index 64a948211c3..3390f5759e7 100644
--- a/tests/integration/targets/rds_instance/roles/rds_instance/tasks/test_restore_instance.yml
+++ b/tests/integration/targets/rds_instance/roles/rds_instance/tasks/test_restore_instance.yml
@@ -16,7 +16,7 @@
- name: Create a source DB instance
rds_instance:
- id: "{{ instance_id }}"
+ id: "{{ instance_id }}-s"
state: present
engine: mysql
backup_retention_period: 1
@@ -29,13 +29,13 @@
- assert:
that:
- source_db.changed
- - "source_db.db_instance_identifier == '{{ instance_id }}'"
+ - "source_db.db_instance_identifier == '{{ instance_id }}-s'"
- name: Create a point in time DB instance
rds_instance:
- id: "{{ instance_id }}-point-in-time"
+ id: "{{ instance_id }}"
state: present
- source_db_instance_identifier: "{{ instance_id }}"
+ source_db_instance_identifier: "{{ instance_id }}-s"
creation_source: instance
engine: mysql
username: "{{ username }}"
@@ -47,9 +47,9 @@
- name: Test idempotence with a point in time replica
rds_instance:
- id: "{{ instance_id }}-point-in-time"
+ id: "{{ instance_id }}"
state: present
- source_db_instance_identifier: "{{ instance_id }}"
+ source_db_instance_identifier: "{{ instance_id }}-s"
creation_source: instance
engine: mysql
username: "{{ username }}"
@@ -62,20 +62,22 @@
- assert:
that:
- not result.changed
+ - "result.db_instance_identifier == '{{ instance_id }}'"
always:
- name: Remove the DB instance
rds_instance:
- id: "{{ instance_id }}"
+ id: "{{ instance_id }}-s"
state: absent
skip_final_snapshot: True
+ wait: false
ignore_errors: yes
-
- name: Remove the point in time restored DB
rds_instance:
- id: "{{ instance_id }}-point-in-time"
+ id: "{{ instance_id }}"
state: absent
skip_final_snapshot: True
+ wait: false
ignore_errors: yes
diff --git a/tests/integration/targets/rds_instance/roles/rds_instance/tasks/test_snapshot.yml b/tests/integration/targets/rds_instance/roles/rds_instance/tasks/test_snapshot.yml
deleted file mode 100644
index 131f9753e88..00000000000
--- a/tests/integration/targets/rds_instance/roles/rds_instance/tasks/test_snapshot.yml
+++ /dev/null
@@ -1,83 +0,0 @@
----
- - block:
-
- - name: Getting shared snapshots
- rds_snapshot_info:
- snapshot_type: "shared"
- register: result
-
- - assert:
- that:
- - not result.changed
- - result.cluster_snapshots is defined
- - result.snapshots is defined
-
- - name: Ensure the resource doesn't exist
- rds_instance:
- db_instance_identifier: "{{ instance_id }}"
- state: absent
- skip_final_snapshot: True
- register: result
-
- - assert:
- that:
- - not result.changed
- ignore_errors: yes
-
- - name: Create a mariadb instance
- rds_instance:
- db_instance_identifier: "{{ instance_id }}"
- state: present
- engine: mariadb
- username: "{{ username }}"
- password: "{{ password }}"
- db_instance_class: "{{ db_instance_class }}"
- allocated_storage: "{{ allocated_storage }}"
- tags:
- Name: "{{ instance_id }}"
- Created_by: Ansible rds_instance tests
- register: result
-
- - assert:
- that:
- - result.changed
- - "result.db_instance_identifier == '{{ instance_id }}'"
- - "result.tags | length == 2"
- - "result.tags.Name == '{{ instance_id }}'"
- - "result.tags.Created_by == 'Ansible rds_instance tests'"
-
- - name: Getting public snapshots
- rds_snapshot_info:
- db_instance_identifier: "{{ instance_id }}"
- snapshot_type: "public"
- register: result
-
- - assert:
- that:
- - not result.changed
- - result.cluster_snapshots is not defined
- - result.snapshots is defined
-
- - name: Ensure the resource doesn't exist
- rds_instance:
- db_instance_identifier: "{{ instance_id }}"
- state: absent
- skip_final_snapshot: True
- register: result
-
- - assert:
- that:
- - result.changed
-
- # TODO ideally we test with an actual shared snapshot - but we'd need a second account - making tests fairly complicated?
-
- always:
-
- - name: Delete the instance
- rds_instance:
- id: "{{ item }}"
- state: absent
- skip_final_snapshot: True
- loop:
- - "{{ instance_id }}"
- ignore_errors: yes
diff --git a/tests/integration/targets/rds_instance/roles/rds_instance/tasks/test_states.yml b/tests/integration/targets/rds_instance/roles/rds_instance/tasks/test_states.yml
index 7b16f81a183..0321dc99d7c 100644
--- a/tests/integration/targets/rds_instance/roles/rds_instance/tasks/test_states.yml
+++ b/tests/integration/targets/rds_instance/roles/rds_instance/tasks/test_states.yml
@@ -1,246 +1,159 @@
---
- - block:
-
- - name: Ensure the resource doesn't exist
- rds_instance:
- id: "{{ instance_id }}"
- state: absent
- skip_final_snapshot: True
- register: result
-
- - assert:
- that:
- - not result.changed
- ignore_errors: yes
-
- - name: Check Mode - Create a mariadb instance
- rds_instance:
- id: "{{ instance_id }}"
- state: present
- engine: mariadb
- username: "{{ username }}"
- password: "{{ password }}"
- db_instance_class: "{{ db_instance_class }}"
- allocated_storage: "{{ allocated_storage }}"
- register: result
- check_mode: yes
-
- - assert:
- that:
- - result.changed
-
- - name: Create a mariadb instance
- rds_instance:
- id: "{{ instance_id }}"
- state: present
- engine: mariadb
- username: "{{ username }}"
- password: "{{ password }}"
- db_instance_class: "{{ db_instance_class }}"
- allocated_storage: "{{ allocated_storage }}"
- register: result
-
- - assert:
- that:
- - result.changed
- - "result.db_instance_identifier == '{{ instance_id }}'"
-
- - name: Idempotence
- rds_instance:
- id: '{{ instance_id }}'
- state: present
- engine: mariadb
- username: "{{ username }}"
- password: "{{ password }}"
- db_instance_class: "{{ db_instance_class }}"
- allocated_storage: "{{ allocated_storage }}"
- register: result
-
- - assert:
- that:
- - not result.changed
- - result.db_instance_identifier
-
- - name: Idempotence with minimal options
- rds_instance:
- id: '{{ instance_id }}'
- state: present
- register: result
-
- - assert:
- that:
- - not result.changed
- - result.db_instance_identifier
-
- - name: Check Mode - stop the instance
- rds_instance:
- id: '{{ instance_id }}'
- state: stopped
- register: result
- check_mode: yes
-
- - assert:
- that:
- - result.changed
-
- - name: Stop the instance
- rds_instance:
- id: '{{ instance_id }}'
- state: stopped
- register: result
-
- - assert:
- that:
- - result.changed
-
- - name: Check Mode - idempotence
- rds_instance:
- id: '{{ instance_id }}'
- state: stopped
- register: result
- check_mode: yes
-
- - assert:
- that:
- - not result.changed
-
- - name: Idempotence
- rds_instance:
- id: '{{ instance_id }}'
- state: stopped
- register: result
-
- - assert:
- that:
- - not result.changed
-
- - name: Check mode - reboot a stopped instance
- rds_instance:
- id: '{{ instance_id }}'
- state: rebooted
- register: result
- check_mode: yes
-
- - assert:
- that:
- - result.changed
-
- - name: Reboot a stopped instance
- rds_instance:
- id: '{{ instance_id }}'
- state: rebooted
- register: result
-
- - assert:
- that:
- - result.changed
-
- - name: Check Mode - start the instance
- rds_instance:
- id: '{{ instance_id }}'
- state: started
- register: result
- check_mode: yes
-
- - assert:
- that:
- - not result.changed
-
- - name: Stop the instance
- rds_instance:
- id: '{{ instance_id }}'
- state: stopped
-
- - name: Start the instance
- rds_instance:
- id: '{{ instance_id }}'
- state: started
- register: result
-
- - assert:
- that:
- - result.changed
-
- - name: take a snapshot
- rds_snapshot:
- db_instance_identifier: '{{ instance_id }}'
- db_snapshot_identifier: '{{ resource_prefix }}-test-snapshot'
- state: present
- wait: yes
-
- - name: take a snapshot - idempotence
- rds_snapshot:
- db_instance_identifier: '{{ instance_id }}'
- db_snapshot_identifier: '{{ resource_prefix }}-test-snapshot'
- state: present
- register: result
-
- - assert:
- that:
- - not result.changed
-
- - name: check snapshot is ok
- rds_snapshot_info:
- db_snapshot_identifier: '{{ resource_prefix }}-test-snapshot'
- register: result
-
- - assert:
- that:
- - (result.snapshots | length) == 1
-
- - name: remove a snapshot without wait
- rds_snapshot:
- db_snapshot_identifier: '{{ resource_prefix }}-test-snapshot'
- state: absent
- register: result
-
- - assert:
- that:
- - result.changed
-
- - name: remove a snapshot without wait - idempotence
- rds_snapshot:
- db_snapshot_identifier: '{{ resource_prefix }}-test-snapshot'
- state: absent
- wait: yes
- register: result
-
- - assert:
- that:
- - not result.changed
-
- - name: remove a snapshot with wait - idempotence
- rds_snapshot:
- db_snapshot_identifier: '{{ resource_prefix }}-test-snapshot'
- state: absent
- wait: yes
- register: result
-
- - assert:
- that:
- - not result.changed
-
- - name: check snapshot is removed
- rds_snapshot_info:
- db_snapshot_identifier: '{{ resource_prefix }}-test-snapshot'
- register: result
-
- - assert:
- that:
- - not result.snapshots
-
- always:
-
- - name: remove snapshot
- rds_snapshot:
- db_snapshot_identifier: '{{ resource_prefix }}-test-snapshot'
- state: absent
- wait: yes
- ignore_errors: yes
-
- - name: Remove DB instance
- rds_instance:
- id: '{{ instance_id }}'
- state: absent
- skip_final_snapshot: True
- ignore_errors: yes
+- block:
+ - name: Ensure the resource doesn't exist
+ rds_instance:
+ id: "{{ instance_id }}"
+ state: absent
+ skip_final_snapshot: True
+ register: result
+
+ - assert:
+ that:
+ - not result.changed
+ ignore_errors: yes
+
+ - name: Create a mariadb instance
+ rds_instance:
+ id: "{{ instance_id }}"
+ state: present
+ engine: mariadb
+ username: "{{ username }}"
+ password: "{{ password }}"
+ db_instance_class: "{{ db_instance_class }}"
+ allocated_storage: "{{ allocated_storage }}"
+ tags:
+ Name: "{{ instance_id }}"
+ Created_by: Ansible rds_instance tests
+ register: result
+
+ - assert:
+ that:
+ - result.changed
+ - "result.db_instance_identifier == '{{ instance_id }}'"
+ - "result.tags | length == 2"
+ - "result.tags.Name == '{{ instance_id }}'"
+ - "result.tags.Created_by == 'Ansible rds_instance tests'"
+
+ # Test stopping / rebooting instances
+ - name: Check mode - reboot a stopped instance
+ rds_instance:
+ id: "{{ instance_id }}"
+ state: rebooted
+ register: result
+ check_mode: yes
+
+ - assert:
+ that:
+ - result.changed
+
+ - name: Reboot a stopped instance
+ rds_instance:
+ id: "{{ instance_id }}"
+ state: rebooted
+ register: result
+
+ - assert:
+ that:
+ - result.changed
+
+ - name: Check Mode - stop the instance
+ rds_instance:
+ id: "{{ instance_id }}"
+ state: stopped
+ register: result
+ check_mode: yes
+
+ - assert:
+ that:
+ - result.changed
+
+ - name: Stop the instance
+ rds_instance:
+ id: "{{ instance_id }}"
+ state: stopped
+ register: result
+
+ - assert:
+ that:
+ - result.changed
+
+ - name: Check Mode - idempotence
+ rds_instance:
+ id: "{{ instance_id }}"
+ state: stopped
+ register: result
+ check_mode: yes
+
+ - assert:
+ that:
+ - not result.changed
+
+ - name: Idempotence
+ rds_instance:
+ id: "{{ instance_id }}"
+ state: stopped
+ register: result
+
+ - assert:
+ that:
+ - not result.changed
+
+ - name: Check Mode - start the instance
+ rds_instance:
+ id: "{{ instance_id }}"
+ state: started
+ register: result
+ check_mode: yes
+
+ - assert:
+ that:
+ - result.changed
+
+ - name: Start the instance
+ rds_instance:
+ id: "{{ instance_id }}"
+ state: started
+ register: result
+
+ - assert:
+ that:
+ - result.changed
+
+ # Test final snapshot on deletion
+ - name: Delete the DB instance
+ rds_instance:
+ id: "{{ instance_id }}"
+ state: absent
+ final_snapshot_identifier: "{{ instance_id }}"
+ register: result
+
+ - assert:
+ that:
+ - result.changed
+ - "result.final_snapshot.db_instance_identifier == '{{ instance_id }}'"
+
+ - name: Check that snapshot exists
+ rds_snapshot_info:
+ db_snapshot_identifier: "{{ instance_id }}"
+ register: result
+
+ - assert:
+ that:
+ - "result.snapshots | length == 1"
+ - "result.snapshots.0.engine == 'mariadb'"
+
+ always:
+ - name: remove snapshot
+ rds_snapshot:
+ db_snapshot_identifier: "{{ resource_prefix }}-test-snapshot"
+ state: absent
+ wait: false
+ ignore_errors: yes
+
+ - name: Remove DB instance
+ rds_instance:
+ id: "{{ instance_id }}"
+ state: absent
+ skip_final_snapshot: True
+ wait: false
+ ignore_errors: yes
diff --git a/tests/integration/targets/rds_instance/roles/rds_instance/tasks/test_tagging.yml b/tests/integration/targets/rds_instance/roles/rds_instance/tasks/test_tagging.yml
new file mode 100644
index 00000000000..0cdd9c1b7a5
--- /dev/null
+++ b/tests/integration/targets/rds_instance/roles/rds_instance/tasks/test_tagging.yml
@@ -0,0 +1,129 @@
+---
+- block:
+ - name: Ensure the resource doesn't exist
+ rds_instance:
+ id: "{{ instance_id }}"
+ state: absent
+ skip_final_snapshot: True
+ register: result
+
+ - assert:
+ that:
+ - not result.changed
+ ignore_errors: yes
+
+ # Test invalid bad options
+ - name: Create a DB instance with an invalid engine
+ rds_instance:
+ id: "{{ instance_id }}"
+ state: present
+ engine: thisisnotavalidengine
+ username: "{{ username }}"
+ password: "{{ password }}"
+ db_instance_class: "{{ db_instance_class }}"
+ allocated_storage: "{{ allocated_storage }}"
+ register: result
+ ignore_errors: True
+
+ - assert:
+ that:
+ - result.failed
+ - '"DB engine thisisnotavalidengine should be one of" in result.msg'
+
+ # Test creation, adding tags and enabling encryption
+ - name: Create a mariadb instance
+ rds_instance:
+ id: "{{ instance_id }}"
+ state: present
+ engine: mariadb
+ username: "{{ username }}"
+ password: "{{ password }}"
+ db_instance_class: "{{ db_instance_class }}"
+ allocated_storage: "{{ allocated_storage }}"
+ storage_encrypted: True
+ tags:
+ Name: "{{ instance_id }}"
+ Created_by: Ansible rds_instance tests
+ register: result
+
+ - assert:
+ that:
+ - result.changed
+ - "result.db_instance_identifier == '{{ instance_id }}'"
+ - "result.tags | length == 2"
+ - "result.tags.Name == '{{ instance_id }}'"
+ - "result.tags.Created_by == 'Ansible rds_instance tests'"
+ - result.kms_key_id
+ - result.storage_encrypted == true
+
+ - name: Test impotency omitting tags
+ rds_instance:
+ id: "{{ instance_id }}"
+ state: present
+ engine: mariadb
+ username: "{{ username }}"
+ password: "{{ password }}"
+ db_instance_class: "{{ db_instance_class }}"
+ allocated_storage: "{{ allocated_storage }}"
+ register: result
+
+ - assert:
+ that:
+ - not result.changed
+ - result.db_instance_identifier
+ - "result.tags | length == 2"
+
+ - name: Idempotence with minimal options
+ rds_instance:
+ id: "{{ instance_id }}"
+ state: present
+ register: result
+
+ - assert:
+ that:
+ - not result.changed
+ - result.db_instance_identifier
+ - "result.tags | length == 2"
+
+ - name: Test tags are not purged if purge_tags is False
+ rds_instance:
+ db_instance_identifier: "{{ instance_id }}"
+ state: present
+ engine: mariadb
+ username: "{{ username }}"
+ password: "{{ password }}"
+ db_instance_class: "{{ db_instance_class }}"
+ allocated_storage: "{{ allocated_storage }}"
+ tags: {}
+ purge_tags: False
+ register: result
+
+ - assert:
+ that:
+ - not result.changed
+ - "result.tags | length == 2"
+
+ - name: Add a tag and remove a tag
+ rds_instance:
+ db_instance_identifier: "{{ instance_id }}"
+ state: present
+ tags:
+ Name: "{{ instance_id }}-new"
+ Created_by: Ansible rds_instance tests
+ purge_tags: True
+ register: result
+
+ - assert:
+ that:
+ - result.changed
+ - "result.tags | length == 2"
+ - "result.tags.Name == '{{ instance_id }}-new'"
+
+ always:
+ - name: Remove DB instance
+ rds_instance:
+ id: "{{ instance_id }}"
+ state: absent
+ skip_final_snapshot: True
+ wait: false
+ ignore_errors: yes
diff --git a/tests/integration/targets/rds_instance/roles/rds_instance/tasks/test_tags.yml b/tests/integration/targets/rds_instance/roles/rds_instance/tasks/test_tags.yml
deleted file mode 100644
index 353daec1f31..00000000000
--- a/tests/integration/targets/rds_instance/roles/rds_instance/tasks/test_tags.yml
+++ /dev/null
@@ -1,241 +0,0 @@
----
- - block:
-
- - name: Ensure the resource doesn't exist
- rds_instance:
- db_instance_identifier: "{{ instance_id }}"
- state: absent
- skip_final_snapshot: True
- register: result
-
- - assert:
- that:
- - not result.changed
- ignore_errors: yes
-
- - name: Create a mariadb instance
- rds_instance:
- db_instance_identifier: "{{ instance_id }}"
- state: present
- engine: mariadb
- username: "{{ username }}"
- password: "{{ password }}"
- db_instance_class: "{{ db_instance_class }}"
- allocated_storage: "{{ allocated_storage }}"
- tags:
- Name: "{{ instance_id }}"
- Created_by: Ansible rds_instance tests
- register: result
-
- - assert:
- that:
- - result.changed
- - "result.db_instance_identifier == '{{ instance_id }}'"
- - "result.tags | length == 2"
- - "result.tags.Name == '{{ instance_id }}'"
- - "result.tags.Created_by == 'Ansible rds_instance tests'"
-
- - name: Test idempotence omitting tags
- rds_instance:
- db_instance_identifier: "{{ instance_id }}"
- state: present
- engine: mariadb
- username: "{{ username }}"
- password: "{{ password }}"
- db_instance_class: "{{ db_instance_class }}"
- allocated_storage: "{{ allocated_storage }}"
- register: result
-
- - assert:
- that:
- - not result.changed
- - "result.tags | length == 2"
-
- - name: Test tags are not purged if purge_tags is False
- rds_instance:
- db_instance_identifier: "{{ instance_id }}"
- state: present
- engine: mariadb
- username: "{{ username }}"
- password: "{{ password }}"
- db_instance_class: "{{ db_instance_class }}"
- allocated_storage: "{{ allocated_storage }}"
- tags: {}
- purge_tags: False
- register: result
-
- - assert:
- that:
- - not result.changed
- - "result.tags | length == 2"
-
- - name: Add a tag and remove a tag
- rds_instance:
- db_instance_identifier: "{{ instance_id }}"
- state: present
- tags:
- Name: "{{ instance_id }}-new"
- Created_by: Ansible rds_instance tests
- purge_tags: True
- register: result
-
- - assert:
- that:
- - result.changed
- - "result.tags | length == 2"
- - "result.tags.Name == '{{ instance_id }}-new'"
-
- - name: Remove all tags
- rds_instance:
- db_instance_identifier: "{{ instance_id }}"
- state: present
- engine: mariadb
- username: "{{ username }}"
- password: "{{ password }}"
- db_instance_class: "{{ db_instance_class }}"
- allocated_storage: "{{ allocated_storage }}"
- tags: {}
- register: result
-
- - assert:
- that:
- - result.changed
- - not result.tags
-
- - name: snapshot instance without tags
- rds_snapshot:
- db_instance_identifier: "{{ instance_id }}"
- db_snapshot_identifier: "{{ resource_prefix }}-test-tags"
- state: present
- wait: yes
- register: result
-
- - assert:
- that:
- - result.changed
- - not result.tags
-
- - name: add tags to snapshot
- rds_snapshot:
- db_instance_identifier: "{{ instance_id }}"
- db_snapshot_identifier: "{{ resource_prefix }}-test-tags"
- state: present
- tags:
- one: hello
- two: world
- register: result
-
- - assert:
- that:
- - result.changed
- - result.tags | length == 2
-
- - name: add tags to snapshot - idempotence
- rds_snapshot:
- db_instance_identifier: "{{ instance_id }}"
- db_snapshot_identifier: "{{ resource_prefix }}-test-tags"
- state: present
- tags:
- one: hello
- two: world
- register: result
-
- - assert:
- that:
- - not result.changed
- - result.tags | length == 2
-
- - name: add tag to snapshot using purge_tags False
- rds_snapshot:
- db_instance_identifier: "{{ instance_id }}"
- db_snapshot_identifier: "{{ resource_prefix }}-test-tags"
- state: present
- tags:
- one: hello
- three: another
- purge_tags: False
- register: result
-
- - assert:
- that:
- - result.changed
- - result.tags | length == 3
-
- - name: rerun tags but not setting purge_tags
- rds_snapshot:
- db_instance_identifier: "{{ instance_id }}"
- db_snapshot_identifier: "{{ resource_prefix }}-test-tags"
- state: present
- tags:
- one: hello
- three: another
- register: result
-
- - assert:
- that:
- - result.changed
- - result.tags | length == 2
-
- - name: rerun tags but not setting purge_tags - idempotence
- rds_snapshot:
- db_instance_identifier: "{{ instance_id }}"
- db_snapshot_identifier: "{{ resource_prefix }}-test-tags"
- state: present
- tags:
- one: hello
- three: another
- register: result
-
- - assert:
- that:
- - not result.changed
- - result.tags | length == 2
-
- - name: remove snapshot
- rds_snapshot:
- db_instance_identifier: "{{ instance_id }}"
- db_snapshot_identifier: "{{ resource_prefix }}-test-tags"
- state: absent
- wait: yes
- register: result
-
- - assert:
- that:
- - result.changed
-
- - name: create snapshot with tags
- rds_snapshot:
- db_instance_identifier: "{{ instance_id }}"
- db_snapshot_identifier: "{{ resource_prefix }}-test-tags"
- state: present
- tags:
- one: hello
- three: another
- purge_tags: yes
- wait: yes
- register: result
-
- - assert:
- that:
- - result.changed
- - result.tags | length == 2
-
- always:
-
- - name: tidy up snapshot
- rds_snapshot:
- db_instance_identifier: "{{ instance_id }}"
- db_snapshot_identifier: "{{ resource_prefix }}-test-tags"
- state: absent
- ignore_errors: yes
-
- - name: Ensure the resource doesn't exist
- rds_instance:
- db_instance_identifier: "{{ instance_id }}"
- state: absent
- skip_final_snapshot: True
- register: result
-
- - assert:
- that:
- - result.changed
diff --git a/tests/integration/targets/rds_instance/roles/rds_instance/tasks/test_vpc_security_groups.yml b/tests/integration/targets/rds_instance/roles/rds_instance/tasks/test_vpc_security_groups.yml
index 940ce5b0fae..d797d965323 100644
--- a/tests/integration/targets/rds_instance/roles/rds_instance/tasks/test_vpc_security_groups.yml
+++ b/tests/integration/targets/rds_instance/roles/rds_instance/tasks/test_vpc_security_groups.yml
@@ -192,11 +192,3 @@
retries: 30
until: vpc_result is not failed
delay: 10
-
- - name: Ensure the resource doesn't exist
- rds_instance:
- id: "{{ instance_id }}"
- state: absent
- skip_final_snapshot: True
- register: result
- ignore_errors: yes
diff --git a/tests/integration/targets/redshift/defaults/main.yml b/tests/integration/targets/redshift/defaults/main.yml
index 61d01727e5e..18046aa1f5e 100644
--- a/tests/integration/targets/redshift/defaults/main.yml
+++ b/tests/integration/targets/redshift/defaults/main.yml
@@ -1,7 +1,6 @@
---
# defaults file for test_redshift
-unique_id: "{{ resource_prefix | hash('md5') }}"
-redshift_cluster_name: 'ansible-test-{{ unique_id }}'
+redshift_cluster_name: 'ansible-test-{{ tiny_prefix }}'
reshift_master_password: "th1s_is_A_test"
redshift_master_username: "master_user"
node_type: "dc2.large"
diff --git a/tests/integration/targets/redshift_subnet_group/aliases b/tests/integration/targets/redshift_subnet_group/aliases
new file mode 100644
index 00000000000..4ef4b2067d0
--- /dev/null
+++ b/tests/integration/targets/redshift_subnet_group/aliases
@@ -0,0 +1 @@
+cloud/aws
diff --git a/tests/integration/targets/redshift_subnet_group/defaults/main.yml b/tests/integration/targets/redshift_subnet_group/defaults/main.yml
new file mode 100644
index 00000000000..ea8921880a9
--- /dev/null
+++ b/tests/integration/targets/redshift_subnet_group/defaults/main.yml
@@ -0,0 +1,42 @@
+---
+availability_zone: '{{ ec2_availability_zone_names[0] }}'
+
+vpc_name: '{{ resource_prefix }}'
+subnet_name_a: '{{ resource_prefix }}-a'
+subnet_name_b: '{{ resource_prefix }}-b'
+subnet_name_c: '{{ resource_prefix }}-c'
+subnet_name_d: '{{ resource_prefix }}-d'
+
+vpc_cidr: '10.{{ 256 | random(seed=resource_prefix) }}.0.0/16'
+subnet_cidr_a: '10.{{ 256 | random(seed=resource_prefix) }}.1.0/24'
+subnet_cidr_b: '10.{{ 256 | random(seed=resource_prefix) }}.2.0/24'
+subnet_cidr_c: '10.{{ 256 | random(seed=resource_prefix) }}.3.0/24'
+subnet_cidr_d: '10.{{ 256 | random(seed=resource_prefix) }}.4.0/24'
+
+subnet_zone_a: '{{ ec2_availability_zone_names[0] }}'
+subnet_zone_b: '{{ ec2_availability_zone_names[1] }}'
+subnet_zone_c: '{{ ec2_availability_zone_names[0] }}'
+subnet_zone_d: '{{ ec2_availability_zone_names[1] }}'
+
+group_name: '{{ resource_prefix }}'
+description_default: 'Subnet Description'
+description_updated: 'updated subnet description'
+
+# Tagging not currently supported, planned with boto3 upgrade
+tags_default:
+ snake_case_key: snake_case_value
+ camelCaseKey: camelCaseValue
+ PascalCaseKey: PascalCaseValue
+ 'key with spaces': value with spaces
+ 'Upper With Spaces': Upper With Spaces
+
+partial_tags:
+ snake_case_key: snake_case_value
+ camelCaseKey: camelCaseValue
+
+updated_tags:
+ updated_snake_case_key: updated_snake_case_value
+ updatedCamelCaseKey: updatedCamelCaseValue
+ UpdatedPascalCaseKey: UpdatedPascalCaseValue
+ 'updated key with spaces': updated value with spaces
+ 'updated Upper With Spaces': Updated Upper With Spaces
diff --git a/tests/integration/targets/redshift_subnet_group/meta/main.yml b/tests/integration/targets/redshift_subnet_group/meta/main.yml
new file mode 100644
index 00000000000..930e8622824
--- /dev/null
+++ b/tests/integration/targets/redshift_subnet_group/meta/main.yml
@@ -0,0 +1,3 @@
+dependencies:
+ - prepare_tests
+ - setup_ec2_facts
diff --git a/tests/integration/targets/redshift_subnet_group/tasks/main.yml b/tests/integration/targets/redshift_subnet_group/tasks/main.yml
new file mode 100644
index 00000000000..e15ee9b9313
--- /dev/null
+++ b/tests/integration/targets/redshift_subnet_group/tasks/main.yml
@@ -0,0 +1,692 @@
+---
+# redshift_subnet_group integration tests
+#
+# Current module limitations:
+# - check_mode not supported
+# - Tagging not supported
+# - Module is not idempotent
+# - Returned values *very* limited
+#
+- module_defaults:
+ group/aws:
+ aws_access_key: '{{ aws_access_key }}'
+ aws_secret_key: '{{ aws_secret_key }}'
+ security_token: '{{ security_token | default(omit) }}'
+ region: '{{ aws_region }}'
+ block:
+
+ # ============================================================
+
+ - name: Create Subnet Group with no subnets - check_mode
+ redshift_subnet_group:
+ state: present
+ name: '{{ group_name }}'
+ register: create_group
+ ignore_errors: True
+ check_mode: True
+
+ - name: Check result - Create Subnet Group with no subnets - check_mode
+ assert:
+ that:
+ - create_group is failed
+ # Check we caught the issue before trying to create
+ - '"CreateClusterSubnetGroup" not in create_group.resource_actions'
+ # Check that we don't refer to the boto3 parameter
+ - '"subnetIds" not in create_group.msg'
+ # Loosely check the message
+ - '"subnet" in create_group.msg'
+ - '"At least" in create_group.msg'
+
+ - name: Create Subnet Group with no subnets
+ redshift_subnet_group:
+ state: present
+ name: '{{ group_name }}'
+ register: create_group
+ ignore_errors: True
+
+ - name: Check result - Create Subnet Group with no subnets
+ assert:
+ that:
+ - create_group is failed
+ # Check we caught the issue before trying to create
+ - '"CreateClusterSubnetGroup" not in create_group.resource_actions'
+ # Check that we don't refer to the boto3 parameter
+ - '"subnetIds" not in create_group.msg'
+ # Loosely check the message
+ - '"subnet" in create_group.msg'
+ - '"At least" in create_group.msg'
+
+ # ============================================================
+ # Setup infra needed for tests
+ - name: create a VPC
+ ec2_vpc_net:
+ state: present
+ name: '{{ vpc_name }}'
+ cidr_block: '{{ vpc_cidr }}'
+ tags:
+ TestPrefix: '{{ resource_prefix }}'
+ register: vpc_result
+
+ - name: create subnets
+ ec2_vpc_subnet:
+ state: present
+ cidr: '{{ item.cidr }}'
+ az: '{{ item.zone }}'
+ vpc_id: '{{ vpc_result.vpc.id }}'
+ tags:
+ Name: '{{ item.name }}'
+ TestPrefix: '{{ resource_prefix }}'
+ register: vpc_subnet_create
+ loop:
+ - name: '{{ subnet_name_a }}'
+ cidr: '{{ subnet_cidr_a }}'
+ zone: '{{ subnet_zone_a }}'
+ - name: '{{ subnet_name_b }}'
+ cidr: '{{ subnet_cidr_b }}'
+ zone: '{{ subnet_zone_b }}'
+ - name: '{{ subnet_name_c }}'
+ cidr: '{{ subnet_cidr_c }}'
+ zone: '{{ subnet_zone_c }}'
+ - name: '{{ subnet_name_d }}'
+ cidr: '{{ subnet_cidr_d }}'
+ zone: '{{ subnet_zone_d }}'
+
+ - name: Store IDs of subnets and VPC
+ set_fact:
+ vpc_id: '{{ vpc_result.vpc.id }}'
+ subnet_id_a: '{{ vpc_subnet_create.results[0].subnet.id }}'
+ subnet_id_b: '{{ vpc_subnet_create.results[1].subnet.id }}'
+ subnet_id_c: '{{ vpc_subnet_create.results[2].subnet.id }}'
+ subnet_id_d: '{{ vpc_subnet_create.results[3].subnet.id }}'
+
+ # ============================================================
+
+ - name: Create Subnet Group - check_mode
+ redshift_subnet_group:
+ state: present
+ group_name: '{{ group_name }}'
+ group_description: '{{ description_default }}'
+ group_subnets:
+ - '{{ subnet_id_a }}'
+ - '{{ subnet_id_b }}'
+ register: create_group
+ check_mode: True
+
+ - name: Check result - Create Subnet Group - check_mode
+ assert:
+ that:
+ - create_group is successful
+ - create_group is changed
+
+ - name: Create Subnet Group
+ redshift_subnet_group:
+ state: present
+ group_name: '{{ group_name }}'
+ group_description: '{{ description_default }}'
+ group_subnets:
+ - '{{ subnet_id_a }}'
+ - '{{ subnet_id_b }}'
+ register: create_group
+
+ - name: Check result - Create Subnet Group
+ assert:
+ that:
+ - create_group is successful
+ - create_group is changed
+ - '"group" in create_group'
+ - '"name" in create_group.group'
+ - '"vpc_id" in create_group.group'
+ - create_group.group.name == group_name
+ - create_group.group.vpc_id == vpc_id
+ - '"cluster_subnet_group" in create_group'
+ - '"description" in create_group.cluster_subnet_group'
+ - '"subnet_ids" in create_group.cluster_subnet_group'
+ - '"vpc_id" in create_group.cluster_subnet_group'
+ - create_group.cluster_subnet_group.name == group_name
+ - create_group.cluster_subnet_group.description == description_default
+ - subnet_id_a in create_group.cluster_subnet_group.subnet_ids
+ - subnet_id_b in create_group.cluster_subnet_group.subnet_ids
+ - subnet_id_c not in create_group.cluster_subnet_group.subnet_ids
+ - subnet_id_d not in create_group.cluster_subnet_group.subnet_ids
+ - create_group.cluster_subnet_group.vpc_id == vpc_id
+
+ - name: Create Subnet Group - idempotency - check_mode
+ redshift_subnet_group:
+ state: present
+ group_name: '{{ group_name }}'
+ group_description: '{{ description_default }}'
+ group_subnets:
+ - '{{ subnet_id_a }}'
+ - '{{ subnet_id_b }}'
+ register: create_group
+ check_mode: True
+
+ - name: Check result - Create Subnet Group - idempotency - check_mode
+ assert:
+ that:
+ - create_group is successful
+ - create_group is not changed
+
+ - name: Create Subnet Group - idempotency
+ redshift_subnet_group:
+ state: present
+ group_name: '{{ group_name }}'
+ group_description: '{{ description_default }}'
+ group_subnets:
+ - '{{ subnet_id_a }}'
+ - '{{ subnet_id_b }}'
+ register: create_group
+
+ - name: Check result - Create Subnet Group - idempotency
+ assert:
+ that:
+ - create_group is successful
+ - create_group is not changed
+ - '"group" in create_group'
+ - '"name" in create_group.group'
+ - '"vpc_id" in create_group.group'
+ - create_group.group.name == group_name
+ - create_group.group.vpc_id == vpc_id
+ - '"cluster_subnet_group" in create_group'
+ - '"description" in create_group.cluster_subnet_group'
+ - '"subnet_ids" in create_group.cluster_subnet_group'
+ - '"vpc_id" in create_group.cluster_subnet_group'
+ - create_group.cluster_subnet_group.name == group_name
+ - create_group.cluster_subnet_group.description == description_default
+ - subnet_id_a in create_group.cluster_subnet_group.subnet_ids
+ - subnet_id_b in create_group.cluster_subnet_group.subnet_ids
+ - subnet_id_c not in create_group.cluster_subnet_group.subnet_ids
+ - subnet_id_d not in create_group.cluster_subnet_group.subnet_ids
+ - create_group.cluster_subnet_group.vpc_id == vpc_id
+
+ # ============================================================
+
+ - name: Update Subnet Group Description - check_mode
+ redshift_subnet_group:
+ state: present
+ group_name: '{{ group_name }}'
+ group_description: '{{ description_updated }}'
+ ## No longer mandatory
+ # group_subnets:
+ # - '{{ subnet_id_a }}'
+ # - '{{ subnet_id_b }}'
+ register: update_description
+ check_mode: True
+
+ - name: Check result - Update Subnet Group Description - check_mode
+ assert:
+ that:
+ - update_description is successful
+ - update_description is changed
+
+ - name: Update Subnet Group Description
+ redshift_subnet_group:
+ state: present
+ group_name: '{{ group_name }}'
+ group_description: '{{ description_updated }}'
+ ## No longer mandatory
+ # group_subnets:
+ # - '{{ subnet_id_a }}'
+ # - '{{ subnet_id_b }}'
+ register: update_description
+
+ - name: Check result - Update Subnet Group Description
+ assert:
+ that:
+ - update_description is successful
+ - update_description is changed
+ - '"group" in update_description'
+ - '"name" in update_description.group'
+ - '"vpc_id" in update_description.group'
+ - update_description.group.name == group_name
+ - update_description.group.vpc_id == vpc_id
+ - '"cluster_subnet_group" in update_description'
+ - '"description" in update_description.cluster_subnet_group'
+ - '"subnet_ids" in update_description.cluster_subnet_group'
+ - '"vpc_id" in update_description.cluster_subnet_group'
+ - update_description.cluster_subnet_group.name == group_name
+ - update_description.cluster_subnet_group.description == description_updated
+ - subnet_id_a in update_description.cluster_subnet_group.subnet_ids
+ - subnet_id_b in update_description.cluster_subnet_group.subnet_ids
+ - subnet_id_c not in update_description.cluster_subnet_group.subnet_ids
+ - subnet_id_d not in update_description.cluster_subnet_group.subnet_ids
+ - update_description.cluster_subnet_group.vpc_id == vpc_id
+
+ - name: Update Subnet Group Description - idempotency - check_mode
+ redshift_subnet_group:
+ state: present
+ group_name: '{{ group_name }}'
+ group_description: '{{ description_updated }}'
+ ## No longer mandatory
+ # group_subnets:
+ # - '{{ subnet_id_a }}'
+ # - '{{ subnet_id_b }}'
+ register: update_description
+ check_mode: True
+
+ - name: Check result - Update Subnet Group Description - idempotency - check_mode
+ assert:
+ that:
+ - update_description is successful
+ - update_description is not changed
+
+ - name: Update Subnet Group Description - idempotency
+ redshift_subnet_group:
+ state: present
+ group_name: '{{ group_name }}'
+ group_description: '{{ description_updated }}'
+ ## No longer mandatory
+ # group_subnets:
+ # - '{{ subnet_id_a }}'
+ # - '{{ subnet_id_b }}'
+ register: update_description
+
+ - name: Check result - Update Subnet Group Description - idempotency
+ assert:
+ that:
+ - update_description is successful
+ - update_description is not changed
+ - '"group" in update_description'
+ - '"name" in update_description.group'
+ - '"vpc_id" in update_description.group'
+ - update_description.group.name == group_name
+ - update_description.group.vpc_id == vpc_id
+ - '"cluster_subnet_group" in update_description'
+ - '"description" in update_description.cluster_subnet_group'
+ - '"subnet_ids" in update_description.cluster_subnet_group'
+ - '"vpc_id" in update_description.cluster_subnet_group'
+ - update_description.cluster_subnet_group.name == group_name
+ - update_description.cluster_subnet_group.description == description_updated
+ - subnet_id_a in update_description.cluster_subnet_group.subnet_ids
+ - subnet_id_b in update_description.cluster_subnet_group.subnet_ids
+ - subnet_id_c not in update_description.cluster_subnet_group.subnet_ids
+ - subnet_id_d not in update_description.cluster_subnet_group.subnet_ids
+ - update_description.cluster_subnet_group.vpc_id == vpc_id
+
+ # ============================================================
+
+ - name: Update Subnet Group subnets - check_mode
+ redshift_subnet_group:
+ state: present
+ group_name: '{{ group_name }}'
+ ## No longer mandatory
+ # group_description: '{{ description_updated }}'
+ group_subnets:
+ - '{{ subnet_id_c }}'
+ - '{{ subnet_id_d }}'
+ register: update_subnets
+ check_mode: True
+
+ - name: Check result - Update Subnet Group subnets - check_mode
+ assert:
+ that:
+ - update_subnets is successful
+ - update_subnets is changed
+
+ - name: Update Subnet Group subnets
+ redshift_subnet_group:
+ state: present
+ group_name: '{{ group_name }}'
+ ## No longer mandatory
+ # group_description: '{{ description_updated }}'
+ group_subnets:
+ - '{{ subnet_id_c }}'
+ - '{{ subnet_id_d }}'
+ register: update_subnets
+
+ - name: Check result - Update Subnet Group subnets
+ assert:
+ that:
+ - update_subnets is successful
+ - update_subnets is changed
+ - '"group" in update_subnets'
+ - '"name" in update_subnets.group'
+ - '"vpc_id" in update_subnets.group'
+ - update_subnets.group.name == group_name
+ - update_subnets.group.vpc_id == vpc_id
+ - '"cluster_subnet_group" in update_subnets'
+ - '"description" in update_subnets.cluster_subnet_group'
+ - '"subnet_ids" in update_subnets.cluster_subnet_group'
+ - '"vpc_id" in update_subnets.cluster_subnet_group'
+ - update_subnets.cluster_subnet_group.name == group_name
+ - update_subnets.cluster_subnet_group.description == description_updated
+ - subnet_id_a not in update_subnets.cluster_subnet_group.subnet_ids
+ - subnet_id_b not in update_subnets.cluster_subnet_group.subnet_ids
+ - subnet_id_c in update_subnets.cluster_subnet_group.subnet_ids
+ - subnet_id_d in update_subnets.cluster_subnet_group.subnet_ids
+ - update_subnets.cluster_subnet_group.vpc_id == vpc_id
+
+ - name: Update Subnet Group subnets - idempotency - check_mode
+ redshift_subnet_group:
+ state: present
+ group_name: '{{ group_name }}'
+ ## No longer mandatory
+ # group_description: '{{ description_updated }}'
+ group_subnets:
+ - '{{ subnet_id_c }}'
+ - '{{ subnet_id_d }}'
+ register: update_subnets
+ check_mode: True
+
+ - name: Check result - Update Subnet Group subnets - idempotency - check_mode
+ assert:
+ that:
+ - update_subnets is successful
+ - update_subnets is not changed
+
+ - name: Update Subnet Group subnets - idempotency
+ redshift_subnet_group:
+ state: present
+ group_name: '{{ group_name }}'
+ ## No longer mandatory
+ # group_description: '{{ description_updated }}'
+ group_subnets:
+ - '{{ subnet_id_c }}'
+ - '{{ subnet_id_d }}'
+ register: update_subnets
+
+ - name: Check result - Update Subnet Group subnets - idempotency
+ assert:
+ that:
+ - update_subnets is successful
+ - update_subnets is not changed
+ - '"group" in update_subnets'
+ - '"name" in update_subnets.group'
+ - '"vpc_id" in update_subnets.group'
+ - update_subnets.group.name == group_name
+ - update_subnets.group.vpc_id == vpc_id
+ - '"cluster_subnet_group" in update_subnets'
+ - '"description" in update_subnets.cluster_subnet_group'
+ - '"subnet_ids" in update_subnets.cluster_subnet_group'
+ - '"vpc_id" in update_subnets.cluster_subnet_group'
+ - update_subnets.cluster_subnet_group.name == group_name
+ - update_subnets.cluster_subnet_group.description == description_updated
+ - subnet_id_a not in update_subnets.cluster_subnet_group.subnet_ids
+ - subnet_id_b not in update_subnets.cluster_subnet_group.subnet_ids
+ - subnet_id_c in update_subnets.cluster_subnet_group.subnet_ids
+ - subnet_id_d in update_subnets.cluster_subnet_group.subnet_ids
+ - update_subnets.cluster_subnet_group.vpc_id == vpc_id
+
+ # ============================================================
+
+ - name: Delete Subnet Group - check_mode
+ redshift_subnet_group:
+ state: absent
+ group_name: '{{ group_name }}'
+ register: delete_group
+ check_mode: True
+
+ - name: Check result - Delete Subnet Group - check_mode
+ assert:
+ that:
+ - delete_group is changed
+
+ - name: Delete Subnet Group
+ redshift_subnet_group:
+ state: absent
+ group_name: '{{ group_name }}'
+ register: delete_group
+
+ - name: Check result - Delete Subnet Group
+ assert:
+ that:
+ - delete_group is changed
+
+ - name: Delete Subnet Group - idempotency - check_mode
+ redshift_subnet_group:
+ state: absent
+ group_name: '{{ group_name }}'
+ register: delete_group
+ check_mode: True
+
+ - name: Check result - Delete Subnet Group - idempotency - check_mode
+ assert:
+ that:
+ - delete_group is not changed
+
+ - name: Delete Subnet Group - idempotency
+ redshift_subnet_group:
+ state: absent
+ group_name: '{{ group_name }}'
+ register: delete_group
+
+ - name: Check result - Delete Subnet Group - idempotency
+ assert:
+ that:
+ - delete_group is not changed
+
+ # ============================================================
+
+ - name: Create minimal Subnet Group - check_mode
+ redshift_subnet_group:
+ state: present
+ name: '{{ group_name }}'
+ subnets:
+ - '{{ subnet_id_a }}'
+ register: create_group
+ check_mode: True
+
+ - name: Check result - Create minimal Subnet Group - check_mode
+ assert:
+ that:
+ - create_group is successful
+ - create_group is changed
+
+ - name: Create minimal Subnet Group
+ redshift_subnet_group:
+ state: present
+ name: '{{ group_name }}'
+ subnets:
+ - '{{ subnet_id_a }}'
+ register: create_group
+
+ - name: Check result - Create minimal Subnet Group
+ assert:
+ that:
+ - create_group is successful
+ - create_group is changed
+ - '"group" in create_group'
+ - '"name" in create_group.group'
+ - '"vpc_id" in create_group.group'
+ - create_group.group.name == group_name
+ - create_group.group.vpc_id == vpc_id
+ - '"cluster_subnet_group" in create_group'
+ - '"description" in create_group.cluster_subnet_group'
+ - '"subnet_ids" in create_group.cluster_subnet_group'
+ - '"vpc_id" in create_group.cluster_subnet_group'
+ - create_group.cluster_subnet_group.name == group_name
+ - create_group.cluster_subnet_group.description == group_name
+ - subnet_id_a in create_group.cluster_subnet_group.subnet_ids
+ - subnet_id_b not in create_group.cluster_subnet_group.subnet_ids
+ - subnet_id_c not in create_group.cluster_subnet_group.subnet_ids
+ - subnet_id_d not in create_group.cluster_subnet_group.subnet_ids
+ - create_group.cluster_subnet_group.vpc_id == vpc_id
+
+ - name: Create minimal Subnet Group - idempotency - check_mode
+ redshift_subnet_group:
+ state: present
+ name: '{{ group_name }}'
+ subnets:
+ - '{{ subnet_id_a }}'
+ register: create_group
+ check_mode: True
+
+ - name: Check result - Create minimal Subnet Group - idempotency - check_mode
+ assert:
+ that:
+ - create_group is successful
+ - create_group is not changed
+
+ - name: Create minimal Subnet Group - idempotency
+ redshift_subnet_group:
+ state: present
+ name: '{{ group_name }}'
+ subnets:
+ - '{{ subnet_id_a }}'
+ register: create_group
+
+ - name: Check result - Create minimal Subnet Group - idempotency
+ assert:
+ that:
+ - create_group is successful
+ - create_group is not changed
+ - '"group" in create_group'
+ - '"name" in create_group.group'
+ - '"vpc_id" in create_group.group'
+ - create_group.group.name == group_name
+ - create_group.group.vpc_id == vpc_id
+ - '"cluster_subnet_group" in create_group'
+ - '"description" in create_group.cluster_subnet_group'
+ - '"subnet_ids" in create_group.cluster_subnet_group'
+ - '"vpc_id" in create_group.cluster_subnet_group'
+ - create_group.cluster_subnet_group.name == group_name
+ - create_group.cluster_subnet_group.description == group_name
+ - subnet_id_a in create_group.cluster_subnet_group.subnet_ids
+ - subnet_id_b not in create_group.cluster_subnet_group.subnet_ids
+ - subnet_id_c not in create_group.cluster_subnet_group.subnet_ids
+ - subnet_id_d not in create_group.cluster_subnet_group.subnet_ids
+ - create_group.cluster_subnet_group.vpc_id == vpc_id
+
+ # ============================================================
+
+ - name: Full Update Subnet Group - check_mode
+ redshift_subnet_group:
+ state: present
+ name: '{{ group_name }}'
+ description: '{{ description_updated }}'
+ subnets:
+ - '{{ subnet_id_a }}'
+ - '{{ subnet_id_b }}'
+ register: update_complex
+ check_mode: True
+
+ - name: Check result - Full Update Subnet Group - check_mode
+ assert:
+ that:
+ - update_complex is successful
+ - update_complex is changed
+
+ - name: Full Update Subnet Group
+ redshift_subnet_group:
+ state: present
+ name: '{{ group_name }}'
+ description: '{{ description_updated }}'
+ subnets:
+ - '{{ subnet_id_a }}'
+ - '{{ subnet_id_b }}'
+ register: update_complex
+
+ - name: Check result - Full Update Subnet Group
+ assert:
+ that:
+ - update_complex is successful
+ - update_complex is changed
+ - '"group" in update_complex'
+ - '"name" in update_complex.group'
+ - '"vpc_id" in update_complex.group'
+ - update_complex.group.name == group_name
+ - update_complex.group.vpc_id == vpc_id
+ - '"cluster_subnet_group" in update_complex'
+ - '"description" in update_complex.cluster_subnet_group'
+ - '"subnet_ids" in update_complex.cluster_subnet_group'
+ - '"vpc_id" in update_complex.cluster_subnet_group'
+ - update_complex.cluster_subnet_group.name == group_name
+ - update_complex.cluster_subnet_group.description == description_updated
+ - subnet_id_a in update_complex.cluster_subnet_group.subnet_ids
+ - subnet_id_b in update_complex.cluster_subnet_group.subnet_ids
+ - subnet_id_c not in update_complex.cluster_subnet_group.subnet_ids
+ - subnet_id_d not in update_complex.cluster_subnet_group.subnet_ids
+ - update_complex.cluster_subnet_group.vpc_id == vpc_id
+
+ - name: Full Update Subnet Group - idempotency - check_mode
+ redshift_subnet_group:
+ state: present
+ name: '{{ group_name }}'
+ description: '{{ description_updated }}'
+ subnets:
+ - '{{ subnet_id_a }}'
+ - '{{ subnet_id_b }}'
+ register: update_complex
+ check_mode: True
+
+ - name: Check result - Full Update Subnet Group - idempotency - check_mode
+ assert:
+ that:
+ - update_complex is successful
+ - update_complex is not changed
+
+ - name: Full Update Subnet Group - idempotency
+ redshift_subnet_group:
+ state: present
+ name: '{{ group_name }}'
+ description: '{{ description_updated }}'
+ subnets:
+ - '{{ subnet_id_a }}'
+ - '{{ subnet_id_b }}'
+ register: update_complex
+
+ - name: Check result - Full Update Subnet Group - idempotency
+ assert:
+ that:
+ - update_complex is successful
+ - update_complex is not changed
+ - '"group" in update_complex'
+ - '"name" in update_complex.group'
+ - '"vpc_id" in update_complex.group'
+ - update_complex.group.name == group_name
+ - update_complex.group.vpc_id == vpc_id
+ - '"cluster_subnet_group" in update_complex'
+ - '"description" in update_complex.cluster_subnet_group'
+ - '"subnet_ids" in update_complex.cluster_subnet_group'
+ - '"vpc_id" in update_complex.cluster_subnet_group'
+ - update_complex.cluster_subnet_group.name == group_name
+ - update_complex.cluster_subnet_group.description == description_updated
+ - subnet_id_a in update_complex.cluster_subnet_group.subnet_ids
+ - subnet_id_b in update_complex.cluster_subnet_group.subnet_ids
+ - subnet_id_c not in update_complex.cluster_subnet_group.subnet_ids
+ - subnet_id_d not in update_complex.cluster_subnet_group.subnet_ids
+ - update_complex.cluster_subnet_group.vpc_id == vpc_id
+
+ # ============================================================
+
+ - name: Delete Subnet Group
+ redshift_subnet_group:
+ state: absent
+ name: '{{ group_name }}'
+ register: delete_group
+
+ - name: Check result - Delete Subnet Group
+ assert:
+ that:
+ - delete_group is changed
+
+ always:
+
+ ################################################
+ # TEARDOWN STARTS HERE
+ ################################################
+
+ - name: Delete Subnet Group
+ redshift_subnet_group:
+ state: absent
+ group_name: '{{ group_name }}'
+ ignore_errors: True
+
+ - name: tidy up subnet
+ ec2_vpc_subnet:
+ state: absent
+ cidr: '{{ item }}'
+ vpc_id: '{{ vpc_result.vpc.id }}'
+ loop:
+ - '{{ subnet_cidr_a }}'
+ - '{{ subnet_cidr_b }}'
+ - '{{ subnet_cidr_c }}'
+ - '{{ subnet_cidr_d }}'
+ ignore_errors: True
+
+ - name: tidy up VPC
+ ec2_vpc_net:
+ state: absent
+ name: '{{ vpc_name }}'
+ cidr_block: '{{ vpc_cidr }}'
+ ignore_errors: True
diff --git a/tests/integration/targets/route53/tasks/main.yml b/tests/integration/targets/route53/tasks/main.yml
index 18f10ae2987..c5312437f0b 100644
--- a/tests/integration/targets/route53/tasks/main.yml
+++ b/tests/integration/targets/route53/tasks/main.yml
@@ -29,12 +29,15 @@
route53_zone:
zone: '{{ zone_one }}'
comment: 'Created in Ansible test {{ resource_prefix }}'
+ tags:
+ TestTag: '{{ resource_prefix }}.z1'
register: z1
- assert:
that:
- z1 is success
- z1 is changed
- "z1.comment == 'Created in Ansible test {{ resource_prefix }}'"
+ - "z1.tags.TestTag == '{{ resource_prefix }}.z1'"
- name: 'Get zone details'
route53_info:
@@ -53,12 +56,15 @@
vpc_id: '{{ vpc.vpc.id }}'
vpc_region: '{{ aws_region }}'
comment: Created in Ansible test {{ resource_prefix }}
+ tags:
+ TestTag: '{{ resource_prefix }}.z2'
register: z2
- assert:
that:
- z2 is success
- z2 is changed
- "z2.comment == 'Created in Ansible test {{ resource_prefix }}'"
+ - "z2.tags.TestTag == '{{ resource_prefix }}.z2'"
- name: Get zone details
route53_info:
@@ -503,6 +509,42 @@
- alias_record is not failed
- alias_record is not changed
+ - name: 'Create a weighted record'
+ route53:
+ state: present
+ zone: '{{ zone_one }}'
+ record: 'weighted.{{ zone_one }}'
+ type: CNAME
+ value: 'zid_test.{{ zone_one }}'
+ overwrite: True
+ identifier: "host1@www"
+ weight: 100
+ region: '{{ omit }}'
+ register: weighted_record
+ - name: 'This should be changed'
+ assert:
+ that:
+ - weighted_record is not failed
+ - weighted_record is changed
+
+ - name: 'Re-Create a weighted record'
+ route53:
+ state: present
+ zone: '{{ zone_one }}'
+ record: 'weighted.{{ zone_one }}'
+ type: CNAME
+ value: 'zid_test.{{ zone_one }}'
+ overwrite: True
+ identifier: "host1@www"
+ weight: 100
+ region: '{{ omit }}'
+ register: weighted_record
+ - name: 'This should not be changed'
+ assert:
+ that:
+ - weighted_record is not failed
+ - weighted_record is not changed
+
always:
- route53_info:
query: record_sets
@@ -521,6 +563,20 @@
loop: '{{ z1_records.ResourceRecordSets | selectattr("Type", "in", ["A", "AAAA", "CNAME", "CAA"]) | list }}'
when:
- '"AliasTarget" in item'
+ - name: 'Loop over A/AAAA/CNAME records and delete them'
+ route53:
+ state: absent
+ zone: '{{ zone_one }}'
+ record: '{{ item.Name }}'
+ type: '{{ item.Type }}'
+ value: '{{ item.ResourceRecords | map(attribute="Value") | join(",") }}'
+ identifier: '{{ item.SetIdentifier }}'
+ region: '{{ omit }}'
+ ignore_errors: True
+ loop: '{{ z1_records.ResourceRecordSets | selectattr("Type", "in", ["A", "AAAA", "CNAME", "CAA"]) | list }}'
+ when:
+ - '"ResourceRecords" in item'
+ - '"SetIdentifier" in item'
- name: 'Loop over A/AAAA/CNAME records and delete them'
route53:
state: absent
@@ -551,6 +607,21 @@
loop: '{{ z2_records.ResourceRecordSets | selectattr("Type", "in", ["A", "AAAA", "CNAME", "CAA"]) | list }}'
when:
- '"AliasTarget" in item'
+ - name: 'Loop over A/AAAA/CNAME records and delete them'
+ route53:
+ state: absent
+ zone: '{{ zone_two }}'
+ record: '{{ item.Name }}'
+ type: '{{ item.Type }}'
+ value: '{{ item.ResourceRecords | map(attribute="Value") | join(",") }}'
+ identifier: '{{ item.SetIdentifier }}'
+ region: '{{ omit }}'
+ private_zone: true
+ ignore_errors: True
+ loop: '{{ z2_records.ResourceRecordSets | selectattr("Type", "in", ["A", "AAAA", "CNAME", "CAA"]) | list }}'
+ when:
+ - '"ResourceRecords" in item'
+ - '"SetIdentifier" in item'
- name: 'Loop over A/AAAA/CNAME records and delete them'
route53:
state: absent
diff --git a/tests/integration/targets/route53_health_check/aliases b/tests/integration/targets/route53_health_check/aliases
new file mode 100644
index 00000000000..4ef4b2067d0
--- /dev/null
+++ b/tests/integration/targets/route53_health_check/aliases
@@ -0,0 +1 @@
+cloud/aws
diff --git a/tests/integration/targets/route53_health_check/defaults/main.yml b/tests/integration/targets/route53_health_check/defaults/main.yml
new file mode 100644
index 00000000000..3763717e6d0
--- /dev/null
+++ b/tests/integration/targets/route53_health_check/defaults/main.yml
@@ -0,0 +1,33 @@
+---
+# route53_health_check integration tests
+#
+# Module uses the following as an 'ID'
+# (the real ID is automatically assigned after creation)
+# - ip_address
+# - fqdn
+# - port
+# - type
+# - request_interval
+
+#ip_address: We allocate an EIP due to route53 restrictions
+fqdn: '{{ tiny_prefix }}.route53-health.ansible.test'
+port: 8080
+type: 'TCP'
+request_interval: 30
+
+# modifiable
+# - resource_path
+# - string_match
+# - failure_threshold
+
+failure_threshold: 5
+failure_threshold_updated: 1
+
+# For resource_path we need an HTTP/HTTPS type check
+# for string_match we need an _STR_MATCH type
+type_https_match: 'HTTPS_STR_MATCH'
+type_http_match: 'HTTP_STR_MATCH'
+resource_path: '/health.php'
+resource_path_updated: '/healthz'
+string_match: 'Hello'
+string_match_updated: 'Hello World'
diff --git a/tests/integration/targets/route53_health_check/meta/main.yml b/tests/integration/targets/route53_health_check/meta/main.yml
new file mode 100644
index 00000000000..930e8622824
--- /dev/null
+++ b/tests/integration/targets/route53_health_check/meta/main.yml
@@ -0,0 +1,3 @@
+dependencies:
+ - prepare_tests
+ - setup_ec2_facts
diff --git a/tests/integration/targets/route53_health_check/tasks/main.yml b/tests/integration/targets/route53_health_check/tasks/main.yml
new file mode 100644
index 00000000000..426a0461703
--- /dev/null
+++ b/tests/integration/targets/route53_health_check/tasks/main.yml
@@ -0,0 +1,1731 @@
+---
+# route53_health_check integration tests
+#
+# Module uses the following as an 'ID'
+# (the real ID is automatically assigned after creation)
+# - ip_address
+# - fqdn
+# - port
+# - type (immutable)
+# - request_interval (immutable)
+#
+# modifiable
+# - resource_path
+# - string_match
+# - failure_threshold
+# - disabled
+#
+- module_defaults:
+ group/aws:
+ aws_access_key: '{{ aws_access_key }}'
+ aws_secret_key: '{{ aws_secret_key }}'
+ security_token: '{{ security_token | default(omit) }}'
+ region: '{{ aws_region }}'
+ block:
+ # Route53 can only test against routable IPs. Request an EIP so some poor
+ # soul doesn't get randomly hit by our testing.
+ - name: Allocate an EIP we can test against
+ ec2_eip:
+ state: present
+ register: eip
+
+ - set_fact:
+ ip_address: '{{ eip.public_ip }}'
+
+ # Minimum possible definition
+ - name: 'Create a TCP health check - check_mode'
+ route53_health_check:
+ state: present
+ ip_address: '{{ ip_address }}'
+ port: '{{ port }}'
+ type: '{{ type }}'
+ register: create_check
+ check_mode: true
+
+ - name: 'Check result - Create a TCP health check - check_mode'
+ assert:
+ that:
+ - create_check is successful
+ - create_check is changed
+
+ - name: 'Create a TCP health check'
+ route53_health_check:
+ state: present
+ ip_address: '{{ ip_address }}'
+ port: '{{ port }}'
+ type: '{{ type }}'
+ register: create_check
+
+ - name: 'Check result - Create a TCP health check'
+ assert:
+ that:
+ - create_check is successful
+ - create_check is changed
+ - '"health_check" in create_check'
+ - '"id" in _health_check'
+ - '"action" in _health_check'
+ - '"health_check_version" in _health_check'
+ - '"tags" in _health_check'
+ - create_check.health_check.action == 'create'
+ - '"health_check_config" in create_check.health_check'
+ - '"type" in _check_config'
+ - '"disabled" in _check_config'
+ - '"failure_threshold" in _check_config'
+ - '"request_interval" in _check_config'
+ - '"fully_qualified_domain_name" not in _check_config'
+ - '"ip_address" in _check_config'
+ - '"port" in _check_config'
+ - '"resource_path" not in _check_config'
+ - '"search_string" not in _check_config'
+ - _check_config.disabled == false
+ - _check_config.type == 'TCP'
+ - _check_config.failure_threshold == 3
+ - _check_config.request_interval == 30
+ - _check_config.ip_address == ip_address
+ - _check_config.port == port
+ vars:
+ _health_check: '{{ create_check.health_check }}'
+ _check_config: '{{ _health_check.health_check_config }}'
+
+ - set_fact:
+ tcp_check_id: '{{ create_check.health_check.id }}'
+
+ - name: 'Create a TCP health check - idempotency - check_mode'
+ route53_health_check:
+ state: present
+ ip_address: '{{ ip_address }}'
+ port: '{{ port }}'
+ type: '{{ type }}'
+ register: create_check
+ check_mode: true
+
+ - name: 'Check result - Create a TCP health check - idempotency - check_mode'
+ assert:
+ that:
+ - create_check is successful
+ - create_check is not changed
+
+ - name: 'Create a TCP health check - idempotency'
+ route53_health_check:
+ state: present
+ ip_address: '{{ ip_address }}'
+ port: '{{ port }}'
+ type: '{{ type }}'
+ register: create_check
+
+ - name: 'Check result - Create a TCP health check - idempotency'
+ assert:
+ that:
+ - create_check is successful
+ - create_check is not changed
+ - '"health_check" in create_check'
+ - '"id" in create_check.health_check'
+ - _health_check.id == tcp_check_id
+ - '"id" in _health_check'
+ - '"action" in _health_check'
+ - '"health_check_version" in _health_check'
+ - '"tags" in _health_check'
+ - create_check.health_check.action is none
+ - '"health_check_config" in create_check.health_check'
+ - '"type" in _check_config'
+ - '"disabled" in _check_config'
+ - '"failure_threshold" in _check_config'
+ - '"request_interval" in _check_config'
+ - '"fully_qualified_domain_name" not in _check_config'
+ - '"ip_address" in _check_config'
+ - '"port" in _check_config'
+ - '"resource_path" not in _check_config'
+ - '"search_string" not in _check_config'
+ - _check_config.disabled == false
+ - _check_config.type == 'TCP'
+ - _check_config.request_interval == 30
+ - _check_config.failure_threshold == 3
+ - _check_config.ip_address == ip_address
+ - _check_config.port == port
+ vars:
+ _health_check: '{{ create_check.health_check }}'
+ _check_config: '{{ _health_check.health_check_config }}'
+
+ # Update an attribute
+ - name: 'Update TCP health check - set threshold - check_mode'
+ route53_health_check:
+ state: present
+ ip_address: '{{ ip_address }}'
+ port: '{{ port }}'
+ type: '{{ type }}'
+ failure_threshold: '{{ failure_threshold_updated }}'
+ register: update_threshold
+ check_mode: true
+
+ - name: 'Check result - Update TCP health check - set threshold - check_mode'
+ assert:
+ that:
+ - update_threshold is successful
+ - update_threshold is changed
+
+ - name: 'Update TCP health check - set threshold'
+ route53_health_check:
+ state: present
+ ip_address: '{{ ip_address }}'
+ port: '{{ port }}'
+ type: '{{ type }}'
+ failure_threshold: '{{ failure_threshold_updated }}'
+ register: update_threshold
+
+ - name: 'Check result - Update TCP health check - set threshold'
+ assert:
+ that:
+ - update_threshold is successful
+ - update_threshold is changed
+ - '"health_check" in update_threshold'
+ - '"id" in _health_check'
+ - _health_check.id == tcp_check_id
+ - '"action" in _health_check'
+ - '"health_check_version" in _health_check'
+ - '"tags" in _health_check'
+ - create_check.health_check.action is none
+ - '"health_check_config" in create_check.health_check'
+ - '"type" in _check_config'
+ - '"disabled" in _check_config'
+ - '"failure_threshold" in _check_config'
+ - '"request_interval" in _check_config'
+ - '"fully_qualified_domain_name" not in _check_config'
+ - '"ip_address" in _check_config'
+ - '"port" in _check_config'
+ - '"resource_path" not in _check_config'
+ - '"search_string" not in _check_config'
+ - _check_config.disabled == false
+ - _check_config.type == 'TCP'
+ - _check_config.request_interval == 30
+ - _check_config.failure_threshold == failure_threshold_updated
+ - _check_config.ip_address == ip_address
+ - _check_config.port == port
+ vars:
+ _health_check: '{{ update_threshold.health_check }}'
+ _check_config: '{{ _health_check.health_check_config }}'
+
+ - name: 'Update TCP health check - set threshold - idempotency - check_mode'
+ route53_health_check:
+ state: present
+ ip_address: '{{ ip_address }}'
+ port: '{{ port }}'
+ type: '{{ type }}'
+ failure_threshold: '{{ failure_threshold_updated }}'
+ register: update_threshold
+ check_mode: true
+
+ - name: 'Check result - Update TCP health check - set threshold - idempotency - check_mode'
+ assert:
+ that:
+ - update_threshold is successful
+ - update_threshold is not changed
+
+ - name: 'Update TCP health check - set threshold - idempotency'
+ route53_health_check:
+ state: present
+ ip_address: '{{ ip_address }}'
+ port: '{{ port }}'
+ type: '{{ type }}'
+ failure_threshold: '{{ failure_threshold_updated }}'
+ register: update_threshold
+
+ - name: 'Check result - Update TCP health check - set threshold - idempotency'
+ assert:
+ that:
+ - update_threshold is successful
+ - update_threshold is not changed
+ - '"health_check" in update_threshold'
+ - '"id" in _health_check'
+ - _health_check.id == tcp_check_id
+ - '"action" in _health_check'
+ - '"health_check_version" in _health_check'
+ - '"tags" in _health_check'
+ - create_check.health_check.action is none
+ - '"health_check_config" in create_check.health_check'
+ - '"type" in _check_config'
+ - '"disabled" in _check_config'
+ - '"failure_threshold" in _check_config'
+ - '"request_interval" in _check_config'
+ - '"fully_qualified_domain_name" not in _check_config'
+ - '"ip_address" in _check_config'
+ - '"port" in _check_config'
+ - '"resource_path" not in _check_config'
+ - '"search_string" not in _check_config'
+ - _check_config.disabled == false
+ - _check_config.type == 'TCP'
+ - _check_config.request_interval == 30
+ - _check_config.failure_threshold == failure_threshold_updated
+ - _check_config.ip_address == ip_address
+ - _check_config.port == port
+ vars:
+ _health_check: '{{ update_threshold.health_check }}'
+ _check_config: '{{ _health_check.health_check_config }}'
+
+ - name: 'Update TCP health check - set disabled - check_mode'
+ route53_health_check:
+ state: present
+ ip_address: '{{ ip_address }}'
+ port: '{{ port }}'
+ type: '{{ type }}'
+ disabled: true
+ register: update_disabled
+ check_mode: true
+
+ - name: 'Check result - Update TCP health check - set disabled - check_mode'
+ assert:
+ that:
+ - update_disabled is successful
+ - update_disabled is changed
+
+ - name: 'Update TCP health check - set disabled'
+ route53_health_check:
+ state: present
+ ip_address: '{{ ip_address }}'
+ port: '{{ port }}'
+ type: '{{ type }}'
+ disabled: true
+ register: update_disabled
+
+ - name: 'Check result - Update TCP health check - set disabled'
+ assert:
+ that:
+ - update_disabled is successful
+ - update_disabled is changed
+ - '"health_check" in update_disabled'
+ - '"id" in _health_check'
+ - _health_check.id == tcp_check_id
+ - '"action" in _health_check'
+ - '"health_check_version" in _health_check'
+ - '"tags" in _health_check'
+ - create_check.health_check.action is none
+ - '"health_check_config" in create_check.health_check'
+ - '"type" in _check_config'
+ - '"disabled" in _check_config'
+ - '"failure_threshold" in _check_config'
+ - '"request_interval" in _check_config'
+ - '"fully_qualified_domain_name" not in _check_config'
+ - '"ip_address" in _check_config'
+ - '"port" in _check_config'
+ - '"resource_path" not in _check_config'
+ - '"search_string" not in _check_config'
+ - _check_config.disabled == true
+ - _check_config.type == 'TCP'
+ - _check_config.request_interval == 30
+ - _check_config.failure_threshold == failure_threshold_updated
+ - _check_config.ip_address == ip_address
+ - _check_config.port == port
+ vars:
+ _health_check: '{{ update_disabled.health_check }}'
+ _check_config: '{{ _health_check.health_check_config }}'
+
+ - name: 'Update TCP health check - set disabled - idempotency - check_mode'
+ route53_health_check:
+ state: present
+ ip_address: '{{ ip_address }}'
+ port: '{{ port }}'
+ type: '{{ type }}'
+ disabled: true
+ register: update_disabled
+ check_mode: true
+
+ - name: 'Check result - Update TCP health check - set disabled - idempotency - check_mode'
+ assert:
+ that:
+ - update_disabled is successful
+ - update_disabled is not changed
+
+ - name: 'Update TCP health check - set disabled - idempotency'
+ route53_health_check:
+ state: present
+ ip_address: '{{ ip_address }}'
+ port: '{{ port }}'
+ type: '{{ type }}'
+ disabled: true
+ register: update_disabled
+
+ - name: 'Check result - Update TCP health check - set disabled - idempotency'
+ assert:
+ that:
+ - update_disabled is successful
+ - update_disabled is not changed
+ - '"health_check" in update_disabled'
+ - '"id" in _health_check'
+ - _health_check.id == tcp_check_id
+ - '"action" in _health_check'
+ - '"health_check_version" in _health_check'
+ - '"tags" in _health_check'
+ - create_check.health_check.action is none
+ - '"health_check_config" in create_check.health_check'
+ - '"type" in _check_config'
+ - '"disabled" in _check_config'
+ - '"failure_threshold" in _check_config'
+ - '"request_interval" in _check_config'
+ - '"fully_qualified_domain_name" not in _check_config'
+ - '"ip_address" in _check_config'
+ - '"port" in _check_config'
+ - '"resource_path" not in _check_config'
+ - '"search_string" not in _check_config'
+ - _check_config.disabled == true
+ - _check_config.type == 'TCP'
+ - _check_config.request_interval == 30
+ - _check_config.failure_threshold == failure_threshold_updated
+ - _check_config.ip_address == ip_address
+ - _check_config.port == port
+ vars:
+ _health_check: '{{ update_disabled.health_check }}'
+ _check_config: '{{ _health_check.health_check_config }}'
+
+ - name: 'Update TCP health check - set tags - check_mode'
+ route53_health_check:
+ state: present
+ ip_address: '{{ ip_address }}'
+ port: '{{ port }}'
+ type: '{{ type }}'
+ tags:
+ CamelCase: CamelCaseValue
+ snake_case: snake_case_value
+ "with space": Some value
+ purge_tags: false
+ register: update_tags
+ check_mode: true
+
+ - name: 'Check result - Update TCP health check - set tags - check_mode'
+ assert:
+ that:
+ - update_tags is successful
+ - update_tags is changed
+
+ - name: 'Update TCP health check - set tags'
+ route53_health_check:
+ state: present
+ ip_address: '{{ ip_address }}'
+ port: '{{ port }}'
+ type: '{{ type }}'
+ tags:
+ CamelCase: CamelCaseValue
+ snake_case: snake_case_value
+ "with space": Some value
+ purge_tags: false
+ register: update_tags
+
+ - name: 'Check result - Update TCP health check - set tags'
+ assert:
+ that:
+ - update_tags is successful
+ - update_tags is changed
+ - '"health_check" in update_tags'
+ - '"id" in _health_check'
+ - _health_check.id == tcp_check_id
+ - '"action" in _health_check'
+ - '"health_check_version" in _health_check'
+ - '"tags" in _health_check'
+ - '"CamelCase" in _health_check.tags'
+ - _health_check.tags['CamelCase'] == 'CamelCaseValue'
+ - '"snake_case" in _health_check.tags'
+ - _health_check.tags['snake_case'] == 'snake_case_value'
+ - '"with space" in _health_check.tags'
+ - _health_check.tags['with space'] == 'Some value'
+ - create_check.health_check.action is none
+ - '"health_check_config" in create_check.health_check'
+ - '"type" in _check_config'
+ - '"disabled" in _check_config'
+ - '"failure_threshold" in _check_config'
+ - '"request_interval" in _check_config'
+ - '"fully_qualified_domain_name" not in _check_config'
+ - '"ip_address" in _check_config'
+ - '"port" in _check_config'
+ - '"resource_path" not in _check_config'
+ - '"search_string" not in _check_config'
+ - _check_config.disabled == true
+ - _check_config.type == 'TCP'
+ - _check_config.request_interval == 30
+ - _check_config.failure_threshold == failure_threshold_updated
+ - _check_config.ip_address == ip_address
+ - _check_config.port == port
+ vars:
+ _health_check: '{{ update_tags.health_check }}'
+ _check_config: '{{ _health_check.health_check_config }}'
+
+ - name: 'Update TCP health check - set tags - idempotency - check_mode'
+ route53_health_check:
+ state: present
+ ip_address: '{{ ip_address }}'
+ port: '{{ port }}'
+ type: '{{ type }}'
+ tags:
+ CamelCase: CamelCaseValue
+ snake_case: snake_case_value
+ "with space": Some value
+ purge_tags: false
+ register: update_tags
+ check_mode: true
+
+ - name: 'Check result - Update TCP health check - set tags - idempotency - check_mode'
+ assert:
+ that:
+ - update_tags is successful
+ - update_tags is not changed
+
+ - name: 'Update TCP health check - set tags - idempotency'
+ route53_health_check:
+ state: present
+ ip_address: '{{ ip_address }}'
+ port: '{{ port }}'
+ type: '{{ type }}'
+ tags:
+ CamelCase: CamelCaseValue
+ snake_case: snake_case_value
+ "with space": Some value
+ purge_tags: false
+ register: update_tags
+
+ - name: 'Check result - Update TCP health check - set tags - idempotency'
+ assert:
+ that:
+ - update_tags is successful
+ - update_tags is not changed
+ - '"health_check" in update_tags'
+ - '"id" in _health_check'
+ - _health_check.id == tcp_check_id
+ - '"action" in _health_check'
+ - '"health_check_version" in _health_check'
+ - '"tags" in _health_check'
+ - '"CamelCase" in _health_check.tags'
+ - _health_check.tags['CamelCase'] == 'CamelCaseValue'
+ - '"snake_case" in _health_check.tags'
+ - _health_check.tags['snake_case'] == 'snake_case_value'
+ - '"with space" in _health_check.tags'
+ - _health_check.tags['with space'] == 'Some value'
+ - create_check.health_check.action is none
+ - '"health_check_config" in create_check.health_check'
+ - '"type" in _check_config'
+ - '"disabled" in _check_config'
+ - '"failure_threshold" in _check_config'
+ - '"request_interval" in _check_config'
+ - '"fully_qualified_domain_name" not in _check_config'
+ - '"ip_address" in _check_config'
+ - '"port" in _check_config'
+ - '"resource_path" not in _check_config'
+ - '"search_string" not in _check_config'
+ - _check_config.disabled == true
+ - _check_config.type == 'TCP'
+ - _check_config.request_interval == 30
+ - _check_config.failure_threshold == failure_threshold_updated
+ - _check_config.ip_address == ip_address
+ - _check_config.port == port
+ vars:
+ _health_check: '{{ update_tags.health_check }}'
+ _check_config: '{{ _health_check.health_check_config }}'
+
+ - name: 'Update TCP health check - add tags - check_mode'
+ route53_health_check:
+ state: present
+ ip_address: '{{ ip_address }}'
+ port: '{{ port }}'
+ type: '{{ type }}'
+ tags:
+ anotherTag: anotherValue
+ purge_tags: false
+ register: add_tags
+ check_mode: true
+
+ - name: 'Check result - Update TCP health check - add tags - check_mode'
+ assert:
+ that:
+ - add_tags is successful
+ - add_tags is changed
+
+ - name: 'Update TCP health check - add tags'
+ route53_health_check:
+ state: present
+ ip_address: '{{ ip_address }}'
+ port: '{{ port }}'
+ type: '{{ type }}'
+ tags:
+ anotherTag: anotherValue
+ purge_tags: false
+ register: add_tags
+
+ - name: 'Check result - Update TCP health check - add tags'
+ assert:
+ that:
+ - add_tags is successful
+ - add_tags is changed
+ - '"health_check" in add_tags'
+ - '"id" in _health_check'
+ - _health_check.id == tcp_check_id
+ - '"action" in _health_check'
+ - '"health_check_version" in _health_check'
+ - '"tags" in _health_check'
+ - '"CamelCase" in _health_check.tags'
+ - _health_check.tags['CamelCase'] == 'CamelCaseValue'
+ - '"snake_case" in _health_check.tags'
+ - _health_check.tags['snake_case'] == 'snake_case_value'
+ - '"with space" in _health_check.tags'
+ - _health_check.tags['with space'] == 'Some value'
+ - '"anotherTag" in _health_check.tags'
+ - _health_check.tags['anotherTag'] == 'anotherValue'
+ - create_check.health_check.action is none
+ - '"health_check_config" in create_check.health_check'
+ - '"type" in _check_config'
+ - '"disabled" in _check_config'
+ - '"failure_threshold" in _check_config'
+ - '"request_interval" in _check_config'
+ - '"fully_qualified_domain_name" not in _check_config'
+ - '"ip_address" in _check_config'
+ - '"port" in _check_config'
+ - '"resource_path" not in _check_config'
+ - '"search_string" not in _check_config'
+ - _check_config.disabled == true
+ - _check_config.type == 'TCP'
+ - _check_config.request_interval == 30
+ - _check_config.failure_threshold == failure_threshold_updated
+ - _check_config.ip_address == ip_address
+ - _check_config.port == port
+ vars:
+ _health_check: '{{ add_tags.health_check }}'
+ _check_config: '{{ _health_check.health_check_config }}'
+
+ - name: 'Update TCP health check - add tags - idempotency - check_mode'
+ route53_health_check:
+ state: present
+ ip_address: '{{ ip_address }}'
+ port: '{{ port }}'
+ type: '{{ type }}'
+ tags:
+ anotherTag: anotherValue
+ purge_tags: false
+ register: add_tags
+ check_mode: true
+
+ - name: 'Check result - Update TCP health check - add tags - idempotency - check_mode'
+ assert:
+ that:
+ - add_tags is successful
+ - add_tags is not changed
+
+ - name: 'Update TCP health check - add tags - idempotency'
+ route53_health_check:
+ state: present
+ ip_address: '{{ ip_address }}'
+ port: '{{ port }}'
+ type: '{{ type }}'
+ tags:
+ anotherTag: anotherValue
+ purge_tags: false
+ register: add_tags
+
+ - name: 'Check result - Update TCP health check - add tags - idempotency'
+ assert:
+ that:
+ - add_tags is successful
+ - add_tags is not changed
+ - '"health_check" in add_tags'
+ - '"id" in _health_check'
+ - _health_check.id == tcp_check_id
+ - '"action" in _health_check'
+ - '"health_check_version" in _health_check'
+ - '"tags" in _health_check'
+ - '"CamelCase" in _health_check.tags'
+ - _health_check.tags['CamelCase'] == 'CamelCaseValue'
+ - '"snake_case" in _health_check.tags'
+ - _health_check.tags['snake_case'] == 'snake_case_value'
+ - '"with space" in _health_check.tags'
+ - _health_check.tags['with space'] == 'Some value'
+ - '"anotherTag" in _health_check.tags'
+ - _health_check.tags['anotherTag'] == 'anotherValue'
+ - create_check.health_check.action is none
+ - '"health_check_config" in create_check.health_check'
+ - '"type" in _check_config'
+ - '"disabled" in _check_config'
+ - '"failure_threshold" in _check_config'
+ - '"request_interval" in _check_config'
+ - '"fully_qualified_domain_name" not in _check_config'
+ - '"ip_address" in _check_config'
+ - '"port" in _check_config'
+ - '"resource_path" not in _check_config'
+ - '"search_string" not in _check_config'
+ - _check_config.disabled == true
+ - _check_config.type == 'TCP'
+ - _check_config.request_interval == 30
+ - _check_config.failure_threshold == failure_threshold_updated
+ - _check_config.ip_address == ip_address
+ - _check_config.port == port
+ vars:
+ _health_check: '{{ add_tags.health_check }}'
+ _check_config: '{{ _health_check.health_check_config }}'
+
+ - name: 'Update TCP health check - purge tags - check_mode'
+ route53_health_check:
+ state: present
+ ip_address: '{{ ip_address }}'
+ port: '{{ port }}'
+ type: '{{ type }}'
+ tags:
+ anotherTag: anotherValue
+ purge_tags: true
+ register: purge_tags
+ check_mode: true
+
+ - name: 'Check result - Update TCP health check - purge tags - check_mode'
+ assert:
+ that:
+ - purge_tags is successful
+ - purge_tags is changed
+
+ - name: 'Update TCP health check - purge tags'
+ route53_health_check:
+ state: present
+ ip_address: '{{ ip_address }}'
+ port: '{{ port }}'
+ type: '{{ type }}'
+ tags:
+ anotherTag: anotherValue
+ purge_tags: true
+ register: purge_tags
+
+ - name: 'Check result - Update TCP health check - purge tags'
+ assert:
+ that:
+ - purge_tags is successful
+ - purge_tags is changed
+ - '"health_check" in purge_tags'
+ - '"id" in _health_check'
+ - _health_check.id == tcp_check_id
+ - '"action" in _health_check'
+ - '"health_check_version" in _health_check'
+ - '"tags" in _health_check'
+ - '"CamelCase" not in _health_check.tags'
+ - '"snake_case" not in _health_check.tags'
+ - '"with space" not in _health_check.tags'
+ - '"anotherTag" in _health_check.tags'
+ - _health_check.tags['anotherTag'] == 'anotherValue'
+ - create_check.health_check.action is none
+ - '"health_check_config" in create_check.health_check'
+ - '"type" in _check_config'
+ - '"disabled" in _check_config'
+ - '"failure_threshold" in _check_config'
+ - '"request_interval" in _check_config'
+ - '"fully_qualified_domain_name" not in _check_config'
+ - '"ip_address" in _check_config'
+ - '"port" in _check_config'
+ - '"resource_path" not in _check_config'
+ - '"search_string" not in _check_config'
+ - _check_config.disabled == true
+ - _check_config.type == 'TCP'
+ - _check_config.request_interval == 30
+ - _check_config.failure_threshold == failure_threshold_updated
+ - _check_config.ip_address == ip_address
+ - _check_config.port == port
+ vars:
+ _health_check: '{{ purge_tags.health_check }}'
+ _check_config: '{{ _health_check.health_check_config }}'
+
+ - name: 'Update TCP health check - purge tags - idempotency - check_mode'
+ route53_health_check:
+ state: present
+ ip_address: '{{ ip_address }}'
+ port: '{{ port }}'
+ type: '{{ type }}'
+ tags:
+ anotherTag: anotherValue
+ purge_tags: true
+ register: purge_tags
+ check_mode: true
+
+ - name: 'Check result - Update TCP health check - purge tags - idempotency - check_mode'
+ assert:
+ that:
+ - purge_tags is successful
+ - purge_tags is not changed
+
+ - name: 'Update TCP health check - purge tags - idempotency'
+ route53_health_check:
+ state: present
+ ip_address: '{{ ip_address }}'
+ port: '{{ port }}'
+ type: '{{ type }}'
+ tags:
+ anotherTag: anotherValue
+ purge_tags: true
+ register: purge_tags
+
+ - name: 'Check result - Update TCP health check - purge tags - idempotency'
+ assert:
+ that:
+ - purge_tags is successful
+ - purge_tags is not changed
+ - '"health_check" in purge_tags'
+ - '"id" in _health_check'
+ - _health_check.id == tcp_check_id
+ - '"action" in _health_check'
+ - '"health_check_version" in _health_check'
+ - '"tags" in _health_check'
+ - '"CamelCase" not in _health_check.tags'
+ - '"snake_case" not in _health_check.tags'
+ - '"with space" not in _health_check.tags'
+ - '"anotherTag" in _health_check.tags'
+ - _health_check.tags['anotherTag'] == 'anotherValue'
+ - create_check.health_check.action is none
+ - '"health_check_config" in create_check.health_check'
+ - '"type" in _check_config'
+ - '"disabled" in _check_config'
+ - '"failure_threshold" in _check_config'
+ - '"request_interval" in _check_config'
+ - '"fully_qualified_domain_name" not in _check_config'
+ - '"ip_address" in _check_config'
+ - '"port" in _check_config'
+ - '"resource_path" not in _check_config'
+ - '"search_string" not in _check_config'
+ - _check_config.disabled == true
+ - _check_config.type == 'TCP'
+ - _check_config.request_interval == 30
+ - _check_config.failure_threshold == failure_threshold_updated
+ - _check_config.ip_address == ip_address
+ - _check_config.port == port
+ vars:
+ _health_check: '{{ purge_tags.health_check }}'
+ _check_config: '{{ _health_check.health_check_config }}'
+
+ # Delete the check
+ - name: 'Delete TCP health check - check_mode'
+ route53_health_check:
+ state: absent
+ ip_address: '{{ ip_address }}'
+ port: '{{ port }}'
+ type: '{{ type }}'
+ register: delete_tcp
+ check_mode: True
+
+ - name: 'Check result - Delete TCP health check - check_mode'
+ assert:
+ that:
+ - delete_tcp is successful
+ - delete_tcp is changed
+
+ - name: 'Delete TCP health check'
+ route53_health_check:
+ state: absent
+ ip_address: '{{ ip_address }}'
+ port: '{{ port }}'
+ type: '{{ type }}'
+ register: delete_tcp
+
+ - name: 'Check result - Delete TCP health check'
+ assert:
+ that:
+ - delete_tcp is successful
+ - delete_tcp is changed
+
+ - name: 'Delete TCP health check - idempotency - check_mode'
+ route53_health_check:
+ state: absent
+ ip_address: '{{ ip_address }}'
+ port: '{{ port }}'
+ type: '{{ type }}'
+ register: delete_tcp
+ check_mode: True
+
+ - name: 'Check result - Delete TCP health check - idempotency - check_mode'
+ assert:
+ that:
+ - delete_tcp is successful
+ - delete_tcp is not changed
+
+ - name: 'Delete TCP health check - idempotency'
+ route53_health_check:
+ state: absent
+ ip_address: '{{ ip_address }}'
+ port: '{{ port }}'
+ type: '{{ type }}'
+ register: delete_tcp
+
+ - name: 'Check result - Delete TCP health check - idempotency'
+ assert:
+ that:
+ - delete_tcp is successful
+ - delete_tcp is not changed
+
+ # Create an HTTPS_STR_MATCH healthcheck so we can try out more settings
+ - name: 'Create a HTTPS_STR_MATCH health check - check_mode'
+ route53_health_check:
+ state: present
+ ip_address: '{{ ip_address }}'
+ port: '{{ port }}'
+ type: '{{ type_https_match }}'
+ fqdn: '{{ fqdn }}'
+ request_interval: '{{ request_interval }}'
+ string_match: '{{ string_match }}'
+ register: create_match
+ check_mode: true
+
+ - name: 'Check result - Create a HTTPS_STR_MATCH health check - check_mode'
+ assert:
+ that:
+ - create_match is successful
+ - create_match is changed
+
+ - name: 'Create a HTTPS_STR_MATCH health check'
+ route53_health_check:
+ state: present
+ ip_address: '{{ ip_address }}'
+ port: '{{ port }}'
+ type: '{{ type_https_match }}'
+ fqdn: '{{ fqdn }}'
+ request_interval: '{{ request_interval }}'
+ string_match: '{{ string_match }}'
+ register: create_match
+
+ - name: 'Check result - Create a HTTPS_STR_MATCH health check'
+ assert:
+ that:
+ - create_match is successful
+ - create_match is changed
+ - '"health_check" in create_match'
+ - '"id" in _health_check'
+ - _health_check.id != tcp_check_id
+ - '"action" in _health_check'
+ - '"health_check_version" in _health_check'
+ - '"tags" in _health_check'
+ - create_check.health_check.action is none
+ - '"health_check_config" in create_check.health_check'
+ - '"type" in _check_config'
+ - '"disabled" in _check_config'
+ - '"failure_threshold" in _check_config'
+ - '"request_interval" in _check_config'
+ - '"fully_qualified_domain_name" in _check_config'
+ - '"ip_address" in _check_config'
+ - '"port" in _check_config'
+ - '"resource_path" not in _check_config'
+ - '"search_string" in _check_config'
+ - _check_config.disabled == false
+ - _check_config.type == 'HTTPS_STR_MATCH'
+ - _check_config.request_interval == request_interval
+ - _check_config.failure_threshold == 3
+ - _check_config.fully_qualified_domain_name == fqdn
+ - _check_config.ip_address == ip_address
+ - _check_config.port == port
+ - _check_config.search_string == string_match
+ vars:
+ _health_check: '{{ create_match.health_check }}'
+ _check_config: '{{ _health_check.health_check_config }}'
+
+ - set_fact:
+ match_check_id: '{{ create_match.health_check.id }}'
+
+ - name: 'Create a HTTPS_STR_MATCH health check - idempotency - check_mode'
+ route53_health_check:
+ state: present
+ ip_address: '{{ ip_address }}'
+ port: '{{ port }}'
+ type: '{{ type_https_match }}'
+ fqdn: '{{ fqdn }}'
+ request_interval: '{{ request_interval }}'
+ string_match: '{{ string_match }}'
+ register: create_match
+ check_mode: true
+
+ - name: 'Check result - Create a HTTPS_STR_MATCH health check - idempotency - check_mode'
+ assert:
+ that:
+ - create_match is successful
+ - create_match is not changed
+
+ - name: 'Create a HTTPS_STR_MATCH health check - idempotency'
+ route53_health_check:
+ state: present
+ ip_address: '{{ ip_address }}'
+ port: '{{ port }}'
+ type: '{{ type_https_match }}'
+ fqdn: '{{ fqdn }}'
+ request_interval: '{{ request_interval }}'
+ string_match: '{{ string_match }}'
+ register: create_match
+
+ - name: 'Check result - Create a HTTPS_STR_MATCH health check - idempotency'
+ assert:
+ that:
+ - create_match is successful
+ - create_match is not changed
+ - '"health_check" in create_match'
+ - '"id" in _health_check'
+ - _health_check.id == match_check_id
+ - '"action" in _health_check'
+ - '"health_check_version" in _health_check'
+ - '"tags" in _health_check'
+ - create_check.health_check.action is none
+ - '"health_check_config" in create_check.health_check'
+ - '"type" in _check_config'
+ - '"disabled" in _check_config'
+ - '"failure_threshold" in _check_config'
+ - '"request_interval" in _check_config'
+ - '"fully_qualified_domain_name" in _check_config'
+ - '"ip_address" in _check_config'
+ - '"port" in _check_config'
+ - '"resource_path" not in _check_config'
+ - '"search_string" in _check_config'
+ - _check_config.disabled == false
+ - _check_config.type == type_https_match
+ - _check_config.request_interval == request_interval
+ - _check_config.failure_threshold == 3
+ - _check_config.fully_qualified_domain_name == fqdn
+ - _check_config.ip_address == ip_address
+ - _check_config.port == port
+ - _check_config.search_string == string_match
+ vars:
+ _health_check: '{{ create_match.health_check }}'
+ _check_config: '{{ _health_check.health_check_config }}'
+
+ - name: 'Update HTTPS health check - set resource_path - check_mode'
+ route53_health_check:
+ state: present
+ ip_address: '{{ ip_address }}'
+ port: '{{ port }}'
+ type: '{{ type_https_match }}'
+ fqdn: '{{ fqdn }}'
+ request_interval: '{{ request_interval }}'
+ resource_path: '{{ resource_path }}'
+ register: update_resource_path
+ check_mode: true
+
+ - name: 'Check result - Update HTTPS health check - set resource_path - check_mode'
+ assert:
+ that:
+ - update_resource_path is successful
+ - update_resource_path is changed
+
+ - name: 'Update HTTPS health check - set resource_path'
+ route53_health_check:
+ state: present
+ ip_address: '{{ ip_address }}'
+ port: '{{ port }}'
+ type: '{{ type_https_match }}'
+ fqdn: '{{ fqdn }}'
+ request_interval: '{{ request_interval }}'
+ resource_path: '{{ resource_path }}'
+ register: update_resource_path
+
+ - name: 'Check result - Update HTTPS health check - set resource_path'
+ assert:
+ that:
+ - update_resource_path is successful
+ - update_resource_path is changed
+ - '"health_check" in update_resource_path'
+ - '"id" in _health_check'
+ - _health_check.id == match_check_id
+ - '"action" in _health_check'
+ - '"health_check_version" in _health_check'
+ - '"tags" in _health_check'
+ - create_check.health_check.action is none
+ - '"health_check_config" in create_check.health_check'
+ - '"type" in _check_config'
+ - '"disabled" in _check_config'
+ - '"failure_threshold" in _check_config'
+ - '"request_interval" in _check_config'
+ - '"fully_qualified_domain_name" in _check_config'
+ - '"ip_address" in _check_config'
+ - '"port" in _check_config'
+ - '"resource_path" in _check_config'
+ - '"search_string" in _check_config'
+ - _check_config.disabled == false
+ - _check_config.type == type_https_match
+ - _check_config.request_interval == request_interval
+ - _check_config.failure_threshold == 3
+ - _check_config.fully_qualified_domain_name == fqdn
+ - _check_config.ip_address == ip_address
+ - _check_config.port == port
+ - _check_config.resource_path == resource_path
+ - _check_config.search_string == string_match
+ vars:
+ _health_check: '{{ update_resource_path.health_check }}'
+ _check_config: '{{ _health_check.health_check_config }}'
+
+ - name: 'Update HTTPS health check - set resource_path - idempotency - check_mode'
+ route53_health_check:
+ state: present
+ ip_address: '{{ ip_address }}'
+ port: '{{ port }}'
+ type: '{{ type_https_match }}'
+ fqdn: '{{ fqdn }}'
+ request_interval: '{{ request_interval }}'
+ resource_path: '{{ resource_path }}'
+ register: update_resource_path
+ check_mode: true
+
+ - name: 'Check result - Update HTTPS health check - set resource_path - idempotency - check_mode'
+ assert:
+ that:
+ - update_resource_path is successful
+ - update_resource_path is not changed
+
+ - name: 'Update HTTPS health check - set resource_path - idempotency'
+ route53_health_check:
+ state: present
+ ip_address: '{{ ip_address }}'
+ port: '{{ port }}'
+ type: '{{ type_https_match }}'
+ fqdn: '{{ fqdn }}'
+ request_interval: '{{ request_interval }}'
+ resource_path: '{{ resource_path }}'
+ register: update_resource_path
+
+ - name: 'Check result - Update HTTPS health check - set resource_path - idempotency'
+ assert:
+ that:
+ - update_resource_path is successful
+ - update_resource_path is not changed
+ - '"health_check" in update_resource_path'
+ - '"id" in _health_check'
+ - _health_check.id == match_check_id
+ - '"action" in _health_check'
+ - '"health_check_version" in _health_check'
+ - '"tags" in _health_check'
+ - create_check.health_check.action is none
+ - '"health_check_config" in create_check.health_check'
+ - '"type" in _check_config'
+ - '"disabled" in _check_config'
+ - '"failure_threshold" in _check_config'
+ - '"request_interval" in _check_config'
+ - '"fully_qualified_domain_name" in _check_config'
+ - '"ip_address" in _check_config'
+ - '"port" in _check_config'
+ - '"resource_path" in _check_config'
+ - '"search_string" in _check_config'
+ - _check_config.disabled == false
+ - _check_config.type == type_https_match
+ - _check_config.request_interval == request_interval
+ - _check_config.failure_threshold == 3
+ - _check_config.fully_qualified_domain_name == fqdn
+ - _check_config.ip_address == ip_address
+ - _check_config.port == port
+ - _check_config.resource_path == resource_path
+ - _check_config.search_string == string_match
+ vars:
+ _health_check: '{{ update_resource_path.health_check }}'
+ _check_config: '{{ _health_check.health_check_config }}'
+
+ - name: 'Update HTTPS health check - set string_match - check_mode'
+ route53_health_check:
+ state: present
+ ip_address: '{{ ip_address }}'
+ port: '{{ port }}'
+ type: '{{ type_https_match }}'
+ fqdn: '{{ fqdn }}'
+ request_interval: '{{ request_interval }}'
+ string_match: '{{ string_match_updated }}'
+ register: update_string_match
+ check_mode: true
+
+ - name: 'Check result - Update HTTPS health check - set string_match - check_mode'
+ assert:
+ that:
+ - update_string_match is successful
+ - update_string_match is changed
+
+ - name: 'Update HTTPS health check - set string_match'
+ route53_health_check:
+ state: present
+ ip_address: '{{ ip_address }}'
+ port: '{{ port }}'
+ type: '{{ type_https_match }}'
+ fqdn: '{{ fqdn }}'
+ request_interval: '{{ request_interval }}'
+ string_match: '{{ string_match_updated }}'
+ register: update_string_match
+
+ - name: 'Check result - Update HTTPS health check - set string_match'
+ assert:
+ that:
+ - update_string_match is successful
+ - update_string_match is changed
+ - '"health_check" in update_string_match'
+ - '"id" in _health_check'
+ - _health_check.id == match_check_id
+ - '"action" in _health_check'
+ - '"health_check_version" in _health_check'
+ - '"tags" in _health_check'
+ - create_check.health_check.action is none
+ - '"health_check_config" in create_check.health_check'
+ - '"type" in _check_config'
+ - '"disabled" in _check_config'
+ - '"failure_threshold" in _check_config'
+ - '"request_interval" in _check_config'
+ - '"fully_qualified_domain_name" in _check_config'
+ - '"ip_address" in _check_config'
+ - '"port" in _check_config'
+ - '"resource_path" in _check_config'
+ - '"search_string" in _check_config'
+ - _check_config.disabled == false
+ - _check_config.type == type_https_match
+ - _check_config.request_interval == request_interval
+ - _check_config.failure_threshold == 3
+ - _check_config.fully_qualified_domain_name == fqdn
+ - _check_config.ip_address == ip_address
+ - _check_config.port == port
+ - _check_config.resource_path == resource_path
+ - _check_config.search_string == string_match_updated
+ vars:
+ _health_check: '{{ update_string_match.health_check }}'
+ _check_config: '{{ _health_check.health_check_config }}'
+
+ - name: 'Update HTTPS health check - set string_match - idempotency - check_mode'
+ route53_health_check:
+ state: present
+ ip_address: '{{ ip_address }}'
+ port: '{{ port }}'
+ type: '{{ type_https_match }}'
+ fqdn: '{{ fqdn }}'
+ request_interval: '{{ request_interval }}'
+ string_match: '{{ string_match_updated }}'
+ register: update_string_match
+ check_mode: true
+
+ - name: 'Check result - Update HTTPS health check - set string_match - idempotency - check_mode'
+ assert:
+ that:
+ - update_string_match is successful
+ - update_string_match is not changed
+
+ - name: 'Update HTTPS health check - set string_match - idempotency'
+ route53_health_check:
+ state: present
+ ip_address: '{{ ip_address }}'
+ port: '{{ port }}'
+ type: '{{ type_https_match }}'
+ fqdn: '{{ fqdn }}'
+ request_interval: '{{ request_interval }}'
+ string_match: '{{ string_match_updated }}'
+ register: update_string_match
+
+ - name: 'Check result - Update HTTPS health check - set string_match - idempotency'
+ assert:
+ that:
+ - update_string_match is successful
+ - update_string_match is not changed
+ - '"health_check" in update_string_match'
+ - '"id" in _health_check'
+ - _health_check.id == match_check_id
+ - '"action" in _health_check'
+ - '"health_check_version" in _health_check'
+ - '"tags" in _health_check'
+ - create_check.health_check.action is none
+ - '"health_check_config" in create_check.health_check'
+ - '"type" in _check_config'
+ - '"disabled" in _check_config'
+ - '"failure_threshold" in _check_config'
+ - '"request_interval" in _check_config'
+ - '"fully_qualified_domain_name" in _check_config'
+ - '"ip_address" in _check_config'
+ - '"port" in _check_config'
+ - '"resource_path" in _check_config'
+ - '"search_string" in _check_config'
+ - _check_config.disabled == false
+ - _check_config.type == type_https_match
+ - _check_config.request_interval == request_interval
+ - _check_config.failure_threshold == 3
+ - _check_config.fully_qualified_domain_name == fqdn
+ - _check_config.ip_address == ip_address
+ - _check_config.port == port
+ - _check_config.resource_path == resource_path
+ - _check_config.search_string == string_match_updated
+ vars:
+ _health_check: '{{ update_string_match.health_check }}'
+ _check_config: '{{ _health_check.health_check_config }}'
+
+ # Test deletion
+ - name: 'Delete HTTPS health check - check_mode'
+ route53_health_check:
+ state: absent
+ ip_address: '{{ ip_address }}'
+ port: '{{ port }}'
+ type: '{{ type_https_match }}'
+ fqdn: '{{ fqdn }}'
+ request_interval: '{{ request_interval }}'
+ register: delete_match
+ check_mode: true
+
+ - name: 'Check result - Delete HTTPS health check - check_mode'
+ assert:
+ that:
+ - delete_match is successful
+ - delete_match is changed
+
+ - name: 'Delete HTTPS health check'
+ route53_health_check:
+ state: absent
+ ip_address: '{{ ip_address }}'
+ port: '{{ port }}'
+ type: '{{ type_https_match }}'
+ fqdn: '{{ fqdn }}'
+ request_interval: '{{ request_interval }}'
+ register: delete_match
+
+ - name: 'Check result - Delete HTTPS health check'
+ assert:
+ that:
+ - delete_match is successful
+ - delete_match is changed
+
+ - name: 'Delete HTTPS health check - idempotency - check_mode'
+ route53_health_check:
+ state: absent
+ ip_address: '{{ ip_address }}'
+ port: '{{ port }}'
+ type: '{{ type_https_match }}'
+ fqdn: '{{ fqdn }}'
+ request_interval: '{{ request_interval }}'
+ register: delete_match
+ check_mode: true
+
+ - name: 'Check result - Delete HTTPS health check - idempotency - check_mode'
+ assert:
+ that:
+ - delete_match is successful
+ - delete_match is not changed
+
+ - name: 'Delete HTTPS health check - idempotency'
+ route53_health_check:
+ state: absent
+ ip_address: '{{ ip_address }}'
+ port: '{{ port }}'
+ type: '{{ type_https_match }}'
+ fqdn: '{{ fqdn }}'
+ request_interval: '{{ request_interval }}'
+ register: delete_match
+
+ - name: 'Check result - Delete HTTPS health check - idempotency'
+ assert:
+ that:
+ - delete_match is successful
+ - delete_match is not changed
+
+ # Create an HTTP health check with lots of settings we can update
+ - name: 'Create Complex health check - check_mode'
+ route53_health_check:
+ state: present
+ ip_address: '{{ ip_address }}'
+ port: '{{ port }}'
+ type: '{{ type_http_match }}'
+ fqdn: '{{ fqdn }}'
+ request_interval: '{{ request_interval }}'
+ string_match: '{{ string_match }}'
+ resource_path: '{{ resource_path }}'
+ failure_threshold: '{{ failure_threshold }}'
+ disabled: true
+ tags:
+ CamelCase: CamelCaseValue
+ snake_case: snake_case_value
+ "with space": Some value
+ purge_tags: false
+ register: create_complex
+ check_mode: true
+
+ - name: 'Check result - Create Complex health check - check_mode'
+ assert:
+ that:
+ - create_complex is successful
+ - create_complex is changed
+
+ - name: 'Create Complex health check'
+ route53_health_check:
+ state: present
+ ip_address: '{{ ip_address }}'
+ port: '{{ port }}'
+ type: '{{ type_http_match }}'
+ fqdn: '{{ fqdn }}'
+ request_interval: '{{ request_interval }}'
+ string_match: '{{ string_match }}'
+ resource_path: '{{ resource_path }}'
+ failure_threshold: '{{ failure_threshold }}'
+ disabled: true
+ tags:
+ CamelCase: CamelCaseValue
+ snake_case: snake_case_value
+ "with space": Some value
+ purge_tags: false
+ register: create_complex
+
+ - name: 'Check result - Create Complex health check'
+ assert:
+ that:
+ - create_complex is successful
+ - create_complex is changed
+ - '"health_check" in create_complex'
+ - '"id" in _health_check'
+ - _health_check.id != tcp_check_id
+ - _health_check.id != match_check_id
+ - '"action" in _health_check'
+ - '"health_check_version" in _health_check'
+ - '"tags" in _health_check'
+ - '"CamelCase" in _health_check.tags'
+ - _health_check.tags['CamelCase'] == 'CamelCaseValue'
+ - '"snake_case" in _health_check.tags'
+ - _health_check.tags['snake_case'] == 'snake_case_value'
+ - '"with space" in _health_check.tags'
+ - _health_check.tags['with space'] == 'Some value'
+ - create_check.health_check.action is none
+ - '"health_check_config" in create_check.health_check'
+ - '"type" in _check_config'
+ - '"disabled" in _check_config'
+ - '"failure_threshold" in _check_config'
+ - '"request_interval" in _check_config'
+ - '"fully_qualified_domain_name" in _check_config'
+ - '"ip_address" in _check_config'
+ - '"port" in _check_config'
+ - '"resource_path" in _check_config'
+ - '"search_string" in _check_config'
+ - _check_config.disabled == true
+ - _check_config.type == type_http_match
+ - _check_config.request_interval == request_interval
+ - _check_config.failure_threshold == failure_threshold
+ - _check_config.fully_qualified_domain_name == fqdn
+ - _check_config.ip_address == ip_address
+ - _check_config.port == port
+ - _check_config.resource_path == resource_path
+ - _check_config.search_string == string_match
+ vars:
+ _health_check: '{{ create_complex.health_check }}'
+ _check_config: '{{ _health_check.health_check_config }}'
+
+ - set_fact:
+ complex_check_id: '{{ create_complex.health_check.id }}'
+
+ - name: 'Create Complex health check - idempotency - check_mode'
+ route53_health_check:
+ state: present
+ ip_address: '{{ ip_address }}'
+ port: '{{ port }}'
+ type: '{{ type_http_match }}'
+ fqdn: '{{ fqdn }}'
+ request_interval: '{{ request_interval }}'
+ string_match: '{{ string_match }}'
+ resource_path: '{{ resource_path }}'
+ failure_threshold: '{{ failure_threshold }}'
+ disabled: true
+ tags:
+ CamelCase: CamelCaseValue
+ snake_case: snake_case_value
+ "with space": Some value
+ purge_tags: false
+ register: create_complex
+ check_mode: true
+
+ - name: 'Check result - Create Complex health check - idempotency - check_mode'
+ assert:
+ that:
+ - create_complex is successful
+ - create_complex is not changed
+
+ - name: 'Create Complex health check - idempotency'
+ route53_health_check:
+ state: present
+ ip_address: '{{ ip_address }}'
+ port: '{{ port }}'
+ type: '{{ type_http_match }}'
+ fqdn: '{{ fqdn }}'
+ request_interval: '{{ request_interval }}'
+ string_match: '{{ string_match }}'
+ resource_path: '{{ resource_path }}'
+ failure_threshold: '{{ failure_threshold }}'
+ disabled: true
+ tags:
+ CamelCase: CamelCaseValue
+ snake_case: snake_case_value
+ "with space": Some value
+ purge_tags: false
+ register: create_complex
+
+ - name: 'Check result - Create Complex health check - idempotency'
+ assert:
+ that:
+ - create_complex is successful
+ - create_complex is not changed
+ - '"health_check" in create_complex'
+ - '"id" in _health_check'
+ - _health_check.id == complex_check_id
+ - '"action" in _health_check'
+ - '"health_check_version" in _health_check'
+ - '"tags" in _health_check'
+ - '"CamelCase" in _health_check.tags'
+ - _health_check.tags['CamelCase'] == 'CamelCaseValue'
+ - '"snake_case" in _health_check.tags'
+ - _health_check.tags['snake_case'] == 'snake_case_value'
+ - '"with space" in _health_check.tags'
+ - _health_check.tags['with space'] == 'Some value'
+ - create_check.health_check.action is none
+ - '"health_check_config" in create_check.health_check'
+ - '"type" in _check_config'
+ - '"disabled" in _check_config'
+ - '"failure_threshold" in _check_config'
+ - '"request_interval" in _check_config'
+ - '"fully_qualified_domain_name" in _check_config'
+ - '"ip_address" in _check_config'
+ - '"port" in _check_config'
+ - '"resource_path" in _check_config'
+ - '"search_string" in _check_config'
+ - _check_config.disabled == true
+ - _check_config.type == type_http_match
+ - _check_config.request_interval == request_interval
+ - _check_config.failure_threshold == failure_threshold
+ - _check_config.fully_qualified_domain_name == fqdn
+ - _check_config.ip_address == ip_address
+ - _check_config.port == port
+ - _check_config.resource_path == resource_path
+ - _check_config.search_string == string_match
+ vars:
+ _health_check: '{{ create_complex.health_check }}'
+ _check_config: '{{ _health_check.health_check_config }}'
+
+ - name: 'Update Complex health check - check_mode'
+ route53_health_check:
+ state: present
+ ip_address: '{{ ip_address }}'
+ port: '{{ port }}'
+ type: '{{ type_http_match }}'
+ fqdn: '{{ fqdn }}'
+ request_interval: '{{ request_interval }}'
+ string_match: '{{ string_match_updated }}'
+ resource_path: '{{ resource_path_updated }}'
+ failure_threshold: '{{ failure_threshold_updated }}'
+ register: update_complex
+ check_mode: true
+
+ - name: 'Check result - Update Complex health check - check_mode'
+ assert:
+ that:
+ - update_complex is successful
+ - update_complex is changed
+
+ - name: 'Update Complex health check'
+ route53_health_check:
+ state: present
+ ip_address: '{{ ip_address }}'
+ port: '{{ port }}'
+ type: '{{ type_http_match }}'
+ fqdn: '{{ fqdn }}'
+ request_interval: '{{ request_interval }}'
+ string_match: '{{ string_match_updated }}'
+ resource_path: '{{ resource_path_updated }}'
+ failure_threshold: '{{ failure_threshold_updated }}'
+ register: update_complex
+
+ - name: 'Check result - Update Complex health check'
+ assert:
+ that:
+ - update_complex is successful
+ - update_complex is changed
+ - '"health_check" in update_complex'
+ - '"id" in _health_check'
+ - _health_check.id == complex_check_id
+ - '"action" in _health_check'
+ - '"health_check_version" in _health_check'
+ - '"tags" in _health_check'
+ - '"CamelCase" in _health_check.tags'
+ - _health_check.tags['CamelCase'] == 'CamelCaseValue'
+ - '"snake_case" in _health_check.tags'
+ - _health_check.tags['snake_case'] == 'snake_case_value'
+ - '"with space" in _health_check.tags'
+ - _health_check.tags['with space'] == 'Some value'
+ - create_check.health_check.action is none
+ - '"health_check_config" in create_check.health_check'
+ - '"type" in _check_config'
+ - '"disabled" in _check_config'
+ - '"failure_threshold" in _check_config'
+ - '"request_interval" in _check_config'
+ - '"fully_qualified_domain_name" in _check_config'
+ - '"ip_address" in _check_config'
+ - '"port" in _check_config'
+ - '"resource_path" in _check_config'
+ - '"search_string" in _check_config'
+ - _check_config.disabled == true
+ - _check_config.type == type_http_match
+ - _check_config.request_interval == request_interval
+ - _check_config.failure_threshold == failure_threshold_updated
+ - _check_config.fully_qualified_domain_name == fqdn
+ - _check_config.ip_address == ip_address
+ - _check_config.port == port
+ - _check_config.resource_path == resource_path_updated
+ - _check_config.search_string == string_match_updated
+ vars:
+ _health_check: '{{ update_complex.health_check }}'
+ _check_config: '{{ _health_check.health_check_config }}'
+
+ - name: 'Update Complex health check - idempotency - check_mode'
+ route53_health_check:
+ state: present
+ ip_address: '{{ ip_address }}'
+ port: '{{ port }}'
+ type: '{{ type_http_match }}'
+ fqdn: '{{ fqdn }}'
+ request_interval: '{{ request_interval }}'
+ string_match: '{{ string_match_updated }}'
+ resource_path: '{{ resource_path_updated }}'
+ failure_threshold: '{{ failure_threshold_updated }}'
+ register: update_complex
+ check_mode: true
+
+ - name: 'Check result - Update Complex health check - idempotency - check_mode'
+ assert:
+ that:
+ - update_complex is successful
+ - update_complex is not changed
+
+ - name: 'Update Complex health check - idempotency'
+ route53_health_check:
+ state: present
+ ip_address: '{{ ip_address }}'
+ port: '{{ port }}'
+ type: '{{ type_http_match }}'
+ fqdn: '{{ fqdn }}'
+ request_interval: '{{ request_interval }}'
+ string_match: '{{ string_match_updated }}'
+ resource_path: '{{ resource_path_updated }}'
+ failure_threshold: '{{ failure_threshold_updated }}'
+ register: update_complex
+
+ - name: 'Check result - Update Complex health check - idempotency'
+ assert:
+ that:
+ - update_complex is successful
+ - update_complex is not changed
+ - '"health_check" in update_complex'
+ - '"id" in _health_check'
+ - _health_check.id == complex_check_id
+ - '"action" in _health_check'
+ - '"health_check_version" in _health_check'
+ - '"tags" in _health_check'
+ - '"CamelCase" in _health_check.tags'
+ - _health_check.tags['CamelCase'] == 'CamelCaseValue'
+ - '"snake_case" in _health_check.tags'
+ - _health_check.tags['snake_case'] == 'snake_case_value'
+ - '"with space" in _health_check.tags'
+ - _health_check.tags['with space'] == 'Some value'
+ - create_check.health_check.action is none
+ - '"health_check_config" in create_check.health_check'
+ - '"type" in _check_config'
+ - '"disabled" in _check_config'
+ - '"failure_threshold" in _check_config'
+ - '"request_interval" in _check_config'
+ - '"fully_qualified_domain_name" in _check_config'
+ - '"ip_address" in _check_config'
+ - '"port" in _check_config'
+ - '"resource_path" in _check_config'
+ - '"search_string" in _check_config'
+ - _check_config.disabled == true
+ - _check_config.type == type_http_match
+ - _check_config.request_interval == request_interval
+ - _check_config.failure_threshold == failure_threshold_updated
+ - _check_config.fully_qualified_domain_name == fqdn
+ - _check_config.ip_address == ip_address
+ - _check_config.port == port
+ - _check_config.resource_path == resource_path_updated
+ - _check_config.search_string == string_match_updated
+ vars:
+ _health_check: '{{ update_complex.health_check }}'
+ _check_config: '{{ _health_check.health_check_config }}'
+
+ - name: 'Delete Complex health check - check_mode'
+ route53_health_check:
+ state: absent
+ ip_address: '{{ ip_address }}'
+ port: '{{ port }}'
+ type: '{{ type_http_match }}'
+ fqdn: '{{ fqdn }}'
+ request_interval: '{{ request_interval }}'
+ register: delete_complex
+ check_mode: true
+
+ - name: 'Check result - Delete Complex health check - check_mode'
+ assert:
+ that:
+ - delete_complex is successful
+ - delete_complex is changed
+
+ - name: 'Delete Complex health check'
+ route53_health_check:
+ state: absent
+ ip_address: '{{ ip_address }}'
+ port: '{{ port }}'
+ type: '{{ type_http_match }}'
+ fqdn: '{{ fqdn }}'
+ request_interval: '{{ request_interval }}'
+ register: delete_complex
+
+ - name: 'Check result - Delete Complex health check'
+ assert:
+ that:
+ - delete_complex is successful
+ - delete_complex is changed
+
+ - name: 'Delete Complex health check - idempotency - check_mode'
+ route53_health_check:
+ state: absent
+ ip_address: '{{ ip_address }}'
+ port: '{{ port }}'
+ type: '{{ type_http_match }}'
+ fqdn: '{{ fqdn }}'
+ request_interval: '{{ request_interval }}'
+ register: delete_complex
+ check_mode: true
+
+ - name: 'Check result - Delete Complex health check - idempotency - check_mode'
+ assert:
+ that:
+ - delete_complex is successful
+ - delete_complex is not changed
+
+ - name: 'Delete Complex health check - idempotency'
+ route53_health_check:
+ state: absent
+ ip_address: '{{ ip_address }}'
+ port: '{{ port }}'
+ type: '{{ type_http_match }}'
+ fqdn: '{{ fqdn }}'
+ request_interval: '{{ request_interval }}'
+ register: delete_complex
+
+ - name: 'Check result - Delete Complex health check - idempotency'
+ assert:
+ that:
+ - delete_complex is successful
+ - delete_complex is not changed
+
+ always:
+
+ ################################################
+ # TEARDOWN STARTS HERE
+ ################################################
+
+ - name: 'Delete TCP health check'
+ route53_health_check:
+ state: absent
+ ip_address: '{{ ip_address }}'
+ port: '{{ port }}'
+ type: '{{ type }}'
+ ignore_errors: true
+
+ - name: 'Delete HTTPS health check'
+ route53_health_check:
+ state: absent
+ ip_address: '{{ ip_address }}'
+ port: '{{ port }}'
+ type: '{{ type_https_match }}'
+ fqdn: '{{ fqdn }}'
+ request_interval: '{{ request_interval }}'
+ ignore_errors: true
+
+ - name: 'Delete Complex health check'
+ route53_health_check:
+ state: absent
+ ip_address: '{{ ip_address }}'
+ port: '{{ port }}'
+ type: '{{ type_http_match }}'
+ fqdn: '{{ fqdn }}'
+ request_interval: '{{ request_interval }}'
+ ignore_errors: true
+
+ - name: release EIP
+ ec2_eip:
+ state: absent
+ public_ip: '{{ ip_address }}'
+ ignore_errors: true
diff --git a/tests/integration/targets/route53_zone/tasks/main.yml b/tests/integration/targets/route53_zone/tasks/main.yml
index 5fe154a6712..9731c4a5c46 100644
--- a/tests/integration/targets/route53_zone/tasks/main.yml
+++ b/tests/integration/targets/route53_zone/tasks/main.yml
@@ -27,6 +27,9 @@
zone: "{{ resource_prefix }}.public"
comment: original comment
state: present
+ tags:
+ TestTag: "{{ resource_prefix }}"
+ another_tag: "{{ resource_prefix }} again"
register: output
- assert:
@@ -34,6 +37,8 @@
- output.changed
- output.comment == 'original comment'
- output.name == '{{ resource_prefix }}.public.'
+ - output.tags.TestTag == '{{ resource_prefix }}'
+ - output.tags.another_tag == '{{ resource_prefix }} again'
- not output.private_zone
# ============================================================
@@ -42,6 +47,9 @@
zone: "{{ resource_prefix }}.check.public"
comment: original comment
state: present
+ tags:
+ TestTag: "{{ resource_prefix }}"
+ another_tag: "{{ resource_prefix }} again"
register: output
check_mode: yes
@@ -50,6 +58,8 @@
- output.changed
- output.comment == 'original comment'
- output.name == '{{ resource_prefix }}.check.public.'
+ - output.tags.TestTag == '{{ resource_prefix }}'
+ - output.tags.another_tag == '{{ resource_prefix }} again'
- not output.private_zone
# ============================================================
@@ -58,6 +68,9 @@
zone: "{{ resource_prefix }}.public"
comment: original comment
state: present
+ tags:
+ TestTag: "{{ resource_prefix }}"
+ another_tag: "{{ resource_prefix }} again"
register: output
- assert:
@@ -65,6 +78,8 @@
- not output.changed
- output.comment == 'original comment'
- output.name == '{{ resource_prefix }}.public.'
+ - output.tags.TestTag == '{{ resource_prefix }}'
+ - output.tags.another_tag == '{{ resource_prefix }} again'
- not output.private_zone
- name: Do an idemptotent update of a public zone (CHECK MODE)
@@ -72,6 +87,9 @@
zone: "{{ resource_prefix }}.public"
comment: original comment
state: present
+ tags:
+ TestTag: "{{ resource_prefix }}"
+ another_tag: "{{ resource_prefix }} again"
register: output
check_mode: yes
@@ -80,26 +98,50 @@
- not output.changed
- output.comment == 'original comment'
- output.name == '{{ resource_prefix }}.public.'
+ - output.tags.TestTag == '{{ resource_prefix }}'
+ - output.tags.another_tag == '{{ resource_prefix }} again'
- not output.private_zone
# ============================================================
- - name: Update comment of a public zone
+ - name: Modify tags on a public zone
+ route53_zone:
+ zone: "{{ resource_prefix }}.public"
+ comment: original comment
+ state: present
+ tags:
+ AnotherTag: "{{ resource_prefix }}.anothertag"
+ purge_tags: true
+ register: output
+
+ - assert:
+ that:
+ - output.changed
+ - "'TestTag' not in output.tags"
+ - output.tags.AnotherTag == '{{ resource_prefix }}.anothertag'
+
+ # ============================================================
+ - name: Update comment and remove tags of a public zone
route53_zone:
zone: "{{ resource_prefix }}.public"
comment: updated comment
state: present
+ purge_tags: true
+ tags: {}
register: output
- assert:
that:
- output.changed
- output.result.comment == "updated comment"
+ - not output.tags
- - name: Update comment of a public zone (CHECK MODE)
+ - name: Update comment and remove tags of a public zone (CHECK MODE)
route53_zone:
zone: "{{ resource_prefix }}.public"
comment: updated comment for check
state: present
+ purge_tags: true
+ tags: {}
register: output
check_mode: yes
@@ -107,6 +149,7 @@
that:
- output.changed
- output.result.comment == "updated comment for check"
+ - not output.tags
# ============================================================
- name: Delete public zone (CHECK MODE)
diff --git a/tests/integration/targets/s3_bucket_notification/defaults/main.yml b/tests/integration/targets/s3_bucket_notification/defaults/main.yml
index cb05de1adbe..0f6633b6ed5 100644
--- a/tests/integration/targets/s3_bucket_notification/defaults/main.yml
+++ b/tests/integration/targets/s3_bucket_notification/defaults/main.yml
@@ -3,7 +3,6 @@
lambda_function_name: '{{ resource_prefix }}'
# IAM role names have to be less than 64 characters
# we hash the resource_prefix to get a shorter, unique string
-unique_id: "{{ resource_prefix | hash('md5') |truncate(8, True, '') }}"
-bucket_name: '{{ unique_id }}-bucket'
-lambda_name: '{{ unique_id }}-lambda'
-lambda_role_name: 'ansible-test-{{ unique_id }}-s3-notifications'
+bucket_name: '{{ tiny_prefix }}-bucket'
+lambda_name: '{{ tiny_prefix }}-lambda'
+lambda_role_name: 'ansible-test-{{ tiny_prefix }}-s3-notifications'
diff --git a/tests/integration/targets/s3_lifecycle/defaults/main.yml b/tests/integration/targets/s3_lifecycle/defaults/main.yml
index 2783b0e9ec0..3015292c6cb 100644
--- a/tests/integration/targets/s3_lifecycle/defaults/main.yml
+++ b/tests/integration/targets/s3_lifecycle/defaults/main.yml
@@ -1,2 +1 @@
-unique_id: "{{ resource_prefix | hash('md5') |truncate(8, True, '') }}"
-bucket_name: '{{ unique_id }}-s3-lifecycle'
+bucket_name: '{{ tiny_prefix }}-s3-lifecycle'
diff --git a/tests/integration/targets/s3_logging/defaults/main.yml b/tests/integration/targets/s3_logging/defaults/main.yml
index 7b46f93a1d5..f8f1d758746 100644
--- a/tests/integration/targets/s3_logging/defaults/main.yml
+++ b/tests/integration/targets/s3_logging/defaults/main.yml
@@ -1,5 +1,4 @@
---
-unique_id: "{{ resource_prefix | hash('md5') |truncate(8, True, '') }}"
-test_bucket: '{{ unique_id }}-s3-logging'
-log_bucket_1: '{{ unique_id }}-logs-1'
-log_bucket_2: '{{ unique_id }}-logs-2'
+test_bucket: '{{ tiny_prefix }}-s3-logging'
+log_bucket_1: '{{ tiny_prefix }}-logs-1'
+log_bucket_2: '{{ tiny_prefix }}-logs-2'
diff --git a/tests/integration/targets/s3_metrics_configuration/defaults/main.yml b/tests/integration/targets/s3_metrics_configuration/defaults/main.yml
index cb97ba137db..85f5435bd8b 100644
--- a/tests/integration/targets/s3_metrics_configuration/defaults/main.yml
+++ b/tests/integration/targets/s3_metrics_configuration/defaults/main.yml
@@ -1,3 +1,2 @@
---
-unique_id: "{{ resource_prefix | hash('md5') |truncate(8, True, '') }}"
-test_bucket: '{{ unique_id }}-testbucket'
+test_bucket: '{{ tiny_prefix }}-testbucket'
diff --git a/tests/integration/targets/s3_sync/defaults/main.yml b/tests/integration/targets/s3_sync/defaults/main.yml
index 3455994493a..b48f03b7849 100644
--- a/tests/integration/targets/s3_sync/defaults/main.yml
+++ b/tests/integration/targets/s3_sync/defaults/main.yml
@@ -1,3 +1,3 @@
-unique_id: "{{ resource_prefix | hash('md5') |truncate(8, True, '') }}"
-test_bucket: "{{ unique_id }}-testbucket-ansible"
-test_bucket_2: "{{ unique_id }}-testbucket-ansible-2"
+test_bucket: "{{ tiny_prefix }}-testbucket-ansible"
+test_bucket_2: "{{ tiny_prefix }}-testbucket-ansible-2"
+test_bucket_3: "{{ tiny_prefix }}-testbucket-ansible-3"
diff --git a/tests/integration/targets/s3_sync/tasks/main.yml b/tests/integration/targets/s3_sync/tasks/main.yml
index eb72de27251..667a5b34c4b 100644
--- a/tests/integration/targets/s3_sync/tasks/main.yml
+++ b/tests/integration/targets/s3_sync/tasks/main.yml
@@ -77,6 +77,7 @@
- assert:
that:
- output is changed
+
# ============================================================
- name: Sync files already present
@@ -99,6 +100,27 @@
that:
- output is not changed
+ # ============================================================
+ - name: Create a third s3_bucket
+ s3_bucket:
+ name: "{{ test_bucket_3 }}"
+ state: present
+ register: output
+
+ - assert:
+ that:
+ - output.changed
+ - output.name == "{{ test_bucket_3 }}"
+ - not output.requester_pays
+
+ - name: Sync individual file with remote bucket
+ s3_sync:
+ bucket: "{{ test_bucket_3 }}"
+ file_root: "{{ output_dir }}/s3_sync/test1.txt"
+ register: output
+ - assert:
+ that:
+ - output is changed
# ============================================================
# DOCUMENTATION EXAMPLES
@@ -123,6 +145,60 @@
- output is changed
always:
+
+ - name: Empty all buckets before deleting
+ block:
+ - name: list test_bucket objects
+ aws_s3:
+ bucket: "{{ test_bucket }}"
+ mode: list
+ register: objects
+ ignore_errors: true
+
+ - name: remove objects from test_bucket
+ aws_s3:
+ bucket: "{{ test_bucket }}"
+ mode: delobj
+ object: "{{ obj }}"
+ with_items: "{{ objects.s3_keys }}"
+ loop_control:
+ loop_var: obj
+ ignore_errors: true
+
+ - name: list test_bucket_2 objects
+ aws_s3:
+ bucket: "{{ test_bucket_2 }}"
+ mode: list
+ register: objects
+ ignore_errors: true
+
+ - name: remove objects from test_bucket_2
+ aws_s3:
+ bucket: "{{ test_bucket_2 }}"
+ mode: delobj
+ object: "{{ obj }}"
+ with_items: "{{ objects.s3_keys }}"
+ loop_control:
+ loop_var: obj
+ ignore_errors: true
+
+ - name: list test_bucket_3 objects
+ aws_s3:
+ bucket: "{{ test_bucket_3 }}"
+ mode: list
+ register: objects
+ ignore_errors: true
+
+ - name: remove objects from test_bucket_3
+ aws_s3:
+ bucket: "{{ test_bucket_3 }}"
+ mode: delobj
+ object: "{{ obj }}"
+ with_items: "{{ objects.s3_keys }}"
+ loop_control:
+ loop_var: obj
+ ignore_errors: true
+
- name: Ensure all buckets are deleted
s3_bucket:
name: "{{item}}"
@@ -132,3 +208,4 @@
with_items:
- "{{ test_bucket }}"
- "{{ test_bucket_2 }}"
+ - "{{ test_bucket_3 }}"
diff --git a/tests/integration/targets/setup_botocore_pip/defaults/main.yml b/tests/integration/targets/setup_botocore_pip/defaults/main.yml
new file mode 100644
index 00000000000..5a50b775907
--- /dev/null
+++ b/tests/integration/targets/setup_botocore_pip/defaults/main.yml
@@ -0,0 +1,2 @@
+default_botocore_version: '1.18.0'
+default_boto3_version: '1.15.0'
diff --git a/tests/integration/targets/setup_botocore_pip/handlers/main.yml b/tests/integration/targets/setup_botocore_pip/handlers/main.yml
new file mode 100644
index 00000000000..2536d1ac773
--- /dev/null
+++ b/tests/integration/targets/setup_botocore_pip/handlers/main.yml
@@ -0,0 +1,2 @@
+- name: 'Delete temporary pip environment'
+ include_tasks: cleanup.yml
diff --git a/tests/integration/targets/setup_botocore_pip/tasks/cleanup.yml b/tests/integration/targets/setup_botocore_pip/tasks/cleanup.yml
new file mode 100644
index 00000000000..25b3ec27efc
--- /dev/null
+++ b/tests/integration/targets/setup_botocore_pip/tasks/cleanup.yml
@@ -0,0 +1,5 @@
+- name: 'Delete temporary pip environment'
+ file:
+ path: "{{ botocore_pip_directory }}"
+ state: absent
+ no_log: yes
diff --git a/tests/integration/targets/setup_botocore_pip/tasks/main.yml b/tests/integration/targets/setup_botocore_pip/tasks/main.yml
new file mode 100644
index 00000000000..b183b7d726d
--- /dev/null
+++ b/tests/integration/targets/setup_botocore_pip/tasks/main.yml
@@ -0,0 +1,42 @@
+- name: 'Ensure that we have virtualenv available to us'
+ pip:
+ name: virtualenv
+
+- name: 'Create temporary directory for pip environment'
+ tempfile:
+ state: directory
+ prefix: botocore
+ suffix: .test
+ register: botocore_pip_directory
+ notify:
+ - 'Delete temporary pip environment'
+
+- name: 'Record temporary directory'
+ set_fact:
+ botocore_pip_directory: "{{ botocore_pip_directory.path }}"
+
+- set_fact:
+ botocore_virtualenv: "{{ botocore_pip_directory }}/virtualenv"
+ botocore_virtualenv_command: "{{ ansible_python_interpreter }} -m virtualenv"
+
+- set_fact:
+ botocore_virtualenv_interpreter: "{{ botocore_virtualenv }}/bin/python"
+
+- pip:
+ name:
+ - 'boto3{{ _boto3_comparison }}{{ _boto3_version }}'
+ - 'botocore{{ _botocore_comparison }}{{ _botocore_version }}'
+ - 'coverage<5'
+ virtualenv: "{{ botocore_virtualenv }}"
+ virtualenv_command: "{{ botocore_virtualenv_command }}"
+ virtualenv_site_packages: no
+ vars:
+ _boto3_version: '{{ boto3_version | default(default_boto3_version) }}'
+ _botocore_version: '{{ botocore_version | default(default_botocore_version) }}'
+ _is_default_boto3: '{{ _boto3_version == default_boto3_version }}'
+ _is_default_botocore: '{{ _botocore_version == default_botocore_version }}'
+ # Only set the default to >= if the other dep has been updated and the dep has not been set
+ _default_boto3_comparison: '{% if _is_default_boto3 and not _is_default_botocore %}>={% else %}=={% endif %}'
+ _default_botocore_comparison: '{% if _is_default_botocore and not _is_default_boto3 %}>={% else %}=={% endif %}'
+ _boto3_comparison: '{{ boto3_comparison | default(_default_boto3_comparison) }}'
+ _botocore_comparison: '{{ botocore_comparison | default(_default_botocore_comparison) }}'
diff --git a/tests/integration/targets/setup_ec2_facts/defaults/main.yml b/tests/integration/targets/setup_ec2_facts/defaults/main.yml
new file mode 100644
index 00000000000..e02cb60128a
--- /dev/null
+++ b/tests/integration/targets/setup_ec2_facts/defaults/main.yml
@@ -0,0 +1,5 @@
+ec2_ami_owner_id: '125523088429'
+#ec2_ami_name: 'Fedora-Cloud-Base-*.x86_64*'
+ec2_ami_name: 'CentOS Stream 9 x86_64*'
+#ec2_ami_ssh_user: 'fedora'
+ec2_ami_ssh_user: 'centos'
diff --git a/tests/integration/targets/setup_ec2_facts/tasks/main.yml b/tests/integration/targets/setup_ec2_facts/tasks/main.yml
new file mode 100644
index 00000000000..f41791073a3
--- /dev/null
+++ b/tests/integration/targets/setup_ec2_facts/tasks/main.yml
@@ -0,0 +1,53 @@
+---
+# Setup a couple of common facts about the AWS Region
+#
+# Information about availablity zones
+# - ec2_availability_zone_names
+#
+# An EC2 AMI that can be used for spinning up Instances performs as search
+# rather than hardcoding the IDs so we're not limited to specific Regions
+# - ec2_ami_id
+#
+- module_defaults:
+ group/aws:
+ aws_access_key: '{{ aws_access_key }}'
+ aws_secret_key: '{{ aws_secret_key }}'
+ security_token: '{{ security_token | default(omit) }}'
+ region: '{{ aws_region }}'
+
+ run_once: True
+ block:
+ # ============================================================
+
+ - name: Get available AZs
+ aws_az_info:
+ filters:
+ region-name: '{{ aws_region }}'
+ register: _az_info
+
+ - name: Pick an AZ
+ set_fact:
+ ec2_availability_zone_names: '{{ _az_info.availability_zones | selectattr("zone_name", "defined") | map(attribute="zone_name") | list }}'
+
+ # ============================================================
+
+ - name: Get a list of images
+ ec2_ami_info:
+ filters:
+ name: '{{ ec2_ami_name }}'
+ owner-id: '{{ ec2_ami_owner_id }}'
+ architecture: x86_64
+ virtualization-type: hvm
+ root-device-type: ebs
+ register: _images_info
+ # Very spammy
+ no_log: True
+
+ - name: Set Fact for latest AMI
+ vars:
+ latest_image: '{{ _images_info.images | sort(attribute="creation_date") | reverse | first }}'
+ set_fact:
+ ec2_ami_id: '{{ latest_image.image_id }}'
+ ec2_ami_details: '{{ latest_image }}'
+ ec2_ami_root_disk: '{{ latest_image.block_device_mappings[0].device_name }}'
+ ec2_ami_ssh_user: '{{ ec2_ami_ssh_user }}'
diff --git a/tests/integration/targets/setup_sshkey/files/ec2-fingerprint.py b/tests/integration/targets/setup_sshkey/files/ec2-fingerprint.py
new file mode 100644
index 00000000000..ea2f51b0f4c
--- /dev/null
+++ b/tests/integration/targets/setup_sshkey/files/ec2-fingerprint.py
@@ -0,0 +1,33 @@
+#!/usr/bin/env python
+"""
+Reads an OpenSSH Public key and spits out the 'AWS' MD5 sum
+The equivalent of
+
+ssh-keygen -f id_rsa.pub -e -m PKCS8 | openssl pkey -pubin -outform DER | openssl md5 -c | cut -f 2 -d ' '
+
+(but without needing the OpenSSL CLI)
+"""
+
+from __future__ import absolute_import, division, print_function
+__metaclass__ = type
+
+import hashlib
+import sys
+from Crypto.PublicKey import RSA
+
+if len(sys.argv) == 0:
+ ssh_public_key = "id_rsa.pub"
+else:
+ ssh_public_key = sys.argv[1]
+
+with open(ssh_public_key, 'r') as key_fh:
+ data = key_fh.read()
+
+# Convert from SSH format to DER format
+public_key = RSA.importKey(data).exportKey('DER')
+md5digest = hashlib.md5(public_key).hexdigest()
+# Format the md5sum into the normal format
+pairs = zip(md5digest[::2], md5digest[1::2])
+md5string = ":".join(["".join(pair) for pair in pairs])
+
+print(md5string)
diff --git a/tests/integration/targets/setup_sshkey/tasks/main.yml b/tests/integration/targets/setup_sshkey/tasks/main.yml
new file mode 100644
index 00000000000..31bd2176e5c
--- /dev/null
+++ b/tests/integration/targets/setup_sshkey/tasks/main.yml
@@ -0,0 +1,71 @@
+# (c) 2014, James Laska
+
+# This file is part of Ansible
+#
+# Ansible is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Ansible is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Ansible. If not, see .
+
+- name: create a temp dir
+ tempfile:
+ state: directory
+ register: sshkey_dir
+ tags:
+ - prepare
+
+- name: ensure script is available
+ copy:
+ src: ec2-fingerprint.py
+ dest: '{{ sshkey_dir.path }}/ec2-fingerprint.py'
+ mode: 0700
+ tags:
+ - prepare
+
+- name: Set location of SSH keys
+ set_fact:
+ sshkey: '{{ sshkey_dir.path }}/key_one'
+ another_sshkey: '{{ sshkey_dir.path }}/key_two'
+ sshkey_pub: '{{ sshkey_dir.path }}/key_one.pub'
+ another_sshkey_pub: '{{ sshkey_dir.path }}/key_two.pub'
+
+- name: generate sshkey
+ shell: echo 'y' | ssh-keygen -P '' -f '{{ sshkey }}'
+ tags:
+ - prepare
+
+- name: record fingerprint
+ shell: '{{ sshkey_dir.path }}/ec2-fingerprint.py {{ sshkey_pub }}'
+ register: fingerprint
+ tags:
+ - prepare
+
+- name: generate another_sshkey
+ shell: echo 'y' | ssh-keygen -P '' -f {{ another_sshkey }}
+ tags:
+ - prepare
+
+- name: record another fingerprint
+ shell: '{{ sshkey_dir.path }}/ec2-fingerprint.py {{ another_sshkey_pub }}'
+ register: another_fingerprint
+ tags:
+ - prepare
+
+- name: set facts for future roles
+ set_fact:
+ # Public SSH keys (OpenSSH format)
+ key_material: "{{ lookup('file', sshkey_pub) }}"
+ another_key_material: "{{ lookup('file', another_sshkey_pub) }}"
+ # AWS 'fingerprint' (md5digest)
+ fingerprint: '{{ fingerprint.stdout }}'
+ another_fingerprint: '{{ another_fingerprint.stdout }}'
+ tags:
+ - prepare
diff --git a/tests/integration/targets/sns_topic/defaults/main.yml b/tests/integration/targets/sns_topic/defaults/main.yml
index c0134d0a286..6f14aff4cd4 100644
--- a/tests/integration/targets/sns_topic/defaults/main.yml
+++ b/tests/integration/targets/sns_topic/defaults/main.yml
@@ -1,7 +1,5 @@
# we hash the resource_prefix to get a shorter, unique string
-unique_id: "{{ resource_prefix | hash('md5') }}"
-
-sns_topic_topic_name: "ansible-test-{{ unique_id }}-topic"
+sns_topic_topic_name: "ansible-test-{{ tiny_prefix }}-topic"
sns_topic_subscriptions:
- endpoint: "{{ sns_topic_subscriber_arn }}"
protocol: "lambda"
@@ -10,5 +8,5 @@ sns_topic_third_party_region: "{{ sns_topic_third_party_topic_arn.split(':')[3]
# additional test resource namings
sns_topic_lambda_function: "sns_topic_lambda"
-sns_topic_lambda_name: "ansible-test-{{ unique_id }}-{{ sns_topic_lambda_function }}"
-sns_topic_lambda_role: "ansible-test-{{ unique_id }}-sns-lambda"
+sns_topic_lambda_name: "ansible-test-{{ tiny_prefix }}-{{ sns_topic_lambda_function }}"
+sns_topic_lambda_role: "ansible-test-{{ tiny_prefix }}-sns-lambda"
diff --git a/tests/integration/targets/sns_topic/tasks/main.yml b/tests/integration/targets/sns_topic/tasks/main.yml
index 891b162e4d2..94214b20fa9 100644
--- a/tests/integration/targets/sns_topic/tasks/main.yml
+++ b/tests/integration/targets/sns_topic/tasks/main.yml
@@ -127,7 +127,7 @@
delivery_policy:
http:
defaultHealthyRetryPolicy:
- minDelayTarget: 20
+ minDelayTarget: "20"
maxDelayTarget: 20
numRetries: 3
numMaxDelayRetries: 0
@@ -153,7 +153,7 @@
delivery_policy:
http:
defaultHealthyRetryPolicy:
- minDelayTarget: 20
+ minDelayTarget: "20"
maxDelayTarget: 20
numRetries: 3
numMaxDelayRetries: 0
@@ -179,7 +179,7 @@
delivery_policy:
http:
defaultHealthyRetryPolicy:
- minDelayTarget: 40
+ minDelayTarget: "40"
maxDelayTarget: 40
numRetries: 6
numMaxDelayRetries: 0
diff --git a/tests/integration/targets/sts_assume_role/defaults/main.yml b/tests/integration/targets/sts_assume_role/defaults/main.yml
index 1287fe1f5b9..17072d6a4fd 100644
--- a/tests/integration/targets/sts_assume_role/defaults/main.yml
+++ b/tests/integration/targets/sts_assume_role/defaults/main.yml
@@ -1,2 +1 @@
-unique_id: "{{ resource_prefix | hash('md5') }}"
-iam_role_name: "ansible-test-sts-{{ unique_id }}"
+iam_role_name: "ansible-test-{{ tiny_prefix }}"
diff --git a/tests/requirements.yml b/tests/requirements.yml
index 27240dbf096..3480da42122 100644
--- a/tests/requirements.yml
+++ b/tests/requirements.yml
@@ -1,7 +1,7 @@
integration_tests_dependencies:
-- amazon.aws >= 1.5.0
+- amazon.aws >= 2.0.0
- ansible.windows
- community.crypto
- community.general
unit_tests_dependencies:
-- amazon.aws >= 1.5.0
+- amazon.aws >= 2.0.0
diff --git a/tests/sanity/ignore-2.10.txt b/tests/sanity/ignore-2.10.txt
index 88220c9863a..09a7e9cbb50 100644
--- a/tests/sanity/ignore-2.10.txt
+++ b/tests/sanity/ignore-2.10.txt
@@ -1,2162 +1 @@
-plugins/modules/__init__.py compile-2.6!skip
-plugins/modules/__init__.py compile-2.7!skip
-plugins/modules/__init__.py compile-3.5!skip
-plugins/modules/__init__.py compile-3.6!skip
-plugins/modules/__init__.py compile-3.7!skip
-plugins/modules/__init__.py future-import-boilerplate!skip
-plugins/modules/__init__.py import-2.6!skip
-plugins/modules/__init__.py import-2.7!skip
-plugins/modules/__init__.py import-3.5!skip
-plugins/modules/__init__.py import-3.6!skip
-plugins/modules/__init__.py import-3.7!skip
-plugins/modules/__init__.py metaclass-boilerplate!skip
-plugins/modules/aws_acm.py compile-2.6!skip
-plugins/modules/aws_acm.py compile-2.7!skip
-plugins/modules/aws_acm.py compile-3.5!skip
-plugins/modules/aws_acm.py compile-3.6!skip
-plugins/modules/aws_acm.py compile-3.7!skip
-plugins/modules/aws_acm.py future-import-boilerplate!skip
-plugins/modules/aws_acm.py import-2.6!skip
-plugins/modules/aws_acm.py import-2.7!skip
-plugins/modules/aws_acm.py import-3.5!skip
-plugins/modules/aws_acm.py import-3.6!skip
-plugins/modules/aws_acm.py import-3.7!skip
-plugins/modules/aws_acm.py metaclass-boilerplate!skip
-plugins/modules/aws_acm_info.py compile-2.6!skip
-plugins/modules/aws_acm_info.py compile-2.7!skip
-plugins/modules/aws_acm_info.py compile-3.5!skip
-plugins/modules/aws_acm_info.py compile-3.6!skip
-plugins/modules/aws_acm_info.py compile-3.7!skip
-plugins/modules/aws_acm_info.py future-import-boilerplate!skip
-plugins/modules/aws_acm_info.py import-2.6!skip
-plugins/modules/aws_acm_info.py import-2.7!skip
-plugins/modules/aws_acm_info.py import-3.5!skip
-plugins/modules/aws_acm_info.py import-3.6!skip
-plugins/modules/aws_acm_info.py import-3.7!skip
-plugins/modules/aws_acm_info.py metaclass-boilerplate!skip
-plugins/modules/aws_api_gateway.py compile-2.6!skip
-plugins/modules/aws_api_gateway.py compile-2.7!skip
-plugins/modules/aws_api_gateway.py compile-3.5!skip
-plugins/modules/aws_api_gateway.py compile-3.6!skip
-plugins/modules/aws_api_gateway.py compile-3.7!skip
-plugins/modules/aws_api_gateway.py future-import-boilerplate!skip
-plugins/modules/aws_api_gateway.py import-2.6!skip
-plugins/modules/aws_api_gateway.py import-2.7!skip
-plugins/modules/aws_api_gateway.py import-3.5!skip
-plugins/modules/aws_api_gateway.py import-3.6!skip
-plugins/modules/aws_api_gateway.py import-3.7!skip
-plugins/modules/aws_api_gateway.py metaclass-boilerplate!skip
-plugins/modules/aws_application_scaling_policy.py compile-2.6!skip
-plugins/modules/aws_application_scaling_policy.py compile-2.7!skip
-plugins/modules/aws_application_scaling_policy.py compile-3.5!skip
-plugins/modules/aws_application_scaling_policy.py compile-3.6!skip
-plugins/modules/aws_application_scaling_policy.py compile-3.7!skip
-plugins/modules/aws_application_scaling_policy.py future-import-boilerplate!skip
-plugins/modules/aws_application_scaling_policy.py import-2.6!skip
-plugins/modules/aws_application_scaling_policy.py import-2.7!skip
-plugins/modules/aws_application_scaling_policy.py import-3.5!skip
-plugins/modules/aws_application_scaling_policy.py import-3.6!skip
-plugins/modules/aws_application_scaling_policy.py import-3.7!skip
-plugins/modules/aws_application_scaling_policy.py metaclass-boilerplate!skip
-plugins/modules/aws_batch_compute_environment.py compile-2.6!skip
-plugins/modules/aws_batch_compute_environment.py compile-2.7!skip
-plugins/modules/aws_batch_compute_environment.py compile-3.5!skip
-plugins/modules/aws_batch_compute_environment.py compile-3.6!skip
-plugins/modules/aws_batch_compute_environment.py compile-3.7!skip
-plugins/modules/aws_batch_compute_environment.py future-import-boilerplate!skip
-plugins/modules/aws_batch_compute_environment.py import-2.6!skip
-plugins/modules/aws_batch_compute_environment.py import-2.7!skip
-plugins/modules/aws_batch_compute_environment.py import-3.5!skip
-plugins/modules/aws_batch_compute_environment.py import-3.6!skip
-plugins/modules/aws_batch_compute_environment.py import-3.7!skip
-plugins/modules/aws_batch_compute_environment.py metaclass-boilerplate!skip
-plugins/modules/aws_batch_job_definition.py compile-2.6!skip
-plugins/modules/aws_batch_job_definition.py compile-2.7!skip
-plugins/modules/aws_batch_job_definition.py compile-3.5!skip
-plugins/modules/aws_batch_job_definition.py compile-3.6!skip
-plugins/modules/aws_batch_job_definition.py compile-3.7!skip
-plugins/modules/aws_batch_job_definition.py future-import-boilerplate!skip
-plugins/modules/aws_batch_job_definition.py import-2.6!skip
-plugins/modules/aws_batch_job_definition.py import-2.7!skip
-plugins/modules/aws_batch_job_definition.py import-3.5!skip
-plugins/modules/aws_batch_job_definition.py import-3.6!skip
-plugins/modules/aws_batch_job_definition.py import-3.7!skip
-plugins/modules/aws_batch_job_definition.py metaclass-boilerplate!skip
-plugins/modules/aws_batch_job_queue.py compile-2.6!skip
-plugins/modules/aws_batch_job_queue.py compile-2.7!skip
-plugins/modules/aws_batch_job_queue.py compile-3.5!skip
-plugins/modules/aws_batch_job_queue.py compile-3.6!skip
-plugins/modules/aws_batch_job_queue.py compile-3.7!skip
-plugins/modules/aws_batch_job_queue.py future-import-boilerplate!skip
-plugins/modules/aws_batch_job_queue.py import-2.6!skip
-plugins/modules/aws_batch_job_queue.py import-2.7!skip
-plugins/modules/aws_batch_job_queue.py import-3.5!skip
-plugins/modules/aws_batch_job_queue.py import-3.6!skip
-plugins/modules/aws_batch_job_queue.py import-3.7!skip
-plugins/modules/aws_batch_job_queue.py metaclass-boilerplate!skip
-plugins/modules/aws_codebuild.py compile-2.6!skip
-plugins/modules/aws_codebuild.py compile-2.7!skip
-plugins/modules/aws_codebuild.py compile-3.5!skip
-plugins/modules/aws_codebuild.py compile-3.6!skip
-plugins/modules/aws_codebuild.py compile-3.7!skip
-plugins/modules/aws_codebuild.py future-import-boilerplate!skip
-plugins/modules/aws_codebuild.py import-2.6!skip
-plugins/modules/aws_codebuild.py import-2.7!skip
-plugins/modules/aws_codebuild.py import-3.5!skip
-plugins/modules/aws_codebuild.py import-3.6!skip
-plugins/modules/aws_codebuild.py import-3.7!skip
-plugins/modules/aws_codebuild.py metaclass-boilerplate!skip
-plugins/modules/aws_codecommit.py compile-2.6!skip
-plugins/modules/aws_codecommit.py compile-2.7!skip
-plugins/modules/aws_codecommit.py compile-3.5!skip
-plugins/modules/aws_codecommit.py compile-3.6!skip
-plugins/modules/aws_codecommit.py compile-3.7!skip
-plugins/modules/aws_codecommit.py future-import-boilerplate!skip
-plugins/modules/aws_codecommit.py import-2.6!skip
-plugins/modules/aws_codecommit.py import-2.7!skip
-plugins/modules/aws_codecommit.py import-3.5!skip
-plugins/modules/aws_codecommit.py import-3.6!skip
-plugins/modules/aws_codecommit.py import-3.7!skip
-plugins/modules/aws_codecommit.py metaclass-boilerplate!skip
-plugins/modules/aws_codepipeline.py compile-2.6!skip
-plugins/modules/aws_codepipeline.py compile-2.7!skip
-plugins/modules/aws_codepipeline.py compile-3.5!skip
-plugins/modules/aws_codepipeline.py compile-3.6!skip
-plugins/modules/aws_codepipeline.py compile-3.7!skip
-plugins/modules/aws_codepipeline.py future-import-boilerplate!skip
-plugins/modules/aws_codepipeline.py import-2.6!skip
-plugins/modules/aws_codepipeline.py import-2.7!skip
-plugins/modules/aws_codepipeline.py import-3.5!skip
-plugins/modules/aws_codepipeline.py import-3.6!skip
-plugins/modules/aws_codepipeline.py import-3.7!skip
-plugins/modules/aws_codepipeline.py metaclass-boilerplate!skip
-plugins/modules/aws_config_aggregation_authorization.py compile-2.6!skip
-plugins/modules/aws_config_aggregation_authorization.py compile-2.7!skip
-plugins/modules/aws_config_aggregation_authorization.py compile-3.5!skip
-plugins/modules/aws_config_aggregation_authorization.py compile-3.6!skip
-plugins/modules/aws_config_aggregation_authorization.py compile-3.7!skip
-plugins/modules/aws_config_aggregation_authorization.py future-import-boilerplate!skip
-plugins/modules/aws_config_aggregation_authorization.py import-2.6!skip
-plugins/modules/aws_config_aggregation_authorization.py import-2.7!skip
-plugins/modules/aws_config_aggregation_authorization.py import-3.5!skip
-plugins/modules/aws_config_aggregation_authorization.py import-3.6!skip
-plugins/modules/aws_config_aggregation_authorization.py import-3.7!skip
-plugins/modules/aws_config_aggregation_authorization.py metaclass-boilerplate!skip
-plugins/modules/aws_config_aggregator.py compile-2.6!skip
-plugins/modules/aws_config_aggregator.py compile-2.7!skip
-plugins/modules/aws_config_aggregator.py compile-3.5!skip
-plugins/modules/aws_config_aggregator.py compile-3.6!skip
-plugins/modules/aws_config_aggregator.py compile-3.7!skip
-plugins/modules/aws_config_aggregator.py future-import-boilerplate!skip
-plugins/modules/aws_config_aggregator.py import-2.6!skip
-plugins/modules/aws_config_aggregator.py import-2.7!skip
-plugins/modules/aws_config_aggregator.py import-3.5!skip
-plugins/modules/aws_config_aggregator.py import-3.6!skip
-plugins/modules/aws_config_aggregator.py import-3.7!skip
-plugins/modules/aws_config_aggregator.py metaclass-boilerplate!skip
-plugins/modules/aws_config_delivery_channel.py compile-2.6!skip
-plugins/modules/aws_config_delivery_channel.py compile-2.7!skip
-plugins/modules/aws_config_delivery_channel.py compile-3.5!skip
-plugins/modules/aws_config_delivery_channel.py compile-3.6!skip
-plugins/modules/aws_config_delivery_channel.py compile-3.7!skip
-plugins/modules/aws_config_delivery_channel.py future-import-boilerplate!skip
-plugins/modules/aws_config_delivery_channel.py import-2.6!skip
-plugins/modules/aws_config_delivery_channel.py import-2.7!skip
-plugins/modules/aws_config_delivery_channel.py import-3.5!skip
-plugins/modules/aws_config_delivery_channel.py import-3.6!skip
-plugins/modules/aws_config_delivery_channel.py import-3.7!skip
-plugins/modules/aws_config_delivery_channel.py metaclass-boilerplate!skip
-plugins/modules/aws_config_recorder.py compile-2.6!skip
-plugins/modules/aws_config_recorder.py compile-2.7!skip
-plugins/modules/aws_config_recorder.py compile-3.5!skip
-plugins/modules/aws_config_recorder.py compile-3.6!skip
-plugins/modules/aws_config_recorder.py compile-3.7!skip
-plugins/modules/aws_config_recorder.py future-import-boilerplate!skip
-plugins/modules/aws_config_recorder.py import-2.6!skip
-plugins/modules/aws_config_recorder.py import-2.7!skip
-plugins/modules/aws_config_recorder.py import-3.5!skip
-plugins/modules/aws_config_recorder.py import-3.6!skip
-plugins/modules/aws_config_recorder.py import-3.7!skip
-plugins/modules/aws_config_recorder.py metaclass-boilerplate!skip
-plugins/modules/aws_config_rule.py compile-2.6!skip
-plugins/modules/aws_config_rule.py compile-2.7!skip
-plugins/modules/aws_config_rule.py compile-3.5!skip
-plugins/modules/aws_config_rule.py compile-3.6!skip
-plugins/modules/aws_config_rule.py compile-3.7!skip
-plugins/modules/aws_config_rule.py future-import-boilerplate!skip
-plugins/modules/aws_config_rule.py import-2.6!skip
-plugins/modules/aws_config_rule.py import-2.7!skip
-plugins/modules/aws_config_rule.py import-3.5!skip
-plugins/modules/aws_config_rule.py import-3.6!skip
-plugins/modules/aws_config_rule.py import-3.7!skip
-plugins/modules/aws_config_rule.py metaclass-boilerplate!skip
-plugins/modules/aws_direct_connect_confirm_connection.py compile-2.6!skip
-plugins/modules/aws_direct_connect_confirm_connection.py compile-2.7!skip
-plugins/modules/aws_direct_connect_confirm_connection.py compile-3.5!skip
-plugins/modules/aws_direct_connect_confirm_connection.py compile-3.6!skip
-plugins/modules/aws_direct_connect_confirm_connection.py compile-3.7!skip
-plugins/modules/aws_direct_connect_confirm_connection.py future-import-boilerplate!skip
-plugins/modules/aws_direct_connect_confirm_connection.py import-2.6!skip
-plugins/modules/aws_direct_connect_confirm_connection.py import-2.7!skip
-plugins/modules/aws_direct_connect_confirm_connection.py import-3.5!skip
-plugins/modules/aws_direct_connect_confirm_connection.py import-3.6!skip
-plugins/modules/aws_direct_connect_confirm_connection.py import-3.7!skip
-plugins/modules/aws_direct_connect_confirm_connection.py metaclass-boilerplate!skip
-plugins/modules/aws_direct_connect_connection.py compile-2.6!skip
-plugins/modules/aws_direct_connect_connection.py compile-2.7!skip
-plugins/modules/aws_direct_connect_connection.py compile-3.5!skip
-plugins/modules/aws_direct_connect_connection.py compile-3.6!skip
-plugins/modules/aws_direct_connect_connection.py compile-3.7!skip
-plugins/modules/aws_direct_connect_connection.py future-import-boilerplate!skip
-plugins/modules/aws_direct_connect_connection.py import-2.6!skip
-plugins/modules/aws_direct_connect_connection.py import-2.7!skip
-plugins/modules/aws_direct_connect_connection.py import-3.5!skip
-plugins/modules/aws_direct_connect_connection.py import-3.6!skip
-plugins/modules/aws_direct_connect_connection.py import-3.7!skip
-plugins/modules/aws_direct_connect_connection.py metaclass-boilerplate!skip
-plugins/modules/aws_direct_connect_gateway.py compile-2.6!skip
-plugins/modules/aws_direct_connect_gateway.py compile-2.7!skip
-plugins/modules/aws_direct_connect_gateway.py compile-3.5!skip
-plugins/modules/aws_direct_connect_gateway.py compile-3.6!skip
-plugins/modules/aws_direct_connect_gateway.py compile-3.7!skip
-plugins/modules/aws_direct_connect_gateway.py future-import-boilerplate!skip
-plugins/modules/aws_direct_connect_gateway.py import-2.6!skip
-plugins/modules/aws_direct_connect_gateway.py import-2.7!skip
-plugins/modules/aws_direct_connect_gateway.py import-3.5!skip
-plugins/modules/aws_direct_connect_gateway.py import-3.6!skip
-plugins/modules/aws_direct_connect_gateway.py import-3.7!skip
-plugins/modules/aws_direct_connect_gateway.py metaclass-boilerplate!skip
-plugins/modules/aws_direct_connect_link_aggregation_group.py compile-2.6!skip
-plugins/modules/aws_direct_connect_link_aggregation_group.py compile-2.7!skip
-plugins/modules/aws_direct_connect_link_aggregation_group.py compile-3.5!skip
-plugins/modules/aws_direct_connect_link_aggregation_group.py compile-3.6!skip
-plugins/modules/aws_direct_connect_link_aggregation_group.py compile-3.7!skip
-plugins/modules/aws_direct_connect_link_aggregation_group.py future-import-boilerplate!skip
-plugins/modules/aws_direct_connect_link_aggregation_group.py import-2.6!skip
-plugins/modules/aws_direct_connect_link_aggregation_group.py import-2.7!skip
-plugins/modules/aws_direct_connect_link_aggregation_group.py import-3.5!skip
-plugins/modules/aws_direct_connect_link_aggregation_group.py import-3.6!skip
-plugins/modules/aws_direct_connect_link_aggregation_group.py import-3.7!skip
-plugins/modules/aws_direct_connect_link_aggregation_group.py metaclass-boilerplate!skip
-plugins/modules/aws_direct_connect_virtual_interface.py compile-2.6!skip
-plugins/modules/aws_direct_connect_virtual_interface.py compile-2.7!skip
-plugins/modules/aws_direct_connect_virtual_interface.py compile-3.5!skip
-plugins/modules/aws_direct_connect_virtual_interface.py compile-3.6!skip
-plugins/modules/aws_direct_connect_virtual_interface.py compile-3.7!skip
-plugins/modules/aws_direct_connect_virtual_interface.py future-import-boilerplate!skip
-plugins/modules/aws_direct_connect_virtual_interface.py import-2.6!skip
-plugins/modules/aws_direct_connect_virtual_interface.py import-2.7!skip
-plugins/modules/aws_direct_connect_virtual_interface.py import-3.5!skip
-plugins/modules/aws_direct_connect_virtual_interface.py import-3.6!skip
-plugins/modules/aws_direct_connect_virtual_interface.py import-3.7!skip
-plugins/modules/aws_direct_connect_virtual_interface.py metaclass-boilerplate!skip
-plugins/modules/aws_eks_cluster.py compile-2.6!skip
-plugins/modules/aws_eks_cluster.py compile-2.7!skip
-plugins/modules/aws_eks_cluster.py compile-3.5!skip
-plugins/modules/aws_eks_cluster.py compile-3.6!skip
-plugins/modules/aws_eks_cluster.py compile-3.7!skip
-plugins/modules/aws_eks_cluster.py future-import-boilerplate!skip
-plugins/modules/aws_eks_cluster.py import-2.6!skip
-plugins/modules/aws_eks_cluster.py import-2.7!skip
-plugins/modules/aws_eks_cluster.py import-3.5!skip
-plugins/modules/aws_eks_cluster.py import-3.6!skip
-plugins/modules/aws_eks_cluster.py import-3.7!skip
-plugins/modules/aws_eks_cluster.py metaclass-boilerplate!skip
-plugins/modules/aws_elasticbeanstalk_app.py compile-2.6!skip
-plugins/modules/aws_elasticbeanstalk_app.py compile-2.7!skip
-plugins/modules/aws_elasticbeanstalk_app.py compile-3.5!skip
-plugins/modules/aws_elasticbeanstalk_app.py compile-3.6!skip
-plugins/modules/aws_elasticbeanstalk_app.py compile-3.7!skip
-plugins/modules/aws_elasticbeanstalk_app.py future-import-boilerplate!skip
-plugins/modules/aws_elasticbeanstalk_app.py import-2.6!skip
-plugins/modules/aws_elasticbeanstalk_app.py import-2.7!skip
-plugins/modules/aws_elasticbeanstalk_app.py import-3.5!skip
-plugins/modules/aws_elasticbeanstalk_app.py import-3.6!skip
-plugins/modules/aws_elasticbeanstalk_app.py import-3.7!skip
-plugins/modules/aws_elasticbeanstalk_app.py metaclass-boilerplate!skip
-plugins/modules/aws_glue_connection.py compile-2.6!skip
-plugins/modules/aws_glue_connection.py compile-2.7!skip
-plugins/modules/aws_glue_connection.py compile-3.5!skip
-plugins/modules/aws_glue_connection.py compile-3.6!skip
-plugins/modules/aws_glue_connection.py compile-3.7!skip
-plugins/modules/aws_glue_connection.py future-import-boilerplate!skip
-plugins/modules/aws_glue_connection.py import-2.6!skip
-plugins/modules/aws_glue_connection.py import-2.7!skip
-plugins/modules/aws_glue_connection.py import-3.5!skip
-plugins/modules/aws_glue_connection.py import-3.6!skip
-plugins/modules/aws_glue_connection.py import-3.7!skip
-plugins/modules/aws_glue_connection.py metaclass-boilerplate!skip
-plugins/modules/aws_glue_job.py compile-2.6!skip
-plugins/modules/aws_glue_job.py compile-2.7!skip
-plugins/modules/aws_glue_job.py compile-3.5!skip
-plugins/modules/aws_glue_job.py compile-3.6!skip
-plugins/modules/aws_glue_job.py compile-3.7!skip
-plugins/modules/aws_glue_job.py future-import-boilerplate!skip
-plugins/modules/aws_glue_job.py import-2.6!skip
-plugins/modules/aws_glue_job.py import-2.7!skip
-plugins/modules/aws_glue_job.py import-3.5!skip
-plugins/modules/aws_glue_job.py import-3.6!skip
-plugins/modules/aws_glue_job.py import-3.7!skip
-plugins/modules/aws_glue_job.py metaclass-boilerplate!skip
-plugins/modules/aws_inspector_target.py compile-2.6!skip
-plugins/modules/aws_inspector_target.py compile-2.7!skip
-plugins/modules/aws_inspector_target.py compile-3.5!skip
-plugins/modules/aws_inspector_target.py compile-3.6!skip
-plugins/modules/aws_inspector_target.py compile-3.7!skip
-plugins/modules/aws_inspector_target.py future-import-boilerplate!skip
-plugins/modules/aws_inspector_target.py import-2.6!skip
-plugins/modules/aws_inspector_target.py import-2.7!skip
-plugins/modules/aws_inspector_target.py import-3.5!skip
-plugins/modules/aws_inspector_target.py import-3.6!skip
-plugins/modules/aws_inspector_target.py import-3.7!skip
-plugins/modules/aws_inspector_target.py metaclass-boilerplate!skip
-plugins/modules/aws_kms.py compile-2.6!skip
-plugins/modules/aws_kms.py compile-2.7!skip
-plugins/modules/aws_kms.py compile-3.5!skip
-plugins/modules/aws_kms.py compile-3.6!skip
-plugins/modules/aws_kms.py compile-3.7!skip
-plugins/modules/aws_kms.py future-import-boilerplate!skip
-plugins/modules/aws_kms.py import-2.6!skip
-plugins/modules/aws_kms.py import-2.7!skip
-plugins/modules/aws_kms.py import-3.5!skip
-plugins/modules/aws_kms.py import-3.6!skip
-plugins/modules/aws_kms.py import-3.7!skip
-plugins/modules/aws_kms.py metaclass-boilerplate!skip
-plugins/modules/aws_kms_info.py compile-2.6!skip
-plugins/modules/aws_kms_info.py compile-2.7!skip
-plugins/modules/aws_kms_info.py compile-3.5!skip
-plugins/modules/aws_kms_info.py compile-3.6!skip
-plugins/modules/aws_kms_info.py compile-3.7!skip
-plugins/modules/aws_kms_info.py future-import-boilerplate!skip
-plugins/modules/aws_kms_info.py import-2.6!skip
-plugins/modules/aws_kms_info.py import-2.7!skip
-plugins/modules/aws_kms_info.py import-3.5!skip
-plugins/modules/aws_kms_info.py import-3.6!skip
-plugins/modules/aws_kms_info.py import-3.7!skip
-plugins/modules/aws_kms_info.py metaclass-boilerplate!skip
-plugins/modules/aws_region_info.py compile-2.6!skip
-plugins/modules/aws_region_info.py compile-2.7!skip
-plugins/modules/aws_region_info.py compile-3.5!skip
-plugins/modules/aws_region_info.py compile-3.6!skip
-plugins/modules/aws_region_info.py compile-3.7!skip
-plugins/modules/aws_region_info.py future-import-boilerplate!skip
-plugins/modules/aws_region_info.py import-2.6!skip
-plugins/modules/aws_region_info.py import-2.7!skip
-plugins/modules/aws_region_info.py import-3.5!skip
-plugins/modules/aws_region_info.py import-3.6!skip
-plugins/modules/aws_region_info.py import-3.7!skip
-plugins/modules/aws_region_info.py metaclass-boilerplate!skip
-plugins/modules/aws_s3_bucket_info.py compile-2.6!skip
-plugins/modules/aws_s3_bucket_info.py compile-2.7!skip
-plugins/modules/aws_s3_bucket_info.py compile-3.5!skip
-plugins/modules/aws_s3_bucket_info.py compile-3.6!skip
-plugins/modules/aws_s3_bucket_info.py compile-3.7!skip
-plugins/modules/aws_s3_bucket_info.py future-import-boilerplate!skip
-plugins/modules/aws_s3_bucket_info.py import-2.6!skip
-plugins/modules/aws_s3_bucket_info.py import-2.7!skip
-plugins/modules/aws_s3_bucket_info.py import-3.5!skip
-plugins/modules/aws_s3_bucket_info.py import-3.6!skip
-plugins/modules/aws_s3_bucket_info.py import-3.7!skip
-plugins/modules/aws_s3_bucket_info.py metaclass-boilerplate!skip
-plugins/modules/aws_s3_cors.py compile-2.6!skip
-plugins/modules/aws_s3_cors.py compile-2.7!skip
-plugins/modules/aws_s3_cors.py compile-3.5!skip
-plugins/modules/aws_s3_cors.py compile-3.6!skip
-plugins/modules/aws_s3_cors.py compile-3.7!skip
-plugins/modules/aws_s3_cors.py future-import-boilerplate!skip
-plugins/modules/aws_s3_cors.py import-2.6!skip
-plugins/modules/aws_s3_cors.py import-2.7!skip
-plugins/modules/aws_s3_cors.py import-3.5!skip
-plugins/modules/aws_s3_cors.py import-3.6!skip
-plugins/modules/aws_s3_cors.py import-3.7!skip
-plugins/modules/aws_s3_cors.py metaclass-boilerplate!skip
-plugins/modules/aws_secret.py compile-2.6!skip
-plugins/modules/aws_secret.py compile-2.7!skip
-plugins/modules/aws_secret.py compile-3.5!skip
-plugins/modules/aws_secret.py compile-3.6!skip
-plugins/modules/aws_secret.py compile-3.7!skip
-plugins/modules/aws_secret.py future-import-boilerplate!skip
-plugins/modules/aws_secret.py import-2.6!skip
-plugins/modules/aws_secret.py import-2.7!skip
-plugins/modules/aws_secret.py import-3.5!skip
-plugins/modules/aws_secret.py import-3.6!skip
-plugins/modules/aws_secret.py import-3.7!skip
-plugins/modules/aws_secret.py metaclass-boilerplate!skip
-plugins/modules/aws_ses_identity.py compile-2.6!skip
-plugins/modules/aws_ses_identity.py compile-2.7!skip
-plugins/modules/aws_ses_identity.py compile-3.5!skip
-plugins/modules/aws_ses_identity.py compile-3.6!skip
-plugins/modules/aws_ses_identity.py compile-3.7!skip
-plugins/modules/aws_ses_identity.py future-import-boilerplate!skip
-plugins/modules/aws_ses_identity.py import-2.6!skip
-plugins/modules/aws_ses_identity.py import-2.7!skip
-plugins/modules/aws_ses_identity.py import-3.5!skip
-plugins/modules/aws_ses_identity.py import-3.6!skip
-plugins/modules/aws_ses_identity.py import-3.7!skip
-plugins/modules/aws_ses_identity.py metaclass-boilerplate!skip
-plugins/modules/aws_ses_identity_policy.py compile-2.6!skip
-plugins/modules/aws_ses_identity_policy.py compile-2.7!skip
-plugins/modules/aws_ses_identity_policy.py compile-3.5!skip
-plugins/modules/aws_ses_identity_policy.py compile-3.6!skip
-plugins/modules/aws_ses_identity_policy.py compile-3.7!skip
-plugins/modules/aws_ses_identity_policy.py future-import-boilerplate!skip
-plugins/modules/aws_ses_identity_policy.py import-2.6!skip
-plugins/modules/aws_ses_identity_policy.py import-2.7!skip
-plugins/modules/aws_ses_identity_policy.py import-3.5!skip
-plugins/modules/aws_ses_identity_policy.py import-3.6!skip
-plugins/modules/aws_ses_identity_policy.py import-3.7!skip
-plugins/modules/aws_ses_identity_policy.py metaclass-boilerplate!skip
-plugins/modules/aws_ses_rule_set.py compile-2.6!skip
-plugins/modules/aws_ses_rule_set.py compile-2.7!skip
-plugins/modules/aws_ses_rule_set.py compile-3.5!skip
-plugins/modules/aws_ses_rule_set.py compile-3.6!skip
-plugins/modules/aws_ses_rule_set.py compile-3.7!skip
-plugins/modules/aws_ses_rule_set.py future-import-boilerplate!skip
-plugins/modules/aws_ses_rule_set.py import-2.6!skip
-plugins/modules/aws_ses_rule_set.py import-2.7!skip
-plugins/modules/aws_ses_rule_set.py import-3.5!skip
-plugins/modules/aws_ses_rule_set.py import-3.6!skip
-plugins/modules/aws_ses_rule_set.py import-3.7!skip
-plugins/modules/aws_ses_rule_set.py metaclass-boilerplate!skip
-plugins/modules/aws_sgw_info.py compile-2.6!skip
-plugins/modules/aws_sgw_info.py compile-2.7!skip
-plugins/modules/aws_sgw_info.py compile-3.5!skip
-plugins/modules/aws_sgw_info.py compile-3.6!skip
-plugins/modules/aws_sgw_info.py compile-3.7!skip
-plugins/modules/aws_sgw_info.py future-import-boilerplate!skip
-plugins/modules/aws_sgw_info.py import-2.6!skip
-plugins/modules/aws_sgw_info.py import-2.7!skip
-plugins/modules/aws_sgw_info.py import-3.5!skip
-plugins/modules/aws_sgw_info.py import-3.6!skip
-plugins/modules/aws_sgw_info.py import-3.7!skip
-plugins/modules/aws_sgw_info.py metaclass-boilerplate!skip
-plugins/modules/aws_ssm_parameter_store.py compile-2.6!skip
-plugins/modules/aws_ssm_parameter_store.py compile-2.7!skip
-plugins/modules/aws_ssm_parameter_store.py compile-3.5!skip
-plugins/modules/aws_ssm_parameter_store.py compile-3.6!skip
-plugins/modules/aws_ssm_parameter_store.py compile-3.7!skip
-plugins/modules/aws_ssm_parameter_store.py future-import-boilerplate!skip
-plugins/modules/aws_ssm_parameter_store.py import-2.6!skip
-plugins/modules/aws_ssm_parameter_store.py import-2.7!skip
-plugins/modules/aws_ssm_parameter_store.py import-3.5!skip
-plugins/modules/aws_ssm_parameter_store.py import-3.6!skip
-plugins/modules/aws_ssm_parameter_store.py import-3.7!skip
-plugins/modules/aws_ssm_parameter_store.py metaclass-boilerplate!skip
-plugins/modules/aws_step_functions_state_machine.py compile-2.6!skip
-plugins/modules/aws_step_functions_state_machine.py compile-2.7!skip
-plugins/modules/aws_step_functions_state_machine.py compile-3.5!skip
-plugins/modules/aws_step_functions_state_machine.py compile-3.6!skip
-plugins/modules/aws_step_functions_state_machine.py compile-3.7!skip
-plugins/modules/aws_step_functions_state_machine.py future-import-boilerplate!skip
-plugins/modules/aws_step_functions_state_machine.py import-2.6!skip
-plugins/modules/aws_step_functions_state_machine.py import-2.7!skip
-plugins/modules/aws_step_functions_state_machine.py import-3.5!skip
-plugins/modules/aws_step_functions_state_machine.py import-3.6!skip
-plugins/modules/aws_step_functions_state_machine.py import-3.7!skip
-plugins/modules/aws_step_functions_state_machine.py metaclass-boilerplate!skip
-plugins/modules/aws_step_functions_state_machine_execution.py compile-2.6!skip
-plugins/modules/aws_step_functions_state_machine_execution.py compile-2.7!skip
-plugins/modules/aws_step_functions_state_machine_execution.py compile-3.5!skip
-plugins/modules/aws_step_functions_state_machine_execution.py compile-3.6!skip
-plugins/modules/aws_step_functions_state_machine_execution.py compile-3.7!skip
-plugins/modules/aws_step_functions_state_machine_execution.py future-import-boilerplate!skip
-plugins/modules/aws_step_functions_state_machine_execution.py import-2.6!skip
-plugins/modules/aws_step_functions_state_machine_execution.py import-2.7!skip
-plugins/modules/aws_step_functions_state_machine_execution.py import-3.5!skip
-plugins/modules/aws_step_functions_state_machine_execution.py import-3.6!skip
-plugins/modules/aws_step_functions_state_machine_execution.py import-3.7!skip
-plugins/modules/aws_step_functions_state_machine_execution.py metaclass-boilerplate!skip
-plugins/modules/aws_waf_condition.py compile-2.6!skip
-plugins/modules/aws_waf_condition.py compile-2.7!skip
-plugins/modules/aws_waf_condition.py compile-3.5!skip
-plugins/modules/aws_waf_condition.py compile-3.6!skip
-plugins/modules/aws_waf_condition.py compile-3.7!skip
-plugins/modules/aws_waf_condition.py future-import-boilerplate!skip
-plugins/modules/aws_waf_condition.py import-2.6!skip
-plugins/modules/aws_waf_condition.py import-2.7!skip
-plugins/modules/aws_waf_condition.py import-3.5!skip
-plugins/modules/aws_waf_condition.py import-3.6!skip
-plugins/modules/aws_waf_condition.py import-3.7!skip
-plugins/modules/aws_waf_condition.py metaclass-boilerplate!skip
-plugins/modules/aws_waf_info.py compile-2.6!skip
-plugins/modules/aws_waf_info.py compile-2.7!skip
-plugins/modules/aws_waf_info.py compile-3.5!skip
-plugins/modules/aws_waf_info.py compile-3.6!skip
-plugins/modules/aws_waf_info.py compile-3.7!skip
-plugins/modules/aws_waf_info.py future-import-boilerplate!skip
-plugins/modules/aws_waf_info.py import-2.6!skip
-plugins/modules/aws_waf_info.py import-2.7!skip
-plugins/modules/aws_waf_info.py import-3.5!skip
-plugins/modules/aws_waf_info.py import-3.6!skip
-plugins/modules/aws_waf_info.py import-3.7!skip
-plugins/modules/aws_waf_info.py metaclass-boilerplate!skip
-plugins/modules/aws_waf_rule.py compile-2.6!skip
-plugins/modules/aws_waf_rule.py compile-2.7!skip
-plugins/modules/aws_waf_rule.py compile-3.5!skip
-plugins/modules/aws_waf_rule.py compile-3.6!skip
-plugins/modules/aws_waf_rule.py compile-3.7!skip
-plugins/modules/aws_waf_rule.py future-import-boilerplate!skip
-plugins/modules/aws_waf_rule.py import-2.6!skip
-plugins/modules/aws_waf_rule.py import-2.7!skip
-plugins/modules/aws_waf_rule.py import-3.5!skip
-plugins/modules/aws_waf_rule.py import-3.6!skip
-plugins/modules/aws_waf_rule.py import-3.7!skip
-plugins/modules/aws_waf_rule.py metaclass-boilerplate!skip
-plugins/modules/aws_waf_web_acl.py compile-2.6!skip
-plugins/modules/aws_waf_web_acl.py compile-2.7!skip
-plugins/modules/aws_waf_web_acl.py compile-3.5!skip
-plugins/modules/aws_waf_web_acl.py compile-3.6!skip
-plugins/modules/aws_waf_web_acl.py compile-3.7!skip
-plugins/modules/aws_waf_web_acl.py future-import-boilerplate!skip
-plugins/modules/aws_waf_web_acl.py import-2.6!skip
-plugins/modules/aws_waf_web_acl.py import-2.7!skip
-plugins/modules/aws_waf_web_acl.py import-3.5!skip
-plugins/modules/aws_waf_web_acl.py import-3.6!skip
-plugins/modules/aws_waf_web_acl.py import-3.7!skip
-plugins/modules/aws_waf_web_acl.py metaclass-boilerplate!skip
-plugins/modules/cloudformation_exports_info.py compile-2.6!skip
-plugins/modules/cloudformation_exports_info.py compile-2.7!skip
-plugins/modules/cloudformation_exports_info.py compile-3.5!skip
-plugins/modules/cloudformation_exports_info.py compile-3.6!skip
-plugins/modules/cloudformation_exports_info.py compile-3.7!skip
-plugins/modules/cloudformation_exports_info.py future-import-boilerplate!skip
-plugins/modules/cloudformation_exports_info.py import-2.6!skip
-plugins/modules/cloudformation_exports_info.py import-2.7!skip
-plugins/modules/cloudformation_exports_info.py import-3.5!skip
-plugins/modules/cloudformation_exports_info.py import-3.6!skip
-plugins/modules/cloudformation_exports_info.py import-3.7!skip
-plugins/modules/cloudformation_exports_info.py metaclass-boilerplate!skip
-plugins/modules/cloudformation_stack_set.py compile-2.6!skip
-plugins/modules/cloudformation_stack_set.py compile-2.7!skip
-plugins/modules/cloudformation_stack_set.py compile-3.5!skip
-plugins/modules/cloudformation_stack_set.py compile-3.6!skip
-plugins/modules/cloudformation_stack_set.py compile-3.7!skip
-plugins/modules/cloudformation_stack_set.py future-import-boilerplate!skip
-plugins/modules/cloudformation_stack_set.py import-2.6!skip
-plugins/modules/cloudformation_stack_set.py import-2.7!skip
-plugins/modules/cloudformation_stack_set.py import-3.5!skip
-plugins/modules/cloudformation_stack_set.py import-3.6!skip
-plugins/modules/cloudformation_stack_set.py import-3.7!skip
-plugins/modules/cloudformation_stack_set.py metaclass-boilerplate!skip
-plugins/modules/cloudfront_distribution.py compile-2.6!skip
-plugins/modules/cloudfront_distribution.py compile-2.7!skip
-plugins/modules/cloudfront_distribution.py compile-3.5!skip
-plugins/modules/cloudfront_distribution.py compile-3.6!skip
-plugins/modules/cloudfront_distribution.py compile-3.7!skip
-plugins/modules/cloudfront_distribution.py future-import-boilerplate!skip
-plugins/modules/cloudfront_distribution.py import-2.6!skip
-plugins/modules/cloudfront_distribution.py import-2.7!skip
-plugins/modules/cloudfront_distribution.py import-3.5!skip
-plugins/modules/cloudfront_distribution.py import-3.6!skip
-plugins/modules/cloudfront_distribution.py import-3.7!skip
-plugins/modules/cloudfront_distribution.py metaclass-boilerplate!skip
-plugins/modules/cloudfront_info.py compile-2.6!skip
-plugins/modules/cloudfront_info.py compile-2.7!skip
-plugins/modules/cloudfront_info.py compile-3.5!skip
-plugins/modules/cloudfront_info.py compile-3.6!skip
-plugins/modules/cloudfront_info.py compile-3.7!skip
-plugins/modules/cloudfront_info.py future-import-boilerplate!skip
-plugins/modules/cloudfront_info.py import-2.6!skip
-plugins/modules/cloudfront_info.py import-2.7!skip
-plugins/modules/cloudfront_info.py import-3.5!skip
-plugins/modules/cloudfront_info.py import-3.6!skip
-plugins/modules/cloudfront_info.py import-3.7!skip
-plugins/modules/cloudfront_info.py metaclass-boilerplate!skip
-plugins/modules/cloudfront_invalidation.py compile-2.6!skip
-plugins/modules/cloudfront_invalidation.py compile-2.7!skip
-plugins/modules/cloudfront_invalidation.py compile-3.5!skip
-plugins/modules/cloudfront_invalidation.py compile-3.6!skip
-plugins/modules/cloudfront_invalidation.py compile-3.7!skip
-plugins/modules/cloudfront_invalidation.py future-import-boilerplate!skip
-plugins/modules/cloudfront_invalidation.py import-2.6!skip
-plugins/modules/cloudfront_invalidation.py import-2.7!skip
-plugins/modules/cloudfront_invalidation.py import-3.5!skip
-plugins/modules/cloudfront_invalidation.py import-3.6!skip
-plugins/modules/cloudfront_invalidation.py import-3.7!skip
-plugins/modules/cloudfront_invalidation.py metaclass-boilerplate!skip
-plugins/modules/cloudfront_origin_access_identity.py compile-2.6!skip
-plugins/modules/cloudfront_origin_access_identity.py compile-2.7!skip
-plugins/modules/cloudfront_origin_access_identity.py compile-3.5!skip
-plugins/modules/cloudfront_origin_access_identity.py compile-3.6!skip
-plugins/modules/cloudfront_origin_access_identity.py compile-3.7!skip
-plugins/modules/cloudfront_origin_access_identity.py future-import-boilerplate!skip
-plugins/modules/cloudfront_origin_access_identity.py import-2.6!skip
-plugins/modules/cloudfront_origin_access_identity.py import-2.7!skip
-plugins/modules/cloudfront_origin_access_identity.py import-3.5!skip
-plugins/modules/cloudfront_origin_access_identity.py import-3.6!skip
-plugins/modules/cloudfront_origin_access_identity.py import-3.7!skip
-plugins/modules/cloudfront_origin_access_identity.py metaclass-boilerplate!skip
-plugins/modules/cloudtrail.py compile-2.6!skip
-plugins/modules/cloudtrail.py compile-2.7!skip
-plugins/modules/cloudtrail.py compile-3.5!skip
-plugins/modules/cloudtrail.py compile-3.6!skip
-plugins/modules/cloudtrail.py compile-3.7!skip
-plugins/modules/cloudtrail.py future-import-boilerplate!skip
-plugins/modules/cloudtrail.py import-2.6!skip
-plugins/modules/cloudtrail.py import-2.7!skip
-plugins/modules/cloudtrail.py import-3.5!skip
-plugins/modules/cloudtrail.py import-3.6!skip
-plugins/modules/cloudtrail.py import-3.7!skip
-plugins/modules/cloudtrail.py metaclass-boilerplate!skip
-plugins/modules/cloudwatchevent_rule.py compile-2.6!skip
-plugins/modules/cloudwatchevent_rule.py compile-2.7!skip
-plugins/modules/cloudwatchevent_rule.py compile-3.5!skip
-plugins/modules/cloudwatchevent_rule.py compile-3.6!skip
-plugins/modules/cloudwatchevent_rule.py compile-3.7!skip
-plugins/modules/cloudwatchevent_rule.py future-import-boilerplate!skip
-plugins/modules/cloudwatchevent_rule.py import-2.6!skip
-plugins/modules/cloudwatchevent_rule.py import-2.7!skip
-plugins/modules/cloudwatchevent_rule.py import-3.5!skip
-plugins/modules/cloudwatchevent_rule.py import-3.6!skip
-plugins/modules/cloudwatchevent_rule.py import-3.7!skip
-plugins/modules/cloudwatchevent_rule.py metaclass-boilerplate!skip
-plugins/modules/cloudwatchlogs_log_group.py compile-2.6!skip
-plugins/modules/cloudwatchlogs_log_group.py compile-2.7!skip
-plugins/modules/cloudwatchlogs_log_group.py compile-3.5!skip
-plugins/modules/cloudwatchlogs_log_group.py compile-3.6!skip
-plugins/modules/cloudwatchlogs_log_group.py compile-3.7!skip
-plugins/modules/cloudwatchlogs_log_group.py future-import-boilerplate!skip
-plugins/modules/cloudwatchlogs_log_group.py import-2.6!skip
-plugins/modules/cloudwatchlogs_log_group.py import-2.7!skip
-plugins/modules/cloudwatchlogs_log_group.py import-3.5!skip
-plugins/modules/cloudwatchlogs_log_group.py import-3.6!skip
-plugins/modules/cloudwatchlogs_log_group.py import-3.7!skip
-plugins/modules/cloudwatchlogs_log_group.py metaclass-boilerplate!skip
-plugins/modules/cloudwatchlogs_log_group_info.py compile-2.6!skip
-plugins/modules/cloudwatchlogs_log_group_info.py compile-2.7!skip
-plugins/modules/cloudwatchlogs_log_group_info.py compile-3.5!skip
-plugins/modules/cloudwatchlogs_log_group_info.py compile-3.6!skip
-plugins/modules/cloudwatchlogs_log_group_info.py compile-3.7!skip
-plugins/modules/cloudwatchlogs_log_group_info.py future-import-boilerplate!skip
-plugins/modules/cloudwatchlogs_log_group_info.py import-2.6!skip
-plugins/modules/cloudwatchlogs_log_group_info.py import-2.7!skip
-plugins/modules/cloudwatchlogs_log_group_info.py import-3.5!skip
-plugins/modules/cloudwatchlogs_log_group_info.py import-3.6!skip
-plugins/modules/cloudwatchlogs_log_group_info.py import-3.7!skip
-plugins/modules/cloudwatchlogs_log_group_info.py metaclass-boilerplate!skip
-plugins/modules/cloudwatchlogs_log_group_metric_filter.py compile-2.6!skip
-plugins/modules/cloudwatchlogs_log_group_metric_filter.py compile-2.7!skip
-plugins/modules/cloudwatchlogs_log_group_metric_filter.py compile-3.5!skip
-plugins/modules/cloudwatchlogs_log_group_metric_filter.py compile-3.6!skip
-plugins/modules/cloudwatchlogs_log_group_metric_filter.py compile-3.7!skip
-plugins/modules/cloudwatchlogs_log_group_metric_filter.py future-import-boilerplate!skip
-plugins/modules/cloudwatchlogs_log_group_metric_filter.py import-2.6!skip
-plugins/modules/cloudwatchlogs_log_group_metric_filter.py import-2.7!skip
-plugins/modules/cloudwatchlogs_log_group_metric_filter.py import-3.5!skip
-plugins/modules/cloudwatchlogs_log_group_metric_filter.py import-3.6!skip
-plugins/modules/cloudwatchlogs_log_group_metric_filter.py import-3.7!skip
-plugins/modules/cloudwatchlogs_log_group_metric_filter.py metaclass-boilerplate!skip
-plugins/modules/data_pipeline.py compile-2.6!skip
-plugins/modules/data_pipeline.py compile-2.7!skip
-plugins/modules/data_pipeline.py compile-3.5!skip
-plugins/modules/data_pipeline.py compile-3.6!skip
-plugins/modules/data_pipeline.py compile-3.7!skip
-plugins/modules/data_pipeline.py future-import-boilerplate!skip
-plugins/modules/data_pipeline.py import-2.6!skip
-plugins/modules/data_pipeline.py import-2.7!skip
-plugins/modules/data_pipeline.py import-3.5!skip
-plugins/modules/data_pipeline.py import-3.6!skip
-plugins/modules/data_pipeline.py import-3.7!skip
-plugins/modules/data_pipeline.py metaclass-boilerplate!skip
-plugins/modules/dms_endpoint.py compile-2.6!skip
-plugins/modules/dms_endpoint.py compile-2.7!skip
-plugins/modules/dms_endpoint.py compile-3.5!skip
-plugins/modules/dms_endpoint.py compile-3.6!skip
-plugins/modules/dms_endpoint.py compile-3.7!skip
-plugins/modules/dms_endpoint.py future-import-boilerplate!skip
-plugins/modules/dms_endpoint.py import-2.6!skip
-plugins/modules/dms_endpoint.py import-2.7!skip
-plugins/modules/dms_endpoint.py import-3.5!skip
-plugins/modules/dms_endpoint.py import-3.6!skip
-plugins/modules/dms_endpoint.py import-3.7!skip
-plugins/modules/dms_endpoint.py metaclass-boilerplate!skip
-plugins/modules/dms_replication_subnet_group.py compile-2.6!skip
-plugins/modules/dms_replication_subnet_group.py compile-2.7!skip
-plugins/modules/dms_replication_subnet_group.py compile-3.5!skip
-plugins/modules/dms_replication_subnet_group.py compile-3.6!skip
-plugins/modules/dms_replication_subnet_group.py compile-3.7!skip
-plugins/modules/dms_replication_subnet_group.py future-import-boilerplate!skip
-plugins/modules/dms_replication_subnet_group.py import-2.6!skip
-plugins/modules/dms_replication_subnet_group.py import-2.7!skip
-plugins/modules/dms_replication_subnet_group.py import-3.5!skip
-plugins/modules/dms_replication_subnet_group.py import-3.6!skip
-plugins/modules/dms_replication_subnet_group.py import-3.7!skip
-plugins/modules/dms_replication_subnet_group.py metaclass-boilerplate!skip
-plugins/modules/dynamodb_table.py compile-2.6!skip
-plugins/modules/dynamodb_table.py compile-2.7!skip
-plugins/modules/dynamodb_table.py compile-3.5!skip
-plugins/modules/dynamodb_table.py compile-3.6!skip
-plugins/modules/dynamodb_table.py compile-3.7!skip
-plugins/modules/dynamodb_table.py future-import-boilerplate!skip
-plugins/modules/dynamodb_table.py import-2.6!skip
-plugins/modules/dynamodb_table.py import-2.7!skip
-plugins/modules/dynamodb_table.py import-3.5!skip
-plugins/modules/dynamodb_table.py import-3.6!skip
-plugins/modules/dynamodb_table.py import-3.7!skip
-plugins/modules/dynamodb_table.py metaclass-boilerplate!skip
-plugins/modules/dynamodb_ttl.py compile-2.6!skip
-plugins/modules/dynamodb_ttl.py compile-2.7!skip
-plugins/modules/dynamodb_ttl.py compile-3.5!skip
-plugins/modules/dynamodb_ttl.py compile-3.6!skip
-plugins/modules/dynamodb_ttl.py compile-3.7!skip
-plugins/modules/dynamodb_ttl.py future-import-boilerplate!skip
-plugins/modules/dynamodb_ttl.py import-2.6!skip
-plugins/modules/dynamodb_ttl.py import-2.7!skip
-plugins/modules/dynamodb_ttl.py import-3.5!skip
-plugins/modules/dynamodb_ttl.py import-3.6!skip
-plugins/modules/dynamodb_ttl.py import-3.7!skip
-plugins/modules/dynamodb_ttl.py metaclass-boilerplate!skip
-plugins/modules/ec2_ami_copy.py compile-2.6!skip
-plugins/modules/ec2_ami_copy.py compile-2.7!skip
-plugins/modules/ec2_ami_copy.py compile-3.5!skip
-plugins/modules/ec2_ami_copy.py compile-3.6!skip
-plugins/modules/ec2_ami_copy.py compile-3.7!skip
-plugins/modules/ec2_ami_copy.py future-import-boilerplate!skip
-plugins/modules/ec2_ami_copy.py import-2.6!skip
-plugins/modules/ec2_ami_copy.py import-2.7!skip
-plugins/modules/ec2_ami_copy.py import-3.5!skip
-plugins/modules/ec2_ami_copy.py import-3.6!skip
-plugins/modules/ec2_ami_copy.py import-3.7!skip
-plugins/modules/ec2_ami_copy.py metaclass-boilerplate!skip
-plugins/modules/ec2_asg.py compile-2.6!skip
-plugins/modules/ec2_asg.py compile-2.7!skip
-plugins/modules/ec2_asg.py compile-3.5!skip
-plugins/modules/ec2_asg.py compile-3.6!skip
-plugins/modules/ec2_asg.py compile-3.7!skip
-plugins/modules/ec2_asg.py future-import-boilerplate!skip
-plugins/modules/ec2_asg.py import-2.6!skip
-plugins/modules/ec2_asg.py import-2.7!skip
-plugins/modules/ec2_asg.py import-3.5!skip
-plugins/modules/ec2_asg.py import-3.6!skip
-plugins/modules/ec2_asg.py import-3.7!skip
-plugins/modules/ec2_asg.py metaclass-boilerplate!skip
-plugins/modules/ec2_asg_info.py compile-2.6!skip
-plugins/modules/ec2_asg_info.py compile-2.7!skip
-plugins/modules/ec2_asg_info.py compile-3.5!skip
-plugins/modules/ec2_asg_info.py compile-3.6!skip
-plugins/modules/ec2_asg_info.py compile-3.7!skip
-plugins/modules/ec2_asg_info.py future-import-boilerplate!skip
-plugins/modules/ec2_asg_info.py import-2.6!skip
-plugins/modules/ec2_asg_info.py import-2.7!skip
-plugins/modules/ec2_asg_info.py import-3.5!skip
-plugins/modules/ec2_asg_info.py import-3.6!skip
-plugins/modules/ec2_asg_info.py import-3.7!skip
-plugins/modules/ec2_asg_info.py metaclass-boilerplate!skip
-plugins/modules/ec2_asg_lifecycle_hook.py compile-2.6!skip
-plugins/modules/ec2_asg_lifecycle_hook.py compile-2.7!skip
-plugins/modules/ec2_asg_lifecycle_hook.py compile-3.5!skip
-plugins/modules/ec2_asg_lifecycle_hook.py compile-3.6!skip
-plugins/modules/ec2_asg_lifecycle_hook.py compile-3.7!skip
-plugins/modules/ec2_asg_lifecycle_hook.py future-import-boilerplate!skip
-plugins/modules/ec2_asg_lifecycle_hook.py import-2.6!skip
-plugins/modules/ec2_asg_lifecycle_hook.py import-2.7!skip
-plugins/modules/ec2_asg_lifecycle_hook.py import-3.5!skip
-plugins/modules/ec2_asg_lifecycle_hook.py import-3.6!skip
-plugins/modules/ec2_asg_lifecycle_hook.py import-3.7!skip
-plugins/modules/ec2_asg_lifecycle_hook.py metaclass-boilerplate!skip
-plugins/modules/ec2_customer_gateway.py compile-2.6!skip
-plugins/modules/ec2_customer_gateway.py compile-2.7!skip
-plugins/modules/ec2_customer_gateway.py compile-3.5!skip
-plugins/modules/ec2_customer_gateway.py compile-3.6!skip
-plugins/modules/ec2_customer_gateway.py compile-3.7!skip
-plugins/modules/ec2_customer_gateway.py future-import-boilerplate!skip
-plugins/modules/ec2_customer_gateway.py import-2.6!skip
-plugins/modules/ec2_customer_gateway.py import-2.7!skip
-plugins/modules/ec2_customer_gateway.py import-3.5!skip
-plugins/modules/ec2_customer_gateway.py import-3.6!skip
-plugins/modules/ec2_customer_gateway.py import-3.7!skip
-plugins/modules/ec2_customer_gateway.py metaclass-boilerplate!skip
-plugins/modules/ec2_customer_gateway_info.py compile-2.6!skip
-plugins/modules/ec2_customer_gateway_info.py compile-2.7!skip
-plugins/modules/ec2_customer_gateway_info.py compile-3.5!skip
-plugins/modules/ec2_customer_gateway_info.py compile-3.6!skip
-plugins/modules/ec2_customer_gateway_info.py compile-3.7!skip
-plugins/modules/ec2_customer_gateway_info.py future-import-boilerplate!skip
-plugins/modules/ec2_customer_gateway_info.py import-2.6!skip
-plugins/modules/ec2_customer_gateway_info.py import-2.7!skip
-plugins/modules/ec2_customer_gateway_info.py import-3.5!skip
-plugins/modules/ec2_customer_gateway_info.py import-3.6!skip
-plugins/modules/ec2_customer_gateway_info.py import-3.7!skip
-plugins/modules/ec2_customer_gateway_info.py metaclass-boilerplate!skip
-plugins/modules/ec2_eip.py compile-2.6!skip
-plugins/modules/ec2_eip.py compile-2.7!skip
-plugins/modules/ec2_eip.py compile-3.5!skip
-plugins/modules/ec2_eip.py compile-3.6!skip
-plugins/modules/ec2_eip.py compile-3.7!skip
-plugins/modules/ec2_eip.py future-import-boilerplate!skip
-plugins/modules/ec2_eip.py import-2.6!skip
-plugins/modules/ec2_eip.py import-2.7!skip
-plugins/modules/ec2_eip.py import-3.5!skip
-plugins/modules/ec2_eip.py import-3.6!skip
-plugins/modules/ec2_eip.py import-3.7!skip
-plugins/modules/ec2_eip.py metaclass-boilerplate!skip
-plugins/modules/ec2_eip_info.py compile-2.6!skip
-plugins/modules/ec2_eip_info.py compile-2.7!skip
-plugins/modules/ec2_eip_info.py compile-3.5!skip
-plugins/modules/ec2_eip_info.py compile-3.6!skip
-plugins/modules/ec2_eip_info.py compile-3.7!skip
-plugins/modules/ec2_eip_info.py future-import-boilerplate!skip
-plugins/modules/ec2_eip_info.py import-2.6!skip
-plugins/modules/ec2_eip_info.py import-2.7!skip
-plugins/modules/ec2_eip_info.py import-3.5!skip
-plugins/modules/ec2_eip_info.py import-3.6!skip
-plugins/modules/ec2_eip_info.py import-3.7!skip
-plugins/modules/ec2_eip_info.py metaclass-boilerplate!skip
-plugins/modules/ec2_elb_info.py compile-2.6!skip
-plugins/modules/ec2_elb_info.py compile-2.7!skip
-plugins/modules/ec2_elb_info.py compile-3.5!skip
-plugins/modules/ec2_elb_info.py compile-3.6!skip
-plugins/modules/ec2_elb_info.py compile-3.7!skip
-plugins/modules/ec2_elb_info.py future-import-boilerplate!skip
-plugins/modules/ec2_elb_info.py import-2.6!skip
-plugins/modules/ec2_elb_info.py import-2.7!skip
-plugins/modules/ec2_elb_info.py import-3.5!skip
-plugins/modules/ec2_elb_info.py import-3.6!skip
-plugins/modules/ec2_elb_info.py import-3.7!skip
-plugins/modules/ec2_elb_info.py metaclass-boilerplate!skip
-plugins/modules/ec2_launch_template.py compile-2.6!skip
-plugins/modules/ec2_launch_template.py compile-2.7!skip
-plugins/modules/ec2_launch_template.py compile-3.5!skip
-plugins/modules/ec2_launch_template.py compile-3.6!skip
-plugins/modules/ec2_launch_template.py compile-3.7!skip
-plugins/modules/ec2_launch_template.py future-import-boilerplate!skip
-plugins/modules/ec2_launch_template.py import-2.6!skip
-plugins/modules/ec2_launch_template.py import-2.7!skip
-plugins/modules/ec2_launch_template.py import-3.5!skip
-plugins/modules/ec2_launch_template.py import-3.6!skip
-plugins/modules/ec2_launch_template.py import-3.7!skip
-plugins/modules/ec2_launch_template.py metaclass-boilerplate!skip
-plugins/modules/ec2_lc.py compile-2.6!skip
-plugins/modules/ec2_lc.py compile-2.7!skip
-plugins/modules/ec2_lc.py compile-3.5!skip
-plugins/modules/ec2_lc.py compile-3.6!skip
-plugins/modules/ec2_lc.py compile-3.7!skip
-plugins/modules/ec2_lc.py future-import-boilerplate!skip
-plugins/modules/ec2_lc.py import-2.6!skip
-plugins/modules/ec2_lc.py import-2.7!skip
-plugins/modules/ec2_lc.py import-3.5!skip
-plugins/modules/ec2_lc.py import-3.6!skip
-plugins/modules/ec2_lc.py import-3.7!skip
-plugins/modules/ec2_lc.py metaclass-boilerplate!skip
-plugins/modules/ec2_lc_find.py compile-2.6!skip
-plugins/modules/ec2_lc_find.py compile-2.7!skip
-plugins/modules/ec2_lc_find.py compile-3.5!skip
-plugins/modules/ec2_lc_find.py compile-3.6!skip
-plugins/modules/ec2_lc_find.py compile-3.7!skip
-plugins/modules/ec2_lc_find.py future-import-boilerplate!skip
-plugins/modules/ec2_lc_find.py import-2.6!skip
-plugins/modules/ec2_lc_find.py import-2.7!skip
-plugins/modules/ec2_lc_find.py import-3.5!skip
-plugins/modules/ec2_lc_find.py import-3.6!skip
-plugins/modules/ec2_lc_find.py import-3.7!skip
-plugins/modules/ec2_lc_find.py metaclass-boilerplate!skip
-plugins/modules/ec2_lc_info.py compile-2.6!skip
-plugins/modules/ec2_lc_info.py compile-2.7!skip
-plugins/modules/ec2_lc_info.py compile-3.5!skip
-plugins/modules/ec2_lc_info.py compile-3.6!skip
-plugins/modules/ec2_lc_info.py compile-3.7!skip
-plugins/modules/ec2_lc_info.py future-import-boilerplate!skip
-plugins/modules/ec2_lc_info.py import-2.6!skip
-plugins/modules/ec2_lc_info.py import-2.7!skip
-plugins/modules/ec2_lc_info.py import-3.5!skip
-plugins/modules/ec2_lc_info.py import-3.6!skip
-plugins/modules/ec2_lc_info.py import-3.7!skip
-plugins/modules/ec2_lc_info.py metaclass-boilerplate!skip
-plugins/modules/ec2_metric_alarm.py compile-2.6!skip
-plugins/modules/ec2_metric_alarm.py compile-2.7!skip
-plugins/modules/ec2_metric_alarm.py compile-3.5!skip
-plugins/modules/ec2_metric_alarm.py compile-3.6!skip
-plugins/modules/ec2_metric_alarm.py compile-3.7!skip
-plugins/modules/ec2_metric_alarm.py future-import-boilerplate!skip
-plugins/modules/ec2_metric_alarm.py import-2.6!skip
-plugins/modules/ec2_metric_alarm.py import-2.7!skip
-plugins/modules/ec2_metric_alarm.py import-3.5!skip
-plugins/modules/ec2_metric_alarm.py import-3.6!skip
-plugins/modules/ec2_metric_alarm.py import-3.7!skip
-plugins/modules/ec2_metric_alarm.py metaclass-boilerplate!skip
-plugins/modules/ec2_placement_group.py compile-2.6!skip
-plugins/modules/ec2_placement_group.py compile-2.7!skip
-plugins/modules/ec2_placement_group.py compile-3.5!skip
-plugins/modules/ec2_placement_group.py compile-3.6!skip
-plugins/modules/ec2_placement_group.py compile-3.7!skip
-plugins/modules/ec2_placement_group.py future-import-boilerplate!skip
-plugins/modules/ec2_placement_group.py import-2.6!skip
-plugins/modules/ec2_placement_group.py import-2.7!skip
-plugins/modules/ec2_placement_group.py import-3.5!skip
-plugins/modules/ec2_placement_group.py import-3.6!skip
-plugins/modules/ec2_placement_group.py import-3.7!skip
-plugins/modules/ec2_placement_group.py metaclass-boilerplate!skip
-plugins/modules/ec2_placement_group_info.py compile-2.6!skip
-plugins/modules/ec2_placement_group_info.py compile-2.7!skip
-plugins/modules/ec2_placement_group_info.py compile-3.5!skip
-plugins/modules/ec2_placement_group_info.py compile-3.6!skip
-plugins/modules/ec2_placement_group_info.py compile-3.7!skip
-plugins/modules/ec2_placement_group_info.py future-import-boilerplate!skip
-plugins/modules/ec2_placement_group_info.py import-2.6!skip
-plugins/modules/ec2_placement_group_info.py import-2.7!skip
-plugins/modules/ec2_placement_group_info.py import-3.5!skip
-plugins/modules/ec2_placement_group_info.py import-3.6!skip
-plugins/modules/ec2_placement_group_info.py import-3.7!skip
-plugins/modules/ec2_placement_group_info.py metaclass-boilerplate!skip
-plugins/modules/ec2_scaling_policy.py compile-2.6!skip
-plugins/modules/ec2_scaling_policy.py compile-2.7!skip
-plugins/modules/ec2_scaling_policy.py compile-3.5!skip
-plugins/modules/ec2_scaling_policy.py compile-3.6!skip
-plugins/modules/ec2_scaling_policy.py compile-3.7!skip
-plugins/modules/ec2_scaling_policy.py future-import-boilerplate!skip
-plugins/modules/ec2_scaling_policy.py import-2.6!skip
-plugins/modules/ec2_scaling_policy.py import-2.7!skip
-plugins/modules/ec2_scaling_policy.py import-3.5!skip
-plugins/modules/ec2_scaling_policy.py import-3.6!skip
-plugins/modules/ec2_scaling_policy.py import-3.7!skip
-plugins/modules/ec2_scaling_policy.py metaclass-boilerplate!skip
-plugins/modules/ec2_snapshot_copy.py compile-2.6!skip
-plugins/modules/ec2_snapshot_copy.py compile-2.7!skip
-plugins/modules/ec2_snapshot_copy.py compile-3.5!skip
-plugins/modules/ec2_snapshot_copy.py compile-3.6!skip
-plugins/modules/ec2_snapshot_copy.py compile-3.7!skip
-plugins/modules/ec2_snapshot_copy.py future-import-boilerplate!skip
-plugins/modules/ec2_snapshot_copy.py import-2.6!skip
-plugins/modules/ec2_snapshot_copy.py import-2.7!skip
-plugins/modules/ec2_snapshot_copy.py import-3.5!skip
-plugins/modules/ec2_snapshot_copy.py import-3.6!skip
-plugins/modules/ec2_snapshot_copy.py import-3.7!skip
-plugins/modules/ec2_snapshot_copy.py metaclass-boilerplate!skip
-plugins/modules/ec2_transit_gateway.py compile-2.6!skip
-plugins/modules/ec2_transit_gateway.py compile-2.7!skip
-plugins/modules/ec2_transit_gateway.py compile-3.5!skip
-plugins/modules/ec2_transit_gateway.py compile-3.6!skip
-plugins/modules/ec2_transit_gateway.py compile-3.7!skip
-plugins/modules/ec2_transit_gateway.py future-import-boilerplate!skip
-plugins/modules/ec2_transit_gateway.py import-2.6!skip
-plugins/modules/ec2_transit_gateway.py import-2.7!skip
-plugins/modules/ec2_transit_gateway.py import-3.5!skip
-plugins/modules/ec2_transit_gateway.py import-3.6!skip
-plugins/modules/ec2_transit_gateway.py import-3.7!skip
-plugins/modules/ec2_transit_gateway.py metaclass-boilerplate!skip
-plugins/modules/ec2_transit_gateway_info.py compile-2.6!skip
-plugins/modules/ec2_transit_gateway_info.py compile-2.7!skip
-plugins/modules/ec2_transit_gateway_info.py compile-3.5!skip
-plugins/modules/ec2_transit_gateway_info.py compile-3.6!skip
-plugins/modules/ec2_transit_gateway_info.py compile-3.7!skip
-plugins/modules/ec2_transit_gateway_info.py future-import-boilerplate!skip
-plugins/modules/ec2_transit_gateway_info.py import-2.6!skip
-plugins/modules/ec2_transit_gateway_info.py import-2.7!skip
-plugins/modules/ec2_transit_gateway_info.py import-3.5!skip
-plugins/modules/ec2_transit_gateway_info.py import-3.6!skip
-plugins/modules/ec2_transit_gateway_info.py import-3.7!skip
-plugins/modules/ec2_transit_gateway_info.py metaclass-boilerplate!skip
-plugins/modules/ec2_vpc_egress_igw.py compile-2.6!skip
-plugins/modules/ec2_vpc_egress_igw.py compile-2.7!skip
-plugins/modules/ec2_vpc_egress_igw.py compile-3.5!skip
-plugins/modules/ec2_vpc_egress_igw.py compile-3.6!skip
-plugins/modules/ec2_vpc_egress_igw.py compile-3.7!skip
-plugins/modules/ec2_vpc_egress_igw.py future-import-boilerplate!skip
-plugins/modules/ec2_vpc_egress_igw.py import-2.6!skip
-plugins/modules/ec2_vpc_egress_igw.py import-2.7!skip
-plugins/modules/ec2_vpc_egress_igw.py import-3.5!skip
-plugins/modules/ec2_vpc_egress_igw.py import-3.6!skip
-plugins/modules/ec2_vpc_egress_igw.py import-3.7!skip
-plugins/modules/ec2_vpc_egress_igw.py metaclass-boilerplate!skip
-plugins/modules/ec2_vpc_endpoint.py compile-2.6!skip
-plugins/modules/ec2_vpc_endpoint.py compile-2.7!skip
-plugins/modules/ec2_vpc_endpoint.py compile-3.5!skip
-plugins/modules/ec2_vpc_endpoint.py compile-3.6!skip
-plugins/modules/ec2_vpc_endpoint.py compile-3.7!skip
-plugins/modules/ec2_vpc_endpoint.py future-import-boilerplate!skip
-plugins/modules/ec2_vpc_endpoint.py import-2.6!skip
-plugins/modules/ec2_vpc_endpoint.py import-2.7!skip
-plugins/modules/ec2_vpc_endpoint.py import-3.5!skip
-plugins/modules/ec2_vpc_endpoint.py import-3.6!skip
-plugins/modules/ec2_vpc_endpoint.py import-3.7!skip
-plugins/modules/ec2_vpc_endpoint.py metaclass-boilerplate!skip
-plugins/modules/ec2_vpc_endpoint_info.py compile-2.6!skip
-plugins/modules/ec2_vpc_endpoint_info.py compile-2.7!skip
-plugins/modules/ec2_vpc_endpoint_info.py compile-3.5!skip
-plugins/modules/ec2_vpc_endpoint_info.py compile-3.6!skip
-plugins/modules/ec2_vpc_endpoint_info.py compile-3.7!skip
-plugins/modules/ec2_vpc_endpoint_info.py future-import-boilerplate!skip
-plugins/modules/ec2_vpc_endpoint_info.py import-2.6!skip
-plugins/modules/ec2_vpc_endpoint_info.py import-2.7!skip
-plugins/modules/ec2_vpc_endpoint_info.py import-3.5!skip
-plugins/modules/ec2_vpc_endpoint_info.py import-3.6!skip
-plugins/modules/ec2_vpc_endpoint_info.py import-3.7!skip
-plugins/modules/ec2_vpc_endpoint_info.py metaclass-boilerplate!skip
-plugins/modules/ec2_vpc_endpoint_service_info.py compile-2.6!skip
-plugins/modules/ec2_vpc_endpoint_service_info.py compile-2.7!skip
-plugins/modules/ec2_vpc_endpoint_service_info.py compile-3.5!skip
-plugins/modules/ec2_vpc_endpoint_service_info.py compile-3.6!skip
-plugins/modules/ec2_vpc_endpoint_service_info.py compile-3.7!skip
-plugins/modules/ec2_vpc_endpoint_service_info.py future-import-boilerplate!skip
-plugins/modules/ec2_vpc_endpoint_service_info.py import-2.6!skip
-plugins/modules/ec2_vpc_endpoint_service_info.py import-2.7!skip
-plugins/modules/ec2_vpc_endpoint_service_info.py import-3.5!skip
-plugins/modules/ec2_vpc_endpoint_service_info.py import-3.6!skip
-plugins/modules/ec2_vpc_endpoint_service_info.py import-3.7!skip
-plugins/modules/ec2_vpc_endpoint_service_info.py metaclass-boilerplate!skip
-plugins/modules/ec2_vpc_igw.py compile-2.6!skip
-plugins/modules/ec2_vpc_igw.py compile-2.7!skip
-plugins/modules/ec2_vpc_igw.py compile-3.5!skip
-plugins/modules/ec2_vpc_igw.py compile-3.6!skip
-plugins/modules/ec2_vpc_igw.py compile-3.7!skip
-plugins/modules/ec2_vpc_igw.py future-import-boilerplate!skip
-plugins/modules/ec2_vpc_igw.py import-2.6!skip
-plugins/modules/ec2_vpc_igw.py import-2.7!skip
-plugins/modules/ec2_vpc_igw.py import-3.5!skip
-plugins/modules/ec2_vpc_igw.py import-3.6!skip
-plugins/modules/ec2_vpc_igw.py import-3.7!skip
-plugins/modules/ec2_vpc_igw.py metaclass-boilerplate!skip
-plugins/modules/ec2_vpc_igw_info.py compile-2.6!skip
-plugins/modules/ec2_vpc_igw_info.py compile-2.7!skip
-plugins/modules/ec2_vpc_igw_info.py compile-3.5!skip
-plugins/modules/ec2_vpc_igw_info.py compile-3.6!skip
-plugins/modules/ec2_vpc_igw_info.py compile-3.7!skip
-plugins/modules/ec2_vpc_igw_info.py future-import-boilerplate!skip
-plugins/modules/ec2_vpc_igw_info.py import-2.6!skip
-plugins/modules/ec2_vpc_igw_info.py import-2.7!skip
-plugins/modules/ec2_vpc_igw_info.py import-3.5!skip
-plugins/modules/ec2_vpc_igw_info.py import-3.6!skip
-plugins/modules/ec2_vpc_igw_info.py import-3.7!skip
-plugins/modules/ec2_vpc_igw_info.py metaclass-boilerplate!skip
-plugins/modules/ec2_vpc_nacl.py compile-2.6!skip
-plugins/modules/ec2_vpc_nacl.py compile-2.7!skip
-plugins/modules/ec2_vpc_nacl.py compile-3.5!skip
-plugins/modules/ec2_vpc_nacl.py compile-3.6!skip
-plugins/modules/ec2_vpc_nacl.py compile-3.7!skip
-plugins/modules/ec2_vpc_nacl.py future-import-boilerplate!skip
-plugins/modules/ec2_vpc_nacl.py import-2.6!skip
-plugins/modules/ec2_vpc_nacl.py import-2.7!skip
-plugins/modules/ec2_vpc_nacl.py import-3.5!skip
-plugins/modules/ec2_vpc_nacl.py import-3.6!skip
-plugins/modules/ec2_vpc_nacl.py import-3.7!skip
-plugins/modules/ec2_vpc_nacl.py metaclass-boilerplate!skip
-plugins/modules/ec2_vpc_nacl_info.py compile-2.6!skip
-plugins/modules/ec2_vpc_nacl_info.py compile-2.7!skip
-plugins/modules/ec2_vpc_nacl_info.py compile-3.5!skip
-plugins/modules/ec2_vpc_nacl_info.py compile-3.6!skip
-plugins/modules/ec2_vpc_nacl_info.py compile-3.7!skip
-plugins/modules/ec2_vpc_nacl_info.py future-import-boilerplate!skip
-plugins/modules/ec2_vpc_nacl_info.py import-2.6!skip
-plugins/modules/ec2_vpc_nacl_info.py import-2.7!skip
-plugins/modules/ec2_vpc_nacl_info.py import-3.5!skip
-plugins/modules/ec2_vpc_nacl_info.py import-3.6!skip
-plugins/modules/ec2_vpc_nacl_info.py import-3.7!skip
-plugins/modules/ec2_vpc_nacl_info.py metaclass-boilerplate!skip
-plugins/modules/ec2_vpc_nat_gateway.py compile-2.6!skip
-plugins/modules/ec2_vpc_nat_gateway.py compile-2.7!skip
-plugins/modules/ec2_vpc_nat_gateway.py compile-3.5!skip
-plugins/modules/ec2_vpc_nat_gateway.py compile-3.6!skip
-plugins/modules/ec2_vpc_nat_gateway.py compile-3.7!skip
-plugins/modules/ec2_vpc_nat_gateway.py future-import-boilerplate!skip
-plugins/modules/ec2_vpc_nat_gateway.py import-2.6!skip
-plugins/modules/ec2_vpc_nat_gateway.py import-2.7!skip
-plugins/modules/ec2_vpc_nat_gateway.py import-3.5!skip
-plugins/modules/ec2_vpc_nat_gateway.py import-3.6!skip
-plugins/modules/ec2_vpc_nat_gateway.py import-3.7!skip
-plugins/modules/ec2_vpc_nat_gateway.py metaclass-boilerplate!skip
-plugins/modules/ec2_vpc_nat_gateway_info.py compile-2.6!skip
-plugins/modules/ec2_vpc_nat_gateway_info.py compile-2.7!skip
-plugins/modules/ec2_vpc_nat_gateway_info.py compile-3.5!skip
-plugins/modules/ec2_vpc_nat_gateway_info.py compile-3.6!skip
-plugins/modules/ec2_vpc_nat_gateway_info.py compile-3.7!skip
-plugins/modules/ec2_vpc_nat_gateway_info.py future-import-boilerplate!skip
-plugins/modules/ec2_vpc_nat_gateway_info.py import-2.6!skip
-plugins/modules/ec2_vpc_nat_gateway_info.py import-2.7!skip
-plugins/modules/ec2_vpc_nat_gateway_info.py import-3.5!skip
-plugins/modules/ec2_vpc_nat_gateway_info.py import-3.6!skip
-plugins/modules/ec2_vpc_nat_gateway_info.py import-3.7!skip
-plugins/modules/ec2_vpc_nat_gateway_info.py metaclass-boilerplate!skip
-plugins/modules/ec2_vpc_peer.py compile-2.6!skip
-plugins/modules/ec2_vpc_peer.py compile-2.7!skip
-plugins/modules/ec2_vpc_peer.py compile-3.5!skip
-plugins/modules/ec2_vpc_peer.py compile-3.6!skip
-plugins/modules/ec2_vpc_peer.py compile-3.7!skip
-plugins/modules/ec2_vpc_peer.py future-import-boilerplate!skip
-plugins/modules/ec2_vpc_peer.py import-2.6!skip
-plugins/modules/ec2_vpc_peer.py import-2.7!skip
-plugins/modules/ec2_vpc_peer.py import-3.5!skip
-plugins/modules/ec2_vpc_peer.py import-3.6!skip
-plugins/modules/ec2_vpc_peer.py import-3.7!skip
-plugins/modules/ec2_vpc_peer.py metaclass-boilerplate!skip
-plugins/modules/ec2_vpc_peering_info.py compile-2.6!skip
-plugins/modules/ec2_vpc_peering_info.py compile-2.7!skip
-plugins/modules/ec2_vpc_peering_info.py compile-3.5!skip
-plugins/modules/ec2_vpc_peering_info.py compile-3.6!skip
-plugins/modules/ec2_vpc_peering_info.py compile-3.7!skip
-plugins/modules/ec2_vpc_peering_info.py future-import-boilerplate!skip
-plugins/modules/ec2_vpc_peering_info.py import-2.6!skip
-plugins/modules/ec2_vpc_peering_info.py import-2.7!skip
-plugins/modules/ec2_vpc_peering_info.py import-3.5!skip
-plugins/modules/ec2_vpc_peering_info.py import-3.6!skip
-plugins/modules/ec2_vpc_peering_info.py import-3.7!skip
-plugins/modules/ec2_vpc_peering_info.py metaclass-boilerplate!skip
-plugins/modules/ec2_vpc_route_table.py compile-2.6!skip
-plugins/modules/ec2_vpc_route_table.py compile-2.7!skip
-plugins/modules/ec2_vpc_route_table.py compile-3.5!skip
-plugins/modules/ec2_vpc_route_table.py compile-3.6!skip
-plugins/modules/ec2_vpc_route_table.py compile-3.7!skip
-plugins/modules/ec2_vpc_route_table.py future-import-boilerplate!skip
-plugins/modules/ec2_vpc_route_table.py import-2.6!skip
-plugins/modules/ec2_vpc_route_table.py import-2.7!skip
-plugins/modules/ec2_vpc_route_table.py import-3.5!skip
-plugins/modules/ec2_vpc_route_table.py import-3.6!skip
-plugins/modules/ec2_vpc_route_table.py import-3.7!skip
-plugins/modules/ec2_vpc_route_table.py metaclass-boilerplate!skip
-plugins/modules/ec2_vpc_route_table_info.py compile-2.6!skip
-plugins/modules/ec2_vpc_route_table_info.py compile-2.7!skip
-plugins/modules/ec2_vpc_route_table_info.py compile-3.5!skip
-plugins/modules/ec2_vpc_route_table_info.py compile-3.6!skip
-plugins/modules/ec2_vpc_route_table_info.py compile-3.7!skip
-plugins/modules/ec2_vpc_route_table_info.py future-import-boilerplate!skip
-plugins/modules/ec2_vpc_route_table_info.py import-2.6!skip
-plugins/modules/ec2_vpc_route_table_info.py import-2.7!skip
-plugins/modules/ec2_vpc_route_table_info.py import-3.5!skip
-plugins/modules/ec2_vpc_route_table_info.py import-3.6!skip
-plugins/modules/ec2_vpc_route_table_info.py import-3.7!skip
-plugins/modules/ec2_vpc_route_table_info.py metaclass-boilerplate!skip
-plugins/modules/ec2_vpc_vgw.py compile-2.6!skip
-plugins/modules/ec2_vpc_vgw.py compile-2.7!skip
-plugins/modules/ec2_vpc_vgw.py compile-3.5!skip
-plugins/modules/ec2_vpc_vgw.py compile-3.6!skip
-plugins/modules/ec2_vpc_vgw.py compile-3.7!skip
-plugins/modules/ec2_vpc_vgw.py future-import-boilerplate!skip
-plugins/modules/ec2_vpc_vgw.py import-2.6!skip
-plugins/modules/ec2_vpc_vgw.py import-2.7!skip
-plugins/modules/ec2_vpc_vgw.py import-3.5!skip
-plugins/modules/ec2_vpc_vgw.py import-3.6!skip
-plugins/modules/ec2_vpc_vgw.py import-3.7!skip
-plugins/modules/ec2_vpc_vgw.py metaclass-boilerplate!skip
-plugins/modules/ec2_vpc_vgw_info.py compile-2.6!skip
-plugins/modules/ec2_vpc_vgw_info.py compile-2.7!skip
-plugins/modules/ec2_vpc_vgw_info.py compile-3.5!skip
-plugins/modules/ec2_vpc_vgw_info.py compile-3.6!skip
-plugins/modules/ec2_vpc_vgw_info.py compile-3.7!skip
-plugins/modules/ec2_vpc_vgw_info.py future-import-boilerplate!skip
-plugins/modules/ec2_vpc_vgw_info.py import-2.6!skip
-plugins/modules/ec2_vpc_vgw_info.py import-2.7!skip
-plugins/modules/ec2_vpc_vgw_info.py import-3.5!skip
-plugins/modules/ec2_vpc_vgw_info.py import-3.6!skip
-plugins/modules/ec2_vpc_vgw_info.py import-3.7!skip
-plugins/modules/ec2_vpc_vgw_info.py metaclass-boilerplate!skip
-plugins/modules/ec2_vpc_vpn.py compile-2.6!skip
-plugins/modules/ec2_vpc_vpn.py compile-2.7!skip
-plugins/modules/ec2_vpc_vpn.py compile-3.5!skip
-plugins/modules/ec2_vpc_vpn.py compile-3.6!skip
-plugins/modules/ec2_vpc_vpn.py compile-3.7!skip
-plugins/modules/ec2_vpc_vpn.py future-import-boilerplate!skip
-plugins/modules/ec2_vpc_vpn.py import-2.6!skip
-plugins/modules/ec2_vpc_vpn.py import-2.7!skip
-plugins/modules/ec2_vpc_vpn.py import-3.5!skip
-plugins/modules/ec2_vpc_vpn.py import-3.6!skip
-plugins/modules/ec2_vpc_vpn.py import-3.7!skip
-plugins/modules/ec2_vpc_vpn.py metaclass-boilerplate!skip
-plugins/modules/ec2_vpc_vpn_info.py compile-2.6!skip
-plugins/modules/ec2_vpc_vpn_info.py compile-2.7!skip
-plugins/modules/ec2_vpc_vpn_info.py compile-3.5!skip
-plugins/modules/ec2_vpc_vpn_info.py compile-3.6!skip
-plugins/modules/ec2_vpc_vpn_info.py compile-3.7!skip
-plugins/modules/ec2_vpc_vpn_info.py future-import-boilerplate!skip
-plugins/modules/ec2_vpc_vpn_info.py import-2.6!skip
-plugins/modules/ec2_vpc_vpn_info.py import-2.7!skip
-plugins/modules/ec2_vpc_vpn_info.py import-3.5!skip
-plugins/modules/ec2_vpc_vpn_info.py import-3.6!skip
-plugins/modules/ec2_vpc_vpn_info.py import-3.7!skip
-plugins/modules/ec2_vpc_vpn_info.py metaclass-boilerplate!skip
-plugins/modules/ec2_win_password.py compile-2.6!skip
-plugins/modules/ec2_win_password.py compile-2.7!skip
-plugins/modules/ec2_win_password.py compile-3.5!skip
-plugins/modules/ec2_win_password.py compile-3.6!skip
-plugins/modules/ec2_win_password.py compile-3.7!skip
-plugins/modules/ec2_win_password.py future-import-boilerplate!skip
-plugins/modules/ec2_win_password.py import-2.6!skip
-plugins/modules/ec2_win_password.py import-2.7!skip
-plugins/modules/ec2_win_password.py import-3.5!skip
-plugins/modules/ec2_win_password.py import-3.6!skip
-plugins/modules/ec2_win_password.py import-3.7!skip
-plugins/modules/ec2_win_password.py metaclass-boilerplate!skip
-plugins/modules/ecs_attribute.py compile-2.6!skip
-plugins/modules/ecs_attribute.py compile-2.7!skip
-plugins/modules/ecs_attribute.py compile-3.5!skip
-plugins/modules/ecs_attribute.py compile-3.6!skip
-plugins/modules/ecs_attribute.py compile-3.7!skip
-plugins/modules/ecs_attribute.py future-import-boilerplate!skip
-plugins/modules/ecs_attribute.py import-2.6!skip
-plugins/modules/ecs_attribute.py import-2.7!skip
-plugins/modules/ecs_attribute.py import-3.5!skip
-plugins/modules/ecs_attribute.py import-3.6!skip
-plugins/modules/ecs_attribute.py import-3.7!skip
-plugins/modules/ecs_attribute.py metaclass-boilerplate!skip
-plugins/modules/ecs_cluster.py compile-2.6!skip
-plugins/modules/ecs_cluster.py compile-2.7!skip
-plugins/modules/ecs_cluster.py compile-3.5!skip
-plugins/modules/ecs_cluster.py compile-3.6!skip
-plugins/modules/ecs_cluster.py compile-3.7!skip
-plugins/modules/ecs_cluster.py future-import-boilerplate!skip
-plugins/modules/ecs_cluster.py import-2.6!skip
-plugins/modules/ecs_cluster.py import-2.7!skip
-plugins/modules/ecs_cluster.py import-3.5!skip
-plugins/modules/ecs_cluster.py import-3.6!skip
-plugins/modules/ecs_cluster.py import-3.7!skip
-plugins/modules/ecs_cluster.py metaclass-boilerplate!skip
-plugins/modules/ecs_ecr.py compile-2.6!skip
-plugins/modules/ecs_ecr.py compile-2.7!skip
-plugins/modules/ecs_ecr.py compile-3.5!skip
-plugins/modules/ecs_ecr.py compile-3.6!skip
-plugins/modules/ecs_ecr.py compile-3.7!skip
-plugins/modules/ecs_ecr.py future-import-boilerplate!skip
-plugins/modules/ecs_ecr.py import-2.6!skip
-plugins/modules/ecs_ecr.py import-2.7!skip
-plugins/modules/ecs_ecr.py import-3.5!skip
-plugins/modules/ecs_ecr.py import-3.6!skip
-plugins/modules/ecs_ecr.py import-3.7!skip
-plugins/modules/ecs_ecr.py metaclass-boilerplate!skip
-plugins/modules/ecs_service.py compile-2.6!skip
-plugins/modules/ecs_service.py compile-2.7!skip
-plugins/modules/ecs_service.py compile-3.5!skip
-plugins/modules/ecs_service.py compile-3.6!skip
-plugins/modules/ecs_service.py compile-3.7!skip
-plugins/modules/ecs_service.py future-import-boilerplate!skip
-plugins/modules/ecs_service.py import-2.6!skip
-plugins/modules/ecs_service.py import-2.7!skip
-plugins/modules/ecs_service.py import-3.5!skip
-plugins/modules/ecs_service.py import-3.6!skip
-plugins/modules/ecs_service.py import-3.7!skip
-plugins/modules/ecs_service.py metaclass-boilerplate!skip
-plugins/modules/ecs_service_info.py compile-2.6!skip
-plugins/modules/ecs_service_info.py compile-2.7!skip
-plugins/modules/ecs_service_info.py compile-3.5!skip
-plugins/modules/ecs_service_info.py compile-3.6!skip
-plugins/modules/ecs_service_info.py compile-3.7!skip
-plugins/modules/ecs_service_info.py future-import-boilerplate!skip
-plugins/modules/ecs_service_info.py import-2.6!skip
-plugins/modules/ecs_service_info.py import-2.7!skip
-plugins/modules/ecs_service_info.py import-3.5!skip
-plugins/modules/ecs_service_info.py import-3.6!skip
-plugins/modules/ecs_service_info.py import-3.7!skip
-plugins/modules/ecs_service_info.py metaclass-boilerplate!skip
-plugins/modules/ecs_tag.py compile-2.6!skip
-plugins/modules/ecs_tag.py compile-2.7!skip
-plugins/modules/ecs_tag.py compile-3.5!skip
-plugins/modules/ecs_tag.py compile-3.6!skip
-plugins/modules/ecs_tag.py compile-3.7!skip
-plugins/modules/ecs_tag.py future-import-boilerplate!skip
-plugins/modules/ecs_tag.py import-2.6!skip
-plugins/modules/ecs_tag.py import-2.7!skip
-plugins/modules/ecs_tag.py import-3.5!skip
-plugins/modules/ecs_tag.py import-3.6!skip
-plugins/modules/ecs_tag.py import-3.7!skip
-plugins/modules/ecs_tag.py metaclass-boilerplate!skip
-plugins/modules/ecs_task.py compile-2.6!skip
-plugins/modules/ecs_task.py compile-2.7!skip
-plugins/modules/ecs_task.py compile-3.5!skip
-plugins/modules/ecs_task.py compile-3.6!skip
-plugins/modules/ecs_task.py compile-3.7!skip
-plugins/modules/ecs_task.py future-import-boilerplate!skip
-plugins/modules/ecs_task.py import-2.6!skip
-plugins/modules/ecs_task.py import-2.7!skip
-plugins/modules/ecs_task.py import-3.5!skip
-plugins/modules/ecs_task.py import-3.6!skip
-plugins/modules/ecs_task.py import-3.7!skip
-plugins/modules/ecs_task.py metaclass-boilerplate!skip
-plugins/modules/ecs_taskdefinition.py compile-2.6!skip
-plugins/modules/ecs_taskdefinition.py compile-2.7!skip
-plugins/modules/ecs_taskdefinition.py compile-3.5!skip
-plugins/modules/ecs_taskdefinition.py compile-3.6!skip
-plugins/modules/ecs_taskdefinition.py compile-3.7!skip
-plugins/modules/ecs_taskdefinition.py future-import-boilerplate!skip
-plugins/modules/ecs_taskdefinition.py import-2.6!skip
-plugins/modules/ecs_taskdefinition.py import-2.7!skip
-plugins/modules/ecs_taskdefinition.py import-3.5!skip
-plugins/modules/ecs_taskdefinition.py import-3.6!skip
-plugins/modules/ecs_taskdefinition.py import-3.7!skip
-plugins/modules/ecs_taskdefinition.py metaclass-boilerplate!skip
-plugins/modules/ecs_taskdefinition_info.py compile-2.6!skip
-plugins/modules/ecs_taskdefinition_info.py compile-2.7!skip
-plugins/modules/ecs_taskdefinition_info.py compile-3.5!skip
-plugins/modules/ecs_taskdefinition_info.py compile-3.6!skip
-plugins/modules/ecs_taskdefinition_info.py compile-3.7!skip
-plugins/modules/ecs_taskdefinition_info.py future-import-boilerplate!skip
-plugins/modules/ecs_taskdefinition_info.py import-2.6!skip
-plugins/modules/ecs_taskdefinition_info.py import-2.7!skip
-plugins/modules/ecs_taskdefinition_info.py import-3.5!skip
-plugins/modules/ecs_taskdefinition_info.py import-3.6!skip
-plugins/modules/ecs_taskdefinition_info.py import-3.7!skip
-plugins/modules/ecs_taskdefinition_info.py metaclass-boilerplate!skip
-plugins/modules/efs.py compile-2.6!skip
-plugins/modules/efs.py compile-2.7!skip
-plugins/modules/efs.py compile-3.5!skip
-plugins/modules/efs.py compile-3.6!skip
-plugins/modules/efs.py compile-3.7!skip
-plugins/modules/efs.py future-import-boilerplate!skip
-plugins/modules/efs.py import-2.6!skip
-plugins/modules/efs.py import-2.7!skip
-plugins/modules/efs.py import-3.5!skip
-plugins/modules/efs.py import-3.6!skip
-plugins/modules/efs.py import-3.7!skip
-plugins/modules/efs.py metaclass-boilerplate!skip
-plugins/modules/efs_info.py compile-2.6!skip
-plugins/modules/efs_info.py compile-2.7!skip
-plugins/modules/efs_info.py compile-3.5!skip
-plugins/modules/efs_info.py compile-3.6!skip
-plugins/modules/efs_info.py compile-3.7!skip
-plugins/modules/efs_info.py future-import-boilerplate!skip
-plugins/modules/efs_info.py import-2.6!skip
-plugins/modules/efs_info.py import-2.7!skip
-plugins/modules/efs_info.py import-3.5!skip
-plugins/modules/efs_info.py import-3.6!skip
-plugins/modules/efs_info.py import-3.7!skip
-plugins/modules/efs_info.py metaclass-boilerplate!skip
-plugins/modules/elasticache.py compile-2.6!skip
-plugins/modules/elasticache.py compile-2.7!skip
-plugins/modules/elasticache.py compile-3.5!skip
-plugins/modules/elasticache.py compile-3.6!skip
-plugins/modules/elasticache.py compile-3.7!skip
-plugins/modules/elasticache.py future-import-boilerplate!skip
-plugins/modules/elasticache.py import-2.6!skip
-plugins/modules/elasticache.py import-2.7!skip
-plugins/modules/elasticache.py import-3.5!skip
-plugins/modules/elasticache.py import-3.6!skip
-plugins/modules/elasticache.py import-3.7!skip
-plugins/modules/elasticache.py metaclass-boilerplate!skip
-plugins/modules/elasticache_info.py compile-2.6!skip
-plugins/modules/elasticache_info.py compile-2.7!skip
-plugins/modules/elasticache_info.py compile-3.5!skip
-plugins/modules/elasticache_info.py compile-3.6!skip
-plugins/modules/elasticache_info.py compile-3.7!skip
-plugins/modules/elasticache_info.py future-import-boilerplate!skip
-plugins/modules/elasticache_info.py import-2.6!skip
-plugins/modules/elasticache_info.py import-2.7!skip
-plugins/modules/elasticache_info.py import-3.5!skip
-plugins/modules/elasticache_info.py import-3.6!skip
-plugins/modules/elasticache_info.py import-3.7!skip
-plugins/modules/elasticache_info.py metaclass-boilerplate!skip
-plugins/modules/elasticache_parameter_group.py compile-2.6!skip
-plugins/modules/elasticache_parameter_group.py compile-2.7!skip
-plugins/modules/elasticache_parameter_group.py compile-3.5!skip
-plugins/modules/elasticache_parameter_group.py compile-3.6!skip
-plugins/modules/elasticache_parameter_group.py compile-3.7!skip
-plugins/modules/elasticache_parameter_group.py future-import-boilerplate!skip
-plugins/modules/elasticache_parameter_group.py import-2.6!skip
-plugins/modules/elasticache_parameter_group.py import-2.7!skip
-plugins/modules/elasticache_parameter_group.py import-3.5!skip
-plugins/modules/elasticache_parameter_group.py import-3.6!skip
-plugins/modules/elasticache_parameter_group.py import-3.7!skip
-plugins/modules/elasticache_parameter_group.py metaclass-boilerplate!skip
-plugins/modules/elasticache_snapshot.py compile-2.6!skip
-plugins/modules/elasticache_snapshot.py compile-2.7!skip
-plugins/modules/elasticache_snapshot.py compile-3.5!skip
-plugins/modules/elasticache_snapshot.py compile-3.6!skip
-plugins/modules/elasticache_snapshot.py compile-3.7!skip
-plugins/modules/elasticache_snapshot.py future-import-boilerplate!skip
-plugins/modules/elasticache_snapshot.py import-2.6!skip
-plugins/modules/elasticache_snapshot.py import-2.7!skip
-plugins/modules/elasticache_snapshot.py import-3.5!skip
-plugins/modules/elasticache_snapshot.py import-3.6!skip
-plugins/modules/elasticache_snapshot.py import-3.7!skip
-plugins/modules/elasticache_snapshot.py metaclass-boilerplate!skip
-plugins/modules/elasticache_subnet_group.py compile-2.6!skip
-plugins/modules/elasticache_subnet_group.py compile-2.7!skip
-plugins/modules/elasticache_subnet_group.py compile-3.5!skip
-plugins/modules/elasticache_subnet_group.py compile-3.6!skip
-plugins/modules/elasticache_subnet_group.py compile-3.7!skip
-plugins/modules/elasticache_subnet_group.py future-import-boilerplate!skip
-plugins/modules/elasticache_subnet_group.py import-2.6!skip
-plugins/modules/elasticache_subnet_group.py import-2.7!skip
-plugins/modules/elasticache_subnet_group.py import-3.5!skip
-plugins/modules/elasticache_subnet_group.py import-3.6!skip
-plugins/modules/elasticache_subnet_group.py import-3.7!skip
-plugins/modules/elasticache_subnet_group.py metaclass-boilerplate!skip
-plugins/modules/elb_application_lb.py compile-2.6!skip
-plugins/modules/elb_application_lb.py compile-2.7!skip
-plugins/modules/elb_application_lb.py compile-3.5!skip
-plugins/modules/elb_application_lb.py compile-3.6!skip
-plugins/modules/elb_application_lb.py compile-3.7!skip
-plugins/modules/elb_application_lb.py future-import-boilerplate!skip
-plugins/modules/elb_application_lb.py import-2.6!skip
-plugins/modules/elb_application_lb.py import-2.7!skip
-plugins/modules/elb_application_lb.py import-3.5!skip
-plugins/modules/elb_application_lb.py import-3.6!skip
-plugins/modules/elb_application_lb.py import-3.7!skip
-plugins/modules/elb_application_lb.py metaclass-boilerplate!skip
-plugins/modules/elb_application_lb_info.py compile-2.6!skip
-plugins/modules/elb_application_lb_info.py compile-2.7!skip
-plugins/modules/elb_application_lb_info.py compile-3.5!skip
-plugins/modules/elb_application_lb_info.py compile-3.6!skip
-plugins/modules/elb_application_lb_info.py compile-3.7!skip
-plugins/modules/elb_application_lb_info.py future-import-boilerplate!skip
-plugins/modules/elb_application_lb_info.py import-2.6!skip
-plugins/modules/elb_application_lb_info.py import-2.7!skip
-plugins/modules/elb_application_lb_info.py import-3.5!skip
-plugins/modules/elb_application_lb_info.py import-3.6!skip
-plugins/modules/elb_application_lb_info.py import-3.7!skip
-plugins/modules/elb_application_lb_info.py metaclass-boilerplate!skip
-plugins/modules/elb_classic_lb_info.py compile-2.6!skip
-plugins/modules/elb_classic_lb_info.py compile-2.7!skip
-plugins/modules/elb_classic_lb_info.py compile-3.5!skip
-plugins/modules/elb_classic_lb_info.py compile-3.6!skip
-plugins/modules/elb_classic_lb_info.py compile-3.7!skip
-plugins/modules/elb_classic_lb_info.py future-import-boilerplate!skip
-plugins/modules/elb_classic_lb_info.py import-2.6!skip
-plugins/modules/elb_classic_lb_info.py import-2.7!skip
-plugins/modules/elb_classic_lb_info.py import-3.5!skip
-plugins/modules/elb_classic_lb_info.py import-3.6!skip
-plugins/modules/elb_classic_lb_info.py import-3.7!skip
-plugins/modules/elb_classic_lb_info.py metaclass-boilerplate!skip
-plugins/modules/elb_instance.py compile-2.6!skip
-plugins/modules/elb_instance.py compile-2.7!skip
-plugins/modules/elb_instance.py compile-3.5!skip
-plugins/modules/elb_instance.py compile-3.6!skip
-plugins/modules/elb_instance.py compile-3.7!skip
-plugins/modules/elb_instance.py future-import-boilerplate!skip
-plugins/modules/elb_instance.py import-2.6!skip
-plugins/modules/elb_instance.py import-2.7!skip
-plugins/modules/elb_instance.py import-3.5!skip
-plugins/modules/elb_instance.py import-3.6!skip
-plugins/modules/elb_instance.py import-3.7!skip
-plugins/modules/elb_instance.py metaclass-boilerplate!skip
-plugins/modules/elb_network_lb.py compile-2.6!skip
-plugins/modules/elb_network_lb.py compile-2.7!skip
-plugins/modules/elb_network_lb.py compile-3.5!skip
-plugins/modules/elb_network_lb.py compile-3.6!skip
-plugins/modules/elb_network_lb.py compile-3.7!skip
-plugins/modules/elb_network_lb.py future-import-boilerplate!skip
-plugins/modules/elb_network_lb.py import-2.6!skip
-plugins/modules/elb_network_lb.py import-2.7!skip
-plugins/modules/elb_network_lb.py import-3.5!skip
-plugins/modules/elb_network_lb.py import-3.6!skip
-plugins/modules/elb_network_lb.py import-3.7!skip
-plugins/modules/elb_network_lb.py metaclass-boilerplate!skip
-plugins/modules/elb_target.py compile-2.6!skip
-plugins/modules/elb_target.py compile-2.7!skip
-plugins/modules/elb_target.py compile-3.5!skip
-plugins/modules/elb_target.py compile-3.6!skip
-plugins/modules/elb_target.py compile-3.7!skip
-plugins/modules/elb_target.py future-import-boilerplate!skip
-plugins/modules/elb_target.py import-2.6!skip
-plugins/modules/elb_target.py import-2.7!skip
-plugins/modules/elb_target.py import-3.5!skip
-plugins/modules/elb_target.py import-3.6!skip
-plugins/modules/elb_target.py import-3.7!skip
-plugins/modules/elb_target.py metaclass-boilerplate!skip
-plugins/modules/elb_target_group.py compile-2.6!skip
-plugins/modules/elb_target_group.py compile-2.7!skip
-plugins/modules/elb_target_group.py compile-3.5!skip
-plugins/modules/elb_target_group.py compile-3.6!skip
-plugins/modules/elb_target_group.py compile-3.7!skip
-plugins/modules/elb_target_group.py future-import-boilerplate!skip
-plugins/modules/elb_target_group.py import-2.6!skip
-plugins/modules/elb_target_group.py import-2.7!skip
-plugins/modules/elb_target_group.py import-3.5!skip
-plugins/modules/elb_target_group.py import-3.6!skip
-plugins/modules/elb_target_group.py import-3.7!skip
-plugins/modules/elb_target_group.py metaclass-boilerplate!skip
-plugins/modules/elb_target_group_info.py compile-2.6!skip
-plugins/modules/elb_target_group_info.py compile-2.7!skip
-plugins/modules/elb_target_group_info.py compile-3.5!skip
-plugins/modules/elb_target_group_info.py compile-3.6!skip
-plugins/modules/elb_target_group_info.py compile-3.7!skip
-plugins/modules/elb_target_group_info.py future-import-boilerplate!skip
-plugins/modules/elb_target_group_info.py import-2.6!skip
-plugins/modules/elb_target_group_info.py import-2.7!skip
-plugins/modules/elb_target_group_info.py import-3.5!skip
-plugins/modules/elb_target_group_info.py import-3.6!skip
-plugins/modules/elb_target_group_info.py import-3.7!skip
-plugins/modules/elb_target_group_info.py metaclass-boilerplate!skip
-plugins/modules/elb_target_info.py compile-2.6!skip
-plugins/modules/elb_target_info.py compile-2.7!skip
-plugins/modules/elb_target_info.py compile-3.5!skip
-plugins/modules/elb_target_info.py compile-3.6!skip
-plugins/modules/elb_target_info.py compile-3.7!skip
-plugins/modules/elb_target_info.py future-import-boilerplate!skip
-plugins/modules/elb_target_info.py import-2.6!skip
-plugins/modules/elb_target_info.py import-2.7!skip
-plugins/modules/elb_target_info.py import-3.5!skip
-plugins/modules/elb_target_info.py import-3.6!skip
-plugins/modules/elb_target_info.py import-3.7!skip
-plugins/modules/elb_target_info.py metaclass-boilerplate!skip
-plugins/modules/execute_lambda.py compile-2.6!skip
-plugins/modules/execute_lambda.py compile-2.7!skip
-plugins/modules/execute_lambda.py compile-3.5!skip
-plugins/modules/execute_lambda.py compile-3.6!skip
-plugins/modules/execute_lambda.py compile-3.7!skip
-plugins/modules/execute_lambda.py future-import-boilerplate!skip
-plugins/modules/execute_lambda.py import-2.6!skip
-plugins/modules/execute_lambda.py import-2.7!skip
-plugins/modules/execute_lambda.py import-3.5!skip
-plugins/modules/execute_lambda.py import-3.6!skip
-plugins/modules/execute_lambda.py import-3.7!skip
-plugins/modules/execute_lambda.py metaclass-boilerplate!skip
-plugins/modules/iam.py compile-2.6!skip
-plugins/modules/iam.py compile-2.7!skip
-plugins/modules/iam.py compile-3.5!skip
-plugins/modules/iam.py compile-3.6!skip
-plugins/modules/iam.py compile-3.7!skip
-plugins/modules/iam.py future-import-boilerplate!skip
-plugins/modules/iam.py import-2.6!skip
-plugins/modules/iam.py import-2.7!skip
-plugins/modules/iam.py import-3.5!skip
-plugins/modules/iam.py import-3.6!skip
-plugins/modules/iam.py import-3.7!skip
-plugins/modules/iam.py metaclass-boilerplate!skip
-plugins/modules/iam_cert.py compile-2.6!skip
-plugins/modules/iam_cert.py compile-2.7!skip
-plugins/modules/iam_cert.py compile-3.5!skip
-plugins/modules/iam_cert.py compile-3.6!skip
-plugins/modules/iam_cert.py compile-3.7!skip
-plugins/modules/iam_cert.py future-import-boilerplate!skip
-plugins/modules/iam_cert.py import-2.6!skip
-plugins/modules/iam_cert.py import-2.7!skip
-plugins/modules/iam_cert.py import-3.5!skip
-plugins/modules/iam_cert.py import-3.6!skip
-plugins/modules/iam_cert.py import-3.7!skip
-plugins/modules/iam_cert.py metaclass-boilerplate!skip
-plugins/modules/iam_group.py compile-2.6!skip
-plugins/modules/iam_group.py compile-2.7!skip
-plugins/modules/iam_group.py compile-3.5!skip
-plugins/modules/iam_group.py compile-3.6!skip
-plugins/modules/iam_group.py compile-3.7!skip
-plugins/modules/iam_group.py future-import-boilerplate!skip
-plugins/modules/iam_group.py import-2.6!skip
-plugins/modules/iam_group.py import-2.7!skip
-plugins/modules/iam_group.py import-3.5!skip
-plugins/modules/iam_group.py import-3.6!skip
-plugins/modules/iam_group.py import-3.7!skip
-plugins/modules/iam_group.py metaclass-boilerplate!skip
-plugins/modules/iam_managed_policy.py compile-2.6!skip
-plugins/modules/iam_managed_policy.py compile-2.7!skip
-plugins/modules/iam_managed_policy.py compile-3.5!skip
-plugins/modules/iam_managed_policy.py compile-3.6!skip
-plugins/modules/iam_managed_policy.py compile-3.7!skip
-plugins/modules/iam_managed_policy.py future-import-boilerplate!skip
-plugins/modules/iam_managed_policy.py import-2.6!skip
-plugins/modules/iam_managed_policy.py import-2.7!skip
-plugins/modules/iam_managed_policy.py import-3.5!skip
-plugins/modules/iam_managed_policy.py import-3.6!skip
-plugins/modules/iam_managed_policy.py import-3.7!skip
-plugins/modules/iam_managed_policy.py metaclass-boilerplate!skip
-plugins/modules/iam_mfa_device_info.py compile-2.6!skip
-plugins/modules/iam_mfa_device_info.py compile-2.7!skip
-plugins/modules/iam_mfa_device_info.py compile-3.5!skip
-plugins/modules/iam_mfa_device_info.py compile-3.6!skip
-plugins/modules/iam_mfa_device_info.py compile-3.7!skip
-plugins/modules/iam_mfa_device_info.py future-import-boilerplate!skip
-plugins/modules/iam_mfa_device_info.py import-2.6!skip
-plugins/modules/iam_mfa_device_info.py import-2.7!skip
-plugins/modules/iam_mfa_device_info.py import-3.5!skip
-plugins/modules/iam_mfa_device_info.py import-3.6!skip
-plugins/modules/iam_mfa_device_info.py import-3.7!skip
-plugins/modules/iam_mfa_device_info.py metaclass-boilerplate!skip
-plugins/modules/iam_password_policy.py compile-2.6!skip
-plugins/modules/iam_password_policy.py compile-2.7!skip
-plugins/modules/iam_password_policy.py compile-3.5!skip
-plugins/modules/iam_password_policy.py compile-3.6!skip
-plugins/modules/iam_password_policy.py compile-3.7!skip
-plugins/modules/iam_password_policy.py future-import-boilerplate!skip
-plugins/modules/iam_password_policy.py import-2.6!skip
-plugins/modules/iam_password_policy.py import-2.7!skip
-plugins/modules/iam_password_policy.py import-3.5!skip
-plugins/modules/iam_password_policy.py import-3.6!skip
-plugins/modules/iam_password_policy.py import-3.7!skip
-plugins/modules/iam_password_policy.py metaclass-boilerplate!skip
-plugins/modules/iam_policy.py compile-2.6!skip
-plugins/modules/iam_policy.py compile-2.7!skip
-plugins/modules/iam_policy.py compile-3.5!skip
-plugins/modules/iam_policy.py compile-3.6!skip
-plugins/modules/iam_policy.py compile-3.7!skip
-plugins/modules/iam_policy.py future-import-boilerplate!skip
-plugins/modules/iam_policy.py import-2.6!skip
-plugins/modules/iam_policy.py import-2.7!skip
-plugins/modules/iam_policy.py import-3.5!skip
-plugins/modules/iam_policy.py import-3.6!skip
-plugins/modules/iam_policy.py import-3.7!skip
-plugins/modules/iam_policy.py metaclass-boilerplate!skip
-plugins/modules/iam_policy_info.py compile-2.6!skip
-plugins/modules/iam_policy_info.py compile-2.7!skip
-plugins/modules/iam_policy_info.py compile-3.5!skip
-plugins/modules/iam_policy_info.py compile-3.6!skip
-plugins/modules/iam_policy_info.py compile-3.7!skip
-plugins/modules/iam_policy_info.py future-import-boilerplate!skip
-plugins/modules/iam_policy_info.py import-2.6!skip
-plugins/modules/iam_policy_info.py import-2.7!skip
-plugins/modules/iam_policy_info.py import-3.5!skip
-plugins/modules/iam_policy_info.py import-3.6!skip
-plugins/modules/iam_policy_info.py import-3.7!skip
-plugins/modules/iam_policy_info.py metaclass-boilerplate!skip
-plugins/modules/iam_role.py compile-2.6!skip
-plugins/modules/iam_role.py compile-2.7!skip
-plugins/modules/iam_role.py compile-3.5!skip
-plugins/modules/iam_role.py compile-3.6!skip
-plugins/modules/iam_role.py compile-3.7!skip
-plugins/modules/iam_role.py future-import-boilerplate!skip
-plugins/modules/iam_role.py import-2.6!skip
-plugins/modules/iam_role.py import-2.7!skip
-plugins/modules/iam_role.py import-3.5!skip
-plugins/modules/iam_role.py import-3.6!skip
-plugins/modules/iam_role.py import-3.7!skip
-plugins/modules/iam_role.py metaclass-boilerplate!skip
-plugins/modules/iam_role_info.py compile-2.6!skip
-plugins/modules/iam_role_info.py compile-2.7!skip
-plugins/modules/iam_role_info.py compile-3.5!skip
-plugins/modules/iam_role_info.py compile-3.6!skip
-plugins/modules/iam_role_info.py compile-3.7!skip
-plugins/modules/iam_role_info.py future-import-boilerplate!skip
-plugins/modules/iam_role_info.py import-2.6!skip
-plugins/modules/iam_role_info.py import-2.7!skip
-plugins/modules/iam_role_info.py import-3.5!skip
-plugins/modules/iam_role_info.py import-3.6!skip
-plugins/modules/iam_role_info.py import-3.7!skip
-plugins/modules/iam_role_info.py metaclass-boilerplate!skip
-plugins/modules/iam_saml_federation.py compile-2.6!skip
-plugins/modules/iam_saml_federation.py compile-2.7!skip
-plugins/modules/iam_saml_federation.py compile-3.5!skip
-plugins/modules/iam_saml_federation.py compile-3.6!skip
-plugins/modules/iam_saml_federation.py compile-3.7!skip
-plugins/modules/iam_saml_federation.py future-import-boilerplate!skip
-plugins/modules/iam_saml_federation.py import-2.6!skip
-plugins/modules/iam_saml_federation.py import-2.7!skip
-plugins/modules/iam_saml_federation.py import-3.5!skip
-plugins/modules/iam_saml_federation.py import-3.6!skip
-plugins/modules/iam_saml_federation.py import-3.7!skip
-plugins/modules/iam_saml_federation.py metaclass-boilerplate!skip
-plugins/modules/iam_server_certificate_info.py compile-2.6!skip
-plugins/modules/iam_server_certificate_info.py compile-2.7!skip
-plugins/modules/iam_server_certificate_info.py compile-3.5!skip
-plugins/modules/iam_server_certificate_info.py compile-3.6!skip
-plugins/modules/iam_server_certificate_info.py compile-3.7!skip
-plugins/modules/iam_server_certificate_info.py future-import-boilerplate!skip
-plugins/modules/iam_server_certificate_info.py import-2.6!skip
-plugins/modules/iam_server_certificate_info.py import-2.7!skip
-plugins/modules/iam_server_certificate_info.py import-3.5!skip
-plugins/modules/iam_server_certificate_info.py import-3.6!skip
-plugins/modules/iam_server_certificate_info.py import-3.7!skip
-plugins/modules/iam_server_certificate_info.py metaclass-boilerplate!skip
-plugins/modules/iam_user.py compile-2.6!skip
-plugins/modules/iam_user.py compile-2.7!skip
-plugins/modules/iam_user.py compile-3.5!skip
-plugins/modules/iam_user.py compile-3.6!skip
-plugins/modules/iam_user.py compile-3.7!skip
-plugins/modules/iam_user.py future-import-boilerplate!skip
-plugins/modules/iam_user.py import-2.6!skip
-plugins/modules/iam_user.py import-2.7!skip
-plugins/modules/iam_user.py import-3.5!skip
-plugins/modules/iam_user.py import-3.6!skip
-plugins/modules/iam_user.py import-3.7!skip
-plugins/modules/iam_user.py metaclass-boilerplate!skip
-plugins/modules/iam_user_info.py compile-2.6!skip
-plugins/modules/iam_user_info.py compile-2.7!skip
-plugins/modules/iam_user_info.py compile-3.5!skip
-plugins/modules/iam_user_info.py compile-3.6!skip
-plugins/modules/iam_user_info.py compile-3.7!skip
-plugins/modules/iam_user_info.py future-import-boilerplate!skip
-plugins/modules/iam_user_info.py import-2.6!skip
-plugins/modules/iam_user_info.py import-2.7!skip
-plugins/modules/iam_user_info.py import-3.5!skip
-plugins/modules/iam_user_info.py import-3.6!skip
-plugins/modules/iam_user_info.py import-3.7!skip
-plugins/modules/iam_user_info.py metaclass-boilerplate!skip
-plugins/modules/kinesis_stream.py compile-2.6!skip
-plugins/modules/kinesis_stream.py compile-2.7!skip
-plugins/modules/kinesis_stream.py compile-3.5!skip
-plugins/modules/kinesis_stream.py compile-3.6!skip
-plugins/modules/kinesis_stream.py compile-3.7!skip
-plugins/modules/kinesis_stream.py future-import-boilerplate!skip
-plugins/modules/kinesis_stream.py import-2.6!skip
-plugins/modules/kinesis_stream.py import-2.7!skip
-plugins/modules/kinesis_stream.py import-3.5!skip
-plugins/modules/kinesis_stream.py import-3.6!skip
-plugins/modules/kinesis_stream.py import-3.7!skip
-plugins/modules/kinesis_stream.py metaclass-boilerplate!skip
-plugins/modules/lambda.py compile-2.6!skip
-plugins/modules/lambda.py compile-2.7!skip
-plugins/modules/lambda.py compile-3.5!skip
-plugins/modules/lambda.py compile-3.6!skip
-plugins/modules/lambda.py compile-3.7!skip
-plugins/modules/lambda.py future-import-boilerplate!skip
-plugins/modules/lambda.py import-2.6!skip
-plugins/modules/lambda.py import-2.7!skip
-plugins/modules/lambda.py import-3.5!skip
-plugins/modules/lambda.py import-3.6!skip
-plugins/modules/lambda.py import-3.7!skip
-plugins/modules/lambda.py metaclass-boilerplate!skip
-plugins/modules/lambda_alias.py compile-2.6!skip
-plugins/modules/lambda_alias.py compile-2.7!skip
-plugins/modules/lambda_alias.py compile-3.5!skip
-plugins/modules/lambda_alias.py compile-3.6!skip
-plugins/modules/lambda_alias.py compile-3.7!skip
-plugins/modules/lambda_alias.py future-import-boilerplate!skip
-plugins/modules/lambda_alias.py import-2.6!skip
-plugins/modules/lambda_alias.py import-2.7!skip
-plugins/modules/lambda_alias.py import-3.5!skip
-plugins/modules/lambda_alias.py import-3.6!skip
-plugins/modules/lambda_alias.py import-3.7!skip
-plugins/modules/lambda_alias.py metaclass-boilerplate!skip
-plugins/modules/lambda_event.py compile-2.6!skip
-plugins/modules/lambda_event.py compile-2.7!skip
-plugins/modules/lambda_event.py compile-3.5!skip
-plugins/modules/lambda_event.py compile-3.6!skip
-plugins/modules/lambda_event.py compile-3.7!skip
-plugins/modules/lambda_event.py future-import-boilerplate!skip
-plugins/modules/lambda_event.py import-2.6!skip
-plugins/modules/lambda_event.py import-2.7!skip
-plugins/modules/lambda_event.py import-3.5!skip
-plugins/modules/lambda_event.py import-3.6!skip
-plugins/modules/lambda_event.py import-3.7!skip
-plugins/modules/lambda_event.py metaclass-boilerplate!skip
-plugins/modules/lambda_facts.py compile-2.6!skip
-plugins/modules/lambda_facts.py compile-2.7!skip
-plugins/modules/lambda_facts.py compile-3.5!skip
-plugins/modules/lambda_facts.py compile-3.6!skip
-plugins/modules/lambda_facts.py compile-3.7!skip
-plugins/modules/lambda_facts.py future-import-boilerplate!skip
-plugins/modules/lambda_facts.py import-2.6!skip
-plugins/modules/lambda_facts.py import-2.7!skip
-plugins/modules/lambda_facts.py import-3.5!skip
-plugins/modules/lambda_facts.py import-3.6!skip
-plugins/modules/lambda_facts.py import-3.7!skip
-plugins/modules/lambda_facts.py metaclass-boilerplate!skip
-plugins/modules/lambda_info.py compile-2.6!skip
-plugins/modules/lambda_info.py compile-2.7!skip
-plugins/modules/lambda_info.py compile-3.5!skip
-plugins/modules/lambda_info.py compile-3.6!skip
-plugins/modules/lambda_info.py compile-3.7!skip
-plugins/modules/lambda_info.py future-import-boilerplate!skip
-plugins/modules/lambda_info.py import-2.6!skip
-plugins/modules/lambda_info.py import-2.7!skip
-plugins/modules/lambda_info.py import-3.5!skip
-plugins/modules/lambda_info.py import-3.6!skip
-plugins/modules/lambda_info.py import-3.7!skip
-plugins/modules/lambda_info.py metaclass-boilerplate!skip
-plugins/modules/lambda_policy.py compile-2.6!skip
-plugins/modules/lambda_policy.py compile-2.7!skip
-plugins/modules/lambda_policy.py compile-3.5!skip
-plugins/modules/lambda_policy.py compile-3.6!skip
-plugins/modules/lambda_policy.py compile-3.7!skip
-plugins/modules/lambda_policy.py future-import-boilerplate!skip
-plugins/modules/lambda_policy.py import-2.6!skip
-plugins/modules/lambda_policy.py import-2.7!skip
-plugins/modules/lambda_policy.py import-3.5!skip
-plugins/modules/lambda_policy.py import-3.6!skip
-plugins/modules/lambda_policy.py import-3.7!skip
-plugins/modules/lambda_policy.py metaclass-boilerplate!skip
-plugins/modules/lightsail.py compile-2.6!skip
-plugins/modules/lightsail.py compile-2.7!skip
-plugins/modules/lightsail.py compile-3.5!skip
-plugins/modules/lightsail.py compile-3.6!skip
-plugins/modules/lightsail.py compile-3.7!skip
-plugins/modules/lightsail.py future-import-boilerplate!skip
-plugins/modules/lightsail.py import-2.6!skip
-plugins/modules/lightsail.py import-2.7!skip
-plugins/modules/lightsail.py import-3.5!skip
-plugins/modules/lightsail.py import-3.6!skip
-plugins/modules/lightsail.py import-3.7!skip
-plugins/modules/lightsail.py metaclass-boilerplate!skip
-plugins/modules/rds.py compile-2.6!skip
-plugins/modules/rds.py compile-2.7!skip
-plugins/modules/rds.py compile-3.5!skip
-plugins/modules/rds.py compile-3.6!skip
-plugins/modules/rds.py compile-3.7!skip
-plugins/modules/rds.py future-import-boilerplate!skip
-plugins/modules/rds.py import-2.6!skip
-plugins/modules/rds.py import-2.7!skip
-plugins/modules/rds.py import-3.5!skip
-plugins/modules/rds.py import-3.6!skip
-plugins/modules/rds.py import-3.7!skip
-plugins/modules/rds.py metaclass-boilerplate!skip
-plugins/modules/rds_instance.py compile-2.6!skip
-plugins/modules/rds_instance.py compile-2.7!skip
-plugins/modules/rds_instance.py compile-3.5!skip
-plugins/modules/rds_instance.py compile-3.6!skip
-plugins/modules/rds_instance.py compile-3.7!skip
-plugins/modules/rds_instance.py future-import-boilerplate!skip
-plugins/modules/rds_instance.py import-2.6!skip
-plugins/modules/rds_instance.py import-2.7!skip
-plugins/modules/rds_instance.py import-3.5!skip
-plugins/modules/rds_instance.py import-3.6!skip
-plugins/modules/rds_instance.py import-3.7!skip
-plugins/modules/rds_instance.py metaclass-boilerplate!skip
-plugins/modules/rds_instance_info.py compile-2.6!skip
-plugins/modules/rds_instance_info.py compile-2.7!skip
-plugins/modules/rds_instance_info.py compile-3.5!skip
-plugins/modules/rds_instance_info.py compile-3.6!skip
-plugins/modules/rds_instance_info.py compile-3.7!skip
-plugins/modules/rds_instance_info.py future-import-boilerplate!skip
-plugins/modules/rds_instance_info.py import-2.6!skip
-plugins/modules/rds_instance_info.py import-2.7!skip
-plugins/modules/rds_instance_info.py import-3.5!skip
-plugins/modules/rds_instance_info.py import-3.6!skip
-plugins/modules/rds_instance_info.py import-3.7!skip
-plugins/modules/rds_instance_info.py metaclass-boilerplate!skip
-plugins/modules/rds_param_group.py compile-2.6!skip
-plugins/modules/rds_param_group.py compile-2.7!skip
-plugins/modules/rds_param_group.py compile-3.5!skip
-plugins/modules/rds_param_group.py compile-3.6!skip
-plugins/modules/rds_param_group.py compile-3.7!skip
-plugins/modules/rds_param_group.py future-import-boilerplate!skip
-plugins/modules/rds_param_group.py import-2.6!skip
-plugins/modules/rds_param_group.py import-2.7!skip
-plugins/modules/rds_param_group.py import-3.5!skip
-plugins/modules/rds_param_group.py import-3.6!skip
-plugins/modules/rds_param_group.py import-3.7!skip
-plugins/modules/rds_param_group.py metaclass-boilerplate!skip
-plugins/modules/rds_snapshot.py compile-2.6!skip
-plugins/modules/rds_snapshot.py compile-2.7!skip
-plugins/modules/rds_snapshot.py compile-3.5!skip
-plugins/modules/rds_snapshot.py compile-3.6!skip
-plugins/modules/rds_snapshot.py compile-3.7!skip
-plugins/modules/rds_snapshot.py future-import-boilerplate!skip
-plugins/modules/rds_snapshot.py import-2.6!skip
-plugins/modules/rds_snapshot.py import-2.7!skip
-plugins/modules/rds_snapshot.py import-3.5!skip
-plugins/modules/rds_snapshot.py import-3.6!skip
-plugins/modules/rds_snapshot.py import-3.7!skip
-plugins/modules/rds_snapshot.py metaclass-boilerplate!skip
-plugins/modules/rds_snapshot_info.py compile-2.6!skip
-plugins/modules/rds_snapshot_info.py compile-2.7!skip
-plugins/modules/rds_snapshot_info.py compile-3.5!skip
-plugins/modules/rds_snapshot_info.py compile-3.6!skip
-plugins/modules/rds_snapshot_info.py compile-3.7!skip
-plugins/modules/rds_snapshot_info.py future-import-boilerplate!skip
-plugins/modules/rds_snapshot_info.py import-2.6!skip
-plugins/modules/rds_snapshot_info.py import-2.7!skip
-plugins/modules/rds_snapshot_info.py import-3.5!skip
-plugins/modules/rds_snapshot_info.py import-3.6!skip
-plugins/modules/rds_snapshot_info.py import-3.7!skip
-plugins/modules/rds_snapshot_info.py metaclass-boilerplate!skip
-plugins/modules/rds_subnet_group.py compile-2.6!skip
-plugins/modules/rds_subnet_group.py compile-2.7!skip
-plugins/modules/rds_subnet_group.py compile-3.5!skip
-plugins/modules/rds_subnet_group.py compile-3.6!skip
-plugins/modules/rds_subnet_group.py compile-3.7!skip
-plugins/modules/rds_subnet_group.py future-import-boilerplate!skip
-plugins/modules/rds_subnet_group.py import-2.6!skip
-plugins/modules/rds_subnet_group.py import-2.7!skip
-plugins/modules/rds_subnet_group.py import-3.5!skip
-plugins/modules/rds_subnet_group.py import-3.6!skip
-plugins/modules/rds_subnet_group.py import-3.7!skip
-plugins/modules/rds_subnet_group.py metaclass-boilerplate!skip
-plugins/modules/redshift.py compile-2.6!skip
-plugins/modules/redshift.py compile-2.7!skip
-plugins/modules/redshift.py compile-3.5!skip
-plugins/modules/redshift.py compile-3.6!skip
-plugins/modules/redshift.py compile-3.7!skip
-plugins/modules/redshift.py future-import-boilerplate!skip
-plugins/modules/redshift.py import-2.6!skip
-plugins/modules/redshift.py import-2.7!skip
-plugins/modules/redshift.py import-3.5!skip
-plugins/modules/redshift.py import-3.6!skip
-plugins/modules/redshift.py import-3.7!skip
-plugins/modules/redshift.py metaclass-boilerplate!skip
-plugins/modules/redshift_cross_region_snapshots.py compile-2.6!skip
-plugins/modules/redshift_cross_region_snapshots.py compile-2.7!skip
-plugins/modules/redshift_cross_region_snapshots.py compile-3.5!skip
-plugins/modules/redshift_cross_region_snapshots.py compile-3.6!skip
-plugins/modules/redshift_cross_region_snapshots.py compile-3.7!skip
-plugins/modules/redshift_cross_region_snapshots.py future-import-boilerplate!skip
-plugins/modules/redshift_cross_region_snapshots.py import-2.6!skip
-plugins/modules/redshift_cross_region_snapshots.py import-2.7!skip
-plugins/modules/redshift_cross_region_snapshots.py import-3.5!skip
-plugins/modules/redshift_cross_region_snapshots.py import-3.6!skip
-plugins/modules/redshift_cross_region_snapshots.py import-3.7!skip
-plugins/modules/redshift_cross_region_snapshots.py metaclass-boilerplate!skip
-plugins/modules/redshift_info.py compile-2.6!skip
-plugins/modules/redshift_info.py compile-2.7!skip
-plugins/modules/redshift_info.py compile-3.5!skip
-plugins/modules/redshift_info.py compile-3.6!skip
-plugins/modules/redshift_info.py compile-3.7!skip
-plugins/modules/redshift_info.py future-import-boilerplate!skip
-plugins/modules/redshift_info.py import-2.6!skip
-plugins/modules/redshift_info.py import-2.7!skip
-plugins/modules/redshift_info.py import-3.5!skip
-plugins/modules/redshift_info.py import-3.6!skip
-plugins/modules/redshift_info.py import-3.7!skip
-plugins/modules/redshift_info.py metaclass-boilerplate!skip
-plugins/modules/redshift_subnet_group.py compile-2.6!skip
-plugins/modules/redshift_subnet_group.py compile-2.7!skip
-plugins/modules/redshift_subnet_group.py compile-3.5!skip
-plugins/modules/redshift_subnet_group.py compile-3.6!skip
-plugins/modules/redshift_subnet_group.py compile-3.7!skip
-plugins/modules/redshift_subnet_group.py future-import-boilerplate!skip
-plugins/modules/redshift_subnet_group.py import-2.6!skip
-plugins/modules/redshift_subnet_group.py import-2.7!skip
-plugins/modules/redshift_subnet_group.py import-3.5!skip
-plugins/modules/redshift_subnet_group.py import-3.6!skip
-plugins/modules/redshift_subnet_group.py import-3.7!skip
-plugins/modules/redshift_subnet_group.py metaclass-boilerplate!skip
-plugins/modules/route53.py compile-2.6!skip
-plugins/modules/route53.py compile-2.7!skip
-plugins/modules/route53.py compile-3.5!skip
-plugins/modules/route53.py compile-3.6!skip
-plugins/modules/route53.py compile-3.7!skip
-plugins/modules/route53.py future-import-boilerplate!skip
-plugins/modules/route53.py import-2.6!skip
-plugins/modules/route53.py import-2.7!skip
-plugins/modules/route53.py import-3.5!skip
-plugins/modules/route53.py import-3.6!skip
-plugins/modules/route53.py import-3.7!skip
-plugins/modules/route53.py metaclass-boilerplate!skip
-plugins/modules/route53.py validate-modules:parameter-state-invalid-choice
-plugins/modules/route53_health_check.py compile-2.6!skip
-plugins/modules/route53_health_check.py compile-2.7!skip
-plugins/modules/route53_health_check.py compile-3.5!skip
-plugins/modules/route53_health_check.py compile-3.6!skip
-plugins/modules/route53_health_check.py compile-3.7!skip
-plugins/modules/route53_health_check.py future-import-boilerplate!skip
-plugins/modules/route53_health_check.py import-2.6!skip
-plugins/modules/route53_health_check.py import-2.7!skip
-plugins/modules/route53_health_check.py import-3.5!skip
-plugins/modules/route53_health_check.py import-3.6!skip
-plugins/modules/route53_health_check.py import-3.7!skip
-plugins/modules/route53_health_check.py metaclass-boilerplate!skip
-plugins/modules/route53_info.py compile-2.6!skip
-plugins/modules/route53_info.py compile-2.7!skip
-plugins/modules/route53_info.py compile-3.5!skip
-plugins/modules/route53_info.py compile-3.6!skip
-plugins/modules/route53_info.py compile-3.7!skip
-plugins/modules/route53_info.py future-import-boilerplate!skip
-plugins/modules/route53_info.py import-2.6!skip
-plugins/modules/route53_info.py import-2.7!skip
-plugins/modules/route53_info.py import-3.5!skip
-plugins/modules/route53_info.py import-3.6!skip
-plugins/modules/route53_info.py import-3.7!skip
-plugins/modules/route53_info.py metaclass-boilerplate!skip
-plugins/modules/route53_zone.py compile-2.6!skip
-plugins/modules/route53_zone.py compile-2.7!skip
-plugins/modules/route53_zone.py compile-3.5!skip
-plugins/modules/route53_zone.py compile-3.6!skip
-plugins/modules/route53_zone.py compile-3.7!skip
-plugins/modules/route53_zone.py future-import-boilerplate!skip
-plugins/modules/route53_zone.py import-2.6!skip
-plugins/modules/route53_zone.py import-2.7!skip
-plugins/modules/route53_zone.py import-3.5!skip
-plugins/modules/route53_zone.py import-3.6!skip
-plugins/modules/route53_zone.py import-3.7!skip
-plugins/modules/route53_zone.py metaclass-boilerplate!skip
-plugins/modules/s3_bucket_notification.py compile-2.6!skip
-plugins/modules/s3_bucket_notification.py compile-2.7!skip
-plugins/modules/s3_bucket_notification.py compile-3.5!skip
-plugins/modules/s3_bucket_notification.py compile-3.6!skip
-plugins/modules/s3_bucket_notification.py compile-3.7!skip
-plugins/modules/s3_bucket_notification.py future-import-boilerplate!skip
-plugins/modules/s3_bucket_notification.py import-2.6!skip
-plugins/modules/s3_bucket_notification.py import-2.7!skip
-plugins/modules/s3_bucket_notification.py import-3.5!skip
-plugins/modules/s3_bucket_notification.py import-3.6!skip
-plugins/modules/s3_bucket_notification.py import-3.7!skip
-plugins/modules/s3_bucket_notification.py metaclass-boilerplate!skip
-plugins/modules/s3_lifecycle.py compile-2.6!skip
-plugins/modules/s3_lifecycle.py compile-2.7!skip
-plugins/modules/s3_lifecycle.py compile-3.5!skip
-plugins/modules/s3_lifecycle.py compile-3.6!skip
-plugins/modules/s3_lifecycle.py compile-3.7!skip
-plugins/modules/s3_lifecycle.py future-import-boilerplate!skip
-plugins/modules/s3_lifecycle.py import-2.6!skip
-plugins/modules/s3_lifecycle.py import-2.7!skip
-plugins/modules/s3_lifecycle.py import-3.5!skip
-plugins/modules/s3_lifecycle.py import-3.6!skip
-plugins/modules/s3_lifecycle.py import-3.7!skip
-plugins/modules/s3_lifecycle.py metaclass-boilerplate!skip
-plugins/modules/s3_logging.py compile-2.6!skip
-plugins/modules/s3_logging.py compile-2.7!skip
-plugins/modules/s3_logging.py compile-3.5!skip
-plugins/modules/s3_logging.py compile-3.6!skip
-plugins/modules/s3_logging.py compile-3.7!skip
-plugins/modules/s3_logging.py future-import-boilerplate!skip
-plugins/modules/s3_logging.py import-2.6!skip
-plugins/modules/s3_logging.py import-2.7!skip
-plugins/modules/s3_logging.py import-3.5!skip
-plugins/modules/s3_logging.py import-3.6!skip
-plugins/modules/s3_logging.py import-3.7!skip
-plugins/modules/s3_logging.py metaclass-boilerplate!skip
-plugins/modules/s3_metrics_configuration.py compile-2.6!skip
-plugins/modules/s3_metrics_configuration.py compile-2.7!skip
-plugins/modules/s3_metrics_configuration.py compile-3.5!skip
-plugins/modules/s3_metrics_configuration.py compile-3.6!skip
-plugins/modules/s3_metrics_configuration.py compile-3.7!skip
-plugins/modules/s3_metrics_configuration.py future-import-boilerplate!skip
-plugins/modules/s3_metrics_configuration.py import-2.6!skip
-plugins/modules/s3_metrics_configuration.py import-2.7!skip
-plugins/modules/s3_metrics_configuration.py import-3.5!skip
-plugins/modules/s3_metrics_configuration.py import-3.6!skip
-plugins/modules/s3_metrics_configuration.py import-3.7!skip
-plugins/modules/s3_metrics_configuration.py metaclass-boilerplate!skip
-plugins/modules/s3_sync.py compile-2.6!skip
-plugins/modules/s3_sync.py compile-2.7!skip
-plugins/modules/s3_sync.py compile-3.5!skip
-plugins/modules/s3_sync.py compile-3.6!skip
-plugins/modules/s3_sync.py compile-3.7!skip
-plugins/modules/s3_sync.py future-import-boilerplate!skip
-plugins/modules/s3_sync.py import-2.6!skip
-plugins/modules/s3_sync.py import-2.7!skip
-plugins/modules/s3_sync.py import-3.5!skip
-plugins/modules/s3_sync.py import-3.6!skip
-plugins/modules/s3_sync.py import-3.7!skip
-plugins/modules/s3_sync.py metaclass-boilerplate!skip
-plugins/modules/s3_website.py compile-2.6!skip
-plugins/modules/s3_website.py compile-2.7!skip
-plugins/modules/s3_website.py compile-3.5!skip
-plugins/modules/s3_website.py compile-3.6!skip
-plugins/modules/s3_website.py compile-3.7!skip
-plugins/modules/s3_website.py future-import-boilerplate!skip
-plugins/modules/s3_website.py import-2.6!skip
-plugins/modules/s3_website.py import-2.7!skip
-plugins/modules/s3_website.py import-3.5!skip
-plugins/modules/s3_website.py import-3.6!skip
-plugins/modules/s3_website.py import-3.7!skip
-plugins/modules/s3_website.py metaclass-boilerplate!skip
-plugins/modules/sns.py compile-2.6!skip
-plugins/modules/sns.py compile-2.7!skip
-plugins/modules/sns.py compile-3.5!skip
-plugins/modules/sns.py compile-3.6!skip
-plugins/modules/sns.py compile-3.7!skip
-plugins/modules/sns.py future-import-boilerplate!skip
-plugins/modules/sns.py import-2.6!skip
-plugins/modules/sns.py import-2.7!skip
-plugins/modules/sns.py import-3.5!skip
-plugins/modules/sns.py import-3.6!skip
-plugins/modules/sns.py import-3.7!skip
-plugins/modules/sns.py metaclass-boilerplate!skip
-plugins/modules/sns_topic.py compile-2.6!skip
-plugins/modules/sns_topic.py compile-2.7!skip
-plugins/modules/sns_topic.py compile-3.5!skip
-plugins/modules/sns_topic.py compile-3.6!skip
-plugins/modules/sns_topic.py compile-3.7!skip
-plugins/modules/sns_topic.py future-import-boilerplate!skip
-plugins/modules/sns_topic.py import-2.6!skip
-plugins/modules/sns_topic.py import-2.7!skip
-plugins/modules/sns_topic.py import-3.5!skip
-plugins/modules/sns_topic.py import-3.6!skip
-plugins/modules/sns_topic.py import-3.7!skip
-plugins/modules/sns_topic.py metaclass-boilerplate!skip
-plugins/modules/sqs_queue.py compile-2.6!skip
-plugins/modules/sqs_queue.py compile-2.7!skip
-plugins/modules/sqs_queue.py compile-3.5!skip
-plugins/modules/sqs_queue.py compile-3.6!skip
-plugins/modules/sqs_queue.py compile-3.7!skip
-plugins/modules/sqs_queue.py future-import-boilerplate!skip
-plugins/modules/sqs_queue.py import-2.6!skip
-plugins/modules/sqs_queue.py import-2.7!skip
-plugins/modules/sqs_queue.py import-3.5!skip
-plugins/modules/sqs_queue.py import-3.6!skip
-plugins/modules/sqs_queue.py import-3.7!skip
-plugins/modules/sqs_queue.py metaclass-boilerplate!skip
-plugins/modules/sts_assume_role.py compile-2.6!skip
-plugins/modules/sts_assume_role.py compile-2.7!skip
-plugins/modules/sts_assume_role.py compile-3.5!skip
-plugins/modules/sts_assume_role.py compile-3.6!skip
-plugins/modules/sts_assume_role.py compile-3.7!skip
-plugins/modules/sts_assume_role.py future-import-boilerplate!skip
-plugins/modules/sts_assume_role.py import-2.6!skip
-plugins/modules/sts_assume_role.py import-2.7!skip
-plugins/modules/sts_assume_role.py import-3.5!skip
-plugins/modules/sts_assume_role.py import-3.6!skip
-plugins/modules/sts_assume_role.py import-3.7!skip
-plugins/modules/sts_assume_role.py metaclass-boilerplate!skip
-plugins/modules/sts_session_token.py compile-2.6!skip
-plugins/modules/sts_session_token.py compile-2.7!skip
-plugins/modules/sts_session_token.py compile-3.5!skip
-plugins/modules/sts_session_token.py compile-3.6!skip
-plugins/modules/sts_session_token.py compile-3.7!skip
-plugins/modules/sts_session_token.py future-import-boilerplate!skip
-plugins/modules/sts_session_token.py import-2.6!skip
-plugins/modules/sts_session_token.py import-2.7!skip
-plugins/modules/sts_session_token.py import-3.5!skip
-plugins/modules/sts_session_token.py import-3.6!skip
-plugins/modules/sts_session_token.py import-3.7!skip
-plugins/modules/sts_session_token.py metaclass-boilerplate!skip
-plugins/modules/wafv2_ip_set.py compile-2.6!skip
-plugins/modules/wafv2_ip_set.py compile-2.7!skip
-plugins/modules/wafv2_ip_set.py compile-3.5!skip
-plugins/modules/wafv2_ip_set.py compile-3.6!skip
-plugins/modules/wafv2_ip_set.py compile-3.7!skip
-plugins/modules/wafv2_ip_set.py future-import-boilerplate!skip
-plugins/modules/wafv2_ip_set.py import-2.6!skip
-plugins/modules/wafv2_ip_set.py import-2.7!skip
-plugins/modules/wafv2_ip_set.py import-3.5!skip
-plugins/modules/wafv2_ip_set.py import-3.6!skip
-plugins/modules/wafv2_ip_set.py import-3.7!skip
-plugins/modules/wafv2_ip_set.py metaclass-boilerplate!skip
-plugins/modules/wafv2_ip_set_info.py compile-2.6!skip
-plugins/modules/wafv2_ip_set_info.py compile-2.7!skip
-plugins/modules/wafv2_ip_set_info.py compile-3.5!skip
-plugins/modules/wafv2_ip_set_info.py compile-3.6!skip
-plugins/modules/wafv2_ip_set_info.py compile-3.7!skip
-plugins/modules/wafv2_ip_set_info.py future-import-boilerplate!skip
-plugins/modules/wafv2_ip_set_info.py import-2.6!skip
-plugins/modules/wafv2_ip_set_info.py import-2.7!skip
-plugins/modules/wafv2_ip_set_info.py import-3.5!skip
-plugins/modules/wafv2_ip_set_info.py import-3.6!skip
-plugins/modules/wafv2_ip_set_info.py import-3.7!skip
-plugins/modules/wafv2_ip_set_info.py metaclass-boilerplate!skip
-plugins/modules/wafv2_resources.py compile-2.6!skip
-plugins/modules/wafv2_resources.py compile-2.7!skip
-plugins/modules/wafv2_resources.py compile-3.5!skip
-plugins/modules/wafv2_resources.py compile-3.6!skip
-plugins/modules/wafv2_resources.py compile-3.7!skip
-plugins/modules/wafv2_resources.py future-import-boilerplate!skip
-plugins/modules/wafv2_resources.py import-2.6!skip
-plugins/modules/wafv2_resources.py import-2.7!skip
-plugins/modules/wafv2_resources.py import-3.5!skip
-plugins/modules/wafv2_resources.py import-3.6!skip
-plugins/modules/wafv2_resources.py import-3.7!skip
-plugins/modules/wafv2_resources.py metaclass-boilerplate!skip
-plugins/modules/wafv2_resources_info.py compile-2.6!skip
-plugins/modules/wafv2_resources_info.py compile-2.7!skip
-plugins/modules/wafv2_resources_info.py compile-3.5!skip
-plugins/modules/wafv2_resources_info.py compile-3.6!skip
-plugins/modules/wafv2_resources_info.py compile-3.7!skip
-plugins/modules/wafv2_resources_info.py future-import-boilerplate!skip
-plugins/modules/wafv2_resources_info.py import-2.6!skip
-plugins/modules/wafv2_resources_info.py import-2.7!skip
-plugins/modules/wafv2_resources_info.py import-3.5!skip
-plugins/modules/wafv2_resources_info.py import-3.6!skip
-plugins/modules/wafv2_resources_info.py import-3.7!skip
-plugins/modules/wafv2_resources_info.py metaclass-boilerplate!skip
-plugins/modules/wafv2_rule_group.py compile-2.6!skip
-plugins/modules/wafv2_rule_group.py compile-2.7!skip
-plugins/modules/wafv2_rule_group.py compile-3.5!skip
-plugins/modules/wafv2_rule_group.py compile-3.6!skip
-plugins/modules/wafv2_rule_group.py compile-3.7!skip
-plugins/modules/wafv2_rule_group.py future-import-boilerplate!skip
-plugins/modules/wafv2_rule_group.py import-2.6!skip
-plugins/modules/wafv2_rule_group.py import-2.7!skip
-plugins/modules/wafv2_rule_group.py import-3.5!skip
-plugins/modules/wafv2_rule_group.py import-3.6!skip
-plugins/modules/wafv2_rule_group.py import-3.7!skip
-plugins/modules/wafv2_rule_group.py metaclass-boilerplate!skip
-plugins/modules/wafv2_rule_group_info.py compile-2.6!skip
-plugins/modules/wafv2_rule_group_info.py compile-2.7!skip
-plugins/modules/wafv2_rule_group_info.py compile-3.5!skip
-plugins/modules/wafv2_rule_group_info.py compile-3.6!skip
-plugins/modules/wafv2_rule_group_info.py compile-3.7!skip
-plugins/modules/wafv2_rule_group_info.py future-import-boilerplate!skip
-plugins/modules/wafv2_rule_group_info.py import-2.6!skip
-plugins/modules/wafv2_rule_group_info.py import-2.7!skip
-plugins/modules/wafv2_rule_group_info.py import-3.5!skip
-plugins/modules/wafv2_rule_group_info.py import-3.6!skip
-plugins/modules/wafv2_rule_group_info.py import-3.7!skip
-plugins/modules/wafv2_rule_group_info.py metaclass-boilerplate!skip
-plugins/modules/wafv2_web_acl.py compile-2.6!skip
-plugins/modules/wafv2_web_acl.py compile-2.7!skip
-plugins/modules/wafv2_web_acl.py compile-3.5!skip
-plugins/modules/wafv2_web_acl.py compile-3.6!skip
-plugins/modules/wafv2_web_acl.py compile-3.7!skip
-plugins/modules/wafv2_web_acl.py future-import-boilerplate!skip
-plugins/modules/wafv2_web_acl.py import-2.6!skip
-plugins/modules/wafv2_web_acl.py import-2.7!skip
-plugins/modules/wafv2_web_acl.py import-3.5!skip
-plugins/modules/wafv2_web_acl.py import-3.6!skip
-plugins/modules/wafv2_web_acl.py import-3.7!skip
-plugins/modules/wafv2_web_acl.py metaclass-boilerplate!skip
-plugins/modules/wafv2_web_acl_info.py compile-2.6!skip
-plugins/modules/wafv2_web_acl_info.py compile-2.7!skip
-plugins/modules/wafv2_web_acl_info.py compile-3.5!skip
-plugins/modules/wafv2_web_acl_info.py compile-3.6!skip
-plugins/modules/wafv2_web_acl_info.py compile-3.7!skip
-plugins/modules/wafv2_web_acl_info.py future-import-boilerplate!skip
-plugins/modules/wafv2_web_acl_info.py import-2.6!skip
-plugins/modules/wafv2_web_acl_info.py import-2.7!skip
-plugins/modules/wafv2_web_acl_info.py import-3.5!skip
-plugins/modules/wafv2_web_acl_info.py import-3.6!skip
-plugins/modules/wafv2_web_acl_info.py import-3.7!skip
-plugins/modules/wafv2_web_acl_info.py metaclass-boilerplate!skip
-tests/sanity/refresh_ignore_files shebang!skip
+plugins/modules/route53.py validate-modules:parameter-state-invalid-choice # route53_info needs improvements before we can deprecate this
diff --git a/tests/sanity/ignore-2.11.txt b/tests/sanity/ignore-2.11.txt
index a00e429fe2e..e5bade76474 100644
--- a/tests/sanity/ignore-2.11.txt
+++ b/tests/sanity/ignore-2.11.txt
@@ -1,2164 +1,3 @@
-plugins/modules/__init__.py compile-2.6!skip
-plugins/modules/__init__.py compile-2.7!skip
-plugins/modules/__init__.py compile-3.5!skip
-plugins/modules/__init__.py compile-3.6!skip
-plugins/modules/__init__.py compile-3.7!skip
-plugins/modules/__init__.py future-import-boilerplate!skip
-plugins/modules/__init__.py import-2.6!skip
-plugins/modules/__init__.py import-2.7!skip
-plugins/modules/__init__.py import-3.5!skip
-plugins/modules/__init__.py import-3.6!skip
-plugins/modules/__init__.py import-3.7!skip
-plugins/modules/__init__.py metaclass-boilerplate!skip
-plugins/modules/aws_acm.py compile-2.6!skip
-plugins/modules/aws_acm.py compile-2.7!skip
-plugins/modules/aws_acm.py compile-3.5!skip
-plugins/modules/aws_acm.py compile-3.6!skip
-plugins/modules/aws_acm.py compile-3.7!skip
-plugins/modules/aws_acm.py future-import-boilerplate!skip
-plugins/modules/aws_acm.py import-2.6!skip
-plugins/modules/aws_acm.py import-2.7!skip
-plugins/modules/aws_acm.py import-3.5!skip
-plugins/modules/aws_acm.py import-3.6!skip
-plugins/modules/aws_acm.py import-3.7!skip
-plugins/modules/aws_acm.py metaclass-boilerplate!skip
-plugins/modules/aws_acm_info.py compile-2.6!skip
-plugins/modules/aws_acm_info.py compile-2.7!skip
-plugins/modules/aws_acm_info.py compile-3.5!skip
-plugins/modules/aws_acm_info.py compile-3.6!skip
-plugins/modules/aws_acm_info.py compile-3.7!skip
-plugins/modules/aws_acm_info.py future-import-boilerplate!skip
-plugins/modules/aws_acm_info.py import-2.6!skip
-plugins/modules/aws_acm_info.py import-2.7!skip
-plugins/modules/aws_acm_info.py import-3.5!skip
-plugins/modules/aws_acm_info.py import-3.6!skip
-plugins/modules/aws_acm_info.py import-3.7!skip
-plugins/modules/aws_acm_info.py metaclass-boilerplate!skip
-plugins/modules/aws_api_gateway.py compile-2.6!skip
-plugins/modules/aws_api_gateway.py compile-2.7!skip
-plugins/modules/aws_api_gateway.py compile-3.5!skip
-plugins/modules/aws_api_gateway.py compile-3.6!skip
-plugins/modules/aws_api_gateway.py compile-3.7!skip
-plugins/modules/aws_api_gateway.py future-import-boilerplate!skip
-plugins/modules/aws_api_gateway.py import-2.6!skip
-plugins/modules/aws_api_gateway.py import-2.7!skip
-plugins/modules/aws_api_gateway.py import-3.5!skip
-plugins/modules/aws_api_gateway.py import-3.6!skip
-plugins/modules/aws_api_gateway.py import-3.7!skip
-plugins/modules/aws_api_gateway.py metaclass-boilerplate!skip
-plugins/modules/aws_application_scaling_policy.py compile-2.6!skip
-plugins/modules/aws_application_scaling_policy.py compile-2.7!skip
-plugins/modules/aws_application_scaling_policy.py compile-3.5!skip
-plugins/modules/aws_application_scaling_policy.py compile-3.6!skip
-plugins/modules/aws_application_scaling_policy.py compile-3.7!skip
-plugins/modules/aws_application_scaling_policy.py future-import-boilerplate!skip
-plugins/modules/aws_application_scaling_policy.py import-2.6!skip
-plugins/modules/aws_application_scaling_policy.py import-2.7!skip
-plugins/modules/aws_application_scaling_policy.py import-3.5!skip
-plugins/modules/aws_application_scaling_policy.py import-3.6!skip
-plugins/modules/aws_application_scaling_policy.py import-3.7!skip
-plugins/modules/aws_application_scaling_policy.py metaclass-boilerplate!skip
-plugins/modules/aws_batch_compute_environment.py compile-2.6!skip
-plugins/modules/aws_batch_compute_environment.py compile-2.7!skip
-plugins/modules/aws_batch_compute_environment.py compile-3.5!skip
-plugins/modules/aws_batch_compute_environment.py compile-3.6!skip
-plugins/modules/aws_batch_compute_environment.py compile-3.7!skip
-plugins/modules/aws_batch_compute_environment.py future-import-boilerplate!skip
-plugins/modules/aws_batch_compute_environment.py import-2.6!skip
-plugins/modules/aws_batch_compute_environment.py import-2.7!skip
-plugins/modules/aws_batch_compute_environment.py import-3.5!skip
-plugins/modules/aws_batch_compute_environment.py import-3.6!skip
-plugins/modules/aws_batch_compute_environment.py import-3.7!skip
-plugins/modules/aws_batch_compute_environment.py metaclass-boilerplate!skip
-plugins/modules/aws_batch_job_definition.py compile-2.6!skip
-plugins/modules/aws_batch_job_definition.py compile-2.7!skip
-plugins/modules/aws_batch_job_definition.py compile-3.5!skip
-plugins/modules/aws_batch_job_definition.py compile-3.6!skip
-plugins/modules/aws_batch_job_definition.py compile-3.7!skip
-plugins/modules/aws_batch_job_definition.py future-import-boilerplate!skip
-plugins/modules/aws_batch_job_definition.py import-2.6!skip
-plugins/modules/aws_batch_job_definition.py import-2.7!skip
-plugins/modules/aws_batch_job_definition.py import-3.5!skip
-plugins/modules/aws_batch_job_definition.py import-3.6!skip
-plugins/modules/aws_batch_job_definition.py import-3.7!skip
-plugins/modules/aws_batch_job_definition.py metaclass-boilerplate!skip
-plugins/modules/aws_batch_job_queue.py compile-2.6!skip
-plugins/modules/aws_batch_job_queue.py compile-2.7!skip
-plugins/modules/aws_batch_job_queue.py compile-3.5!skip
-plugins/modules/aws_batch_job_queue.py compile-3.6!skip
-plugins/modules/aws_batch_job_queue.py compile-3.7!skip
-plugins/modules/aws_batch_job_queue.py future-import-boilerplate!skip
-plugins/modules/aws_batch_job_queue.py import-2.6!skip
-plugins/modules/aws_batch_job_queue.py import-2.7!skip
-plugins/modules/aws_batch_job_queue.py import-3.5!skip
-plugins/modules/aws_batch_job_queue.py import-3.6!skip
-plugins/modules/aws_batch_job_queue.py import-3.7!skip
-plugins/modules/aws_batch_job_queue.py metaclass-boilerplate!skip
-plugins/modules/aws_codebuild.py compile-2.6!skip
-plugins/modules/aws_codebuild.py compile-2.7!skip
-plugins/modules/aws_codebuild.py compile-3.5!skip
-plugins/modules/aws_codebuild.py compile-3.6!skip
-plugins/modules/aws_codebuild.py compile-3.7!skip
-plugins/modules/aws_codebuild.py future-import-boilerplate!skip
-plugins/modules/aws_codebuild.py import-2.6!skip
-plugins/modules/aws_codebuild.py import-2.7!skip
-plugins/modules/aws_codebuild.py import-3.5!skip
-plugins/modules/aws_codebuild.py import-3.6!skip
-plugins/modules/aws_codebuild.py import-3.7!skip
-plugins/modules/aws_codebuild.py metaclass-boilerplate!skip
-plugins/modules/aws_codecommit.py compile-2.6!skip
-plugins/modules/aws_codecommit.py compile-2.7!skip
-plugins/modules/aws_codecommit.py compile-3.5!skip
-plugins/modules/aws_codecommit.py compile-3.6!skip
-plugins/modules/aws_codecommit.py compile-3.7!skip
-plugins/modules/aws_codecommit.py future-import-boilerplate!skip
-plugins/modules/aws_codecommit.py import-2.6!skip
-plugins/modules/aws_codecommit.py import-2.7!skip
-plugins/modules/aws_codecommit.py import-3.5!skip
-plugins/modules/aws_codecommit.py import-3.6!skip
-plugins/modules/aws_codecommit.py import-3.7!skip
-plugins/modules/aws_codecommit.py metaclass-boilerplate!skip
-plugins/modules/aws_codepipeline.py compile-2.6!skip
-plugins/modules/aws_codepipeline.py compile-2.7!skip
-plugins/modules/aws_codepipeline.py compile-3.5!skip
-plugins/modules/aws_codepipeline.py compile-3.6!skip
-plugins/modules/aws_codepipeline.py compile-3.7!skip
-plugins/modules/aws_codepipeline.py future-import-boilerplate!skip
-plugins/modules/aws_codepipeline.py import-2.6!skip
-plugins/modules/aws_codepipeline.py import-2.7!skip
-plugins/modules/aws_codepipeline.py import-3.5!skip
-plugins/modules/aws_codepipeline.py import-3.6!skip
-plugins/modules/aws_codepipeline.py import-3.7!skip
-plugins/modules/aws_codepipeline.py metaclass-boilerplate!skip
-plugins/modules/aws_config_aggregation_authorization.py compile-2.6!skip
-plugins/modules/aws_config_aggregation_authorization.py compile-2.7!skip
-plugins/modules/aws_config_aggregation_authorization.py compile-3.5!skip
-plugins/modules/aws_config_aggregation_authorization.py compile-3.6!skip
-plugins/modules/aws_config_aggregation_authorization.py compile-3.7!skip
-plugins/modules/aws_config_aggregation_authorization.py future-import-boilerplate!skip
-plugins/modules/aws_config_aggregation_authorization.py import-2.6!skip
-plugins/modules/aws_config_aggregation_authorization.py import-2.7!skip
-plugins/modules/aws_config_aggregation_authorization.py import-3.5!skip
-plugins/modules/aws_config_aggregation_authorization.py import-3.6!skip
-plugins/modules/aws_config_aggregation_authorization.py import-3.7!skip
-plugins/modules/aws_config_aggregation_authorization.py metaclass-boilerplate!skip
-plugins/modules/aws_config_aggregator.py compile-2.6!skip
-plugins/modules/aws_config_aggregator.py compile-2.7!skip
-plugins/modules/aws_config_aggregator.py compile-3.5!skip
-plugins/modules/aws_config_aggregator.py compile-3.6!skip
-plugins/modules/aws_config_aggregator.py compile-3.7!skip
-plugins/modules/aws_config_aggregator.py future-import-boilerplate!skip
-plugins/modules/aws_config_aggregator.py import-2.6!skip
-plugins/modules/aws_config_aggregator.py import-2.7!skip
-plugins/modules/aws_config_aggregator.py import-3.5!skip
-plugins/modules/aws_config_aggregator.py import-3.6!skip
-plugins/modules/aws_config_aggregator.py import-3.7!skip
-plugins/modules/aws_config_aggregator.py metaclass-boilerplate!skip
-plugins/modules/aws_config_delivery_channel.py compile-2.6!skip
-plugins/modules/aws_config_delivery_channel.py compile-2.7!skip
-plugins/modules/aws_config_delivery_channel.py compile-3.5!skip
-plugins/modules/aws_config_delivery_channel.py compile-3.6!skip
-plugins/modules/aws_config_delivery_channel.py compile-3.7!skip
-plugins/modules/aws_config_delivery_channel.py future-import-boilerplate!skip
-plugins/modules/aws_config_delivery_channel.py import-2.6!skip
-plugins/modules/aws_config_delivery_channel.py import-2.7!skip
-plugins/modules/aws_config_delivery_channel.py import-3.5!skip
-plugins/modules/aws_config_delivery_channel.py import-3.6!skip
-plugins/modules/aws_config_delivery_channel.py import-3.7!skip
-plugins/modules/aws_config_delivery_channel.py metaclass-boilerplate!skip
-plugins/modules/aws_config_recorder.py compile-2.6!skip
-plugins/modules/aws_config_recorder.py compile-2.7!skip
-plugins/modules/aws_config_recorder.py compile-3.5!skip
-plugins/modules/aws_config_recorder.py compile-3.6!skip
-plugins/modules/aws_config_recorder.py compile-3.7!skip
-plugins/modules/aws_config_recorder.py future-import-boilerplate!skip
-plugins/modules/aws_config_recorder.py import-2.6!skip
-plugins/modules/aws_config_recorder.py import-2.7!skip
-plugins/modules/aws_config_recorder.py import-3.5!skip
-plugins/modules/aws_config_recorder.py import-3.6!skip
-plugins/modules/aws_config_recorder.py import-3.7!skip
-plugins/modules/aws_config_recorder.py metaclass-boilerplate!skip
-plugins/modules/aws_config_rule.py compile-2.6!skip
-plugins/modules/aws_config_rule.py compile-2.7!skip
-plugins/modules/aws_config_rule.py compile-3.5!skip
-plugins/modules/aws_config_rule.py compile-3.6!skip
-plugins/modules/aws_config_rule.py compile-3.7!skip
-plugins/modules/aws_config_rule.py future-import-boilerplate!skip
-plugins/modules/aws_config_rule.py import-2.6!skip
-plugins/modules/aws_config_rule.py import-2.7!skip
-plugins/modules/aws_config_rule.py import-3.5!skip
-plugins/modules/aws_config_rule.py import-3.6!skip
-plugins/modules/aws_config_rule.py import-3.7!skip
-plugins/modules/aws_config_rule.py metaclass-boilerplate!skip
-plugins/modules/aws_direct_connect_confirm_connection.py compile-2.6!skip
-plugins/modules/aws_direct_connect_confirm_connection.py compile-2.7!skip
-plugins/modules/aws_direct_connect_confirm_connection.py compile-3.5!skip
-plugins/modules/aws_direct_connect_confirm_connection.py compile-3.6!skip
-plugins/modules/aws_direct_connect_confirm_connection.py compile-3.7!skip
-plugins/modules/aws_direct_connect_confirm_connection.py future-import-boilerplate!skip
-plugins/modules/aws_direct_connect_confirm_connection.py import-2.6!skip
-plugins/modules/aws_direct_connect_confirm_connection.py import-2.7!skip
-plugins/modules/aws_direct_connect_confirm_connection.py import-3.5!skip
-plugins/modules/aws_direct_connect_confirm_connection.py import-3.6!skip
-plugins/modules/aws_direct_connect_confirm_connection.py import-3.7!skip
-plugins/modules/aws_direct_connect_confirm_connection.py metaclass-boilerplate!skip
-plugins/modules/aws_direct_connect_connection.py compile-2.6!skip
-plugins/modules/aws_direct_connect_connection.py compile-2.7!skip
-plugins/modules/aws_direct_connect_connection.py compile-3.5!skip
-plugins/modules/aws_direct_connect_connection.py compile-3.6!skip
-plugins/modules/aws_direct_connect_connection.py compile-3.7!skip
-plugins/modules/aws_direct_connect_connection.py future-import-boilerplate!skip
-plugins/modules/aws_direct_connect_connection.py import-2.6!skip
-plugins/modules/aws_direct_connect_connection.py import-2.7!skip
-plugins/modules/aws_direct_connect_connection.py import-3.5!skip
-plugins/modules/aws_direct_connect_connection.py import-3.6!skip
-plugins/modules/aws_direct_connect_connection.py import-3.7!skip
-plugins/modules/aws_direct_connect_connection.py metaclass-boilerplate!skip
-plugins/modules/aws_direct_connect_gateway.py compile-2.6!skip
-plugins/modules/aws_direct_connect_gateway.py compile-2.7!skip
-plugins/modules/aws_direct_connect_gateway.py compile-3.5!skip
-plugins/modules/aws_direct_connect_gateway.py compile-3.6!skip
-plugins/modules/aws_direct_connect_gateway.py compile-3.7!skip
-plugins/modules/aws_direct_connect_gateway.py future-import-boilerplate!skip
-plugins/modules/aws_direct_connect_gateway.py import-2.6!skip
-plugins/modules/aws_direct_connect_gateway.py import-2.7!skip
-plugins/modules/aws_direct_connect_gateway.py import-3.5!skip
-plugins/modules/aws_direct_connect_gateway.py import-3.6!skip
-plugins/modules/aws_direct_connect_gateway.py import-3.7!skip
-plugins/modules/aws_direct_connect_gateway.py metaclass-boilerplate!skip
-plugins/modules/aws_direct_connect_link_aggregation_group.py compile-2.6!skip
-plugins/modules/aws_direct_connect_link_aggregation_group.py compile-2.7!skip
-plugins/modules/aws_direct_connect_link_aggregation_group.py compile-3.5!skip
-plugins/modules/aws_direct_connect_link_aggregation_group.py compile-3.6!skip
-plugins/modules/aws_direct_connect_link_aggregation_group.py compile-3.7!skip
-plugins/modules/aws_direct_connect_link_aggregation_group.py future-import-boilerplate!skip
-plugins/modules/aws_direct_connect_link_aggregation_group.py import-2.6!skip
-plugins/modules/aws_direct_connect_link_aggregation_group.py import-2.7!skip
-plugins/modules/aws_direct_connect_link_aggregation_group.py import-3.5!skip
-plugins/modules/aws_direct_connect_link_aggregation_group.py import-3.6!skip
-plugins/modules/aws_direct_connect_link_aggregation_group.py import-3.7!skip
-plugins/modules/aws_direct_connect_link_aggregation_group.py metaclass-boilerplate!skip
-plugins/modules/aws_direct_connect_virtual_interface.py compile-2.6!skip
-plugins/modules/aws_direct_connect_virtual_interface.py compile-2.7!skip
-plugins/modules/aws_direct_connect_virtual_interface.py compile-3.5!skip
-plugins/modules/aws_direct_connect_virtual_interface.py compile-3.6!skip
-plugins/modules/aws_direct_connect_virtual_interface.py compile-3.7!skip
-plugins/modules/aws_direct_connect_virtual_interface.py future-import-boilerplate!skip
-plugins/modules/aws_direct_connect_virtual_interface.py import-2.6!skip
-plugins/modules/aws_direct_connect_virtual_interface.py import-2.7!skip
-plugins/modules/aws_direct_connect_virtual_interface.py import-3.5!skip
-plugins/modules/aws_direct_connect_virtual_interface.py import-3.6!skip
-plugins/modules/aws_direct_connect_virtual_interface.py import-3.7!skip
-plugins/modules/aws_direct_connect_virtual_interface.py metaclass-boilerplate!skip
-plugins/modules/aws_eks_cluster.py compile-2.6!skip
-plugins/modules/aws_eks_cluster.py compile-2.7!skip
-plugins/modules/aws_eks_cluster.py compile-3.5!skip
-plugins/modules/aws_eks_cluster.py compile-3.6!skip
-plugins/modules/aws_eks_cluster.py compile-3.7!skip
-plugins/modules/aws_eks_cluster.py future-import-boilerplate!skip
-plugins/modules/aws_eks_cluster.py import-2.6!skip
-plugins/modules/aws_eks_cluster.py import-2.7!skip
-plugins/modules/aws_eks_cluster.py import-3.5!skip
-plugins/modules/aws_eks_cluster.py import-3.6!skip
-plugins/modules/aws_eks_cluster.py import-3.7!skip
-plugins/modules/aws_eks_cluster.py metaclass-boilerplate!skip
-plugins/modules/aws_elasticbeanstalk_app.py compile-2.6!skip
-plugins/modules/aws_elasticbeanstalk_app.py compile-2.7!skip
-plugins/modules/aws_elasticbeanstalk_app.py compile-3.5!skip
-plugins/modules/aws_elasticbeanstalk_app.py compile-3.6!skip
-plugins/modules/aws_elasticbeanstalk_app.py compile-3.7!skip
-plugins/modules/aws_elasticbeanstalk_app.py future-import-boilerplate!skip
-plugins/modules/aws_elasticbeanstalk_app.py import-2.6!skip
-plugins/modules/aws_elasticbeanstalk_app.py import-2.7!skip
-plugins/modules/aws_elasticbeanstalk_app.py import-3.5!skip
-plugins/modules/aws_elasticbeanstalk_app.py import-3.6!skip
-plugins/modules/aws_elasticbeanstalk_app.py import-3.7!skip
-plugins/modules/aws_elasticbeanstalk_app.py metaclass-boilerplate!skip
-plugins/modules/aws_glue_connection.py compile-2.6!skip
-plugins/modules/aws_glue_connection.py compile-2.7!skip
-plugins/modules/aws_glue_connection.py compile-3.5!skip
-plugins/modules/aws_glue_connection.py compile-3.6!skip
-plugins/modules/aws_glue_connection.py compile-3.7!skip
-plugins/modules/aws_glue_connection.py future-import-boilerplate!skip
-plugins/modules/aws_glue_connection.py import-2.6!skip
-plugins/modules/aws_glue_connection.py import-2.7!skip
-plugins/modules/aws_glue_connection.py import-3.5!skip
-plugins/modules/aws_glue_connection.py import-3.6!skip
-plugins/modules/aws_glue_connection.py import-3.7!skip
-plugins/modules/aws_glue_connection.py metaclass-boilerplate!skip
-plugins/modules/aws_glue_job.py compile-2.6!skip
-plugins/modules/aws_glue_job.py compile-2.7!skip
-plugins/modules/aws_glue_job.py compile-3.5!skip
-plugins/modules/aws_glue_job.py compile-3.6!skip
-plugins/modules/aws_glue_job.py compile-3.7!skip
-plugins/modules/aws_glue_job.py future-import-boilerplate!skip
-plugins/modules/aws_glue_job.py import-2.6!skip
-plugins/modules/aws_glue_job.py import-2.7!skip
-plugins/modules/aws_glue_job.py import-3.5!skip
-plugins/modules/aws_glue_job.py import-3.6!skip
-plugins/modules/aws_glue_job.py import-3.7!skip
-plugins/modules/aws_glue_job.py metaclass-boilerplate!skip
-plugins/modules/aws_inspector_target.py compile-2.6!skip
-plugins/modules/aws_inspector_target.py compile-2.7!skip
-plugins/modules/aws_inspector_target.py compile-3.5!skip
-plugins/modules/aws_inspector_target.py compile-3.6!skip
-plugins/modules/aws_inspector_target.py compile-3.7!skip
-plugins/modules/aws_inspector_target.py future-import-boilerplate!skip
-plugins/modules/aws_inspector_target.py import-2.6!skip
-plugins/modules/aws_inspector_target.py import-2.7!skip
-plugins/modules/aws_inspector_target.py import-3.5!skip
-plugins/modules/aws_inspector_target.py import-3.6!skip
-plugins/modules/aws_inspector_target.py import-3.7!skip
-plugins/modules/aws_inspector_target.py metaclass-boilerplate!skip
-plugins/modules/aws_kms.py compile-2.6!skip
-plugins/modules/aws_kms.py compile-2.7!skip
-plugins/modules/aws_kms.py compile-3.5!skip
-plugins/modules/aws_kms.py compile-3.6!skip
-plugins/modules/aws_kms.py compile-3.7!skip
-plugins/modules/aws_kms.py future-import-boilerplate!skip
-plugins/modules/aws_kms.py import-2.6!skip
-plugins/modules/aws_kms.py import-2.7!skip
-plugins/modules/aws_kms.py import-3.5!skip
-plugins/modules/aws_kms.py import-3.6!skip
-plugins/modules/aws_kms.py import-3.7!skip
-plugins/modules/aws_kms.py metaclass-boilerplate!skip
-plugins/modules/aws_kms_info.py compile-2.6!skip
-plugins/modules/aws_kms_info.py compile-2.7!skip
-plugins/modules/aws_kms_info.py compile-3.5!skip
-plugins/modules/aws_kms_info.py compile-3.6!skip
-plugins/modules/aws_kms_info.py compile-3.7!skip
-plugins/modules/aws_kms_info.py future-import-boilerplate!skip
-plugins/modules/aws_kms_info.py import-2.6!skip
-plugins/modules/aws_kms_info.py import-2.7!skip
-plugins/modules/aws_kms_info.py import-3.5!skip
-plugins/modules/aws_kms_info.py import-3.6!skip
-plugins/modules/aws_kms_info.py import-3.7!skip
-plugins/modules/aws_kms_info.py metaclass-boilerplate!skip
-plugins/modules/aws_region_info.py compile-2.6!skip
-plugins/modules/aws_region_info.py compile-2.7!skip
-plugins/modules/aws_region_info.py compile-3.5!skip
-plugins/modules/aws_region_info.py compile-3.6!skip
-plugins/modules/aws_region_info.py compile-3.7!skip
-plugins/modules/aws_region_info.py future-import-boilerplate!skip
-plugins/modules/aws_region_info.py import-2.6!skip
-plugins/modules/aws_region_info.py import-2.7!skip
-plugins/modules/aws_region_info.py import-3.5!skip
-plugins/modules/aws_region_info.py import-3.6!skip
-plugins/modules/aws_region_info.py import-3.7!skip
-plugins/modules/aws_region_info.py metaclass-boilerplate!skip
-plugins/modules/aws_s3_bucket_info.py compile-2.6!skip
-plugins/modules/aws_s3_bucket_info.py compile-2.7!skip
-plugins/modules/aws_s3_bucket_info.py compile-3.5!skip
-plugins/modules/aws_s3_bucket_info.py compile-3.6!skip
-plugins/modules/aws_s3_bucket_info.py compile-3.7!skip
-plugins/modules/aws_s3_bucket_info.py future-import-boilerplate!skip
-plugins/modules/aws_s3_bucket_info.py import-2.6!skip
-plugins/modules/aws_s3_bucket_info.py import-2.7!skip
-plugins/modules/aws_s3_bucket_info.py import-3.5!skip
-plugins/modules/aws_s3_bucket_info.py import-3.6!skip
-plugins/modules/aws_s3_bucket_info.py import-3.7!skip
-plugins/modules/aws_s3_bucket_info.py metaclass-boilerplate!skip
-plugins/modules/aws_s3_cors.py compile-2.6!skip
-plugins/modules/aws_s3_cors.py compile-2.7!skip
-plugins/modules/aws_s3_cors.py compile-3.5!skip
-plugins/modules/aws_s3_cors.py compile-3.6!skip
-plugins/modules/aws_s3_cors.py compile-3.7!skip
-plugins/modules/aws_s3_cors.py future-import-boilerplate!skip
-plugins/modules/aws_s3_cors.py import-2.6!skip
-plugins/modules/aws_s3_cors.py import-2.7!skip
-plugins/modules/aws_s3_cors.py import-3.5!skip
-plugins/modules/aws_s3_cors.py import-3.6!skip
-plugins/modules/aws_s3_cors.py import-3.7!skip
-plugins/modules/aws_s3_cors.py metaclass-boilerplate!skip
-plugins/modules/aws_secret.py compile-2.6!skip
-plugins/modules/aws_secret.py compile-2.7!skip
-plugins/modules/aws_secret.py compile-3.5!skip
-plugins/modules/aws_secret.py compile-3.6!skip
-plugins/modules/aws_secret.py compile-3.7!skip
-plugins/modules/aws_secret.py future-import-boilerplate!skip
-plugins/modules/aws_secret.py import-2.6!skip
-plugins/modules/aws_secret.py import-2.7!skip
-plugins/modules/aws_secret.py import-3.5!skip
-plugins/modules/aws_secret.py import-3.6!skip
-plugins/modules/aws_secret.py import-3.7!skip
-plugins/modules/aws_secret.py metaclass-boilerplate!skip
-plugins/modules/aws_ses_identity.py compile-2.6!skip
-plugins/modules/aws_ses_identity.py compile-2.7!skip
-plugins/modules/aws_ses_identity.py compile-3.5!skip
-plugins/modules/aws_ses_identity.py compile-3.6!skip
-plugins/modules/aws_ses_identity.py compile-3.7!skip
-plugins/modules/aws_ses_identity.py future-import-boilerplate!skip
-plugins/modules/aws_ses_identity.py import-2.6!skip
-plugins/modules/aws_ses_identity.py import-2.7!skip
-plugins/modules/aws_ses_identity.py import-3.5!skip
-plugins/modules/aws_ses_identity.py import-3.6!skip
-plugins/modules/aws_ses_identity.py import-3.7!skip
-plugins/modules/aws_ses_identity.py metaclass-boilerplate!skip
-plugins/modules/aws_ses_identity_policy.py compile-2.6!skip
-plugins/modules/aws_ses_identity_policy.py compile-2.7!skip
-plugins/modules/aws_ses_identity_policy.py compile-3.5!skip
-plugins/modules/aws_ses_identity_policy.py compile-3.6!skip
-plugins/modules/aws_ses_identity_policy.py compile-3.7!skip
-plugins/modules/aws_ses_identity_policy.py future-import-boilerplate!skip
-plugins/modules/aws_ses_identity_policy.py import-2.6!skip
-plugins/modules/aws_ses_identity_policy.py import-2.7!skip
-plugins/modules/aws_ses_identity_policy.py import-3.5!skip
-plugins/modules/aws_ses_identity_policy.py import-3.6!skip
-plugins/modules/aws_ses_identity_policy.py import-3.7!skip
-plugins/modules/aws_ses_identity_policy.py metaclass-boilerplate!skip
-plugins/modules/aws_ses_rule_set.py compile-2.6!skip
-plugins/modules/aws_ses_rule_set.py compile-2.7!skip
-plugins/modules/aws_ses_rule_set.py compile-3.5!skip
-plugins/modules/aws_ses_rule_set.py compile-3.6!skip
-plugins/modules/aws_ses_rule_set.py compile-3.7!skip
-plugins/modules/aws_ses_rule_set.py future-import-boilerplate!skip
-plugins/modules/aws_ses_rule_set.py import-2.6!skip
-plugins/modules/aws_ses_rule_set.py import-2.7!skip
-plugins/modules/aws_ses_rule_set.py import-3.5!skip
-plugins/modules/aws_ses_rule_set.py import-3.6!skip
-plugins/modules/aws_ses_rule_set.py import-3.7!skip
-plugins/modules/aws_ses_rule_set.py metaclass-boilerplate!skip
-plugins/modules/aws_sgw_info.py compile-2.6!skip
-plugins/modules/aws_sgw_info.py compile-2.7!skip
-plugins/modules/aws_sgw_info.py compile-3.5!skip
-plugins/modules/aws_sgw_info.py compile-3.6!skip
-plugins/modules/aws_sgw_info.py compile-3.7!skip
-plugins/modules/aws_sgw_info.py future-import-boilerplate!skip
-plugins/modules/aws_sgw_info.py import-2.6!skip
-plugins/modules/aws_sgw_info.py import-2.7!skip
-plugins/modules/aws_sgw_info.py import-3.5!skip
-plugins/modules/aws_sgw_info.py import-3.6!skip
-plugins/modules/aws_sgw_info.py import-3.7!skip
-plugins/modules/aws_sgw_info.py metaclass-boilerplate!skip
-plugins/modules/aws_ssm_parameter_store.py compile-2.6!skip
-plugins/modules/aws_ssm_parameter_store.py compile-2.7!skip
-plugins/modules/aws_ssm_parameter_store.py compile-3.5!skip
-plugins/modules/aws_ssm_parameter_store.py compile-3.6!skip
-plugins/modules/aws_ssm_parameter_store.py compile-3.7!skip
-plugins/modules/aws_ssm_parameter_store.py future-import-boilerplate!skip
-plugins/modules/aws_ssm_parameter_store.py import-2.6!skip
-plugins/modules/aws_ssm_parameter_store.py import-2.7!skip
-plugins/modules/aws_ssm_parameter_store.py import-3.5!skip
-plugins/modules/aws_ssm_parameter_store.py import-3.6!skip
-plugins/modules/aws_ssm_parameter_store.py import-3.7!skip
-plugins/modules/aws_ssm_parameter_store.py metaclass-boilerplate!skip
-plugins/modules/aws_step_functions_state_machine.py compile-2.6!skip
-plugins/modules/aws_step_functions_state_machine.py compile-2.7!skip
-plugins/modules/aws_step_functions_state_machine.py compile-3.5!skip
-plugins/modules/aws_step_functions_state_machine.py compile-3.6!skip
-plugins/modules/aws_step_functions_state_machine.py compile-3.7!skip
-plugins/modules/aws_step_functions_state_machine.py future-import-boilerplate!skip
-plugins/modules/aws_step_functions_state_machine.py import-2.6!skip
-plugins/modules/aws_step_functions_state_machine.py import-2.7!skip
-plugins/modules/aws_step_functions_state_machine.py import-3.5!skip
-plugins/modules/aws_step_functions_state_machine.py import-3.6!skip
-plugins/modules/aws_step_functions_state_machine.py import-3.7!skip
-plugins/modules/aws_step_functions_state_machine.py metaclass-boilerplate!skip
-plugins/modules/aws_step_functions_state_machine_execution.py compile-2.6!skip
-plugins/modules/aws_step_functions_state_machine_execution.py compile-2.7!skip
-plugins/modules/aws_step_functions_state_machine_execution.py compile-3.5!skip
-plugins/modules/aws_step_functions_state_machine_execution.py compile-3.6!skip
-plugins/modules/aws_step_functions_state_machine_execution.py compile-3.7!skip
-plugins/modules/aws_step_functions_state_machine_execution.py future-import-boilerplate!skip
-plugins/modules/aws_step_functions_state_machine_execution.py import-2.6!skip
-plugins/modules/aws_step_functions_state_machine_execution.py import-2.7!skip
-plugins/modules/aws_step_functions_state_machine_execution.py import-3.5!skip
-plugins/modules/aws_step_functions_state_machine_execution.py import-3.6!skip
-plugins/modules/aws_step_functions_state_machine_execution.py import-3.7!skip
-plugins/modules/aws_step_functions_state_machine_execution.py metaclass-boilerplate!skip
-plugins/modules/aws_waf_condition.py compile-2.6!skip
-plugins/modules/aws_waf_condition.py compile-2.7!skip
-plugins/modules/aws_waf_condition.py compile-3.5!skip
-plugins/modules/aws_waf_condition.py compile-3.6!skip
-plugins/modules/aws_waf_condition.py compile-3.7!skip
-plugins/modules/aws_waf_condition.py future-import-boilerplate!skip
-plugins/modules/aws_waf_condition.py import-2.6!skip
-plugins/modules/aws_waf_condition.py import-2.7!skip
-plugins/modules/aws_waf_condition.py import-3.5!skip
-plugins/modules/aws_waf_condition.py import-3.6!skip
-plugins/modules/aws_waf_condition.py import-3.7!skip
-plugins/modules/aws_waf_condition.py metaclass-boilerplate!skip
-plugins/modules/aws_waf_info.py compile-2.6!skip
-plugins/modules/aws_waf_info.py compile-2.7!skip
-plugins/modules/aws_waf_info.py compile-3.5!skip
-plugins/modules/aws_waf_info.py compile-3.6!skip
-plugins/modules/aws_waf_info.py compile-3.7!skip
-plugins/modules/aws_waf_info.py future-import-boilerplate!skip
-plugins/modules/aws_waf_info.py import-2.6!skip
-plugins/modules/aws_waf_info.py import-2.7!skip
-plugins/modules/aws_waf_info.py import-3.5!skip
-plugins/modules/aws_waf_info.py import-3.6!skip
-plugins/modules/aws_waf_info.py import-3.7!skip
-plugins/modules/aws_waf_info.py metaclass-boilerplate!skip
-plugins/modules/aws_waf_rule.py compile-2.6!skip
-plugins/modules/aws_waf_rule.py compile-2.7!skip
-plugins/modules/aws_waf_rule.py compile-3.5!skip
-plugins/modules/aws_waf_rule.py compile-3.6!skip
-plugins/modules/aws_waf_rule.py compile-3.7!skip
-plugins/modules/aws_waf_rule.py future-import-boilerplate!skip
-plugins/modules/aws_waf_rule.py import-2.6!skip
-plugins/modules/aws_waf_rule.py import-2.7!skip
-plugins/modules/aws_waf_rule.py import-3.5!skip
-plugins/modules/aws_waf_rule.py import-3.6!skip
-plugins/modules/aws_waf_rule.py import-3.7!skip
-plugins/modules/aws_waf_rule.py metaclass-boilerplate!skip
-plugins/modules/aws_waf_web_acl.py compile-2.6!skip
-plugins/modules/aws_waf_web_acl.py compile-2.7!skip
-plugins/modules/aws_waf_web_acl.py compile-3.5!skip
-plugins/modules/aws_waf_web_acl.py compile-3.6!skip
-plugins/modules/aws_waf_web_acl.py compile-3.7!skip
-plugins/modules/aws_waf_web_acl.py future-import-boilerplate!skip
-plugins/modules/aws_waf_web_acl.py import-2.6!skip
-plugins/modules/aws_waf_web_acl.py import-2.7!skip
-plugins/modules/aws_waf_web_acl.py import-3.5!skip
-plugins/modules/aws_waf_web_acl.py import-3.6!skip
-plugins/modules/aws_waf_web_acl.py import-3.7!skip
-plugins/modules/aws_waf_web_acl.py metaclass-boilerplate!skip
-plugins/modules/cloudformation_exports_info.py compile-2.6!skip
-plugins/modules/cloudformation_exports_info.py compile-2.7!skip
-plugins/modules/cloudformation_exports_info.py compile-3.5!skip
-plugins/modules/cloudformation_exports_info.py compile-3.6!skip
-plugins/modules/cloudformation_exports_info.py compile-3.7!skip
-plugins/modules/cloudformation_exports_info.py future-import-boilerplate!skip
-plugins/modules/cloudformation_exports_info.py import-2.6!skip
-plugins/modules/cloudformation_exports_info.py import-2.7!skip
-plugins/modules/cloudformation_exports_info.py import-3.5!skip
-plugins/modules/cloudformation_exports_info.py import-3.6!skip
-plugins/modules/cloudformation_exports_info.py import-3.7!skip
-plugins/modules/cloudformation_exports_info.py metaclass-boilerplate!skip
-plugins/modules/cloudformation_stack_set.py compile-2.6!skip
-plugins/modules/cloudformation_stack_set.py compile-2.7!skip
-plugins/modules/cloudformation_stack_set.py compile-3.5!skip
-plugins/modules/cloudformation_stack_set.py compile-3.6!skip
-plugins/modules/cloudformation_stack_set.py compile-3.7!skip
-plugins/modules/cloudformation_stack_set.py future-import-boilerplate!skip
-plugins/modules/cloudformation_stack_set.py import-2.6!skip
-plugins/modules/cloudformation_stack_set.py import-2.7!skip
-plugins/modules/cloudformation_stack_set.py import-3.5!skip
-plugins/modules/cloudformation_stack_set.py import-3.6!skip
-plugins/modules/cloudformation_stack_set.py import-3.7!skip
-plugins/modules/cloudformation_stack_set.py metaclass-boilerplate!skip
-plugins/modules/cloudfront_distribution.py compile-2.6!skip
-plugins/modules/cloudfront_distribution.py compile-2.7!skip
-plugins/modules/cloudfront_distribution.py compile-3.5!skip
-plugins/modules/cloudfront_distribution.py compile-3.6!skip
-plugins/modules/cloudfront_distribution.py compile-3.7!skip
-plugins/modules/cloudfront_distribution.py future-import-boilerplate!skip
-plugins/modules/cloudfront_distribution.py import-2.6!skip
-plugins/modules/cloudfront_distribution.py import-2.7!skip
-plugins/modules/cloudfront_distribution.py import-3.5!skip
-plugins/modules/cloudfront_distribution.py import-3.6!skip
-plugins/modules/cloudfront_distribution.py import-3.7!skip
-plugins/modules/cloudfront_distribution.py metaclass-boilerplate!skip
-plugins/modules/cloudfront_info.py compile-2.6!skip
-plugins/modules/cloudfront_info.py compile-2.7!skip
-plugins/modules/cloudfront_info.py compile-3.5!skip
-plugins/modules/cloudfront_info.py compile-3.6!skip
-plugins/modules/cloudfront_info.py compile-3.7!skip
-plugins/modules/cloudfront_info.py future-import-boilerplate!skip
-plugins/modules/cloudfront_info.py import-2.6!skip
-plugins/modules/cloudfront_info.py import-2.7!skip
-plugins/modules/cloudfront_info.py import-3.5!skip
-plugins/modules/cloudfront_info.py import-3.6!skip
-plugins/modules/cloudfront_info.py import-3.7!skip
-plugins/modules/cloudfront_info.py metaclass-boilerplate!skip
-plugins/modules/cloudfront_info.py pylint:unnecessary-comprehension # Should be an easy fix, but testing is a challenge - test are broken and aliases require a wildcard cert in ACM
-plugins/modules/cloudfront_invalidation.py compile-2.6!skip
-plugins/modules/cloudfront_invalidation.py compile-2.7!skip
-plugins/modules/cloudfront_invalidation.py compile-3.5!skip
-plugins/modules/cloudfront_invalidation.py compile-3.6!skip
-plugins/modules/cloudfront_invalidation.py compile-3.7!skip
-plugins/modules/cloudfront_invalidation.py future-import-boilerplate!skip
-plugins/modules/cloudfront_invalidation.py import-2.6!skip
-plugins/modules/cloudfront_invalidation.py import-2.7!skip
-plugins/modules/cloudfront_invalidation.py import-3.5!skip
-plugins/modules/cloudfront_invalidation.py import-3.6!skip
-plugins/modules/cloudfront_invalidation.py import-3.7!skip
-plugins/modules/cloudfront_invalidation.py metaclass-boilerplate!skip
-plugins/modules/cloudfront_origin_access_identity.py compile-2.6!skip
-plugins/modules/cloudfront_origin_access_identity.py compile-2.7!skip
-plugins/modules/cloudfront_origin_access_identity.py compile-3.5!skip
-plugins/modules/cloudfront_origin_access_identity.py compile-3.6!skip
-plugins/modules/cloudfront_origin_access_identity.py compile-3.7!skip
-plugins/modules/cloudfront_origin_access_identity.py future-import-boilerplate!skip
-plugins/modules/cloudfront_origin_access_identity.py import-2.6!skip
-plugins/modules/cloudfront_origin_access_identity.py import-2.7!skip
-plugins/modules/cloudfront_origin_access_identity.py import-3.5!skip
-plugins/modules/cloudfront_origin_access_identity.py import-3.6!skip
-plugins/modules/cloudfront_origin_access_identity.py import-3.7!skip
-plugins/modules/cloudfront_origin_access_identity.py metaclass-boilerplate!skip
-plugins/modules/cloudtrail.py compile-2.6!skip
-plugins/modules/cloudtrail.py compile-2.7!skip
-plugins/modules/cloudtrail.py compile-3.5!skip
-plugins/modules/cloudtrail.py compile-3.6!skip
-plugins/modules/cloudtrail.py compile-3.7!skip
-plugins/modules/cloudtrail.py future-import-boilerplate!skip
-plugins/modules/cloudtrail.py import-2.6!skip
-plugins/modules/cloudtrail.py import-2.7!skip
-plugins/modules/cloudtrail.py import-3.5!skip
-plugins/modules/cloudtrail.py import-3.6!skip
-plugins/modules/cloudtrail.py import-3.7!skip
-plugins/modules/cloudtrail.py metaclass-boilerplate!skip
-plugins/modules/cloudwatchevent_rule.py compile-2.6!skip
-plugins/modules/cloudwatchevent_rule.py compile-2.7!skip
-plugins/modules/cloudwatchevent_rule.py compile-3.5!skip
-plugins/modules/cloudwatchevent_rule.py compile-3.6!skip
-plugins/modules/cloudwatchevent_rule.py compile-3.7!skip
-plugins/modules/cloudwatchevent_rule.py future-import-boilerplate!skip
-plugins/modules/cloudwatchevent_rule.py import-2.6!skip
-plugins/modules/cloudwatchevent_rule.py import-2.7!skip
-plugins/modules/cloudwatchevent_rule.py import-3.5!skip
-plugins/modules/cloudwatchevent_rule.py import-3.6!skip
-plugins/modules/cloudwatchevent_rule.py import-3.7!skip
-plugins/modules/cloudwatchevent_rule.py metaclass-boilerplate!skip
-plugins/modules/cloudwatchlogs_log_group.py compile-2.6!skip
-plugins/modules/cloudwatchlogs_log_group.py compile-2.7!skip
-plugins/modules/cloudwatchlogs_log_group.py compile-3.5!skip
-plugins/modules/cloudwatchlogs_log_group.py compile-3.6!skip
-plugins/modules/cloudwatchlogs_log_group.py compile-3.7!skip
-plugins/modules/cloudwatchlogs_log_group.py future-import-boilerplate!skip
-plugins/modules/cloudwatchlogs_log_group.py import-2.6!skip
-plugins/modules/cloudwatchlogs_log_group.py import-2.7!skip
-plugins/modules/cloudwatchlogs_log_group.py import-3.5!skip
-plugins/modules/cloudwatchlogs_log_group.py import-3.6!skip
-plugins/modules/cloudwatchlogs_log_group.py import-3.7!skip
-plugins/modules/cloudwatchlogs_log_group.py metaclass-boilerplate!skip
-plugins/modules/cloudwatchlogs_log_group_info.py compile-2.6!skip
-plugins/modules/cloudwatchlogs_log_group_info.py compile-2.7!skip
-plugins/modules/cloudwatchlogs_log_group_info.py compile-3.5!skip
-plugins/modules/cloudwatchlogs_log_group_info.py compile-3.6!skip
-plugins/modules/cloudwatchlogs_log_group_info.py compile-3.7!skip
-plugins/modules/cloudwatchlogs_log_group_info.py future-import-boilerplate!skip
-plugins/modules/cloudwatchlogs_log_group_info.py import-2.6!skip
-plugins/modules/cloudwatchlogs_log_group_info.py import-2.7!skip
-plugins/modules/cloudwatchlogs_log_group_info.py import-3.5!skip
-plugins/modules/cloudwatchlogs_log_group_info.py import-3.6!skip
-plugins/modules/cloudwatchlogs_log_group_info.py import-3.7!skip
-plugins/modules/cloudwatchlogs_log_group_info.py metaclass-boilerplate!skip
-plugins/modules/cloudwatchlogs_log_group_metric_filter.py compile-2.6!skip
-plugins/modules/cloudwatchlogs_log_group_metric_filter.py compile-2.7!skip
-plugins/modules/cloudwatchlogs_log_group_metric_filter.py compile-3.5!skip
-plugins/modules/cloudwatchlogs_log_group_metric_filter.py compile-3.6!skip
-plugins/modules/cloudwatchlogs_log_group_metric_filter.py compile-3.7!skip
-plugins/modules/cloudwatchlogs_log_group_metric_filter.py future-import-boilerplate!skip
-plugins/modules/cloudwatchlogs_log_group_metric_filter.py import-2.6!skip
-plugins/modules/cloudwatchlogs_log_group_metric_filter.py import-2.7!skip
-plugins/modules/cloudwatchlogs_log_group_metric_filter.py import-3.5!skip
-plugins/modules/cloudwatchlogs_log_group_metric_filter.py import-3.6!skip
-plugins/modules/cloudwatchlogs_log_group_metric_filter.py import-3.7!skip
-plugins/modules/cloudwatchlogs_log_group_metric_filter.py metaclass-boilerplate!skip
-plugins/modules/data_pipeline.py compile-2.6!skip
-plugins/modules/data_pipeline.py compile-2.7!skip
-plugins/modules/data_pipeline.py compile-3.5!skip
-plugins/modules/data_pipeline.py compile-3.6!skip
-plugins/modules/data_pipeline.py compile-3.7!skip
-plugins/modules/data_pipeline.py future-import-boilerplate!skip
-plugins/modules/data_pipeline.py import-2.6!skip
-plugins/modules/data_pipeline.py import-2.7!skip
-plugins/modules/data_pipeline.py import-3.5!skip
-plugins/modules/data_pipeline.py import-3.6!skip
-plugins/modules/data_pipeline.py import-3.7!skip
-plugins/modules/data_pipeline.py metaclass-boilerplate!skip
-plugins/modules/dms_endpoint.py compile-2.6!skip
-plugins/modules/dms_endpoint.py compile-2.7!skip
-plugins/modules/dms_endpoint.py compile-3.5!skip
-plugins/modules/dms_endpoint.py compile-3.6!skip
-plugins/modules/dms_endpoint.py compile-3.7!skip
-plugins/modules/dms_endpoint.py future-import-boilerplate!skip
-plugins/modules/dms_endpoint.py import-2.6!skip
-plugins/modules/dms_endpoint.py import-2.7!skip
-plugins/modules/dms_endpoint.py import-3.5!skip
-plugins/modules/dms_endpoint.py import-3.6!skip
-plugins/modules/dms_endpoint.py import-3.7!skip
-plugins/modules/dms_endpoint.py metaclass-boilerplate!skip
-plugins/modules/dms_replication_subnet_group.py compile-2.6!skip
-plugins/modules/dms_replication_subnet_group.py compile-2.7!skip
-plugins/modules/dms_replication_subnet_group.py compile-3.5!skip
-plugins/modules/dms_replication_subnet_group.py compile-3.6!skip
-plugins/modules/dms_replication_subnet_group.py compile-3.7!skip
-plugins/modules/dms_replication_subnet_group.py future-import-boilerplate!skip
-plugins/modules/dms_replication_subnet_group.py import-2.6!skip
-plugins/modules/dms_replication_subnet_group.py import-2.7!skip
-plugins/modules/dms_replication_subnet_group.py import-3.5!skip
-plugins/modules/dms_replication_subnet_group.py import-3.6!skip
-plugins/modules/dms_replication_subnet_group.py import-3.7!skip
-plugins/modules/dms_replication_subnet_group.py metaclass-boilerplate!skip
-plugins/modules/dynamodb_table.py compile-2.6!skip
-plugins/modules/dynamodb_table.py compile-2.7!skip
-plugins/modules/dynamodb_table.py compile-3.5!skip
-plugins/modules/dynamodb_table.py compile-3.6!skip
-plugins/modules/dynamodb_table.py compile-3.7!skip
-plugins/modules/dynamodb_table.py future-import-boilerplate!skip
-plugins/modules/dynamodb_table.py import-2.6!skip
-plugins/modules/dynamodb_table.py import-2.7!skip
-plugins/modules/dynamodb_table.py import-3.5!skip
-plugins/modules/dynamodb_table.py import-3.6!skip
-plugins/modules/dynamodb_table.py import-3.7!skip
-plugins/modules/dynamodb_table.py metaclass-boilerplate!skip
-plugins/modules/dynamodb_ttl.py compile-2.6!skip
-plugins/modules/dynamodb_ttl.py compile-2.7!skip
-plugins/modules/dynamodb_ttl.py compile-3.5!skip
-plugins/modules/dynamodb_ttl.py compile-3.6!skip
-plugins/modules/dynamodb_ttl.py compile-3.7!skip
-plugins/modules/dynamodb_ttl.py future-import-boilerplate!skip
-plugins/modules/dynamodb_ttl.py import-2.6!skip
-plugins/modules/dynamodb_ttl.py import-2.7!skip
-plugins/modules/dynamodb_ttl.py import-3.5!skip
-plugins/modules/dynamodb_ttl.py import-3.6!skip
-plugins/modules/dynamodb_ttl.py import-3.7!skip
-plugins/modules/dynamodb_ttl.py metaclass-boilerplate!skip
-plugins/modules/ec2_ami_copy.py compile-2.6!skip
-plugins/modules/ec2_ami_copy.py compile-2.7!skip
-plugins/modules/ec2_ami_copy.py compile-3.5!skip
-plugins/modules/ec2_ami_copy.py compile-3.6!skip
-plugins/modules/ec2_ami_copy.py compile-3.7!skip
-plugins/modules/ec2_ami_copy.py future-import-boilerplate!skip
-plugins/modules/ec2_ami_copy.py import-2.6!skip
-plugins/modules/ec2_ami_copy.py import-2.7!skip
-plugins/modules/ec2_ami_copy.py import-3.5!skip
-plugins/modules/ec2_ami_copy.py import-3.6!skip
-plugins/modules/ec2_ami_copy.py import-3.7!skip
-plugins/modules/ec2_ami_copy.py metaclass-boilerplate!skip
-plugins/modules/ec2_asg.py compile-2.6!skip
-plugins/modules/ec2_asg.py compile-2.7!skip
-plugins/modules/ec2_asg.py compile-3.5!skip
-plugins/modules/ec2_asg.py compile-3.6!skip
-plugins/modules/ec2_asg.py compile-3.7!skip
-plugins/modules/ec2_asg.py future-import-boilerplate!skip
-plugins/modules/ec2_asg.py import-2.6!skip
-plugins/modules/ec2_asg.py import-2.7!skip
-plugins/modules/ec2_asg.py import-3.5!skip
-plugins/modules/ec2_asg.py import-3.6!skip
-plugins/modules/ec2_asg.py import-3.7!skip
-plugins/modules/ec2_asg.py metaclass-boilerplate!skip
-plugins/modules/ec2_asg_info.py compile-2.6!skip
-plugins/modules/ec2_asg_info.py compile-2.7!skip
-plugins/modules/ec2_asg_info.py compile-3.5!skip
-plugins/modules/ec2_asg_info.py compile-3.6!skip
-plugins/modules/ec2_asg_info.py compile-3.7!skip
-plugins/modules/ec2_asg_info.py future-import-boilerplate!skip
-plugins/modules/ec2_asg_info.py import-2.6!skip
-plugins/modules/ec2_asg_info.py import-2.7!skip
-plugins/modules/ec2_asg_info.py import-3.5!skip
-plugins/modules/ec2_asg_info.py import-3.6!skip
-plugins/modules/ec2_asg_info.py import-3.7!skip
-plugins/modules/ec2_asg_info.py metaclass-boilerplate!skip
-plugins/modules/ec2_asg_lifecycle_hook.py compile-2.6!skip
-plugins/modules/ec2_asg_lifecycle_hook.py compile-2.7!skip
-plugins/modules/ec2_asg_lifecycle_hook.py compile-3.5!skip
-plugins/modules/ec2_asg_lifecycle_hook.py compile-3.6!skip
-plugins/modules/ec2_asg_lifecycle_hook.py compile-3.7!skip
-plugins/modules/ec2_asg_lifecycle_hook.py future-import-boilerplate!skip
-plugins/modules/ec2_asg_lifecycle_hook.py import-2.6!skip
-plugins/modules/ec2_asg_lifecycle_hook.py import-2.7!skip
-plugins/modules/ec2_asg_lifecycle_hook.py import-3.5!skip
-plugins/modules/ec2_asg_lifecycle_hook.py import-3.6!skip
-plugins/modules/ec2_asg_lifecycle_hook.py import-3.7!skip
-plugins/modules/ec2_asg_lifecycle_hook.py metaclass-boilerplate!skip
-plugins/modules/ec2_customer_gateway.py compile-2.6!skip
-plugins/modules/ec2_customer_gateway.py compile-2.7!skip
-plugins/modules/ec2_customer_gateway.py compile-3.5!skip
-plugins/modules/ec2_customer_gateway.py compile-3.6!skip
-plugins/modules/ec2_customer_gateway.py compile-3.7!skip
-plugins/modules/ec2_customer_gateway.py future-import-boilerplate!skip
-plugins/modules/ec2_customer_gateway.py import-2.6!skip
-plugins/modules/ec2_customer_gateway.py import-2.7!skip
-plugins/modules/ec2_customer_gateway.py import-3.5!skip
-plugins/modules/ec2_customer_gateway.py import-3.6!skip
-plugins/modules/ec2_customer_gateway.py import-3.7!skip
-plugins/modules/ec2_customer_gateway.py metaclass-boilerplate!skip
-plugins/modules/ec2_customer_gateway_info.py compile-2.6!skip
-plugins/modules/ec2_customer_gateway_info.py compile-2.7!skip
-plugins/modules/ec2_customer_gateway_info.py compile-3.5!skip
-plugins/modules/ec2_customer_gateway_info.py compile-3.6!skip
-plugins/modules/ec2_customer_gateway_info.py compile-3.7!skip
-plugins/modules/ec2_customer_gateway_info.py future-import-boilerplate!skip
-plugins/modules/ec2_customer_gateway_info.py import-2.6!skip
-plugins/modules/ec2_customer_gateway_info.py import-2.7!skip
-plugins/modules/ec2_customer_gateway_info.py import-3.5!skip
-plugins/modules/ec2_customer_gateway_info.py import-3.6!skip
-plugins/modules/ec2_customer_gateway_info.py import-3.7!skip
-plugins/modules/ec2_customer_gateway_info.py metaclass-boilerplate!skip
-plugins/modules/ec2_eip.py compile-2.6!skip
-plugins/modules/ec2_eip.py compile-2.7!skip
-plugins/modules/ec2_eip.py compile-3.5!skip
-plugins/modules/ec2_eip.py compile-3.6!skip
-plugins/modules/ec2_eip.py compile-3.7!skip
-plugins/modules/ec2_eip.py future-import-boilerplate!skip
-plugins/modules/ec2_eip.py import-2.6!skip
-plugins/modules/ec2_eip.py import-2.7!skip
-plugins/modules/ec2_eip.py import-3.5!skip
-plugins/modules/ec2_eip.py import-3.6!skip
-plugins/modules/ec2_eip.py import-3.7!skip
-plugins/modules/ec2_eip.py metaclass-boilerplate!skip
-plugins/modules/ec2_eip_info.py compile-2.6!skip
-plugins/modules/ec2_eip_info.py compile-2.7!skip
-plugins/modules/ec2_eip_info.py compile-3.5!skip
-plugins/modules/ec2_eip_info.py compile-3.6!skip
-plugins/modules/ec2_eip_info.py compile-3.7!skip
-plugins/modules/ec2_eip_info.py future-import-boilerplate!skip
-plugins/modules/ec2_eip_info.py import-2.6!skip
-plugins/modules/ec2_eip_info.py import-2.7!skip
-plugins/modules/ec2_eip_info.py import-3.5!skip
-plugins/modules/ec2_eip_info.py import-3.6!skip
-plugins/modules/ec2_eip_info.py import-3.7!skip
-plugins/modules/ec2_eip_info.py metaclass-boilerplate!skip
-plugins/modules/ec2_elb_info.py compile-2.6!skip
-plugins/modules/ec2_elb_info.py compile-2.7!skip
-plugins/modules/ec2_elb_info.py compile-3.5!skip
-plugins/modules/ec2_elb_info.py compile-3.6!skip
-plugins/modules/ec2_elb_info.py compile-3.7!skip
-plugins/modules/ec2_elb_info.py future-import-boilerplate!skip
-plugins/modules/ec2_elb_info.py import-2.6!skip
-plugins/modules/ec2_elb_info.py import-2.7!skip
-plugins/modules/ec2_elb_info.py import-3.5!skip
-plugins/modules/ec2_elb_info.py import-3.6!skip
-plugins/modules/ec2_elb_info.py import-3.7!skip
-plugins/modules/ec2_elb_info.py metaclass-boilerplate!skip
-plugins/modules/ec2_launch_template.py compile-2.6!skip
-plugins/modules/ec2_launch_template.py compile-2.7!skip
-plugins/modules/ec2_launch_template.py compile-3.5!skip
-plugins/modules/ec2_launch_template.py compile-3.6!skip
-plugins/modules/ec2_launch_template.py compile-3.7!skip
-plugins/modules/ec2_launch_template.py future-import-boilerplate!skip
-plugins/modules/ec2_launch_template.py import-2.6!skip
-plugins/modules/ec2_launch_template.py import-2.7!skip
-plugins/modules/ec2_launch_template.py import-3.5!skip
-plugins/modules/ec2_launch_template.py import-3.6!skip
-plugins/modules/ec2_launch_template.py import-3.7!skip
-plugins/modules/ec2_launch_template.py metaclass-boilerplate!skip
-plugins/modules/ec2_lc.py compile-2.6!skip
-plugins/modules/ec2_lc.py compile-2.7!skip
-plugins/modules/ec2_lc.py compile-3.5!skip
-plugins/modules/ec2_lc.py compile-3.6!skip
-plugins/modules/ec2_lc.py compile-3.7!skip
-plugins/modules/ec2_lc.py future-import-boilerplate!skip
-plugins/modules/ec2_lc.py import-2.6!skip
-plugins/modules/ec2_lc.py import-2.7!skip
-plugins/modules/ec2_lc.py import-3.5!skip
-plugins/modules/ec2_lc.py import-3.6!skip
-plugins/modules/ec2_lc.py import-3.7!skip
-plugins/modules/ec2_lc.py metaclass-boilerplate!skip
-plugins/modules/ec2_lc_find.py compile-2.6!skip
-plugins/modules/ec2_lc_find.py compile-2.7!skip
-plugins/modules/ec2_lc_find.py compile-3.5!skip
-plugins/modules/ec2_lc_find.py compile-3.6!skip
-plugins/modules/ec2_lc_find.py compile-3.7!skip
-plugins/modules/ec2_lc_find.py future-import-boilerplate!skip
-plugins/modules/ec2_lc_find.py import-2.6!skip
-plugins/modules/ec2_lc_find.py import-2.7!skip
-plugins/modules/ec2_lc_find.py import-3.5!skip
-plugins/modules/ec2_lc_find.py import-3.6!skip
-plugins/modules/ec2_lc_find.py import-3.7!skip
-plugins/modules/ec2_lc_find.py metaclass-boilerplate!skip
-plugins/modules/ec2_lc_info.py compile-2.6!skip
-plugins/modules/ec2_lc_info.py compile-2.7!skip
-plugins/modules/ec2_lc_info.py compile-3.5!skip
-plugins/modules/ec2_lc_info.py compile-3.6!skip
-plugins/modules/ec2_lc_info.py compile-3.7!skip
-plugins/modules/ec2_lc_info.py future-import-boilerplate!skip
-plugins/modules/ec2_lc_info.py import-2.6!skip
-plugins/modules/ec2_lc_info.py import-2.7!skip
-plugins/modules/ec2_lc_info.py import-3.5!skip
-plugins/modules/ec2_lc_info.py import-3.6!skip
-plugins/modules/ec2_lc_info.py import-3.7!skip
-plugins/modules/ec2_lc_info.py metaclass-boilerplate!skip
-plugins/modules/ec2_metric_alarm.py compile-2.6!skip
-plugins/modules/ec2_metric_alarm.py compile-2.7!skip
-plugins/modules/ec2_metric_alarm.py compile-3.5!skip
-plugins/modules/ec2_metric_alarm.py compile-3.6!skip
-plugins/modules/ec2_metric_alarm.py compile-3.7!skip
-plugins/modules/ec2_metric_alarm.py future-import-boilerplate!skip
-plugins/modules/ec2_metric_alarm.py import-2.6!skip
-plugins/modules/ec2_metric_alarm.py import-2.7!skip
-plugins/modules/ec2_metric_alarm.py import-3.5!skip
-plugins/modules/ec2_metric_alarm.py import-3.6!skip
-plugins/modules/ec2_metric_alarm.py import-3.7!skip
-plugins/modules/ec2_metric_alarm.py metaclass-boilerplate!skip
-plugins/modules/ec2_placement_group.py compile-2.6!skip
-plugins/modules/ec2_placement_group.py compile-2.7!skip
-plugins/modules/ec2_placement_group.py compile-3.5!skip
-plugins/modules/ec2_placement_group.py compile-3.6!skip
-plugins/modules/ec2_placement_group.py compile-3.7!skip
-plugins/modules/ec2_placement_group.py future-import-boilerplate!skip
-plugins/modules/ec2_placement_group.py import-2.6!skip
-plugins/modules/ec2_placement_group.py import-2.7!skip
-plugins/modules/ec2_placement_group.py import-3.5!skip
-plugins/modules/ec2_placement_group.py import-3.6!skip
-plugins/modules/ec2_placement_group.py import-3.7!skip
-plugins/modules/ec2_placement_group.py metaclass-boilerplate!skip
-plugins/modules/ec2_placement_group_info.py compile-2.6!skip
-plugins/modules/ec2_placement_group_info.py compile-2.7!skip
-plugins/modules/ec2_placement_group_info.py compile-3.5!skip
-plugins/modules/ec2_placement_group_info.py compile-3.6!skip
-plugins/modules/ec2_placement_group_info.py compile-3.7!skip
-plugins/modules/ec2_placement_group_info.py future-import-boilerplate!skip
-plugins/modules/ec2_placement_group_info.py import-2.6!skip
-plugins/modules/ec2_placement_group_info.py import-2.7!skip
-plugins/modules/ec2_placement_group_info.py import-3.5!skip
-plugins/modules/ec2_placement_group_info.py import-3.6!skip
-plugins/modules/ec2_placement_group_info.py import-3.7!skip
-plugins/modules/ec2_placement_group_info.py metaclass-boilerplate!skip
-plugins/modules/ec2_scaling_policy.py compile-2.6!skip
-plugins/modules/ec2_scaling_policy.py compile-2.7!skip
-plugins/modules/ec2_scaling_policy.py compile-3.5!skip
-plugins/modules/ec2_scaling_policy.py compile-3.6!skip
-plugins/modules/ec2_scaling_policy.py compile-3.7!skip
-plugins/modules/ec2_scaling_policy.py future-import-boilerplate!skip
-plugins/modules/ec2_scaling_policy.py import-2.6!skip
-plugins/modules/ec2_scaling_policy.py import-2.7!skip
-plugins/modules/ec2_scaling_policy.py import-3.5!skip
-plugins/modules/ec2_scaling_policy.py import-3.6!skip
-plugins/modules/ec2_scaling_policy.py import-3.7!skip
-plugins/modules/ec2_scaling_policy.py metaclass-boilerplate!skip
-plugins/modules/ec2_snapshot_copy.py compile-2.6!skip
-plugins/modules/ec2_snapshot_copy.py compile-2.7!skip
-plugins/modules/ec2_snapshot_copy.py compile-3.5!skip
-plugins/modules/ec2_snapshot_copy.py compile-3.6!skip
-plugins/modules/ec2_snapshot_copy.py compile-3.7!skip
-plugins/modules/ec2_snapshot_copy.py future-import-boilerplate!skip
-plugins/modules/ec2_snapshot_copy.py import-2.6!skip
-plugins/modules/ec2_snapshot_copy.py import-2.7!skip
-plugins/modules/ec2_snapshot_copy.py import-3.5!skip
-plugins/modules/ec2_snapshot_copy.py import-3.6!skip
-plugins/modules/ec2_snapshot_copy.py import-3.7!skip
-plugins/modules/ec2_snapshot_copy.py metaclass-boilerplate!skip
-plugins/modules/ec2_transit_gateway.py compile-2.6!skip
-plugins/modules/ec2_transit_gateway.py compile-2.7!skip
-plugins/modules/ec2_transit_gateway.py compile-3.5!skip
-plugins/modules/ec2_transit_gateway.py compile-3.6!skip
-plugins/modules/ec2_transit_gateway.py compile-3.7!skip
-plugins/modules/ec2_transit_gateway.py future-import-boilerplate!skip
-plugins/modules/ec2_transit_gateway.py import-2.6!skip
-plugins/modules/ec2_transit_gateway.py import-2.7!skip
-plugins/modules/ec2_transit_gateway.py import-3.5!skip
-plugins/modules/ec2_transit_gateway.py import-3.6!skip
-plugins/modules/ec2_transit_gateway.py import-3.7!skip
-plugins/modules/ec2_transit_gateway.py metaclass-boilerplate!skip
-plugins/modules/ec2_transit_gateway_info.py compile-2.6!skip
-plugins/modules/ec2_transit_gateway_info.py compile-2.7!skip
-plugins/modules/ec2_transit_gateway_info.py compile-3.5!skip
-plugins/modules/ec2_transit_gateway_info.py compile-3.6!skip
-plugins/modules/ec2_transit_gateway_info.py compile-3.7!skip
-plugins/modules/ec2_transit_gateway_info.py future-import-boilerplate!skip
-plugins/modules/ec2_transit_gateway_info.py import-2.6!skip
-plugins/modules/ec2_transit_gateway_info.py import-2.7!skip
-plugins/modules/ec2_transit_gateway_info.py import-3.5!skip
-plugins/modules/ec2_transit_gateway_info.py import-3.6!skip
-plugins/modules/ec2_transit_gateway_info.py import-3.7!skip
-plugins/modules/ec2_transit_gateway_info.py metaclass-boilerplate!skip
-plugins/modules/ec2_vpc_egress_igw.py compile-2.6!skip
-plugins/modules/ec2_vpc_egress_igw.py compile-2.7!skip
-plugins/modules/ec2_vpc_egress_igw.py compile-3.5!skip
-plugins/modules/ec2_vpc_egress_igw.py compile-3.6!skip
-plugins/modules/ec2_vpc_egress_igw.py compile-3.7!skip
-plugins/modules/ec2_vpc_egress_igw.py future-import-boilerplate!skip
-plugins/modules/ec2_vpc_egress_igw.py import-2.6!skip
-plugins/modules/ec2_vpc_egress_igw.py import-2.7!skip
-plugins/modules/ec2_vpc_egress_igw.py import-3.5!skip
-plugins/modules/ec2_vpc_egress_igw.py import-3.6!skip
-plugins/modules/ec2_vpc_egress_igw.py import-3.7!skip
-plugins/modules/ec2_vpc_egress_igw.py metaclass-boilerplate!skip
-plugins/modules/ec2_vpc_endpoint.py compile-2.6!skip
-plugins/modules/ec2_vpc_endpoint.py compile-2.7!skip
-plugins/modules/ec2_vpc_endpoint.py compile-3.5!skip
-plugins/modules/ec2_vpc_endpoint.py compile-3.6!skip
-plugins/modules/ec2_vpc_endpoint.py compile-3.7!skip
-plugins/modules/ec2_vpc_endpoint.py future-import-boilerplate!skip
-plugins/modules/ec2_vpc_endpoint.py import-2.6!skip
-plugins/modules/ec2_vpc_endpoint.py import-2.7!skip
-plugins/modules/ec2_vpc_endpoint.py import-3.5!skip
-plugins/modules/ec2_vpc_endpoint.py import-3.6!skip
-plugins/modules/ec2_vpc_endpoint.py import-3.7!skip
-plugins/modules/ec2_vpc_endpoint.py metaclass-boilerplate!skip
-plugins/modules/ec2_vpc_endpoint_info.py compile-2.6!skip
-plugins/modules/ec2_vpc_endpoint_info.py compile-2.7!skip
-plugins/modules/ec2_vpc_endpoint_info.py compile-3.5!skip
-plugins/modules/ec2_vpc_endpoint_info.py compile-3.6!skip
-plugins/modules/ec2_vpc_endpoint_info.py compile-3.7!skip
-plugins/modules/ec2_vpc_endpoint_info.py future-import-boilerplate!skip
-plugins/modules/ec2_vpc_endpoint_info.py import-2.6!skip
-plugins/modules/ec2_vpc_endpoint_info.py import-2.7!skip
-plugins/modules/ec2_vpc_endpoint_info.py import-3.5!skip
-plugins/modules/ec2_vpc_endpoint_info.py import-3.6!skip
-plugins/modules/ec2_vpc_endpoint_info.py import-3.7!skip
-plugins/modules/ec2_vpc_endpoint_info.py metaclass-boilerplate!skip
-plugins/modules/ec2_vpc_endpoint_service_info.py compile-2.6!skip
-plugins/modules/ec2_vpc_endpoint_service_info.py compile-2.7!skip
-plugins/modules/ec2_vpc_endpoint_service_info.py compile-3.5!skip
-plugins/modules/ec2_vpc_endpoint_service_info.py compile-3.6!skip
-plugins/modules/ec2_vpc_endpoint_service_info.py compile-3.7!skip
-plugins/modules/ec2_vpc_endpoint_service_info.py future-import-boilerplate!skip
-plugins/modules/ec2_vpc_endpoint_service_info.py import-2.6!skip
-plugins/modules/ec2_vpc_endpoint_service_info.py import-2.7!skip
-plugins/modules/ec2_vpc_endpoint_service_info.py import-3.5!skip
-plugins/modules/ec2_vpc_endpoint_service_info.py import-3.6!skip
-plugins/modules/ec2_vpc_endpoint_service_info.py import-3.7!skip
-plugins/modules/ec2_vpc_endpoint_service_info.py metaclass-boilerplate!skip
-plugins/modules/ec2_vpc_igw.py compile-2.6!skip
-plugins/modules/ec2_vpc_igw.py compile-2.7!skip
-plugins/modules/ec2_vpc_igw.py compile-3.5!skip
-plugins/modules/ec2_vpc_igw.py compile-3.6!skip
-plugins/modules/ec2_vpc_igw.py compile-3.7!skip
-plugins/modules/ec2_vpc_igw.py future-import-boilerplate!skip
-plugins/modules/ec2_vpc_igw.py import-2.6!skip
-plugins/modules/ec2_vpc_igw.py import-2.7!skip
-plugins/modules/ec2_vpc_igw.py import-3.5!skip
-plugins/modules/ec2_vpc_igw.py import-3.6!skip
-plugins/modules/ec2_vpc_igw.py import-3.7!skip
-plugins/modules/ec2_vpc_igw.py metaclass-boilerplate!skip
-plugins/modules/ec2_vpc_igw_info.py compile-2.6!skip
-plugins/modules/ec2_vpc_igw_info.py compile-2.7!skip
-plugins/modules/ec2_vpc_igw_info.py compile-3.5!skip
-plugins/modules/ec2_vpc_igw_info.py compile-3.6!skip
-plugins/modules/ec2_vpc_igw_info.py compile-3.7!skip
-plugins/modules/ec2_vpc_igw_info.py future-import-boilerplate!skip
-plugins/modules/ec2_vpc_igw_info.py import-2.6!skip
-plugins/modules/ec2_vpc_igw_info.py import-2.7!skip
-plugins/modules/ec2_vpc_igw_info.py import-3.5!skip
-plugins/modules/ec2_vpc_igw_info.py import-3.6!skip
-plugins/modules/ec2_vpc_igw_info.py import-3.7!skip
-plugins/modules/ec2_vpc_igw_info.py metaclass-boilerplate!skip
-plugins/modules/ec2_vpc_nacl.py compile-2.6!skip
-plugins/modules/ec2_vpc_nacl.py compile-2.7!skip
-plugins/modules/ec2_vpc_nacl.py compile-3.5!skip
-plugins/modules/ec2_vpc_nacl.py compile-3.6!skip
-plugins/modules/ec2_vpc_nacl.py compile-3.7!skip
-plugins/modules/ec2_vpc_nacl.py future-import-boilerplate!skip
-plugins/modules/ec2_vpc_nacl.py import-2.6!skip
-plugins/modules/ec2_vpc_nacl.py import-2.7!skip
-plugins/modules/ec2_vpc_nacl.py import-3.5!skip
-plugins/modules/ec2_vpc_nacl.py import-3.6!skip
-plugins/modules/ec2_vpc_nacl.py import-3.7!skip
-plugins/modules/ec2_vpc_nacl.py metaclass-boilerplate!skip
-plugins/modules/ec2_vpc_nacl_info.py compile-2.6!skip
-plugins/modules/ec2_vpc_nacl_info.py compile-2.7!skip
-plugins/modules/ec2_vpc_nacl_info.py compile-3.5!skip
-plugins/modules/ec2_vpc_nacl_info.py compile-3.6!skip
-plugins/modules/ec2_vpc_nacl_info.py compile-3.7!skip
-plugins/modules/ec2_vpc_nacl_info.py future-import-boilerplate!skip
-plugins/modules/ec2_vpc_nacl_info.py import-2.6!skip
-plugins/modules/ec2_vpc_nacl_info.py import-2.7!skip
-plugins/modules/ec2_vpc_nacl_info.py import-3.5!skip
-plugins/modules/ec2_vpc_nacl_info.py import-3.6!skip
-plugins/modules/ec2_vpc_nacl_info.py import-3.7!skip
-plugins/modules/ec2_vpc_nacl_info.py metaclass-boilerplate!skip
-plugins/modules/ec2_vpc_nat_gateway.py compile-2.6!skip
-plugins/modules/ec2_vpc_nat_gateway.py compile-2.7!skip
-plugins/modules/ec2_vpc_nat_gateway.py compile-3.5!skip
-plugins/modules/ec2_vpc_nat_gateway.py compile-3.6!skip
-plugins/modules/ec2_vpc_nat_gateway.py compile-3.7!skip
-plugins/modules/ec2_vpc_nat_gateway.py future-import-boilerplate!skip
-plugins/modules/ec2_vpc_nat_gateway.py import-2.6!skip
-plugins/modules/ec2_vpc_nat_gateway.py import-2.7!skip
-plugins/modules/ec2_vpc_nat_gateway.py import-3.5!skip
-plugins/modules/ec2_vpc_nat_gateway.py import-3.6!skip
-plugins/modules/ec2_vpc_nat_gateway.py import-3.7!skip
-plugins/modules/ec2_vpc_nat_gateway.py metaclass-boilerplate!skip
-plugins/modules/ec2_vpc_nat_gateway_info.py compile-2.6!skip
-plugins/modules/ec2_vpc_nat_gateway_info.py compile-2.7!skip
-plugins/modules/ec2_vpc_nat_gateway_info.py compile-3.5!skip
-plugins/modules/ec2_vpc_nat_gateway_info.py compile-3.6!skip
-plugins/modules/ec2_vpc_nat_gateway_info.py compile-3.7!skip
-plugins/modules/ec2_vpc_nat_gateway_info.py future-import-boilerplate!skip
-plugins/modules/ec2_vpc_nat_gateway_info.py import-2.6!skip
-plugins/modules/ec2_vpc_nat_gateway_info.py import-2.7!skip
-plugins/modules/ec2_vpc_nat_gateway_info.py import-3.5!skip
-plugins/modules/ec2_vpc_nat_gateway_info.py import-3.6!skip
-plugins/modules/ec2_vpc_nat_gateway_info.py import-3.7!skip
-plugins/modules/ec2_vpc_nat_gateway_info.py metaclass-boilerplate!skip
-plugins/modules/ec2_vpc_peer.py compile-2.6!skip
-plugins/modules/ec2_vpc_peer.py compile-2.7!skip
-plugins/modules/ec2_vpc_peer.py compile-3.5!skip
-plugins/modules/ec2_vpc_peer.py compile-3.6!skip
-plugins/modules/ec2_vpc_peer.py compile-3.7!skip
-plugins/modules/ec2_vpc_peer.py future-import-boilerplate!skip
-plugins/modules/ec2_vpc_peer.py import-2.6!skip
-plugins/modules/ec2_vpc_peer.py import-2.7!skip
-plugins/modules/ec2_vpc_peer.py import-3.5!skip
-plugins/modules/ec2_vpc_peer.py import-3.6!skip
-plugins/modules/ec2_vpc_peer.py import-3.7!skip
-plugins/modules/ec2_vpc_peer.py metaclass-boilerplate!skip
-plugins/modules/ec2_vpc_peering_info.py compile-2.6!skip
-plugins/modules/ec2_vpc_peering_info.py compile-2.7!skip
-plugins/modules/ec2_vpc_peering_info.py compile-3.5!skip
-plugins/modules/ec2_vpc_peering_info.py compile-3.6!skip
-plugins/modules/ec2_vpc_peering_info.py compile-3.7!skip
-plugins/modules/ec2_vpc_peering_info.py future-import-boilerplate!skip
-plugins/modules/ec2_vpc_peering_info.py import-2.6!skip
-plugins/modules/ec2_vpc_peering_info.py import-2.7!skip
-plugins/modules/ec2_vpc_peering_info.py import-3.5!skip
-plugins/modules/ec2_vpc_peering_info.py import-3.6!skip
-plugins/modules/ec2_vpc_peering_info.py import-3.7!skip
-plugins/modules/ec2_vpc_peering_info.py metaclass-boilerplate!skip
-plugins/modules/ec2_vpc_route_table.py compile-2.6!skip
-plugins/modules/ec2_vpc_route_table.py compile-2.7!skip
-plugins/modules/ec2_vpc_route_table.py compile-3.5!skip
-plugins/modules/ec2_vpc_route_table.py compile-3.6!skip
-plugins/modules/ec2_vpc_route_table.py compile-3.7!skip
-plugins/modules/ec2_vpc_route_table.py future-import-boilerplate!skip
-plugins/modules/ec2_vpc_route_table.py import-2.6!skip
-plugins/modules/ec2_vpc_route_table.py import-2.7!skip
-plugins/modules/ec2_vpc_route_table.py import-3.5!skip
-plugins/modules/ec2_vpc_route_table.py import-3.6!skip
-plugins/modules/ec2_vpc_route_table.py import-3.7!skip
-plugins/modules/ec2_vpc_route_table.py metaclass-boilerplate!skip
-plugins/modules/ec2_vpc_route_table_info.py compile-2.6!skip
-plugins/modules/ec2_vpc_route_table_info.py compile-2.7!skip
-plugins/modules/ec2_vpc_route_table_info.py compile-3.5!skip
-plugins/modules/ec2_vpc_route_table_info.py compile-3.6!skip
-plugins/modules/ec2_vpc_route_table_info.py compile-3.7!skip
-plugins/modules/ec2_vpc_route_table_info.py future-import-boilerplate!skip
-plugins/modules/ec2_vpc_route_table_info.py import-2.6!skip
-plugins/modules/ec2_vpc_route_table_info.py import-2.7!skip
-plugins/modules/ec2_vpc_route_table_info.py import-3.5!skip
-plugins/modules/ec2_vpc_route_table_info.py import-3.6!skip
-plugins/modules/ec2_vpc_route_table_info.py import-3.7!skip
-plugins/modules/ec2_vpc_route_table_info.py metaclass-boilerplate!skip
-plugins/modules/ec2_vpc_vgw.py compile-2.6!skip
-plugins/modules/ec2_vpc_vgw.py compile-2.7!skip
-plugins/modules/ec2_vpc_vgw.py compile-3.5!skip
-plugins/modules/ec2_vpc_vgw.py compile-3.6!skip
-plugins/modules/ec2_vpc_vgw.py compile-3.7!skip
-plugins/modules/ec2_vpc_vgw.py future-import-boilerplate!skip
-plugins/modules/ec2_vpc_vgw.py import-2.6!skip
-plugins/modules/ec2_vpc_vgw.py import-2.7!skip
-plugins/modules/ec2_vpc_vgw.py import-3.5!skip
-plugins/modules/ec2_vpc_vgw.py import-3.6!skip
-plugins/modules/ec2_vpc_vgw.py import-3.7!skip
-plugins/modules/ec2_vpc_vgw.py metaclass-boilerplate!skip
-plugins/modules/ec2_vpc_vgw_info.py compile-2.6!skip
-plugins/modules/ec2_vpc_vgw_info.py compile-2.7!skip
-plugins/modules/ec2_vpc_vgw_info.py compile-3.5!skip
-plugins/modules/ec2_vpc_vgw_info.py compile-3.6!skip
-plugins/modules/ec2_vpc_vgw_info.py compile-3.7!skip
-plugins/modules/ec2_vpc_vgw_info.py future-import-boilerplate!skip
-plugins/modules/ec2_vpc_vgw_info.py import-2.6!skip
-plugins/modules/ec2_vpc_vgw_info.py import-2.7!skip
-plugins/modules/ec2_vpc_vgw_info.py import-3.5!skip
-plugins/modules/ec2_vpc_vgw_info.py import-3.6!skip
-plugins/modules/ec2_vpc_vgw_info.py import-3.7!skip
-plugins/modules/ec2_vpc_vgw_info.py metaclass-boilerplate!skip
-plugins/modules/ec2_vpc_vpn.py compile-2.6!skip
-plugins/modules/ec2_vpc_vpn.py compile-2.7!skip
-plugins/modules/ec2_vpc_vpn.py compile-3.5!skip
-plugins/modules/ec2_vpc_vpn.py compile-3.6!skip
-plugins/modules/ec2_vpc_vpn.py compile-3.7!skip
-plugins/modules/ec2_vpc_vpn.py future-import-boilerplate!skip
-plugins/modules/ec2_vpc_vpn.py import-2.6!skip
-plugins/modules/ec2_vpc_vpn.py import-2.7!skip
-plugins/modules/ec2_vpc_vpn.py import-3.5!skip
-plugins/modules/ec2_vpc_vpn.py import-3.6!skip
-plugins/modules/ec2_vpc_vpn.py import-3.7!skip
-plugins/modules/ec2_vpc_vpn.py metaclass-boilerplate!skip
-plugins/modules/ec2_vpc_vpn_info.py compile-2.6!skip
-plugins/modules/ec2_vpc_vpn_info.py compile-2.7!skip
-plugins/modules/ec2_vpc_vpn_info.py compile-3.5!skip
-plugins/modules/ec2_vpc_vpn_info.py compile-3.6!skip
-plugins/modules/ec2_vpc_vpn_info.py compile-3.7!skip
-plugins/modules/ec2_vpc_vpn_info.py future-import-boilerplate!skip
-plugins/modules/ec2_vpc_vpn_info.py import-2.6!skip
-plugins/modules/ec2_vpc_vpn_info.py import-2.7!skip
-plugins/modules/ec2_vpc_vpn_info.py import-3.5!skip
-plugins/modules/ec2_vpc_vpn_info.py import-3.6!skip
-plugins/modules/ec2_vpc_vpn_info.py import-3.7!skip
-plugins/modules/ec2_vpc_vpn_info.py metaclass-boilerplate!skip
-plugins/modules/ec2_win_password.py compile-2.6!skip
-plugins/modules/ec2_win_password.py compile-2.7!skip
-plugins/modules/ec2_win_password.py compile-3.5!skip
-plugins/modules/ec2_win_password.py compile-3.6!skip
-plugins/modules/ec2_win_password.py compile-3.7!skip
-plugins/modules/ec2_win_password.py future-import-boilerplate!skip
-plugins/modules/ec2_win_password.py import-2.6!skip
-plugins/modules/ec2_win_password.py import-2.7!skip
-plugins/modules/ec2_win_password.py import-3.5!skip
-plugins/modules/ec2_win_password.py import-3.6!skip
-plugins/modules/ec2_win_password.py import-3.7!skip
-plugins/modules/ec2_win_password.py metaclass-boilerplate!skip
-plugins/modules/ecs_attribute.py compile-2.6!skip
-plugins/modules/ecs_attribute.py compile-2.7!skip
-plugins/modules/ecs_attribute.py compile-3.5!skip
-plugins/modules/ecs_attribute.py compile-3.6!skip
-plugins/modules/ecs_attribute.py compile-3.7!skip
-plugins/modules/ecs_attribute.py future-import-boilerplate!skip
-plugins/modules/ecs_attribute.py import-2.6!skip
-plugins/modules/ecs_attribute.py import-2.7!skip
-plugins/modules/ecs_attribute.py import-3.5!skip
-plugins/modules/ecs_attribute.py import-3.6!skip
-plugins/modules/ecs_attribute.py import-3.7!skip
-plugins/modules/ecs_attribute.py metaclass-boilerplate!skip
-plugins/modules/ecs_cluster.py compile-2.6!skip
-plugins/modules/ecs_cluster.py compile-2.7!skip
-plugins/modules/ecs_cluster.py compile-3.5!skip
-plugins/modules/ecs_cluster.py compile-3.6!skip
-plugins/modules/ecs_cluster.py compile-3.7!skip
-plugins/modules/ecs_cluster.py future-import-boilerplate!skip
-plugins/modules/ecs_cluster.py import-2.6!skip
-plugins/modules/ecs_cluster.py import-2.7!skip
-plugins/modules/ecs_cluster.py import-3.5!skip
-plugins/modules/ecs_cluster.py import-3.6!skip
-plugins/modules/ecs_cluster.py import-3.7!skip
-plugins/modules/ecs_cluster.py metaclass-boilerplate!skip
-plugins/modules/ecs_ecr.py compile-2.6!skip
-plugins/modules/ecs_ecr.py compile-2.7!skip
-plugins/modules/ecs_ecr.py compile-3.5!skip
-plugins/modules/ecs_ecr.py compile-3.6!skip
-plugins/modules/ecs_ecr.py compile-3.7!skip
-plugins/modules/ecs_ecr.py future-import-boilerplate!skip
-plugins/modules/ecs_ecr.py import-2.6!skip
-plugins/modules/ecs_ecr.py import-2.7!skip
-plugins/modules/ecs_ecr.py import-3.5!skip
-plugins/modules/ecs_ecr.py import-3.6!skip
-plugins/modules/ecs_ecr.py import-3.7!skip
-plugins/modules/ecs_ecr.py metaclass-boilerplate!skip
-plugins/modules/ecs_service.py compile-2.6!skip
-plugins/modules/ecs_service.py compile-2.7!skip
-plugins/modules/ecs_service.py compile-3.5!skip
-plugins/modules/ecs_service.py compile-3.6!skip
-plugins/modules/ecs_service.py compile-3.7!skip
-plugins/modules/ecs_service.py future-import-boilerplate!skip
-plugins/modules/ecs_service.py import-2.6!skip
-plugins/modules/ecs_service.py import-2.7!skip
-plugins/modules/ecs_service.py import-3.5!skip
-plugins/modules/ecs_service.py import-3.6!skip
-plugins/modules/ecs_service.py import-3.7!skip
-plugins/modules/ecs_service.py metaclass-boilerplate!skip
-plugins/modules/ecs_service_info.py compile-2.6!skip
-plugins/modules/ecs_service_info.py compile-2.7!skip
-plugins/modules/ecs_service_info.py compile-3.5!skip
-plugins/modules/ecs_service_info.py compile-3.6!skip
-plugins/modules/ecs_service_info.py compile-3.7!skip
-plugins/modules/ecs_service_info.py future-import-boilerplate!skip
-plugins/modules/ecs_service_info.py import-2.6!skip
-plugins/modules/ecs_service_info.py import-2.7!skip
-plugins/modules/ecs_service_info.py import-3.5!skip
-plugins/modules/ecs_service_info.py import-3.6!skip
-plugins/modules/ecs_service_info.py import-3.7!skip
-plugins/modules/ecs_service_info.py metaclass-boilerplate!skip
-plugins/modules/ecs_tag.py compile-2.6!skip
-plugins/modules/ecs_tag.py compile-2.7!skip
-plugins/modules/ecs_tag.py compile-3.5!skip
-plugins/modules/ecs_tag.py compile-3.6!skip
-plugins/modules/ecs_tag.py compile-3.7!skip
-plugins/modules/ecs_tag.py future-import-boilerplate!skip
-plugins/modules/ecs_tag.py import-2.6!skip
-plugins/modules/ecs_tag.py import-2.7!skip
-plugins/modules/ecs_tag.py import-3.5!skip
-plugins/modules/ecs_tag.py import-3.6!skip
-plugins/modules/ecs_tag.py import-3.7!skip
-plugins/modules/ecs_tag.py metaclass-boilerplate!skip
-plugins/modules/ecs_task.py compile-2.6!skip
-plugins/modules/ecs_task.py compile-2.7!skip
-plugins/modules/ecs_task.py compile-3.5!skip
-plugins/modules/ecs_task.py compile-3.6!skip
-plugins/modules/ecs_task.py compile-3.7!skip
-plugins/modules/ecs_task.py future-import-boilerplate!skip
-plugins/modules/ecs_task.py import-2.6!skip
-plugins/modules/ecs_task.py import-2.7!skip
-plugins/modules/ecs_task.py import-3.5!skip
-plugins/modules/ecs_task.py import-3.6!skip
-plugins/modules/ecs_task.py import-3.7!skip
-plugins/modules/ecs_task.py metaclass-boilerplate!skip
-plugins/modules/ecs_taskdefinition.py compile-2.6!skip
-plugins/modules/ecs_taskdefinition.py compile-2.7!skip
-plugins/modules/ecs_taskdefinition.py compile-3.5!skip
-plugins/modules/ecs_taskdefinition.py compile-3.6!skip
-plugins/modules/ecs_taskdefinition.py compile-3.7!skip
-plugins/modules/ecs_taskdefinition.py future-import-boilerplate!skip
-plugins/modules/ecs_taskdefinition.py import-2.6!skip
-plugins/modules/ecs_taskdefinition.py import-2.7!skip
-plugins/modules/ecs_taskdefinition.py import-3.5!skip
-plugins/modules/ecs_taskdefinition.py import-3.6!skip
-plugins/modules/ecs_taskdefinition.py import-3.7!skip
-plugins/modules/ecs_taskdefinition.py metaclass-boilerplate!skip
-plugins/modules/ecs_taskdefinition_info.py compile-2.6!skip
-plugins/modules/ecs_taskdefinition_info.py compile-2.7!skip
-plugins/modules/ecs_taskdefinition_info.py compile-3.5!skip
-plugins/modules/ecs_taskdefinition_info.py compile-3.6!skip
-plugins/modules/ecs_taskdefinition_info.py compile-3.7!skip
-plugins/modules/ecs_taskdefinition_info.py future-import-boilerplate!skip
-plugins/modules/ecs_taskdefinition_info.py import-2.6!skip
-plugins/modules/ecs_taskdefinition_info.py import-2.7!skip
-plugins/modules/ecs_taskdefinition_info.py import-3.5!skip
-plugins/modules/ecs_taskdefinition_info.py import-3.6!skip
-plugins/modules/ecs_taskdefinition_info.py import-3.7!skip
-plugins/modules/ecs_taskdefinition_info.py metaclass-boilerplate!skip
-plugins/modules/efs.py compile-2.6!skip
-plugins/modules/efs.py compile-2.7!skip
-plugins/modules/efs.py compile-3.5!skip
-plugins/modules/efs.py compile-3.6!skip
-plugins/modules/efs.py compile-3.7!skip
-plugins/modules/efs.py future-import-boilerplate!skip
-plugins/modules/efs.py import-2.6!skip
-plugins/modules/efs.py import-2.7!skip
-plugins/modules/efs.py import-3.5!skip
-plugins/modules/efs.py import-3.6!skip
-plugins/modules/efs.py import-3.7!skip
-plugins/modules/efs.py metaclass-boilerplate!skip
-plugins/modules/efs_info.py compile-2.6!skip
-plugins/modules/efs_info.py compile-2.7!skip
-plugins/modules/efs_info.py compile-3.5!skip
-plugins/modules/efs_info.py compile-3.6!skip
-plugins/modules/efs_info.py compile-3.7!skip
-plugins/modules/efs_info.py future-import-boilerplate!skip
-plugins/modules/efs_info.py import-2.6!skip
-plugins/modules/efs_info.py import-2.7!skip
-plugins/modules/efs_info.py import-3.5!skip
-plugins/modules/efs_info.py import-3.6!skip
-plugins/modules/efs_info.py import-3.7!skip
-plugins/modules/efs_info.py metaclass-boilerplate!skip
-plugins/modules/elasticache.py compile-2.6!skip
-plugins/modules/elasticache.py compile-2.7!skip
-plugins/modules/elasticache.py compile-3.5!skip
-plugins/modules/elasticache.py compile-3.6!skip
-plugins/modules/elasticache.py compile-3.7!skip
-plugins/modules/elasticache.py future-import-boilerplate!skip
-plugins/modules/elasticache.py import-2.6!skip
-plugins/modules/elasticache.py import-2.7!skip
-plugins/modules/elasticache.py import-3.5!skip
-plugins/modules/elasticache.py import-3.6!skip
-plugins/modules/elasticache.py import-3.7!skip
-plugins/modules/elasticache.py metaclass-boilerplate!skip
-plugins/modules/elasticache_info.py compile-2.6!skip
-plugins/modules/elasticache_info.py compile-2.7!skip
-plugins/modules/elasticache_info.py compile-3.5!skip
-plugins/modules/elasticache_info.py compile-3.6!skip
-plugins/modules/elasticache_info.py compile-3.7!skip
-plugins/modules/elasticache_info.py future-import-boilerplate!skip
-plugins/modules/elasticache_info.py import-2.6!skip
-plugins/modules/elasticache_info.py import-2.7!skip
-plugins/modules/elasticache_info.py import-3.5!skip
-plugins/modules/elasticache_info.py import-3.6!skip
-plugins/modules/elasticache_info.py import-3.7!skip
-plugins/modules/elasticache_info.py metaclass-boilerplate!skip
-plugins/modules/elasticache_parameter_group.py compile-2.6!skip
-plugins/modules/elasticache_parameter_group.py compile-2.7!skip
-plugins/modules/elasticache_parameter_group.py compile-3.5!skip
-plugins/modules/elasticache_parameter_group.py compile-3.6!skip
-plugins/modules/elasticache_parameter_group.py compile-3.7!skip
-plugins/modules/elasticache_parameter_group.py future-import-boilerplate!skip
-plugins/modules/elasticache_parameter_group.py import-2.6!skip
-plugins/modules/elasticache_parameter_group.py import-2.7!skip
-plugins/modules/elasticache_parameter_group.py import-3.5!skip
-plugins/modules/elasticache_parameter_group.py import-3.6!skip
-plugins/modules/elasticache_parameter_group.py import-3.7!skip
-plugins/modules/elasticache_parameter_group.py metaclass-boilerplate!skip
-plugins/modules/elasticache_snapshot.py compile-2.6!skip
-plugins/modules/elasticache_snapshot.py compile-2.7!skip
-plugins/modules/elasticache_snapshot.py compile-3.5!skip
-plugins/modules/elasticache_snapshot.py compile-3.6!skip
-plugins/modules/elasticache_snapshot.py compile-3.7!skip
-plugins/modules/elasticache_snapshot.py future-import-boilerplate!skip
-plugins/modules/elasticache_snapshot.py import-2.6!skip
-plugins/modules/elasticache_snapshot.py import-2.7!skip
-plugins/modules/elasticache_snapshot.py import-3.5!skip
-plugins/modules/elasticache_snapshot.py import-3.6!skip
-plugins/modules/elasticache_snapshot.py import-3.7!skip
-plugins/modules/elasticache_snapshot.py metaclass-boilerplate!skip
-plugins/modules/elasticache_subnet_group.py compile-2.6!skip
-plugins/modules/elasticache_subnet_group.py compile-2.7!skip
-plugins/modules/elasticache_subnet_group.py compile-3.5!skip
-plugins/modules/elasticache_subnet_group.py compile-3.6!skip
-plugins/modules/elasticache_subnet_group.py compile-3.7!skip
-plugins/modules/elasticache_subnet_group.py future-import-boilerplate!skip
-plugins/modules/elasticache_subnet_group.py import-2.6!skip
-plugins/modules/elasticache_subnet_group.py import-2.7!skip
-plugins/modules/elasticache_subnet_group.py import-3.5!skip
-plugins/modules/elasticache_subnet_group.py import-3.6!skip
-plugins/modules/elasticache_subnet_group.py import-3.7!skip
-plugins/modules/elasticache_subnet_group.py metaclass-boilerplate!skip
-plugins/modules/elb_application_lb.py compile-2.6!skip
-plugins/modules/elb_application_lb.py compile-2.7!skip
-plugins/modules/elb_application_lb.py compile-3.5!skip
-plugins/modules/elb_application_lb.py compile-3.6!skip
-plugins/modules/elb_application_lb.py compile-3.7!skip
-plugins/modules/elb_application_lb.py future-import-boilerplate!skip
-plugins/modules/elb_application_lb.py import-2.6!skip
-plugins/modules/elb_application_lb.py import-2.7!skip
-plugins/modules/elb_application_lb.py import-3.5!skip
-plugins/modules/elb_application_lb.py import-3.6!skip
-plugins/modules/elb_application_lb.py import-3.7!skip
-plugins/modules/elb_application_lb.py metaclass-boilerplate!skip
-plugins/modules/elb_application_lb_info.py compile-2.6!skip
-plugins/modules/elb_application_lb_info.py compile-2.7!skip
-plugins/modules/elb_application_lb_info.py compile-3.5!skip
-plugins/modules/elb_application_lb_info.py compile-3.6!skip
-plugins/modules/elb_application_lb_info.py compile-3.7!skip
-plugins/modules/elb_application_lb_info.py future-import-boilerplate!skip
-plugins/modules/elb_application_lb_info.py import-2.6!skip
-plugins/modules/elb_application_lb_info.py import-2.7!skip
-plugins/modules/elb_application_lb_info.py import-3.5!skip
-plugins/modules/elb_application_lb_info.py import-3.6!skip
-plugins/modules/elb_application_lb_info.py import-3.7!skip
-plugins/modules/elb_application_lb_info.py metaclass-boilerplate!skip
-plugins/modules/elb_classic_lb_info.py compile-2.6!skip
-plugins/modules/elb_classic_lb_info.py compile-2.7!skip
-plugins/modules/elb_classic_lb_info.py compile-3.5!skip
-plugins/modules/elb_classic_lb_info.py compile-3.6!skip
-plugins/modules/elb_classic_lb_info.py compile-3.7!skip
-plugins/modules/elb_classic_lb_info.py future-import-boilerplate!skip
-plugins/modules/elb_classic_lb_info.py import-2.6!skip
-plugins/modules/elb_classic_lb_info.py import-2.7!skip
-plugins/modules/elb_classic_lb_info.py import-3.5!skip
-plugins/modules/elb_classic_lb_info.py import-3.6!skip
-plugins/modules/elb_classic_lb_info.py import-3.7!skip
-plugins/modules/elb_classic_lb_info.py metaclass-boilerplate!skip
-plugins/modules/elb_instance.py compile-2.6!skip
-plugins/modules/elb_instance.py compile-2.7!skip
-plugins/modules/elb_instance.py compile-3.5!skip
-plugins/modules/elb_instance.py compile-3.6!skip
-plugins/modules/elb_instance.py compile-3.7!skip
-plugins/modules/elb_instance.py future-import-boilerplate!skip
-plugins/modules/elb_instance.py import-2.6!skip
-plugins/modules/elb_instance.py import-2.7!skip
-plugins/modules/elb_instance.py import-3.5!skip
-plugins/modules/elb_instance.py import-3.6!skip
-plugins/modules/elb_instance.py import-3.7!skip
-plugins/modules/elb_instance.py metaclass-boilerplate!skip
-plugins/modules/elb_network_lb.py compile-2.6!skip
-plugins/modules/elb_network_lb.py compile-2.7!skip
-plugins/modules/elb_network_lb.py compile-3.5!skip
-plugins/modules/elb_network_lb.py compile-3.6!skip
-plugins/modules/elb_network_lb.py compile-3.7!skip
-plugins/modules/elb_network_lb.py future-import-boilerplate!skip
-plugins/modules/elb_network_lb.py import-2.6!skip
-plugins/modules/elb_network_lb.py import-2.7!skip
-plugins/modules/elb_network_lb.py import-3.5!skip
-plugins/modules/elb_network_lb.py import-3.6!skip
-plugins/modules/elb_network_lb.py import-3.7!skip
-plugins/modules/elb_network_lb.py metaclass-boilerplate!skip
-plugins/modules/elb_target.py compile-2.6!skip
-plugins/modules/elb_target.py compile-2.7!skip
-plugins/modules/elb_target.py compile-3.5!skip
-plugins/modules/elb_target.py compile-3.6!skip
-plugins/modules/elb_target.py compile-3.7!skip
-plugins/modules/elb_target.py future-import-boilerplate!skip
-plugins/modules/elb_target.py import-2.6!skip
-plugins/modules/elb_target.py import-2.7!skip
-plugins/modules/elb_target.py import-3.5!skip
-plugins/modules/elb_target.py import-3.6!skip
-plugins/modules/elb_target.py import-3.7!skip
-plugins/modules/elb_target.py metaclass-boilerplate!skip
-plugins/modules/elb_target_group.py compile-2.6!skip
-plugins/modules/elb_target_group.py compile-2.7!skip
-plugins/modules/elb_target_group.py compile-3.5!skip
-plugins/modules/elb_target_group.py compile-3.6!skip
-plugins/modules/elb_target_group.py compile-3.7!skip
-plugins/modules/elb_target_group.py future-import-boilerplate!skip
-plugins/modules/elb_target_group.py import-2.6!skip
-plugins/modules/elb_target_group.py import-2.7!skip
-plugins/modules/elb_target_group.py import-3.5!skip
-plugins/modules/elb_target_group.py import-3.6!skip
-plugins/modules/elb_target_group.py import-3.7!skip
-plugins/modules/elb_target_group.py metaclass-boilerplate!skip
-plugins/modules/elb_target_group_info.py compile-2.6!skip
-plugins/modules/elb_target_group_info.py compile-2.7!skip
-plugins/modules/elb_target_group_info.py compile-3.5!skip
-plugins/modules/elb_target_group_info.py compile-3.6!skip
-plugins/modules/elb_target_group_info.py compile-3.7!skip
-plugins/modules/elb_target_group_info.py future-import-boilerplate!skip
-plugins/modules/elb_target_group_info.py import-2.6!skip
-plugins/modules/elb_target_group_info.py import-2.7!skip
-plugins/modules/elb_target_group_info.py import-3.5!skip
-plugins/modules/elb_target_group_info.py import-3.6!skip
-plugins/modules/elb_target_group_info.py import-3.7!skip
-plugins/modules/elb_target_group_info.py metaclass-boilerplate!skip
-plugins/modules/elb_target_info.py compile-2.6!skip
-plugins/modules/elb_target_info.py compile-2.7!skip
-plugins/modules/elb_target_info.py compile-3.5!skip
-plugins/modules/elb_target_info.py compile-3.6!skip
-plugins/modules/elb_target_info.py compile-3.7!skip
-plugins/modules/elb_target_info.py future-import-boilerplate!skip
-plugins/modules/elb_target_info.py import-2.6!skip
-plugins/modules/elb_target_info.py import-2.7!skip
-plugins/modules/elb_target_info.py import-3.5!skip
-plugins/modules/elb_target_info.py import-3.6!skip
-plugins/modules/elb_target_info.py import-3.7!skip
-plugins/modules/elb_target_info.py metaclass-boilerplate!skip
-plugins/modules/execute_lambda.py compile-2.6!skip
-plugins/modules/execute_lambda.py compile-2.7!skip
-plugins/modules/execute_lambda.py compile-3.5!skip
-plugins/modules/execute_lambda.py compile-3.6!skip
-plugins/modules/execute_lambda.py compile-3.7!skip
-plugins/modules/execute_lambda.py future-import-boilerplate!skip
-plugins/modules/execute_lambda.py import-2.6!skip
-plugins/modules/execute_lambda.py import-2.7!skip
-plugins/modules/execute_lambda.py import-3.5!skip
-plugins/modules/execute_lambda.py import-3.6!skip
-plugins/modules/execute_lambda.py import-3.7!skip
-plugins/modules/execute_lambda.py metaclass-boilerplate!skip
-plugins/modules/iam.py compile-2.6!skip
-plugins/modules/iam.py compile-2.7!skip
-plugins/modules/iam.py compile-3.5!skip
-plugins/modules/iam.py compile-3.6!skip
-plugins/modules/iam.py compile-3.7!skip
-plugins/modules/iam.py future-import-boilerplate!skip
-plugins/modules/iam.py import-2.6!skip
-plugins/modules/iam.py import-2.7!skip
-plugins/modules/iam.py import-3.5!skip
-plugins/modules/iam.py import-3.6!skip
-plugins/modules/iam.py import-3.7!skip
-plugins/modules/iam.py metaclass-boilerplate!skip
-plugins/modules/iam.py pylint:unnecessary-comprehension # iam.py is boto2 so any refactoring can get complex, also it does not have tests
-plugins/modules/iam_cert.py compile-2.6!skip
-plugins/modules/iam_cert.py compile-2.7!skip
-plugins/modules/iam_cert.py compile-3.5!skip
-plugins/modules/iam_cert.py compile-3.6!skip
-plugins/modules/iam_cert.py compile-3.7!skip
-plugins/modules/iam_cert.py future-import-boilerplate!skip
-plugins/modules/iam_cert.py import-2.6!skip
-plugins/modules/iam_cert.py import-2.7!skip
-plugins/modules/iam_cert.py import-3.5!skip
-plugins/modules/iam_cert.py import-3.6!skip
-plugins/modules/iam_cert.py import-3.7!skip
-plugins/modules/iam_cert.py metaclass-boilerplate!skip
-plugins/modules/iam_group.py compile-2.6!skip
-plugins/modules/iam_group.py compile-2.7!skip
-plugins/modules/iam_group.py compile-3.5!skip
-plugins/modules/iam_group.py compile-3.6!skip
-plugins/modules/iam_group.py compile-3.7!skip
-plugins/modules/iam_group.py future-import-boilerplate!skip
-plugins/modules/iam_group.py import-2.6!skip
-plugins/modules/iam_group.py import-2.7!skip
-plugins/modules/iam_group.py import-3.5!skip
-plugins/modules/iam_group.py import-3.6!skip
-plugins/modules/iam_group.py import-3.7!skip
-plugins/modules/iam_group.py metaclass-boilerplate!skip
-plugins/modules/iam_managed_policy.py compile-2.6!skip
-plugins/modules/iam_managed_policy.py compile-2.7!skip
-plugins/modules/iam_managed_policy.py compile-3.5!skip
-plugins/modules/iam_managed_policy.py compile-3.6!skip
-plugins/modules/iam_managed_policy.py compile-3.7!skip
-plugins/modules/iam_managed_policy.py future-import-boilerplate!skip
-plugins/modules/iam_managed_policy.py import-2.6!skip
-plugins/modules/iam_managed_policy.py import-2.7!skip
-plugins/modules/iam_managed_policy.py import-3.5!skip
-plugins/modules/iam_managed_policy.py import-3.6!skip
-plugins/modules/iam_managed_policy.py import-3.7!skip
-plugins/modules/iam_managed_policy.py metaclass-boilerplate!skip
-plugins/modules/iam_mfa_device_info.py compile-2.6!skip
-plugins/modules/iam_mfa_device_info.py compile-2.7!skip
-plugins/modules/iam_mfa_device_info.py compile-3.5!skip
-plugins/modules/iam_mfa_device_info.py compile-3.6!skip
-plugins/modules/iam_mfa_device_info.py compile-3.7!skip
-plugins/modules/iam_mfa_device_info.py future-import-boilerplate!skip
-plugins/modules/iam_mfa_device_info.py import-2.6!skip
-plugins/modules/iam_mfa_device_info.py import-2.7!skip
-plugins/modules/iam_mfa_device_info.py import-3.5!skip
-plugins/modules/iam_mfa_device_info.py import-3.6!skip
-plugins/modules/iam_mfa_device_info.py import-3.7!skip
-plugins/modules/iam_mfa_device_info.py metaclass-boilerplate!skip
-plugins/modules/iam_password_policy.py compile-2.6!skip
-plugins/modules/iam_password_policy.py compile-2.7!skip
-plugins/modules/iam_password_policy.py compile-3.5!skip
-plugins/modules/iam_password_policy.py compile-3.6!skip
-plugins/modules/iam_password_policy.py compile-3.7!skip
-plugins/modules/iam_password_policy.py future-import-boilerplate!skip
-plugins/modules/iam_password_policy.py import-2.6!skip
-plugins/modules/iam_password_policy.py import-2.7!skip
-plugins/modules/iam_password_policy.py import-3.5!skip
-plugins/modules/iam_password_policy.py import-3.6!skip
-plugins/modules/iam_password_policy.py import-3.7!skip
-plugins/modules/iam_password_policy.py metaclass-boilerplate!skip
-plugins/modules/iam_policy.py compile-2.6!skip
-plugins/modules/iam_policy.py compile-2.7!skip
-plugins/modules/iam_policy.py compile-3.5!skip
-plugins/modules/iam_policy.py compile-3.6!skip
-plugins/modules/iam_policy.py compile-3.7!skip
-plugins/modules/iam_policy.py future-import-boilerplate!skip
-plugins/modules/iam_policy.py import-2.6!skip
-plugins/modules/iam_policy.py import-2.7!skip
-plugins/modules/iam_policy.py import-3.5!skip
-plugins/modules/iam_policy.py import-3.6!skip
-plugins/modules/iam_policy.py import-3.7!skip
-plugins/modules/iam_policy.py metaclass-boilerplate!skip
-plugins/modules/iam_policy_info.py compile-2.6!skip
-plugins/modules/iam_policy_info.py compile-2.7!skip
-plugins/modules/iam_policy_info.py compile-3.5!skip
-plugins/modules/iam_policy_info.py compile-3.6!skip
-plugins/modules/iam_policy_info.py compile-3.7!skip
-plugins/modules/iam_policy_info.py future-import-boilerplate!skip
-plugins/modules/iam_policy_info.py import-2.6!skip
-plugins/modules/iam_policy_info.py import-2.7!skip
-plugins/modules/iam_policy_info.py import-3.5!skip
-plugins/modules/iam_policy_info.py import-3.6!skip
-plugins/modules/iam_policy_info.py import-3.7!skip
-plugins/modules/iam_policy_info.py metaclass-boilerplate!skip
-plugins/modules/iam_role.py compile-2.6!skip
-plugins/modules/iam_role.py compile-2.7!skip
-plugins/modules/iam_role.py compile-3.5!skip
-plugins/modules/iam_role.py compile-3.6!skip
-plugins/modules/iam_role.py compile-3.7!skip
-plugins/modules/iam_role.py future-import-boilerplate!skip
-plugins/modules/iam_role.py import-2.6!skip
-plugins/modules/iam_role.py import-2.7!skip
-plugins/modules/iam_role.py import-3.5!skip
-plugins/modules/iam_role.py import-3.6!skip
-plugins/modules/iam_role.py import-3.7!skip
-plugins/modules/iam_role.py metaclass-boilerplate!skip
-plugins/modules/iam_role_info.py compile-2.6!skip
-plugins/modules/iam_role_info.py compile-2.7!skip
-plugins/modules/iam_role_info.py compile-3.5!skip
-plugins/modules/iam_role_info.py compile-3.6!skip
-plugins/modules/iam_role_info.py compile-3.7!skip
-plugins/modules/iam_role_info.py future-import-boilerplate!skip
-plugins/modules/iam_role_info.py import-2.6!skip
-plugins/modules/iam_role_info.py import-2.7!skip
-plugins/modules/iam_role_info.py import-3.5!skip
-plugins/modules/iam_role_info.py import-3.6!skip
-plugins/modules/iam_role_info.py import-3.7!skip
-plugins/modules/iam_role_info.py metaclass-boilerplate!skip
-plugins/modules/iam_saml_federation.py compile-2.6!skip
-plugins/modules/iam_saml_federation.py compile-2.7!skip
-plugins/modules/iam_saml_federation.py compile-3.5!skip
-plugins/modules/iam_saml_federation.py compile-3.6!skip
-plugins/modules/iam_saml_federation.py compile-3.7!skip
-plugins/modules/iam_saml_federation.py future-import-boilerplate!skip
-plugins/modules/iam_saml_federation.py import-2.6!skip
-plugins/modules/iam_saml_federation.py import-2.7!skip
-plugins/modules/iam_saml_federation.py import-3.5!skip
-plugins/modules/iam_saml_federation.py import-3.6!skip
-plugins/modules/iam_saml_federation.py import-3.7!skip
-plugins/modules/iam_saml_federation.py metaclass-boilerplate!skip
-plugins/modules/iam_server_certificate_info.py compile-2.6!skip
-plugins/modules/iam_server_certificate_info.py compile-2.7!skip
-plugins/modules/iam_server_certificate_info.py compile-3.5!skip
-plugins/modules/iam_server_certificate_info.py compile-3.6!skip
-plugins/modules/iam_server_certificate_info.py compile-3.7!skip
-plugins/modules/iam_server_certificate_info.py future-import-boilerplate!skip
-plugins/modules/iam_server_certificate_info.py import-2.6!skip
-plugins/modules/iam_server_certificate_info.py import-2.7!skip
-plugins/modules/iam_server_certificate_info.py import-3.5!skip
-plugins/modules/iam_server_certificate_info.py import-3.6!skip
-plugins/modules/iam_server_certificate_info.py import-3.7!skip
-plugins/modules/iam_server_certificate_info.py metaclass-boilerplate!skip
-plugins/modules/iam_user.py compile-2.6!skip
-plugins/modules/iam_user.py compile-2.7!skip
-plugins/modules/iam_user.py compile-3.5!skip
-plugins/modules/iam_user.py compile-3.6!skip
-plugins/modules/iam_user.py compile-3.7!skip
-plugins/modules/iam_user.py future-import-boilerplate!skip
-plugins/modules/iam_user.py import-2.6!skip
-plugins/modules/iam_user.py import-2.7!skip
-plugins/modules/iam_user.py import-3.5!skip
-plugins/modules/iam_user.py import-3.6!skip
-plugins/modules/iam_user.py import-3.7!skip
-plugins/modules/iam_user.py metaclass-boilerplate!skip
-plugins/modules/iam_user_info.py compile-2.6!skip
-plugins/modules/iam_user_info.py compile-2.7!skip
-plugins/modules/iam_user_info.py compile-3.5!skip
-plugins/modules/iam_user_info.py compile-3.6!skip
-plugins/modules/iam_user_info.py compile-3.7!skip
-plugins/modules/iam_user_info.py future-import-boilerplate!skip
-plugins/modules/iam_user_info.py import-2.6!skip
-plugins/modules/iam_user_info.py import-2.7!skip
-plugins/modules/iam_user_info.py import-3.5!skip
-plugins/modules/iam_user_info.py import-3.6!skip
-plugins/modules/iam_user_info.py import-3.7!skip
-plugins/modules/iam_user_info.py metaclass-boilerplate!skip
-plugins/modules/kinesis_stream.py compile-2.6!skip
-plugins/modules/kinesis_stream.py compile-2.7!skip
-plugins/modules/kinesis_stream.py compile-3.5!skip
-plugins/modules/kinesis_stream.py compile-3.6!skip
-plugins/modules/kinesis_stream.py compile-3.7!skip
-plugins/modules/kinesis_stream.py future-import-boilerplate!skip
-plugins/modules/kinesis_stream.py import-2.6!skip
-plugins/modules/kinesis_stream.py import-2.7!skip
-plugins/modules/kinesis_stream.py import-3.5!skip
-plugins/modules/kinesis_stream.py import-3.6!skip
-plugins/modules/kinesis_stream.py import-3.7!skip
-plugins/modules/kinesis_stream.py metaclass-boilerplate!skip
-plugins/modules/lambda.py compile-2.6!skip
-plugins/modules/lambda.py compile-2.7!skip
-plugins/modules/lambda.py compile-3.5!skip
-plugins/modules/lambda.py compile-3.6!skip
-plugins/modules/lambda.py compile-3.7!skip
-plugins/modules/lambda.py future-import-boilerplate!skip
-plugins/modules/lambda.py import-2.6!skip
-plugins/modules/lambda.py import-2.7!skip
-plugins/modules/lambda.py import-3.5!skip
-plugins/modules/lambda.py import-3.6!skip
-plugins/modules/lambda.py import-3.7!skip
-plugins/modules/lambda.py metaclass-boilerplate!skip
-plugins/modules/lambda_alias.py compile-2.6!skip
-plugins/modules/lambda_alias.py compile-2.7!skip
-plugins/modules/lambda_alias.py compile-3.5!skip
-plugins/modules/lambda_alias.py compile-3.6!skip
-plugins/modules/lambda_alias.py compile-3.7!skip
-plugins/modules/lambda_alias.py future-import-boilerplate!skip
-plugins/modules/lambda_alias.py import-2.6!skip
-plugins/modules/lambda_alias.py import-2.7!skip
-plugins/modules/lambda_alias.py import-3.5!skip
-plugins/modules/lambda_alias.py import-3.6!skip
-plugins/modules/lambda_alias.py import-3.7!skip
-plugins/modules/lambda_alias.py metaclass-boilerplate!skip
-plugins/modules/lambda_event.py compile-2.6!skip
-plugins/modules/lambda_event.py compile-2.7!skip
-plugins/modules/lambda_event.py compile-3.5!skip
-plugins/modules/lambda_event.py compile-3.6!skip
-plugins/modules/lambda_event.py compile-3.7!skip
-plugins/modules/lambda_event.py future-import-boilerplate!skip
-plugins/modules/lambda_event.py import-2.6!skip
-plugins/modules/lambda_event.py import-2.7!skip
-plugins/modules/lambda_event.py import-3.5!skip
-plugins/modules/lambda_event.py import-3.6!skip
-plugins/modules/lambda_event.py import-3.7!skip
-plugins/modules/lambda_event.py metaclass-boilerplate!skip
-plugins/modules/lambda_facts.py compile-2.6!skip
-plugins/modules/lambda_facts.py compile-2.7!skip
-plugins/modules/lambda_facts.py compile-3.5!skip
-plugins/modules/lambda_facts.py compile-3.6!skip
-plugins/modules/lambda_facts.py compile-3.7!skip
-plugins/modules/lambda_facts.py future-import-boilerplate!skip
-plugins/modules/lambda_facts.py import-2.6!skip
-plugins/modules/lambda_facts.py import-2.7!skip
-plugins/modules/lambda_facts.py import-3.5!skip
-plugins/modules/lambda_facts.py import-3.6!skip
-plugins/modules/lambda_facts.py import-3.7!skip
-plugins/modules/lambda_facts.py metaclass-boilerplate!skip
-plugins/modules/lambda_info.py compile-2.6!skip
-plugins/modules/lambda_info.py compile-2.7!skip
-plugins/modules/lambda_info.py compile-3.5!skip
-plugins/modules/lambda_info.py compile-3.6!skip
-plugins/modules/lambda_info.py compile-3.7!skip
-plugins/modules/lambda_info.py future-import-boilerplate!skip
-plugins/modules/lambda_info.py import-2.6!skip
-plugins/modules/lambda_info.py import-2.7!skip
-plugins/modules/lambda_info.py import-3.5!skip
-plugins/modules/lambda_info.py import-3.6!skip
-plugins/modules/lambda_info.py import-3.7!skip
-plugins/modules/lambda_info.py metaclass-boilerplate!skip
-plugins/modules/lambda_policy.py compile-2.6!skip
-plugins/modules/lambda_policy.py compile-2.7!skip
-plugins/modules/lambda_policy.py compile-3.5!skip
-plugins/modules/lambda_policy.py compile-3.6!skip
-plugins/modules/lambda_policy.py compile-3.7!skip
-plugins/modules/lambda_policy.py future-import-boilerplate!skip
-plugins/modules/lambda_policy.py import-2.6!skip
-plugins/modules/lambda_policy.py import-2.7!skip
-plugins/modules/lambda_policy.py import-3.5!skip
-plugins/modules/lambda_policy.py import-3.6!skip
-plugins/modules/lambda_policy.py import-3.7!skip
-plugins/modules/lambda_policy.py metaclass-boilerplate!skip
-plugins/modules/lightsail.py compile-2.6!skip
-plugins/modules/lightsail.py compile-2.7!skip
-plugins/modules/lightsail.py compile-3.5!skip
-plugins/modules/lightsail.py compile-3.6!skip
-plugins/modules/lightsail.py compile-3.7!skip
-plugins/modules/lightsail.py future-import-boilerplate!skip
-plugins/modules/lightsail.py import-2.6!skip
-plugins/modules/lightsail.py import-2.7!skip
-plugins/modules/lightsail.py import-3.5!skip
-plugins/modules/lightsail.py import-3.6!skip
-plugins/modules/lightsail.py import-3.7!skip
-plugins/modules/lightsail.py metaclass-boilerplate!skip
-plugins/modules/rds.py compile-2.6!skip
-plugins/modules/rds.py compile-2.7!skip
-plugins/modules/rds.py compile-3.5!skip
-plugins/modules/rds.py compile-3.6!skip
-plugins/modules/rds.py compile-3.7!skip
-plugins/modules/rds.py future-import-boilerplate!skip
-plugins/modules/rds.py import-2.6!skip
-plugins/modules/rds.py import-2.7!skip
-plugins/modules/rds.py import-3.5!skip
-plugins/modules/rds.py import-3.6!skip
-plugins/modules/rds.py import-3.7!skip
-plugins/modules/rds.py metaclass-boilerplate!skip
-plugins/modules/rds_instance.py compile-2.6!skip
-plugins/modules/rds_instance.py compile-2.7!skip
-plugins/modules/rds_instance.py compile-3.5!skip
-plugins/modules/rds_instance.py compile-3.6!skip
-plugins/modules/rds_instance.py compile-3.7!skip
-plugins/modules/rds_instance.py future-import-boilerplate!skip
-plugins/modules/rds_instance.py import-2.6!skip
-plugins/modules/rds_instance.py import-2.7!skip
-plugins/modules/rds_instance.py import-3.5!skip
-plugins/modules/rds_instance.py import-3.6!skip
-plugins/modules/rds_instance.py import-3.7!skip
-plugins/modules/rds_instance.py metaclass-boilerplate!skip
-plugins/modules/rds_instance_info.py compile-2.6!skip
-plugins/modules/rds_instance_info.py compile-2.7!skip
-plugins/modules/rds_instance_info.py compile-3.5!skip
-plugins/modules/rds_instance_info.py compile-3.6!skip
-plugins/modules/rds_instance_info.py compile-3.7!skip
-plugins/modules/rds_instance_info.py future-import-boilerplate!skip
-plugins/modules/rds_instance_info.py import-2.6!skip
-plugins/modules/rds_instance_info.py import-2.7!skip
-plugins/modules/rds_instance_info.py import-3.5!skip
-plugins/modules/rds_instance_info.py import-3.6!skip
-plugins/modules/rds_instance_info.py import-3.7!skip
-plugins/modules/rds_instance_info.py metaclass-boilerplate!skip
-plugins/modules/rds_param_group.py compile-2.6!skip
-plugins/modules/rds_param_group.py compile-2.7!skip
-plugins/modules/rds_param_group.py compile-3.5!skip
-plugins/modules/rds_param_group.py compile-3.6!skip
-plugins/modules/rds_param_group.py compile-3.7!skip
-plugins/modules/rds_param_group.py future-import-boilerplate!skip
-plugins/modules/rds_param_group.py import-2.6!skip
-plugins/modules/rds_param_group.py import-2.7!skip
-plugins/modules/rds_param_group.py import-3.5!skip
-plugins/modules/rds_param_group.py import-3.6!skip
-plugins/modules/rds_param_group.py import-3.7!skip
-plugins/modules/rds_param_group.py metaclass-boilerplate!skip
-plugins/modules/rds_snapshot.py compile-2.6!skip
-plugins/modules/rds_snapshot.py compile-2.7!skip
-plugins/modules/rds_snapshot.py compile-3.5!skip
-plugins/modules/rds_snapshot.py compile-3.6!skip
-plugins/modules/rds_snapshot.py compile-3.7!skip
-plugins/modules/rds_snapshot.py future-import-boilerplate!skip
-plugins/modules/rds_snapshot.py import-2.6!skip
-plugins/modules/rds_snapshot.py import-2.7!skip
-plugins/modules/rds_snapshot.py import-3.5!skip
-plugins/modules/rds_snapshot.py import-3.6!skip
-plugins/modules/rds_snapshot.py import-3.7!skip
-plugins/modules/rds_snapshot.py metaclass-boilerplate!skip
-plugins/modules/rds_snapshot_info.py compile-2.6!skip
-plugins/modules/rds_snapshot_info.py compile-2.7!skip
-plugins/modules/rds_snapshot_info.py compile-3.5!skip
-plugins/modules/rds_snapshot_info.py compile-3.6!skip
-plugins/modules/rds_snapshot_info.py compile-3.7!skip
-plugins/modules/rds_snapshot_info.py future-import-boilerplate!skip
-plugins/modules/rds_snapshot_info.py import-2.6!skip
-plugins/modules/rds_snapshot_info.py import-2.7!skip
-plugins/modules/rds_snapshot_info.py import-3.5!skip
-plugins/modules/rds_snapshot_info.py import-3.6!skip
-plugins/modules/rds_snapshot_info.py import-3.7!skip
-plugins/modules/rds_snapshot_info.py metaclass-boilerplate!skip
-plugins/modules/rds_subnet_group.py compile-2.6!skip
-plugins/modules/rds_subnet_group.py compile-2.7!skip
-plugins/modules/rds_subnet_group.py compile-3.5!skip
-plugins/modules/rds_subnet_group.py compile-3.6!skip
-plugins/modules/rds_subnet_group.py compile-3.7!skip
-plugins/modules/rds_subnet_group.py future-import-boilerplate!skip
-plugins/modules/rds_subnet_group.py import-2.6!skip
-plugins/modules/rds_subnet_group.py import-2.7!skip
-plugins/modules/rds_subnet_group.py import-3.5!skip
-plugins/modules/rds_subnet_group.py import-3.6!skip
-plugins/modules/rds_subnet_group.py import-3.7!skip
-plugins/modules/rds_subnet_group.py metaclass-boilerplate!skip
-plugins/modules/redshift.py compile-2.6!skip
-plugins/modules/redshift.py compile-2.7!skip
-plugins/modules/redshift.py compile-3.5!skip
-plugins/modules/redshift.py compile-3.6!skip
-plugins/modules/redshift.py compile-3.7!skip
-plugins/modules/redshift.py future-import-boilerplate!skip
-plugins/modules/redshift.py import-2.6!skip
-plugins/modules/redshift.py import-2.7!skip
-plugins/modules/redshift.py import-3.5!skip
-plugins/modules/redshift.py import-3.6!skip
-plugins/modules/redshift.py import-3.7!skip
-plugins/modules/redshift.py metaclass-boilerplate!skip
-plugins/modules/redshift_cross_region_snapshots.py compile-2.6!skip
-plugins/modules/redshift_cross_region_snapshots.py compile-2.7!skip
-plugins/modules/redshift_cross_region_snapshots.py compile-3.5!skip
-plugins/modules/redshift_cross_region_snapshots.py compile-3.6!skip
-plugins/modules/redshift_cross_region_snapshots.py compile-3.7!skip
-plugins/modules/redshift_cross_region_snapshots.py future-import-boilerplate!skip
-plugins/modules/redshift_cross_region_snapshots.py import-2.6!skip
-plugins/modules/redshift_cross_region_snapshots.py import-2.7!skip
-plugins/modules/redshift_cross_region_snapshots.py import-3.5!skip
-plugins/modules/redshift_cross_region_snapshots.py import-3.6!skip
-plugins/modules/redshift_cross_region_snapshots.py import-3.7!skip
-plugins/modules/redshift_cross_region_snapshots.py metaclass-boilerplate!skip
-plugins/modules/redshift_info.py compile-2.6!skip
-plugins/modules/redshift_info.py compile-2.7!skip
-plugins/modules/redshift_info.py compile-3.5!skip
-plugins/modules/redshift_info.py compile-3.6!skip
-plugins/modules/redshift_info.py compile-3.7!skip
-plugins/modules/redshift_info.py future-import-boilerplate!skip
-plugins/modules/redshift_info.py import-2.6!skip
-plugins/modules/redshift_info.py import-2.7!skip
-plugins/modules/redshift_info.py import-3.5!skip
-plugins/modules/redshift_info.py import-3.6!skip
-plugins/modules/redshift_info.py import-3.7!skip
-plugins/modules/redshift_info.py metaclass-boilerplate!skip
-plugins/modules/redshift_subnet_group.py compile-2.6!skip
-plugins/modules/redshift_subnet_group.py compile-2.7!skip
-plugins/modules/redshift_subnet_group.py compile-3.5!skip
-plugins/modules/redshift_subnet_group.py compile-3.6!skip
-plugins/modules/redshift_subnet_group.py compile-3.7!skip
-plugins/modules/redshift_subnet_group.py future-import-boilerplate!skip
-plugins/modules/redshift_subnet_group.py import-2.6!skip
-plugins/modules/redshift_subnet_group.py import-2.7!skip
-plugins/modules/redshift_subnet_group.py import-3.5!skip
-plugins/modules/redshift_subnet_group.py import-3.6!skip
-plugins/modules/redshift_subnet_group.py import-3.7!skip
-plugins/modules/redshift_subnet_group.py metaclass-boilerplate!skip
-plugins/modules/route53.py compile-2.6!skip
-plugins/modules/route53.py compile-2.7!skip
-plugins/modules/route53.py compile-3.5!skip
-plugins/modules/route53.py compile-3.6!skip
-plugins/modules/route53.py compile-3.7!skip
-plugins/modules/route53.py future-import-boilerplate!skip
-plugins/modules/route53.py import-2.6!skip
-plugins/modules/route53.py import-2.7!skip
-plugins/modules/route53.py import-3.5!skip
-plugins/modules/route53.py import-3.6!skip
-plugins/modules/route53.py import-3.7!skip
-plugins/modules/route53.py metaclass-boilerplate!skip
-plugins/modules/route53.py validate-modules:parameter-state-invalid-choice
-plugins/modules/route53_health_check.py compile-2.6!skip
-plugins/modules/route53_health_check.py compile-2.7!skip
-plugins/modules/route53_health_check.py compile-3.5!skip
-plugins/modules/route53_health_check.py compile-3.6!skip
-plugins/modules/route53_health_check.py compile-3.7!skip
-plugins/modules/route53_health_check.py future-import-boilerplate!skip
-plugins/modules/route53_health_check.py import-2.6!skip
-plugins/modules/route53_health_check.py import-2.7!skip
-plugins/modules/route53_health_check.py import-3.5!skip
-plugins/modules/route53_health_check.py import-3.6!skip
-plugins/modules/route53_health_check.py import-3.7!skip
-plugins/modules/route53_health_check.py metaclass-boilerplate!skip
-plugins/modules/route53_info.py compile-2.6!skip
-plugins/modules/route53_info.py compile-2.7!skip
-plugins/modules/route53_info.py compile-3.5!skip
-plugins/modules/route53_info.py compile-3.6!skip
-plugins/modules/route53_info.py compile-3.7!skip
-plugins/modules/route53_info.py future-import-boilerplate!skip
-plugins/modules/route53_info.py import-2.6!skip
-plugins/modules/route53_info.py import-2.7!skip
-plugins/modules/route53_info.py import-3.5!skip
-plugins/modules/route53_info.py import-3.6!skip
-plugins/modules/route53_info.py import-3.7!skip
-plugins/modules/route53_info.py metaclass-boilerplate!skip
-plugins/modules/route53_zone.py compile-2.6!skip
-plugins/modules/route53_zone.py compile-2.7!skip
-plugins/modules/route53_zone.py compile-3.5!skip
-plugins/modules/route53_zone.py compile-3.6!skip
-plugins/modules/route53_zone.py compile-3.7!skip
-plugins/modules/route53_zone.py future-import-boilerplate!skip
-plugins/modules/route53_zone.py import-2.6!skip
-plugins/modules/route53_zone.py import-2.7!skip
-plugins/modules/route53_zone.py import-3.5!skip
-plugins/modules/route53_zone.py import-3.6!skip
-plugins/modules/route53_zone.py import-3.7!skip
-plugins/modules/route53_zone.py metaclass-boilerplate!skip
-plugins/modules/s3_bucket_notification.py compile-2.6!skip
-plugins/modules/s3_bucket_notification.py compile-2.7!skip
-plugins/modules/s3_bucket_notification.py compile-3.5!skip
-plugins/modules/s3_bucket_notification.py compile-3.6!skip
-plugins/modules/s3_bucket_notification.py compile-3.7!skip
-plugins/modules/s3_bucket_notification.py future-import-boilerplate!skip
-plugins/modules/s3_bucket_notification.py import-2.6!skip
-plugins/modules/s3_bucket_notification.py import-2.7!skip
-plugins/modules/s3_bucket_notification.py import-3.5!skip
-plugins/modules/s3_bucket_notification.py import-3.6!skip
-plugins/modules/s3_bucket_notification.py import-3.7!skip
-plugins/modules/s3_bucket_notification.py metaclass-boilerplate!skip
-plugins/modules/s3_lifecycle.py compile-2.6!skip
-plugins/modules/s3_lifecycle.py compile-2.7!skip
-plugins/modules/s3_lifecycle.py compile-3.5!skip
-plugins/modules/s3_lifecycle.py compile-3.6!skip
-plugins/modules/s3_lifecycle.py compile-3.7!skip
-plugins/modules/s3_lifecycle.py future-import-boilerplate!skip
-plugins/modules/s3_lifecycle.py import-2.6!skip
-plugins/modules/s3_lifecycle.py import-2.7!skip
-plugins/modules/s3_lifecycle.py import-3.5!skip
-plugins/modules/s3_lifecycle.py import-3.6!skip
-plugins/modules/s3_lifecycle.py import-3.7!skip
-plugins/modules/s3_lifecycle.py metaclass-boilerplate!skip
-plugins/modules/s3_logging.py compile-2.6!skip
-plugins/modules/s3_logging.py compile-2.7!skip
-plugins/modules/s3_logging.py compile-3.5!skip
-plugins/modules/s3_logging.py compile-3.6!skip
-plugins/modules/s3_logging.py compile-3.7!skip
-plugins/modules/s3_logging.py future-import-boilerplate!skip
-plugins/modules/s3_logging.py import-2.6!skip
-plugins/modules/s3_logging.py import-2.7!skip
-plugins/modules/s3_logging.py import-3.5!skip
-plugins/modules/s3_logging.py import-3.6!skip
-plugins/modules/s3_logging.py import-3.7!skip
-plugins/modules/s3_logging.py metaclass-boilerplate!skip
-plugins/modules/s3_metrics_configuration.py compile-2.6!skip
-plugins/modules/s3_metrics_configuration.py compile-2.7!skip
-plugins/modules/s3_metrics_configuration.py compile-3.5!skip
-plugins/modules/s3_metrics_configuration.py compile-3.6!skip
-plugins/modules/s3_metrics_configuration.py compile-3.7!skip
-plugins/modules/s3_metrics_configuration.py future-import-boilerplate!skip
-plugins/modules/s3_metrics_configuration.py import-2.6!skip
-plugins/modules/s3_metrics_configuration.py import-2.7!skip
-plugins/modules/s3_metrics_configuration.py import-3.5!skip
-plugins/modules/s3_metrics_configuration.py import-3.6!skip
-plugins/modules/s3_metrics_configuration.py import-3.7!skip
-plugins/modules/s3_metrics_configuration.py metaclass-boilerplate!skip
-plugins/modules/s3_sync.py compile-2.6!skip
-plugins/modules/s3_sync.py compile-2.7!skip
-plugins/modules/s3_sync.py compile-3.5!skip
-plugins/modules/s3_sync.py compile-3.6!skip
-plugins/modules/s3_sync.py compile-3.7!skip
-plugins/modules/s3_sync.py future-import-boilerplate!skip
-plugins/modules/s3_sync.py import-2.6!skip
-plugins/modules/s3_sync.py import-2.7!skip
-plugins/modules/s3_sync.py import-3.5!skip
-plugins/modules/s3_sync.py import-3.6!skip
-plugins/modules/s3_sync.py import-3.7!skip
-plugins/modules/s3_sync.py metaclass-boilerplate!skip
-plugins/modules/s3_website.py compile-2.6!skip
-plugins/modules/s3_website.py compile-2.7!skip
-plugins/modules/s3_website.py compile-3.5!skip
-plugins/modules/s3_website.py compile-3.6!skip
-plugins/modules/s3_website.py compile-3.7!skip
-plugins/modules/s3_website.py future-import-boilerplate!skip
-plugins/modules/s3_website.py import-2.6!skip
-plugins/modules/s3_website.py import-2.7!skip
-plugins/modules/s3_website.py import-3.5!skip
-plugins/modules/s3_website.py import-3.6!skip
-plugins/modules/s3_website.py import-3.7!skip
-plugins/modules/s3_website.py metaclass-boilerplate!skip
-plugins/modules/sns.py compile-2.6!skip
-plugins/modules/sns.py compile-2.7!skip
-plugins/modules/sns.py compile-3.5!skip
-plugins/modules/sns.py compile-3.6!skip
-plugins/modules/sns.py compile-3.7!skip
-plugins/modules/sns.py future-import-boilerplate!skip
-plugins/modules/sns.py import-2.6!skip
-plugins/modules/sns.py import-2.7!skip
-plugins/modules/sns.py import-3.5!skip
-plugins/modules/sns.py import-3.6!skip
-plugins/modules/sns.py import-3.7!skip
-plugins/modules/sns.py metaclass-boilerplate!skip
-plugins/modules/sns_topic.py compile-2.6!skip
-plugins/modules/sns_topic.py compile-2.7!skip
-plugins/modules/sns_topic.py compile-3.5!skip
-plugins/modules/sns_topic.py compile-3.6!skip
-plugins/modules/sns_topic.py compile-3.7!skip
-plugins/modules/sns_topic.py future-import-boilerplate!skip
-plugins/modules/sns_topic.py import-2.6!skip
-plugins/modules/sns_topic.py import-2.7!skip
-plugins/modules/sns_topic.py import-3.5!skip
-plugins/modules/sns_topic.py import-3.6!skip
-plugins/modules/sns_topic.py import-3.7!skip
-plugins/modules/sns_topic.py metaclass-boilerplate!skip
-plugins/modules/sqs_queue.py compile-2.6!skip
-plugins/modules/sqs_queue.py compile-2.7!skip
-plugins/modules/sqs_queue.py compile-3.5!skip
-plugins/modules/sqs_queue.py compile-3.6!skip
-plugins/modules/sqs_queue.py compile-3.7!skip
-plugins/modules/sqs_queue.py future-import-boilerplate!skip
-plugins/modules/sqs_queue.py import-2.6!skip
-plugins/modules/sqs_queue.py import-2.7!skip
-plugins/modules/sqs_queue.py import-3.5!skip
-plugins/modules/sqs_queue.py import-3.6!skip
-plugins/modules/sqs_queue.py import-3.7!skip
-plugins/modules/sqs_queue.py metaclass-boilerplate!skip
-plugins/modules/sts_assume_role.py compile-2.6!skip
-plugins/modules/sts_assume_role.py compile-2.7!skip
-plugins/modules/sts_assume_role.py compile-3.5!skip
-plugins/modules/sts_assume_role.py compile-3.6!skip
-plugins/modules/sts_assume_role.py compile-3.7!skip
-plugins/modules/sts_assume_role.py future-import-boilerplate!skip
-plugins/modules/sts_assume_role.py import-2.6!skip
-plugins/modules/sts_assume_role.py import-2.7!skip
-plugins/modules/sts_assume_role.py import-3.5!skip
-plugins/modules/sts_assume_role.py import-3.6!skip
-plugins/modules/sts_assume_role.py import-3.7!skip
-plugins/modules/sts_assume_role.py metaclass-boilerplate!skip
-plugins/modules/sts_session_token.py compile-2.6!skip
-plugins/modules/sts_session_token.py compile-2.7!skip
-plugins/modules/sts_session_token.py compile-3.5!skip
-plugins/modules/sts_session_token.py compile-3.6!skip
-plugins/modules/sts_session_token.py compile-3.7!skip
-plugins/modules/sts_session_token.py future-import-boilerplate!skip
-plugins/modules/sts_session_token.py import-2.6!skip
-plugins/modules/sts_session_token.py import-2.7!skip
-plugins/modules/sts_session_token.py import-3.5!skip
-plugins/modules/sts_session_token.py import-3.6!skip
-plugins/modules/sts_session_token.py import-3.7!skip
-plugins/modules/sts_session_token.py metaclass-boilerplate!skip
-plugins/modules/wafv2_ip_set.py compile-2.6!skip
-plugins/modules/wafv2_ip_set.py compile-2.7!skip
-plugins/modules/wafv2_ip_set.py compile-3.5!skip
-plugins/modules/wafv2_ip_set.py compile-3.6!skip
-plugins/modules/wafv2_ip_set.py compile-3.7!skip
-plugins/modules/wafv2_ip_set.py future-import-boilerplate!skip
-plugins/modules/wafv2_ip_set.py import-2.6!skip
-plugins/modules/wafv2_ip_set.py import-2.7!skip
-plugins/modules/wafv2_ip_set.py import-3.5!skip
-plugins/modules/wafv2_ip_set.py import-3.6!skip
-plugins/modules/wafv2_ip_set.py import-3.7!skip
-plugins/modules/wafv2_ip_set.py metaclass-boilerplate!skip
-plugins/modules/wafv2_ip_set_info.py compile-2.6!skip
-plugins/modules/wafv2_ip_set_info.py compile-2.7!skip
-plugins/modules/wafv2_ip_set_info.py compile-3.5!skip
-plugins/modules/wafv2_ip_set_info.py compile-3.6!skip
-plugins/modules/wafv2_ip_set_info.py compile-3.7!skip
-plugins/modules/wafv2_ip_set_info.py future-import-boilerplate!skip
-plugins/modules/wafv2_ip_set_info.py import-2.6!skip
-plugins/modules/wafv2_ip_set_info.py import-2.7!skip
-plugins/modules/wafv2_ip_set_info.py import-3.5!skip
-plugins/modules/wafv2_ip_set_info.py import-3.6!skip
-plugins/modules/wafv2_ip_set_info.py import-3.7!skip
-plugins/modules/wafv2_ip_set_info.py metaclass-boilerplate!skip
-plugins/modules/wafv2_resources.py compile-2.6!skip
-plugins/modules/wafv2_resources.py compile-2.7!skip
-plugins/modules/wafv2_resources.py compile-3.5!skip
-plugins/modules/wafv2_resources.py compile-3.6!skip
-plugins/modules/wafv2_resources.py compile-3.7!skip
-plugins/modules/wafv2_resources.py future-import-boilerplate!skip
-plugins/modules/wafv2_resources.py import-2.6!skip
-plugins/modules/wafv2_resources.py import-2.7!skip
-plugins/modules/wafv2_resources.py import-3.5!skip
-plugins/modules/wafv2_resources.py import-3.6!skip
-plugins/modules/wafv2_resources.py import-3.7!skip
-plugins/modules/wafv2_resources.py metaclass-boilerplate!skip
-plugins/modules/wafv2_resources_info.py compile-2.6!skip
-plugins/modules/wafv2_resources_info.py compile-2.7!skip
-plugins/modules/wafv2_resources_info.py compile-3.5!skip
-plugins/modules/wafv2_resources_info.py compile-3.6!skip
-plugins/modules/wafv2_resources_info.py compile-3.7!skip
-plugins/modules/wafv2_resources_info.py future-import-boilerplate!skip
-plugins/modules/wafv2_resources_info.py import-2.6!skip
-plugins/modules/wafv2_resources_info.py import-2.7!skip
-plugins/modules/wafv2_resources_info.py import-3.5!skip
-plugins/modules/wafv2_resources_info.py import-3.6!skip
-plugins/modules/wafv2_resources_info.py import-3.7!skip
-plugins/modules/wafv2_resources_info.py metaclass-boilerplate!skip
-plugins/modules/wafv2_rule_group.py compile-2.6!skip
-plugins/modules/wafv2_rule_group.py compile-2.7!skip
-plugins/modules/wafv2_rule_group.py compile-3.5!skip
-plugins/modules/wafv2_rule_group.py compile-3.6!skip
-plugins/modules/wafv2_rule_group.py compile-3.7!skip
-plugins/modules/wafv2_rule_group.py future-import-boilerplate!skip
-plugins/modules/wafv2_rule_group.py import-2.6!skip
-plugins/modules/wafv2_rule_group.py import-2.7!skip
-plugins/modules/wafv2_rule_group.py import-3.5!skip
-plugins/modules/wafv2_rule_group.py import-3.6!skip
-plugins/modules/wafv2_rule_group.py import-3.7!skip
-plugins/modules/wafv2_rule_group.py metaclass-boilerplate!skip
-plugins/modules/wafv2_rule_group_info.py compile-2.6!skip
-plugins/modules/wafv2_rule_group_info.py compile-2.7!skip
-plugins/modules/wafv2_rule_group_info.py compile-3.5!skip
-plugins/modules/wafv2_rule_group_info.py compile-3.6!skip
-plugins/modules/wafv2_rule_group_info.py compile-3.7!skip
-plugins/modules/wafv2_rule_group_info.py future-import-boilerplate!skip
-plugins/modules/wafv2_rule_group_info.py import-2.6!skip
-plugins/modules/wafv2_rule_group_info.py import-2.7!skip
-plugins/modules/wafv2_rule_group_info.py import-3.5!skip
-plugins/modules/wafv2_rule_group_info.py import-3.6!skip
-plugins/modules/wafv2_rule_group_info.py import-3.7!skip
-plugins/modules/wafv2_rule_group_info.py metaclass-boilerplate!skip
-plugins/modules/wafv2_web_acl.py compile-2.6!skip
-plugins/modules/wafv2_web_acl.py compile-2.7!skip
-plugins/modules/wafv2_web_acl.py compile-3.5!skip
-plugins/modules/wafv2_web_acl.py compile-3.6!skip
-plugins/modules/wafv2_web_acl.py compile-3.7!skip
-plugins/modules/wafv2_web_acl.py future-import-boilerplate!skip
-plugins/modules/wafv2_web_acl.py import-2.6!skip
-plugins/modules/wafv2_web_acl.py import-2.7!skip
-plugins/modules/wafv2_web_acl.py import-3.5!skip
-plugins/modules/wafv2_web_acl.py import-3.6!skip
-plugins/modules/wafv2_web_acl.py import-3.7!skip
-plugins/modules/wafv2_web_acl.py metaclass-boilerplate!skip
-plugins/modules/wafv2_web_acl_info.py compile-2.6!skip
-plugins/modules/wafv2_web_acl_info.py compile-2.7!skip
-plugins/modules/wafv2_web_acl_info.py compile-3.5!skip
-plugins/modules/wafv2_web_acl_info.py compile-3.6!skip
-plugins/modules/wafv2_web_acl_info.py compile-3.7!skip
-plugins/modules/wafv2_web_acl_info.py future-import-boilerplate!skip
-plugins/modules/wafv2_web_acl_info.py import-2.6!skip
-plugins/modules/wafv2_web_acl_info.py import-2.7!skip
-plugins/modules/wafv2_web_acl_info.py import-3.5!skip
-plugins/modules/wafv2_web_acl_info.py import-3.6!skip
-plugins/modules/wafv2_web_acl_info.py import-3.7!skip
-plugins/modules/wafv2_web_acl_info.py metaclass-boilerplate!skip
-tests/sanity/refresh_ignore_files shebang!skip
+plugins/modules/cloudfront_info.py pylint:unnecessary-comprehension # (new test) Should be an easy fix, but testing is a challenge - test are broken and aliases require a wildcard cert in ACM
+plugins/modules/iam.py pylint:unnecessary-comprehension # no tests and module is deprecated
+plugins/modules/route53.py validate-modules:parameter-state-invalid-choice # route53_info needs improvements before we can deprecate this
diff --git a/tests/sanity/ignore-2.12.txt b/tests/sanity/ignore-2.12.txt
index a00e429fe2e..e5bade76474 100644
--- a/tests/sanity/ignore-2.12.txt
+++ b/tests/sanity/ignore-2.12.txt
@@ -1,2164 +1,3 @@
-plugins/modules/__init__.py compile-2.6!skip
-plugins/modules/__init__.py compile-2.7!skip
-plugins/modules/__init__.py compile-3.5!skip
-plugins/modules/__init__.py compile-3.6!skip
-plugins/modules/__init__.py compile-3.7!skip
-plugins/modules/__init__.py future-import-boilerplate!skip
-plugins/modules/__init__.py import-2.6!skip
-plugins/modules/__init__.py import-2.7!skip
-plugins/modules/__init__.py import-3.5!skip
-plugins/modules/__init__.py import-3.6!skip
-plugins/modules/__init__.py import-3.7!skip
-plugins/modules/__init__.py metaclass-boilerplate!skip
-plugins/modules/aws_acm.py compile-2.6!skip
-plugins/modules/aws_acm.py compile-2.7!skip
-plugins/modules/aws_acm.py compile-3.5!skip
-plugins/modules/aws_acm.py compile-3.6!skip
-plugins/modules/aws_acm.py compile-3.7!skip
-plugins/modules/aws_acm.py future-import-boilerplate!skip
-plugins/modules/aws_acm.py import-2.6!skip
-plugins/modules/aws_acm.py import-2.7!skip
-plugins/modules/aws_acm.py import-3.5!skip
-plugins/modules/aws_acm.py import-3.6!skip
-plugins/modules/aws_acm.py import-3.7!skip
-plugins/modules/aws_acm.py metaclass-boilerplate!skip
-plugins/modules/aws_acm_info.py compile-2.6!skip
-plugins/modules/aws_acm_info.py compile-2.7!skip
-plugins/modules/aws_acm_info.py compile-3.5!skip
-plugins/modules/aws_acm_info.py compile-3.6!skip
-plugins/modules/aws_acm_info.py compile-3.7!skip
-plugins/modules/aws_acm_info.py future-import-boilerplate!skip
-plugins/modules/aws_acm_info.py import-2.6!skip
-plugins/modules/aws_acm_info.py import-2.7!skip
-plugins/modules/aws_acm_info.py import-3.5!skip
-plugins/modules/aws_acm_info.py import-3.6!skip
-plugins/modules/aws_acm_info.py import-3.7!skip
-plugins/modules/aws_acm_info.py metaclass-boilerplate!skip
-plugins/modules/aws_api_gateway.py compile-2.6!skip
-plugins/modules/aws_api_gateway.py compile-2.7!skip
-plugins/modules/aws_api_gateway.py compile-3.5!skip
-plugins/modules/aws_api_gateway.py compile-3.6!skip
-plugins/modules/aws_api_gateway.py compile-3.7!skip
-plugins/modules/aws_api_gateway.py future-import-boilerplate!skip
-plugins/modules/aws_api_gateway.py import-2.6!skip
-plugins/modules/aws_api_gateway.py import-2.7!skip
-plugins/modules/aws_api_gateway.py import-3.5!skip
-plugins/modules/aws_api_gateway.py import-3.6!skip
-plugins/modules/aws_api_gateway.py import-3.7!skip
-plugins/modules/aws_api_gateway.py metaclass-boilerplate!skip
-plugins/modules/aws_application_scaling_policy.py compile-2.6!skip
-plugins/modules/aws_application_scaling_policy.py compile-2.7!skip
-plugins/modules/aws_application_scaling_policy.py compile-3.5!skip
-plugins/modules/aws_application_scaling_policy.py compile-3.6!skip
-plugins/modules/aws_application_scaling_policy.py compile-3.7!skip
-plugins/modules/aws_application_scaling_policy.py future-import-boilerplate!skip
-plugins/modules/aws_application_scaling_policy.py import-2.6!skip
-plugins/modules/aws_application_scaling_policy.py import-2.7!skip
-plugins/modules/aws_application_scaling_policy.py import-3.5!skip
-plugins/modules/aws_application_scaling_policy.py import-3.6!skip
-plugins/modules/aws_application_scaling_policy.py import-3.7!skip
-plugins/modules/aws_application_scaling_policy.py metaclass-boilerplate!skip
-plugins/modules/aws_batch_compute_environment.py compile-2.6!skip
-plugins/modules/aws_batch_compute_environment.py compile-2.7!skip
-plugins/modules/aws_batch_compute_environment.py compile-3.5!skip
-plugins/modules/aws_batch_compute_environment.py compile-3.6!skip
-plugins/modules/aws_batch_compute_environment.py compile-3.7!skip
-plugins/modules/aws_batch_compute_environment.py future-import-boilerplate!skip
-plugins/modules/aws_batch_compute_environment.py import-2.6!skip
-plugins/modules/aws_batch_compute_environment.py import-2.7!skip
-plugins/modules/aws_batch_compute_environment.py import-3.5!skip
-plugins/modules/aws_batch_compute_environment.py import-3.6!skip
-plugins/modules/aws_batch_compute_environment.py import-3.7!skip
-plugins/modules/aws_batch_compute_environment.py metaclass-boilerplate!skip
-plugins/modules/aws_batch_job_definition.py compile-2.6!skip
-plugins/modules/aws_batch_job_definition.py compile-2.7!skip
-plugins/modules/aws_batch_job_definition.py compile-3.5!skip
-plugins/modules/aws_batch_job_definition.py compile-3.6!skip
-plugins/modules/aws_batch_job_definition.py compile-3.7!skip
-plugins/modules/aws_batch_job_definition.py future-import-boilerplate!skip
-plugins/modules/aws_batch_job_definition.py import-2.6!skip
-plugins/modules/aws_batch_job_definition.py import-2.7!skip
-plugins/modules/aws_batch_job_definition.py import-3.5!skip
-plugins/modules/aws_batch_job_definition.py import-3.6!skip
-plugins/modules/aws_batch_job_definition.py import-3.7!skip
-plugins/modules/aws_batch_job_definition.py metaclass-boilerplate!skip
-plugins/modules/aws_batch_job_queue.py compile-2.6!skip
-plugins/modules/aws_batch_job_queue.py compile-2.7!skip
-plugins/modules/aws_batch_job_queue.py compile-3.5!skip
-plugins/modules/aws_batch_job_queue.py compile-3.6!skip
-plugins/modules/aws_batch_job_queue.py compile-3.7!skip
-plugins/modules/aws_batch_job_queue.py future-import-boilerplate!skip
-plugins/modules/aws_batch_job_queue.py import-2.6!skip
-plugins/modules/aws_batch_job_queue.py import-2.7!skip
-plugins/modules/aws_batch_job_queue.py import-3.5!skip
-plugins/modules/aws_batch_job_queue.py import-3.6!skip
-plugins/modules/aws_batch_job_queue.py import-3.7!skip
-plugins/modules/aws_batch_job_queue.py metaclass-boilerplate!skip
-plugins/modules/aws_codebuild.py compile-2.6!skip
-plugins/modules/aws_codebuild.py compile-2.7!skip
-plugins/modules/aws_codebuild.py compile-3.5!skip
-plugins/modules/aws_codebuild.py compile-3.6!skip
-plugins/modules/aws_codebuild.py compile-3.7!skip
-plugins/modules/aws_codebuild.py future-import-boilerplate!skip
-plugins/modules/aws_codebuild.py import-2.6!skip
-plugins/modules/aws_codebuild.py import-2.7!skip
-plugins/modules/aws_codebuild.py import-3.5!skip
-plugins/modules/aws_codebuild.py import-3.6!skip
-plugins/modules/aws_codebuild.py import-3.7!skip
-plugins/modules/aws_codebuild.py metaclass-boilerplate!skip
-plugins/modules/aws_codecommit.py compile-2.6!skip
-plugins/modules/aws_codecommit.py compile-2.7!skip
-plugins/modules/aws_codecommit.py compile-3.5!skip
-plugins/modules/aws_codecommit.py compile-3.6!skip
-plugins/modules/aws_codecommit.py compile-3.7!skip
-plugins/modules/aws_codecommit.py future-import-boilerplate!skip
-plugins/modules/aws_codecommit.py import-2.6!skip
-plugins/modules/aws_codecommit.py import-2.7!skip
-plugins/modules/aws_codecommit.py import-3.5!skip
-plugins/modules/aws_codecommit.py import-3.6!skip
-plugins/modules/aws_codecommit.py import-3.7!skip
-plugins/modules/aws_codecommit.py metaclass-boilerplate!skip
-plugins/modules/aws_codepipeline.py compile-2.6!skip
-plugins/modules/aws_codepipeline.py compile-2.7!skip
-plugins/modules/aws_codepipeline.py compile-3.5!skip
-plugins/modules/aws_codepipeline.py compile-3.6!skip
-plugins/modules/aws_codepipeline.py compile-3.7!skip
-plugins/modules/aws_codepipeline.py future-import-boilerplate!skip
-plugins/modules/aws_codepipeline.py import-2.6!skip
-plugins/modules/aws_codepipeline.py import-2.7!skip
-plugins/modules/aws_codepipeline.py import-3.5!skip
-plugins/modules/aws_codepipeline.py import-3.6!skip
-plugins/modules/aws_codepipeline.py import-3.7!skip
-plugins/modules/aws_codepipeline.py metaclass-boilerplate!skip
-plugins/modules/aws_config_aggregation_authorization.py compile-2.6!skip
-plugins/modules/aws_config_aggregation_authorization.py compile-2.7!skip
-plugins/modules/aws_config_aggregation_authorization.py compile-3.5!skip
-plugins/modules/aws_config_aggregation_authorization.py compile-3.6!skip
-plugins/modules/aws_config_aggregation_authorization.py compile-3.7!skip
-plugins/modules/aws_config_aggregation_authorization.py future-import-boilerplate!skip
-plugins/modules/aws_config_aggregation_authorization.py import-2.6!skip
-plugins/modules/aws_config_aggregation_authorization.py import-2.7!skip
-plugins/modules/aws_config_aggregation_authorization.py import-3.5!skip
-plugins/modules/aws_config_aggregation_authorization.py import-3.6!skip
-plugins/modules/aws_config_aggregation_authorization.py import-3.7!skip
-plugins/modules/aws_config_aggregation_authorization.py metaclass-boilerplate!skip
-plugins/modules/aws_config_aggregator.py compile-2.6!skip
-plugins/modules/aws_config_aggregator.py compile-2.7!skip
-plugins/modules/aws_config_aggregator.py compile-3.5!skip
-plugins/modules/aws_config_aggregator.py compile-3.6!skip
-plugins/modules/aws_config_aggregator.py compile-3.7!skip
-plugins/modules/aws_config_aggregator.py future-import-boilerplate!skip
-plugins/modules/aws_config_aggregator.py import-2.6!skip
-plugins/modules/aws_config_aggregator.py import-2.7!skip
-plugins/modules/aws_config_aggregator.py import-3.5!skip
-plugins/modules/aws_config_aggregator.py import-3.6!skip
-plugins/modules/aws_config_aggregator.py import-3.7!skip
-plugins/modules/aws_config_aggregator.py metaclass-boilerplate!skip
-plugins/modules/aws_config_delivery_channel.py compile-2.6!skip
-plugins/modules/aws_config_delivery_channel.py compile-2.7!skip
-plugins/modules/aws_config_delivery_channel.py compile-3.5!skip
-plugins/modules/aws_config_delivery_channel.py compile-3.6!skip
-plugins/modules/aws_config_delivery_channel.py compile-3.7!skip
-plugins/modules/aws_config_delivery_channel.py future-import-boilerplate!skip
-plugins/modules/aws_config_delivery_channel.py import-2.6!skip
-plugins/modules/aws_config_delivery_channel.py import-2.7!skip
-plugins/modules/aws_config_delivery_channel.py import-3.5!skip
-plugins/modules/aws_config_delivery_channel.py import-3.6!skip
-plugins/modules/aws_config_delivery_channel.py import-3.7!skip
-plugins/modules/aws_config_delivery_channel.py metaclass-boilerplate!skip
-plugins/modules/aws_config_recorder.py compile-2.6!skip
-plugins/modules/aws_config_recorder.py compile-2.7!skip
-plugins/modules/aws_config_recorder.py compile-3.5!skip
-plugins/modules/aws_config_recorder.py compile-3.6!skip
-plugins/modules/aws_config_recorder.py compile-3.7!skip
-plugins/modules/aws_config_recorder.py future-import-boilerplate!skip
-plugins/modules/aws_config_recorder.py import-2.6!skip
-plugins/modules/aws_config_recorder.py import-2.7!skip
-plugins/modules/aws_config_recorder.py import-3.5!skip
-plugins/modules/aws_config_recorder.py import-3.6!skip
-plugins/modules/aws_config_recorder.py import-3.7!skip
-plugins/modules/aws_config_recorder.py metaclass-boilerplate!skip
-plugins/modules/aws_config_rule.py compile-2.6!skip
-plugins/modules/aws_config_rule.py compile-2.7!skip
-plugins/modules/aws_config_rule.py compile-3.5!skip
-plugins/modules/aws_config_rule.py compile-3.6!skip
-plugins/modules/aws_config_rule.py compile-3.7!skip
-plugins/modules/aws_config_rule.py future-import-boilerplate!skip
-plugins/modules/aws_config_rule.py import-2.6!skip
-plugins/modules/aws_config_rule.py import-2.7!skip
-plugins/modules/aws_config_rule.py import-3.5!skip
-plugins/modules/aws_config_rule.py import-3.6!skip
-plugins/modules/aws_config_rule.py import-3.7!skip
-plugins/modules/aws_config_rule.py metaclass-boilerplate!skip
-plugins/modules/aws_direct_connect_confirm_connection.py compile-2.6!skip
-plugins/modules/aws_direct_connect_confirm_connection.py compile-2.7!skip
-plugins/modules/aws_direct_connect_confirm_connection.py compile-3.5!skip
-plugins/modules/aws_direct_connect_confirm_connection.py compile-3.6!skip
-plugins/modules/aws_direct_connect_confirm_connection.py compile-3.7!skip
-plugins/modules/aws_direct_connect_confirm_connection.py future-import-boilerplate!skip
-plugins/modules/aws_direct_connect_confirm_connection.py import-2.6!skip
-plugins/modules/aws_direct_connect_confirm_connection.py import-2.7!skip
-plugins/modules/aws_direct_connect_confirm_connection.py import-3.5!skip
-plugins/modules/aws_direct_connect_confirm_connection.py import-3.6!skip
-plugins/modules/aws_direct_connect_confirm_connection.py import-3.7!skip
-plugins/modules/aws_direct_connect_confirm_connection.py metaclass-boilerplate!skip
-plugins/modules/aws_direct_connect_connection.py compile-2.6!skip
-plugins/modules/aws_direct_connect_connection.py compile-2.7!skip
-plugins/modules/aws_direct_connect_connection.py compile-3.5!skip
-plugins/modules/aws_direct_connect_connection.py compile-3.6!skip
-plugins/modules/aws_direct_connect_connection.py compile-3.7!skip
-plugins/modules/aws_direct_connect_connection.py future-import-boilerplate!skip
-plugins/modules/aws_direct_connect_connection.py import-2.6!skip
-plugins/modules/aws_direct_connect_connection.py import-2.7!skip
-plugins/modules/aws_direct_connect_connection.py import-3.5!skip
-plugins/modules/aws_direct_connect_connection.py import-3.6!skip
-plugins/modules/aws_direct_connect_connection.py import-3.7!skip
-plugins/modules/aws_direct_connect_connection.py metaclass-boilerplate!skip
-plugins/modules/aws_direct_connect_gateway.py compile-2.6!skip
-plugins/modules/aws_direct_connect_gateway.py compile-2.7!skip
-plugins/modules/aws_direct_connect_gateway.py compile-3.5!skip
-plugins/modules/aws_direct_connect_gateway.py compile-3.6!skip
-plugins/modules/aws_direct_connect_gateway.py compile-3.7!skip
-plugins/modules/aws_direct_connect_gateway.py future-import-boilerplate!skip
-plugins/modules/aws_direct_connect_gateway.py import-2.6!skip
-plugins/modules/aws_direct_connect_gateway.py import-2.7!skip
-plugins/modules/aws_direct_connect_gateway.py import-3.5!skip
-plugins/modules/aws_direct_connect_gateway.py import-3.6!skip
-plugins/modules/aws_direct_connect_gateway.py import-3.7!skip
-plugins/modules/aws_direct_connect_gateway.py metaclass-boilerplate!skip
-plugins/modules/aws_direct_connect_link_aggregation_group.py compile-2.6!skip
-plugins/modules/aws_direct_connect_link_aggregation_group.py compile-2.7!skip
-plugins/modules/aws_direct_connect_link_aggregation_group.py compile-3.5!skip
-plugins/modules/aws_direct_connect_link_aggregation_group.py compile-3.6!skip
-plugins/modules/aws_direct_connect_link_aggregation_group.py compile-3.7!skip
-plugins/modules/aws_direct_connect_link_aggregation_group.py future-import-boilerplate!skip
-plugins/modules/aws_direct_connect_link_aggregation_group.py import-2.6!skip
-plugins/modules/aws_direct_connect_link_aggregation_group.py import-2.7!skip
-plugins/modules/aws_direct_connect_link_aggregation_group.py import-3.5!skip
-plugins/modules/aws_direct_connect_link_aggregation_group.py import-3.6!skip
-plugins/modules/aws_direct_connect_link_aggregation_group.py import-3.7!skip
-plugins/modules/aws_direct_connect_link_aggregation_group.py metaclass-boilerplate!skip
-plugins/modules/aws_direct_connect_virtual_interface.py compile-2.6!skip
-plugins/modules/aws_direct_connect_virtual_interface.py compile-2.7!skip
-plugins/modules/aws_direct_connect_virtual_interface.py compile-3.5!skip
-plugins/modules/aws_direct_connect_virtual_interface.py compile-3.6!skip
-plugins/modules/aws_direct_connect_virtual_interface.py compile-3.7!skip
-plugins/modules/aws_direct_connect_virtual_interface.py future-import-boilerplate!skip
-plugins/modules/aws_direct_connect_virtual_interface.py import-2.6!skip
-plugins/modules/aws_direct_connect_virtual_interface.py import-2.7!skip
-plugins/modules/aws_direct_connect_virtual_interface.py import-3.5!skip
-plugins/modules/aws_direct_connect_virtual_interface.py import-3.6!skip
-plugins/modules/aws_direct_connect_virtual_interface.py import-3.7!skip
-plugins/modules/aws_direct_connect_virtual_interface.py metaclass-boilerplate!skip
-plugins/modules/aws_eks_cluster.py compile-2.6!skip
-plugins/modules/aws_eks_cluster.py compile-2.7!skip
-plugins/modules/aws_eks_cluster.py compile-3.5!skip
-plugins/modules/aws_eks_cluster.py compile-3.6!skip
-plugins/modules/aws_eks_cluster.py compile-3.7!skip
-plugins/modules/aws_eks_cluster.py future-import-boilerplate!skip
-plugins/modules/aws_eks_cluster.py import-2.6!skip
-plugins/modules/aws_eks_cluster.py import-2.7!skip
-plugins/modules/aws_eks_cluster.py import-3.5!skip
-plugins/modules/aws_eks_cluster.py import-3.6!skip
-plugins/modules/aws_eks_cluster.py import-3.7!skip
-plugins/modules/aws_eks_cluster.py metaclass-boilerplate!skip
-plugins/modules/aws_elasticbeanstalk_app.py compile-2.6!skip
-plugins/modules/aws_elasticbeanstalk_app.py compile-2.7!skip
-plugins/modules/aws_elasticbeanstalk_app.py compile-3.5!skip
-plugins/modules/aws_elasticbeanstalk_app.py compile-3.6!skip
-plugins/modules/aws_elasticbeanstalk_app.py compile-3.7!skip
-plugins/modules/aws_elasticbeanstalk_app.py future-import-boilerplate!skip
-plugins/modules/aws_elasticbeanstalk_app.py import-2.6!skip
-plugins/modules/aws_elasticbeanstalk_app.py import-2.7!skip
-plugins/modules/aws_elasticbeanstalk_app.py import-3.5!skip
-plugins/modules/aws_elasticbeanstalk_app.py import-3.6!skip
-plugins/modules/aws_elasticbeanstalk_app.py import-3.7!skip
-plugins/modules/aws_elasticbeanstalk_app.py metaclass-boilerplate!skip
-plugins/modules/aws_glue_connection.py compile-2.6!skip
-plugins/modules/aws_glue_connection.py compile-2.7!skip
-plugins/modules/aws_glue_connection.py compile-3.5!skip
-plugins/modules/aws_glue_connection.py compile-3.6!skip
-plugins/modules/aws_glue_connection.py compile-3.7!skip
-plugins/modules/aws_glue_connection.py future-import-boilerplate!skip
-plugins/modules/aws_glue_connection.py import-2.6!skip
-plugins/modules/aws_glue_connection.py import-2.7!skip
-plugins/modules/aws_glue_connection.py import-3.5!skip
-plugins/modules/aws_glue_connection.py import-3.6!skip
-plugins/modules/aws_glue_connection.py import-3.7!skip
-plugins/modules/aws_glue_connection.py metaclass-boilerplate!skip
-plugins/modules/aws_glue_job.py compile-2.6!skip
-plugins/modules/aws_glue_job.py compile-2.7!skip
-plugins/modules/aws_glue_job.py compile-3.5!skip
-plugins/modules/aws_glue_job.py compile-3.6!skip
-plugins/modules/aws_glue_job.py compile-3.7!skip
-plugins/modules/aws_glue_job.py future-import-boilerplate!skip
-plugins/modules/aws_glue_job.py import-2.6!skip
-plugins/modules/aws_glue_job.py import-2.7!skip
-plugins/modules/aws_glue_job.py import-3.5!skip
-plugins/modules/aws_glue_job.py import-3.6!skip
-plugins/modules/aws_glue_job.py import-3.7!skip
-plugins/modules/aws_glue_job.py metaclass-boilerplate!skip
-plugins/modules/aws_inspector_target.py compile-2.6!skip
-plugins/modules/aws_inspector_target.py compile-2.7!skip
-plugins/modules/aws_inspector_target.py compile-3.5!skip
-plugins/modules/aws_inspector_target.py compile-3.6!skip
-plugins/modules/aws_inspector_target.py compile-3.7!skip
-plugins/modules/aws_inspector_target.py future-import-boilerplate!skip
-plugins/modules/aws_inspector_target.py import-2.6!skip
-plugins/modules/aws_inspector_target.py import-2.7!skip
-plugins/modules/aws_inspector_target.py import-3.5!skip
-plugins/modules/aws_inspector_target.py import-3.6!skip
-plugins/modules/aws_inspector_target.py import-3.7!skip
-plugins/modules/aws_inspector_target.py metaclass-boilerplate!skip
-plugins/modules/aws_kms.py compile-2.6!skip
-plugins/modules/aws_kms.py compile-2.7!skip
-plugins/modules/aws_kms.py compile-3.5!skip
-plugins/modules/aws_kms.py compile-3.6!skip
-plugins/modules/aws_kms.py compile-3.7!skip
-plugins/modules/aws_kms.py future-import-boilerplate!skip
-plugins/modules/aws_kms.py import-2.6!skip
-plugins/modules/aws_kms.py import-2.7!skip
-plugins/modules/aws_kms.py import-3.5!skip
-plugins/modules/aws_kms.py import-3.6!skip
-plugins/modules/aws_kms.py import-3.7!skip
-plugins/modules/aws_kms.py metaclass-boilerplate!skip
-plugins/modules/aws_kms_info.py compile-2.6!skip
-plugins/modules/aws_kms_info.py compile-2.7!skip
-plugins/modules/aws_kms_info.py compile-3.5!skip
-plugins/modules/aws_kms_info.py compile-3.6!skip
-plugins/modules/aws_kms_info.py compile-3.7!skip
-plugins/modules/aws_kms_info.py future-import-boilerplate!skip
-plugins/modules/aws_kms_info.py import-2.6!skip
-plugins/modules/aws_kms_info.py import-2.7!skip
-plugins/modules/aws_kms_info.py import-3.5!skip
-plugins/modules/aws_kms_info.py import-3.6!skip
-plugins/modules/aws_kms_info.py import-3.7!skip
-plugins/modules/aws_kms_info.py metaclass-boilerplate!skip
-plugins/modules/aws_region_info.py compile-2.6!skip
-plugins/modules/aws_region_info.py compile-2.7!skip
-plugins/modules/aws_region_info.py compile-3.5!skip
-plugins/modules/aws_region_info.py compile-3.6!skip
-plugins/modules/aws_region_info.py compile-3.7!skip
-plugins/modules/aws_region_info.py future-import-boilerplate!skip
-plugins/modules/aws_region_info.py import-2.6!skip
-plugins/modules/aws_region_info.py import-2.7!skip
-plugins/modules/aws_region_info.py import-3.5!skip
-plugins/modules/aws_region_info.py import-3.6!skip
-plugins/modules/aws_region_info.py import-3.7!skip
-plugins/modules/aws_region_info.py metaclass-boilerplate!skip
-plugins/modules/aws_s3_bucket_info.py compile-2.6!skip
-plugins/modules/aws_s3_bucket_info.py compile-2.7!skip
-plugins/modules/aws_s3_bucket_info.py compile-3.5!skip
-plugins/modules/aws_s3_bucket_info.py compile-3.6!skip
-plugins/modules/aws_s3_bucket_info.py compile-3.7!skip
-plugins/modules/aws_s3_bucket_info.py future-import-boilerplate!skip
-plugins/modules/aws_s3_bucket_info.py import-2.6!skip
-plugins/modules/aws_s3_bucket_info.py import-2.7!skip
-plugins/modules/aws_s3_bucket_info.py import-3.5!skip
-plugins/modules/aws_s3_bucket_info.py import-3.6!skip
-plugins/modules/aws_s3_bucket_info.py import-3.7!skip
-plugins/modules/aws_s3_bucket_info.py metaclass-boilerplate!skip
-plugins/modules/aws_s3_cors.py compile-2.6!skip
-plugins/modules/aws_s3_cors.py compile-2.7!skip
-plugins/modules/aws_s3_cors.py compile-3.5!skip
-plugins/modules/aws_s3_cors.py compile-3.6!skip
-plugins/modules/aws_s3_cors.py compile-3.7!skip
-plugins/modules/aws_s3_cors.py future-import-boilerplate!skip
-plugins/modules/aws_s3_cors.py import-2.6!skip
-plugins/modules/aws_s3_cors.py import-2.7!skip
-plugins/modules/aws_s3_cors.py import-3.5!skip
-plugins/modules/aws_s3_cors.py import-3.6!skip
-plugins/modules/aws_s3_cors.py import-3.7!skip
-plugins/modules/aws_s3_cors.py metaclass-boilerplate!skip
-plugins/modules/aws_secret.py compile-2.6!skip
-plugins/modules/aws_secret.py compile-2.7!skip
-plugins/modules/aws_secret.py compile-3.5!skip
-plugins/modules/aws_secret.py compile-3.6!skip
-plugins/modules/aws_secret.py compile-3.7!skip
-plugins/modules/aws_secret.py future-import-boilerplate!skip
-plugins/modules/aws_secret.py import-2.6!skip
-plugins/modules/aws_secret.py import-2.7!skip
-plugins/modules/aws_secret.py import-3.5!skip
-plugins/modules/aws_secret.py import-3.6!skip
-plugins/modules/aws_secret.py import-3.7!skip
-plugins/modules/aws_secret.py metaclass-boilerplate!skip
-plugins/modules/aws_ses_identity.py compile-2.6!skip
-plugins/modules/aws_ses_identity.py compile-2.7!skip
-plugins/modules/aws_ses_identity.py compile-3.5!skip
-plugins/modules/aws_ses_identity.py compile-3.6!skip
-plugins/modules/aws_ses_identity.py compile-3.7!skip
-plugins/modules/aws_ses_identity.py future-import-boilerplate!skip
-plugins/modules/aws_ses_identity.py import-2.6!skip
-plugins/modules/aws_ses_identity.py import-2.7!skip
-plugins/modules/aws_ses_identity.py import-3.5!skip
-plugins/modules/aws_ses_identity.py import-3.6!skip
-plugins/modules/aws_ses_identity.py import-3.7!skip
-plugins/modules/aws_ses_identity.py metaclass-boilerplate!skip
-plugins/modules/aws_ses_identity_policy.py compile-2.6!skip
-plugins/modules/aws_ses_identity_policy.py compile-2.7!skip
-plugins/modules/aws_ses_identity_policy.py compile-3.5!skip
-plugins/modules/aws_ses_identity_policy.py compile-3.6!skip
-plugins/modules/aws_ses_identity_policy.py compile-3.7!skip
-plugins/modules/aws_ses_identity_policy.py future-import-boilerplate!skip
-plugins/modules/aws_ses_identity_policy.py import-2.6!skip
-plugins/modules/aws_ses_identity_policy.py import-2.7!skip
-plugins/modules/aws_ses_identity_policy.py import-3.5!skip
-plugins/modules/aws_ses_identity_policy.py import-3.6!skip
-plugins/modules/aws_ses_identity_policy.py import-3.7!skip
-plugins/modules/aws_ses_identity_policy.py metaclass-boilerplate!skip
-plugins/modules/aws_ses_rule_set.py compile-2.6!skip
-plugins/modules/aws_ses_rule_set.py compile-2.7!skip
-plugins/modules/aws_ses_rule_set.py compile-3.5!skip
-plugins/modules/aws_ses_rule_set.py compile-3.6!skip
-plugins/modules/aws_ses_rule_set.py compile-3.7!skip
-plugins/modules/aws_ses_rule_set.py future-import-boilerplate!skip
-plugins/modules/aws_ses_rule_set.py import-2.6!skip
-plugins/modules/aws_ses_rule_set.py import-2.7!skip
-plugins/modules/aws_ses_rule_set.py import-3.5!skip
-plugins/modules/aws_ses_rule_set.py import-3.6!skip
-plugins/modules/aws_ses_rule_set.py import-3.7!skip
-plugins/modules/aws_ses_rule_set.py metaclass-boilerplate!skip
-plugins/modules/aws_sgw_info.py compile-2.6!skip
-plugins/modules/aws_sgw_info.py compile-2.7!skip
-plugins/modules/aws_sgw_info.py compile-3.5!skip
-plugins/modules/aws_sgw_info.py compile-3.6!skip
-plugins/modules/aws_sgw_info.py compile-3.7!skip
-plugins/modules/aws_sgw_info.py future-import-boilerplate!skip
-plugins/modules/aws_sgw_info.py import-2.6!skip
-plugins/modules/aws_sgw_info.py import-2.7!skip
-plugins/modules/aws_sgw_info.py import-3.5!skip
-plugins/modules/aws_sgw_info.py import-3.6!skip
-plugins/modules/aws_sgw_info.py import-3.7!skip
-plugins/modules/aws_sgw_info.py metaclass-boilerplate!skip
-plugins/modules/aws_ssm_parameter_store.py compile-2.6!skip
-plugins/modules/aws_ssm_parameter_store.py compile-2.7!skip
-plugins/modules/aws_ssm_parameter_store.py compile-3.5!skip
-plugins/modules/aws_ssm_parameter_store.py compile-3.6!skip
-plugins/modules/aws_ssm_parameter_store.py compile-3.7!skip
-plugins/modules/aws_ssm_parameter_store.py future-import-boilerplate!skip
-plugins/modules/aws_ssm_parameter_store.py import-2.6!skip
-plugins/modules/aws_ssm_parameter_store.py import-2.7!skip
-plugins/modules/aws_ssm_parameter_store.py import-3.5!skip
-plugins/modules/aws_ssm_parameter_store.py import-3.6!skip
-plugins/modules/aws_ssm_parameter_store.py import-3.7!skip
-plugins/modules/aws_ssm_parameter_store.py metaclass-boilerplate!skip
-plugins/modules/aws_step_functions_state_machine.py compile-2.6!skip
-plugins/modules/aws_step_functions_state_machine.py compile-2.7!skip
-plugins/modules/aws_step_functions_state_machine.py compile-3.5!skip
-plugins/modules/aws_step_functions_state_machine.py compile-3.6!skip
-plugins/modules/aws_step_functions_state_machine.py compile-3.7!skip
-plugins/modules/aws_step_functions_state_machine.py future-import-boilerplate!skip
-plugins/modules/aws_step_functions_state_machine.py import-2.6!skip
-plugins/modules/aws_step_functions_state_machine.py import-2.7!skip
-plugins/modules/aws_step_functions_state_machine.py import-3.5!skip
-plugins/modules/aws_step_functions_state_machine.py import-3.6!skip
-plugins/modules/aws_step_functions_state_machine.py import-3.7!skip
-plugins/modules/aws_step_functions_state_machine.py metaclass-boilerplate!skip
-plugins/modules/aws_step_functions_state_machine_execution.py compile-2.6!skip
-plugins/modules/aws_step_functions_state_machine_execution.py compile-2.7!skip
-plugins/modules/aws_step_functions_state_machine_execution.py compile-3.5!skip
-plugins/modules/aws_step_functions_state_machine_execution.py compile-3.6!skip
-plugins/modules/aws_step_functions_state_machine_execution.py compile-3.7!skip
-plugins/modules/aws_step_functions_state_machine_execution.py future-import-boilerplate!skip
-plugins/modules/aws_step_functions_state_machine_execution.py import-2.6!skip
-plugins/modules/aws_step_functions_state_machine_execution.py import-2.7!skip
-plugins/modules/aws_step_functions_state_machine_execution.py import-3.5!skip
-plugins/modules/aws_step_functions_state_machine_execution.py import-3.6!skip
-plugins/modules/aws_step_functions_state_machine_execution.py import-3.7!skip
-plugins/modules/aws_step_functions_state_machine_execution.py metaclass-boilerplate!skip
-plugins/modules/aws_waf_condition.py compile-2.6!skip
-plugins/modules/aws_waf_condition.py compile-2.7!skip
-plugins/modules/aws_waf_condition.py compile-3.5!skip
-plugins/modules/aws_waf_condition.py compile-3.6!skip
-plugins/modules/aws_waf_condition.py compile-3.7!skip
-plugins/modules/aws_waf_condition.py future-import-boilerplate!skip
-plugins/modules/aws_waf_condition.py import-2.6!skip
-plugins/modules/aws_waf_condition.py import-2.7!skip
-plugins/modules/aws_waf_condition.py import-3.5!skip
-plugins/modules/aws_waf_condition.py import-3.6!skip
-plugins/modules/aws_waf_condition.py import-3.7!skip
-plugins/modules/aws_waf_condition.py metaclass-boilerplate!skip
-plugins/modules/aws_waf_info.py compile-2.6!skip
-plugins/modules/aws_waf_info.py compile-2.7!skip
-plugins/modules/aws_waf_info.py compile-3.5!skip
-plugins/modules/aws_waf_info.py compile-3.6!skip
-plugins/modules/aws_waf_info.py compile-3.7!skip
-plugins/modules/aws_waf_info.py future-import-boilerplate!skip
-plugins/modules/aws_waf_info.py import-2.6!skip
-plugins/modules/aws_waf_info.py import-2.7!skip
-plugins/modules/aws_waf_info.py import-3.5!skip
-plugins/modules/aws_waf_info.py import-3.6!skip
-plugins/modules/aws_waf_info.py import-3.7!skip
-plugins/modules/aws_waf_info.py metaclass-boilerplate!skip
-plugins/modules/aws_waf_rule.py compile-2.6!skip
-plugins/modules/aws_waf_rule.py compile-2.7!skip
-plugins/modules/aws_waf_rule.py compile-3.5!skip
-plugins/modules/aws_waf_rule.py compile-3.6!skip
-plugins/modules/aws_waf_rule.py compile-3.7!skip
-plugins/modules/aws_waf_rule.py future-import-boilerplate!skip
-plugins/modules/aws_waf_rule.py import-2.6!skip
-plugins/modules/aws_waf_rule.py import-2.7!skip
-plugins/modules/aws_waf_rule.py import-3.5!skip
-plugins/modules/aws_waf_rule.py import-3.6!skip
-plugins/modules/aws_waf_rule.py import-3.7!skip
-plugins/modules/aws_waf_rule.py metaclass-boilerplate!skip
-plugins/modules/aws_waf_web_acl.py compile-2.6!skip
-plugins/modules/aws_waf_web_acl.py compile-2.7!skip
-plugins/modules/aws_waf_web_acl.py compile-3.5!skip
-plugins/modules/aws_waf_web_acl.py compile-3.6!skip
-plugins/modules/aws_waf_web_acl.py compile-3.7!skip
-plugins/modules/aws_waf_web_acl.py future-import-boilerplate!skip
-plugins/modules/aws_waf_web_acl.py import-2.6!skip
-plugins/modules/aws_waf_web_acl.py import-2.7!skip
-plugins/modules/aws_waf_web_acl.py import-3.5!skip
-plugins/modules/aws_waf_web_acl.py import-3.6!skip
-plugins/modules/aws_waf_web_acl.py import-3.7!skip
-plugins/modules/aws_waf_web_acl.py metaclass-boilerplate!skip
-plugins/modules/cloudformation_exports_info.py compile-2.6!skip
-plugins/modules/cloudformation_exports_info.py compile-2.7!skip
-plugins/modules/cloudformation_exports_info.py compile-3.5!skip
-plugins/modules/cloudformation_exports_info.py compile-3.6!skip
-plugins/modules/cloudformation_exports_info.py compile-3.7!skip
-plugins/modules/cloudformation_exports_info.py future-import-boilerplate!skip
-plugins/modules/cloudformation_exports_info.py import-2.6!skip
-plugins/modules/cloudformation_exports_info.py import-2.7!skip
-plugins/modules/cloudformation_exports_info.py import-3.5!skip
-plugins/modules/cloudformation_exports_info.py import-3.6!skip
-plugins/modules/cloudformation_exports_info.py import-3.7!skip
-plugins/modules/cloudformation_exports_info.py metaclass-boilerplate!skip
-plugins/modules/cloudformation_stack_set.py compile-2.6!skip
-plugins/modules/cloudformation_stack_set.py compile-2.7!skip
-plugins/modules/cloudformation_stack_set.py compile-3.5!skip
-plugins/modules/cloudformation_stack_set.py compile-3.6!skip
-plugins/modules/cloudformation_stack_set.py compile-3.7!skip
-plugins/modules/cloudformation_stack_set.py future-import-boilerplate!skip
-plugins/modules/cloudformation_stack_set.py import-2.6!skip
-plugins/modules/cloudformation_stack_set.py import-2.7!skip
-plugins/modules/cloudformation_stack_set.py import-3.5!skip
-plugins/modules/cloudformation_stack_set.py import-3.6!skip
-plugins/modules/cloudformation_stack_set.py import-3.7!skip
-plugins/modules/cloudformation_stack_set.py metaclass-boilerplate!skip
-plugins/modules/cloudfront_distribution.py compile-2.6!skip
-plugins/modules/cloudfront_distribution.py compile-2.7!skip
-plugins/modules/cloudfront_distribution.py compile-3.5!skip
-plugins/modules/cloudfront_distribution.py compile-3.6!skip
-plugins/modules/cloudfront_distribution.py compile-3.7!skip
-plugins/modules/cloudfront_distribution.py future-import-boilerplate!skip
-plugins/modules/cloudfront_distribution.py import-2.6!skip
-plugins/modules/cloudfront_distribution.py import-2.7!skip
-plugins/modules/cloudfront_distribution.py import-3.5!skip
-plugins/modules/cloudfront_distribution.py import-3.6!skip
-plugins/modules/cloudfront_distribution.py import-3.7!skip
-plugins/modules/cloudfront_distribution.py metaclass-boilerplate!skip
-plugins/modules/cloudfront_info.py compile-2.6!skip
-plugins/modules/cloudfront_info.py compile-2.7!skip
-plugins/modules/cloudfront_info.py compile-3.5!skip
-plugins/modules/cloudfront_info.py compile-3.6!skip
-plugins/modules/cloudfront_info.py compile-3.7!skip
-plugins/modules/cloudfront_info.py future-import-boilerplate!skip
-plugins/modules/cloudfront_info.py import-2.6!skip
-plugins/modules/cloudfront_info.py import-2.7!skip
-plugins/modules/cloudfront_info.py import-3.5!skip
-plugins/modules/cloudfront_info.py import-3.6!skip
-plugins/modules/cloudfront_info.py import-3.7!skip
-plugins/modules/cloudfront_info.py metaclass-boilerplate!skip
-plugins/modules/cloudfront_info.py pylint:unnecessary-comprehension # Should be an easy fix, but testing is a challenge - test are broken and aliases require a wildcard cert in ACM
-plugins/modules/cloudfront_invalidation.py compile-2.6!skip
-plugins/modules/cloudfront_invalidation.py compile-2.7!skip
-plugins/modules/cloudfront_invalidation.py compile-3.5!skip
-plugins/modules/cloudfront_invalidation.py compile-3.6!skip
-plugins/modules/cloudfront_invalidation.py compile-3.7!skip
-plugins/modules/cloudfront_invalidation.py future-import-boilerplate!skip
-plugins/modules/cloudfront_invalidation.py import-2.6!skip
-plugins/modules/cloudfront_invalidation.py import-2.7!skip
-plugins/modules/cloudfront_invalidation.py import-3.5!skip
-plugins/modules/cloudfront_invalidation.py import-3.6!skip
-plugins/modules/cloudfront_invalidation.py import-3.7!skip
-plugins/modules/cloudfront_invalidation.py metaclass-boilerplate!skip
-plugins/modules/cloudfront_origin_access_identity.py compile-2.6!skip
-plugins/modules/cloudfront_origin_access_identity.py compile-2.7!skip
-plugins/modules/cloudfront_origin_access_identity.py compile-3.5!skip
-plugins/modules/cloudfront_origin_access_identity.py compile-3.6!skip
-plugins/modules/cloudfront_origin_access_identity.py compile-3.7!skip
-plugins/modules/cloudfront_origin_access_identity.py future-import-boilerplate!skip
-plugins/modules/cloudfront_origin_access_identity.py import-2.6!skip
-plugins/modules/cloudfront_origin_access_identity.py import-2.7!skip
-plugins/modules/cloudfront_origin_access_identity.py import-3.5!skip
-plugins/modules/cloudfront_origin_access_identity.py import-3.6!skip
-plugins/modules/cloudfront_origin_access_identity.py import-3.7!skip
-plugins/modules/cloudfront_origin_access_identity.py metaclass-boilerplate!skip
-plugins/modules/cloudtrail.py compile-2.6!skip
-plugins/modules/cloudtrail.py compile-2.7!skip
-plugins/modules/cloudtrail.py compile-3.5!skip
-plugins/modules/cloudtrail.py compile-3.6!skip
-plugins/modules/cloudtrail.py compile-3.7!skip
-plugins/modules/cloudtrail.py future-import-boilerplate!skip
-plugins/modules/cloudtrail.py import-2.6!skip
-plugins/modules/cloudtrail.py import-2.7!skip
-plugins/modules/cloudtrail.py import-3.5!skip
-plugins/modules/cloudtrail.py import-3.6!skip
-plugins/modules/cloudtrail.py import-3.7!skip
-plugins/modules/cloudtrail.py metaclass-boilerplate!skip
-plugins/modules/cloudwatchevent_rule.py compile-2.6!skip
-plugins/modules/cloudwatchevent_rule.py compile-2.7!skip
-plugins/modules/cloudwatchevent_rule.py compile-3.5!skip
-plugins/modules/cloudwatchevent_rule.py compile-3.6!skip
-plugins/modules/cloudwatchevent_rule.py compile-3.7!skip
-plugins/modules/cloudwatchevent_rule.py future-import-boilerplate!skip
-plugins/modules/cloudwatchevent_rule.py import-2.6!skip
-plugins/modules/cloudwatchevent_rule.py import-2.7!skip
-plugins/modules/cloudwatchevent_rule.py import-3.5!skip
-plugins/modules/cloudwatchevent_rule.py import-3.6!skip
-plugins/modules/cloudwatchevent_rule.py import-3.7!skip
-plugins/modules/cloudwatchevent_rule.py metaclass-boilerplate!skip
-plugins/modules/cloudwatchlogs_log_group.py compile-2.6!skip
-plugins/modules/cloudwatchlogs_log_group.py compile-2.7!skip
-plugins/modules/cloudwatchlogs_log_group.py compile-3.5!skip
-plugins/modules/cloudwatchlogs_log_group.py compile-3.6!skip
-plugins/modules/cloudwatchlogs_log_group.py compile-3.7!skip
-plugins/modules/cloudwatchlogs_log_group.py future-import-boilerplate!skip
-plugins/modules/cloudwatchlogs_log_group.py import-2.6!skip
-plugins/modules/cloudwatchlogs_log_group.py import-2.7!skip
-plugins/modules/cloudwatchlogs_log_group.py import-3.5!skip
-plugins/modules/cloudwatchlogs_log_group.py import-3.6!skip
-plugins/modules/cloudwatchlogs_log_group.py import-3.7!skip
-plugins/modules/cloudwatchlogs_log_group.py metaclass-boilerplate!skip
-plugins/modules/cloudwatchlogs_log_group_info.py compile-2.6!skip
-plugins/modules/cloudwatchlogs_log_group_info.py compile-2.7!skip
-plugins/modules/cloudwatchlogs_log_group_info.py compile-3.5!skip
-plugins/modules/cloudwatchlogs_log_group_info.py compile-3.6!skip
-plugins/modules/cloudwatchlogs_log_group_info.py compile-3.7!skip
-plugins/modules/cloudwatchlogs_log_group_info.py future-import-boilerplate!skip
-plugins/modules/cloudwatchlogs_log_group_info.py import-2.6!skip
-plugins/modules/cloudwatchlogs_log_group_info.py import-2.7!skip
-plugins/modules/cloudwatchlogs_log_group_info.py import-3.5!skip
-plugins/modules/cloudwatchlogs_log_group_info.py import-3.6!skip
-plugins/modules/cloudwatchlogs_log_group_info.py import-3.7!skip
-plugins/modules/cloudwatchlogs_log_group_info.py metaclass-boilerplate!skip
-plugins/modules/cloudwatchlogs_log_group_metric_filter.py compile-2.6!skip
-plugins/modules/cloudwatchlogs_log_group_metric_filter.py compile-2.7!skip
-plugins/modules/cloudwatchlogs_log_group_metric_filter.py compile-3.5!skip
-plugins/modules/cloudwatchlogs_log_group_metric_filter.py compile-3.6!skip
-plugins/modules/cloudwatchlogs_log_group_metric_filter.py compile-3.7!skip
-plugins/modules/cloudwatchlogs_log_group_metric_filter.py future-import-boilerplate!skip
-plugins/modules/cloudwatchlogs_log_group_metric_filter.py import-2.6!skip
-plugins/modules/cloudwatchlogs_log_group_metric_filter.py import-2.7!skip
-plugins/modules/cloudwatchlogs_log_group_metric_filter.py import-3.5!skip
-plugins/modules/cloudwatchlogs_log_group_metric_filter.py import-3.6!skip
-plugins/modules/cloudwatchlogs_log_group_metric_filter.py import-3.7!skip
-plugins/modules/cloudwatchlogs_log_group_metric_filter.py metaclass-boilerplate!skip
-plugins/modules/data_pipeline.py compile-2.6!skip
-plugins/modules/data_pipeline.py compile-2.7!skip
-plugins/modules/data_pipeline.py compile-3.5!skip
-plugins/modules/data_pipeline.py compile-3.6!skip
-plugins/modules/data_pipeline.py compile-3.7!skip
-plugins/modules/data_pipeline.py future-import-boilerplate!skip
-plugins/modules/data_pipeline.py import-2.6!skip
-plugins/modules/data_pipeline.py import-2.7!skip
-plugins/modules/data_pipeline.py import-3.5!skip
-plugins/modules/data_pipeline.py import-3.6!skip
-plugins/modules/data_pipeline.py import-3.7!skip
-plugins/modules/data_pipeline.py metaclass-boilerplate!skip
-plugins/modules/dms_endpoint.py compile-2.6!skip
-plugins/modules/dms_endpoint.py compile-2.7!skip
-plugins/modules/dms_endpoint.py compile-3.5!skip
-plugins/modules/dms_endpoint.py compile-3.6!skip
-plugins/modules/dms_endpoint.py compile-3.7!skip
-plugins/modules/dms_endpoint.py future-import-boilerplate!skip
-plugins/modules/dms_endpoint.py import-2.6!skip
-plugins/modules/dms_endpoint.py import-2.7!skip
-plugins/modules/dms_endpoint.py import-3.5!skip
-plugins/modules/dms_endpoint.py import-3.6!skip
-plugins/modules/dms_endpoint.py import-3.7!skip
-plugins/modules/dms_endpoint.py metaclass-boilerplate!skip
-plugins/modules/dms_replication_subnet_group.py compile-2.6!skip
-plugins/modules/dms_replication_subnet_group.py compile-2.7!skip
-plugins/modules/dms_replication_subnet_group.py compile-3.5!skip
-plugins/modules/dms_replication_subnet_group.py compile-3.6!skip
-plugins/modules/dms_replication_subnet_group.py compile-3.7!skip
-plugins/modules/dms_replication_subnet_group.py future-import-boilerplate!skip
-plugins/modules/dms_replication_subnet_group.py import-2.6!skip
-plugins/modules/dms_replication_subnet_group.py import-2.7!skip
-plugins/modules/dms_replication_subnet_group.py import-3.5!skip
-plugins/modules/dms_replication_subnet_group.py import-3.6!skip
-plugins/modules/dms_replication_subnet_group.py import-3.7!skip
-plugins/modules/dms_replication_subnet_group.py metaclass-boilerplate!skip
-plugins/modules/dynamodb_table.py compile-2.6!skip
-plugins/modules/dynamodb_table.py compile-2.7!skip
-plugins/modules/dynamodb_table.py compile-3.5!skip
-plugins/modules/dynamodb_table.py compile-3.6!skip
-plugins/modules/dynamodb_table.py compile-3.7!skip
-plugins/modules/dynamodb_table.py future-import-boilerplate!skip
-plugins/modules/dynamodb_table.py import-2.6!skip
-plugins/modules/dynamodb_table.py import-2.7!skip
-plugins/modules/dynamodb_table.py import-3.5!skip
-plugins/modules/dynamodb_table.py import-3.6!skip
-plugins/modules/dynamodb_table.py import-3.7!skip
-plugins/modules/dynamodb_table.py metaclass-boilerplate!skip
-plugins/modules/dynamodb_ttl.py compile-2.6!skip
-plugins/modules/dynamodb_ttl.py compile-2.7!skip
-plugins/modules/dynamodb_ttl.py compile-3.5!skip
-plugins/modules/dynamodb_ttl.py compile-3.6!skip
-plugins/modules/dynamodb_ttl.py compile-3.7!skip
-plugins/modules/dynamodb_ttl.py future-import-boilerplate!skip
-plugins/modules/dynamodb_ttl.py import-2.6!skip
-plugins/modules/dynamodb_ttl.py import-2.7!skip
-plugins/modules/dynamodb_ttl.py import-3.5!skip
-plugins/modules/dynamodb_ttl.py import-3.6!skip
-plugins/modules/dynamodb_ttl.py import-3.7!skip
-plugins/modules/dynamodb_ttl.py metaclass-boilerplate!skip
-plugins/modules/ec2_ami_copy.py compile-2.6!skip
-plugins/modules/ec2_ami_copy.py compile-2.7!skip
-plugins/modules/ec2_ami_copy.py compile-3.5!skip
-plugins/modules/ec2_ami_copy.py compile-3.6!skip
-plugins/modules/ec2_ami_copy.py compile-3.7!skip
-plugins/modules/ec2_ami_copy.py future-import-boilerplate!skip
-plugins/modules/ec2_ami_copy.py import-2.6!skip
-plugins/modules/ec2_ami_copy.py import-2.7!skip
-plugins/modules/ec2_ami_copy.py import-3.5!skip
-plugins/modules/ec2_ami_copy.py import-3.6!skip
-plugins/modules/ec2_ami_copy.py import-3.7!skip
-plugins/modules/ec2_ami_copy.py metaclass-boilerplate!skip
-plugins/modules/ec2_asg.py compile-2.6!skip
-plugins/modules/ec2_asg.py compile-2.7!skip
-plugins/modules/ec2_asg.py compile-3.5!skip
-plugins/modules/ec2_asg.py compile-3.6!skip
-plugins/modules/ec2_asg.py compile-3.7!skip
-plugins/modules/ec2_asg.py future-import-boilerplate!skip
-plugins/modules/ec2_asg.py import-2.6!skip
-plugins/modules/ec2_asg.py import-2.7!skip
-plugins/modules/ec2_asg.py import-3.5!skip
-plugins/modules/ec2_asg.py import-3.6!skip
-plugins/modules/ec2_asg.py import-3.7!skip
-plugins/modules/ec2_asg.py metaclass-boilerplate!skip
-plugins/modules/ec2_asg_info.py compile-2.6!skip
-plugins/modules/ec2_asg_info.py compile-2.7!skip
-plugins/modules/ec2_asg_info.py compile-3.5!skip
-plugins/modules/ec2_asg_info.py compile-3.6!skip
-plugins/modules/ec2_asg_info.py compile-3.7!skip
-plugins/modules/ec2_asg_info.py future-import-boilerplate!skip
-plugins/modules/ec2_asg_info.py import-2.6!skip
-plugins/modules/ec2_asg_info.py import-2.7!skip
-plugins/modules/ec2_asg_info.py import-3.5!skip
-plugins/modules/ec2_asg_info.py import-3.6!skip
-plugins/modules/ec2_asg_info.py import-3.7!skip
-plugins/modules/ec2_asg_info.py metaclass-boilerplate!skip
-plugins/modules/ec2_asg_lifecycle_hook.py compile-2.6!skip
-plugins/modules/ec2_asg_lifecycle_hook.py compile-2.7!skip
-plugins/modules/ec2_asg_lifecycle_hook.py compile-3.5!skip
-plugins/modules/ec2_asg_lifecycle_hook.py compile-3.6!skip
-plugins/modules/ec2_asg_lifecycle_hook.py compile-3.7!skip
-plugins/modules/ec2_asg_lifecycle_hook.py future-import-boilerplate!skip
-plugins/modules/ec2_asg_lifecycle_hook.py import-2.6!skip
-plugins/modules/ec2_asg_lifecycle_hook.py import-2.7!skip
-plugins/modules/ec2_asg_lifecycle_hook.py import-3.5!skip
-plugins/modules/ec2_asg_lifecycle_hook.py import-3.6!skip
-plugins/modules/ec2_asg_lifecycle_hook.py import-3.7!skip
-plugins/modules/ec2_asg_lifecycle_hook.py metaclass-boilerplate!skip
-plugins/modules/ec2_customer_gateway.py compile-2.6!skip
-plugins/modules/ec2_customer_gateway.py compile-2.7!skip
-plugins/modules/ec2_customer_gateway.py compile-3.5!skip
-plugins/modules/ec2_customer_gateway.py compile-3.6!skip
-plugins/modules/ec2_customer_gateway.py compile-3.7!skip
-plugins/modules/ec2_customer_gateway.py future-import-boilerplate!skip
-plugins/modules/ec2_customer_gateway.py import-2.6!skip
-plugins/modules/ec2_customer_gateway.py import-2.7!skip
-plugins/modules/ec2_customer_gateway.py import-3.5!skip
-plugins/modules/ec2_customer_gateway.py import-3.6!skip
-plugins/modules/ec2_customer_gateway.py import-3.7!skip
-plugins/modules/ec2_customer_gateway.py metaclass-boilerplate!skip
-plugins/modules/ec2_customer_gateway_info.py compile-2.6!skip
-plugins/modules/ec2_customer_gateway_info.py compile-2.7!skip
-plugins/modules/ec2_customer_gateway_info.py compile-3.5!skip
-plugins/modules/ec2_customer_gateway_info.py compile-3.6!skip
-plugins/modules/ec2_customer_gateway_info.py compile-3.7!skip
-plugins/modules/ec2_customer_gateway_info.py future-import-boilerplate!skip
-plugins/modules/ec2_customer_gateway_info.py import-2.6!skip
-plugins/modules/ec2_customer_gateway_info.py import-2.7!skip
-plugins/modules/ec2_customer_gateway_info.py import-3.5!skip
-plugins/modules/ec2_customer_gateway_info.py import-3.6!skip
-plugins/modules/ec2_customer_gateway_info.py import-3.7!skip
-plugins/modules/ec2_customer_gateway_info.py metaclass-boilerplate!skip
-plugins/modules/ec2_eip.py compile-2.6!skip
-plugins/modules/ec2_eip.py compile-2.7!skip
-plugins/modules/ec2_eip.py compile-3.5!skip
-plugins/modules/ec2_eip.py compile-3.6!skip
-plugins/modules/ec2_eip.py compile-3.7!skip
-plugins/modules/ec2_eip.py future-import-boilerplate!skip
-plugins/modules/ec2_eip.py import-2.6!skip
-plugins/modules/ec2_eip.py import-2.7!skip
-plugins/modules/ec2_eip.py import-3.5!skip
-plugins/modules/ec2_eip.py import-3.6!skip
-plugins/modules/ec2_eip.py import-3.7!skip
-plugins/modules/ec2_eip.py metaclass-boilerplate!skip
-plugins/modules/ec2_eip_info.py compile-2.6!skip
-plugins/modules/ec2_eip_info.py compile-2.7!skip
-plugins/modules/ec2_eip_info.py compile-3.5!skip
-plugins/modules/ec2_eip_info.py compile-3.6!skip
-plugins/modules/ec2_eip_info.py compile-3.7!skip
-plugins/modules/ec2_eip_info.py future-import-boilerplate!skip
-plugins/modules/ec2_eip_info.py import-2.6!skip
-plugins/modules/ec2_eip_info.py import-2.7!skip
-plugins/modules/ec2_eip_info.py import-3.5!skip
-plugins/modules/ec2_eip_info.py import-3.6!skip
-plugins/modules/ec2_eip_info.py import-3.7!skip
-plugins/modules/ec2_eip_info.py metaclass-boilerplate!skip
-plugins/modules/ec2_elb_info.py compile-2.6!skip
-plugins/modules/ec2_elb_info.py compile-2.7!skip
-plugins/modules/ec2_elb_info.py compile-3.5!skip
-plugins/modules/ec2_elb_info.py compile-3.6!skip
-plugins/modules/ec2_elb_info.py compile-3.7!skip
-plugins/modules/ec2_elb_info.py future-import-boilerplate!skip
-plugins/modules/ec2_elb_info.py import-2.6!skip
-plugins/modules/ec2_elb_info.py import-2.7!skip
-plugins/modules/ec2_elb_info.py import-3.5!skip
-plugins/modules/ec2_elb_info.py import-3.6!skip
-plugins/modules/ec2_elb_info.py import-3.7!skip
-plugins/modules/ec2_elb_info.py metaclass-boilerplate!skip
-plugins/modules/ec2_launch_template.py compile-2.6!skip
-plugins/modules/ec2_launch_template.py compile-2.7!skip
-plugins/modules/ec2_launch_template.py compile-3.5!skip
-plugins/modules/ec2_launch_template.py compile-3.6!skip
-plugins/modules/ec2_launch_template.py compile-3.7!skip
-plugins/modules/ec2_launch_template.py future-import-boilerplate!skip
-plugins/modules/ec2_launch_template.py import-2.6!skip
-plugins/modules/ec2_launch_template.py import-2.7!skip
-plugins/modules/ec2_launch_template.py import-3.5!skip
-plugins/modules/ec2_launch_template.py import-3.6!skip
-plugins/modules/ec2_launch_template.py import-3.7!skip
-plugins/modules/ec2_launch_template.py metaclass-boilerplate!skip
-plugins/modules/ec2_lc.py compile-2.6!skip
-plugins/modules/ec2_lc.py compile-2.7!skip
-plugins/modules/ec2_lc.py compile-3.5!skip
-plugins/modules/ec2_lc.py compile-3.6!skip
-plugins/modules/ec2_lc.py compile-3.7!skip
-plugins/modules/ec2_lc.py future-import-boilerplate!skip
-plugins/modules/ec2_lc.py import-2.6!skip
-plugins/modules/ec2_lc.py import-2.7!skip
-plugins/modules/ec2_lc.py import-3.5!skip
-plugins/modules/ec2_lc.py import-3.6!skip
-plugins/modules/ec2_lc.py import-3.7!skip
-plugins/modules/ec2_lc.py metaclass-boilerplate!skip
-plugins/modules/ec2_lc_find.py compile-2.6!skip
-plugins/modules/ec2_lc_find.py compile-2.7!skip
-plugins/modules/ec2_lc_find.py compile-3.5!skip
-plugins/modules/ec2_lc_find.py compile-3.6!skip
-plugins/modules/ec2_lc_find.py compile-3.7!skip
-plugins/modules/ec2_lc_find.py future-import-boilerplate!skip
-plugins/modules/ec2_lc_find.py import-2.6!skip
-plugins/modules/ec2_lc_find.py import-2.7!skip
-plugins/modules/ec2_lc_find.py import-3.5!skip
-plugins/modules/ec2_lc_find.py import-3.6!skip
-plugins/modules/ec2_lc_find.py import-3.7!skip
-plugins/modules/ec2_lc_find.py metaclass-boilerplate!skip
-plugins/modules/ec2_lc_info.py compile-2.6!skip
-plugins/modules/ec2_lc_info.py compile-2.7!skip
-plugins/modules/ec2_lc_info.py compile-3.5!skip
-plugins/modules/ec2_lc_info.py compile-3.6!skip
-plugins/modules/ec2_lc_info.py compile-3.7!skip
-plugins/modules/ec2_lc_info.py future-import-boilerplate!skip
-plugins/modules/ec2_lc_info.py import-2.6!skip
-plugins/modules/ec2_lc_info.py import-2.7!skip
-plugins/modules/ec2_lc_info.py import-3.5!skip
-plugins/modules/ec2_lc_info.py import-3.6!skip
-plugins/modules/ec2_lc_info.py import-3.7!skip
-plugins/modules/ec2_lc_info.py metaclass-boilerplate!skip
-plugins/modules/ec2_metric_alarm.py compile-2.6!skip
-plugins/modules/ec2_metric_alarm.py compile-2.7!skip
-plugins/modules/ec2_metric_alarm.py compile-3.5!skip
-plugins/modules/ec2_metric_alarm.py compile-3.6!skip
-plugins/modules/ec2_metric_alarm.py compile-3.7!skip
-plugins/modules/ec2_metric_alarm.py future-import-boilerplate!skip
-plugins/modules/ec2_metric_alarm.py import-2.6!skip
-plugins/modules/ec2_metric_alarm.py import-2.7!skip
-plugins/modules/ec2_metric_alarm.py import-3.5!skip
-plugins/modules/ec2_metric_alarm.py import-3.6!skip
-plugins/modules/ec2_metric_alarm.py import-3.7!skip
-plugins/modules/ec2_metric_alarm.py metaclass-boilerplate!skip
-plugins/modules/ec2_placement_group.py compile-2.6!skip
-plugins/modules/ec2_placement_group.py compile-2.7!skip
-plugins/modules/ec2_placement_group.py compile-3.5!skip
-plugins/modules/ec2_placement_group.py compile-3.6!skip
-plugins/modules/ec2_placement_group.py compile-3.7!skip
-plugins/modules/ec2_placement_group.py future-import-boilerplate!skip
-plugins/modules/ec2_placement_group.py import-2.6!skip
-plugins/modules/ec2_placement_group.py import-2.7!skip
-plugins/modules/ec2_placement_group.py import-3.5!skip
-plugins/modules/ec2_placement_group.py import-3.6!skip
-plugins/modules/ec2_placement_group.py import-3.7!skip
-plugins/modules/ec2_placement_group.py metaclass-boilerplate!skip
-plugins/modules/ec2_placement_group_info.py compile-2.6!skip
-plugins/modules/ec2_placement_group_info.py compile-2.7!skip
-plugins/modules/ec2_placement_group_info.py compile-3.5!skip
-plugins/modules/ec2_placement_group_info.py compile-3.6!skip
-plugins/modules/ec2_placement_group_info.py compile-3.7!skip
-plugins/modules/ec2_placement_group_info.py future-import-boilerplate!skip
-plugins/modules/ec2_placement_group_info.py import-2.6!skip
-plugins/modules/ec2_placement_group_info.py import-2.7!skip
-plugins/modules/ec2_placement_group_info.py import-3.5!skip
-plugins/modules/ec2_placement_group_info.py import-3.6!skip
-plugins/modules/ec2_placement_group_info.py import-3.7!skip
-plugins/modules/ec2_placement_group_info.py metaclass-boilerplate!skip
-plugins/modules/ec2_scaling_policy.py compile-2.6!skip
-plugins/modules/ec2_scaling_policy.py compile-2.7!skip
-plugins/modules/ec2_scaling_policy.py compile-3.5!skip
-plugins/modules/ec2_scaling_policy.py compile-3.6!skip
-plugins/modules/ec2_scaling_policy.py compile-3.7!skip
-plugins/modules/ec2_scaling_policy.py future-import-boilerplate!skip
-plugins/modules/ec2_scaling_policy.py import-2.6!skip
-plugins/modules/ec2_scaling_policy.py import-2.7!skip
-plugins/modules/ec2_scaling_policy.py import-3.5!skip
-plugins/modules/ec2_scaling_policy.py import-3.6!skip
-plugins/modules/ec2_scaling_policy.py import-3.7!skip
-plugins/modules/ec2_scaling_policy.py metaclass-boilerplate!skip
-plugins/modules/ec2_snapshot_copy.py compile-2.6!skip
-plugins/modules/ec2_snapshot_copy.py compile-2.7!skip
-plugins/modules/ec2_snapshot_copy.py compile-3.5!skip
-plugins/modules/ec2_snapshot_copy.py compile-3.6!skip
-plugins/modules/ec2_snapshot_copy.py compile-3.7!skip
-plugins/modules/ec2_snapshot_copy.py future-import-boilerplate!skip
-plugins/modules/ec2_snapshot_copy.py import-2.6!skip
-plugins/modules/ec2_snapshot_copy.py import-2.7!skip
-plugins/modules/ec2_snapshot_copy.py import-3.5!skip
-plugins/modules/ec2_snapshot_copy.py import-3.6!skip
-plugins/modules/ec2_snapshot_copy.py import-3.7!skip
-plugins/modules/ec2_snapshot_copy.py metaclass-boilerplate!skip
-plugins/modules/ec2_transit_gateway.py compile-2.6!skip
-plugins/modules/ec2_transit_gateway.py compile-2.7!skip
-plugins/modules/ec2_transit_gateway.py compile-3.5!skip
-plugins/modules/ec2_transit_gateway.py compile-3.6!skip
-plugins/modules/ec2_transit_gateway.py compile-3.7!skip
-plugins/modules/ec2_transit_gateway.py future-import-boilerplate!skip
-plugins/modules/ec2_transit_gateway.py import-2.6!skip
-plugins/modules/ec2_transit_gateway.py import-2.7!skip
-plugins/modules/ec2_transit_gateway.py import-3.5!skip
-plugins/modules/ec2_transit_gateway.py import-3.6!skip
-plugins/modules/ec2_transit_gateway.py import-3.7!skip
-plugins/modules/ec2_transit_gateway.py metaclass-boilerplate!skip
-plugins/modules/ec2_transit_gateway_info.py compile-2.6!skip
-plugins/modules/ec2_transit_gateway_info.py compile-2.7!skip
-plugins/modules/ec2_transit_gateway_info.py compile-3.5!skip
-plugins/modules/ec2_transit_gateway_info.py compile-3.6!skip
-plugins/modules/ec2_transit_gateway_info.py compile-3.7!skip
-plugins/modules/ec2_transit_gateway_info.py future-import-boilerplate!skip
-plugins/modules/ec2_transit_gateway_info.py import-2.6!skip
-plugins/modules/ec2_transit_gateway_info.py import-2.7!skip
-plugins/modules/ec2_transit_gateway_info.py import-3.5!skip
-plugins/modules/ec2_transit_gateway_info.py import-3.6!skip
-plugins/modules/ec2_transit_gateway_info.py import-3.7!skip
-plugins/modules/ec2_transit_gateway_info.py metaclass-boilerplate!skip
-plugins/modules/ec2_vpc_egress_igw.py compile-2.6!skip
-plugins/modules/ec2_vpc_egress_igw.py compile-2.7!skip
-plugins/modules/ec2_vpc_egress_igw.py compile-3.5!skip
-plugins/modules/ec2_vpc_egress_igw.py compile-3.6!skip
-plugins/modules/ec2_vpc_egress_igw.py compile-3.7!skip
-plugins/modules/ec2_vpc_egress_igw.py future-import-boilerplate!skip
-plugins/modules/ec2_vpc_egress_igw.py import-2.6!skip
-plugins/modules/ec2_vpc_egress_igw.py import-2.7!skip
-plugins/modules/ec2_vpc_egress_igw.py import-3.5!skip
-plugins/modules/ec2_vpc_egress_igw.py import-3.6!skip
-plugins/modules/ec2_vpc_egress_igw.py import-3.7!skip
-plugins/modules/ec2_vpc_egress_igw.py metaclass-boilerplate!skip
-plugins/modules/ec2_vpc_endpoint.py compile-2.6!skip
-plugins/modules/ec2_vpc_endpoint.py compile-2.7!skip
-plugins/modules/ec2_vpc_endpoint.py compile-3.5!skip
-plugins/modules/ec2_vpc_endpoint.py compile-3.6!skip
-plugins/modules/ec2_vpc_endpoint.py compile-3.7!skip
-plugins/modules/ec2_vpc_endpoint.py future-import-boilerplate!skip
-plugins/modules/ec2_vpc_endpoint.py import-2.6!skip
-plugins/modules/ec2_vpc_endpoint.py import-2.7!skip
-plugins/modules/ec2_vpc_endpoint.py import-3.5!skip
-plugins/modules/ec2_vpc_endpoint.py import-3.6!skip
-plugins/modules/ec2_vpc_endpoint.py import-3.7!skip
-plugins/modules/ec2_vpc_endpoint.py metaclass-boilerplate!skip
-plugins/modules/ec2_vpc_endpoint_info.py compile-2.6!skip
-plugins/modules/ec2_vpc_endpoint_info.py compile-2.7!skip
-plugins/modules/ec2_vpc_endpoint_info.py compile-3.5!skip
-plugins/modules/ec2_vpc_endpoint_info.py compile-3.6!skip
-plugins/modules/ec2_vpc_endpoint_info.py compile-3.7!skip
-plugins/modules/ec2_vpc_endpoint_info.py future-import-boilerplate!skip
-plugins/modules/ec2_vpc_endpoint_info.py import-2.6!skip
-plugins/modules/ec2_vpc_endpoint_info.py import-2.7!skip
-plugins/modules/ec2_vpc_endpoint_info.py import-3.5!skip
-plugins/modules/ec2_vpc_endpoint_info.py import-3.6!skip
-plugins/modules/ec2_vpc_endpoint_info.py import-3.7!skip
-plugins/modules/ec2_vpc_endpoint_info.py metaclass-boilerplate!skip
-plugins/modules/ec2_vpc_endpoint_service_info.py compile-2.6!skip
-plugins/modules/ec2_vpc_endpoint_service_info.py compile-2.7!skip
-plugins/modules/ec2_vpc_endpoint_service_info.py compile-3.5!skip
-plugins/modules/ec2_vpc_endpoint_service_info.py compile-3.6!skip
-plugins/modules/ec2_vpc_endpoint_service_info.py compile-3.7!skip
-plugins/modules/ec2_vpc_endpoint_service_info.py future-import-boilerplate!skip
-plugins/modules/ec2_vpc_endpoint_service_info.py import-2.6!skip
-plugins/modules/ec2_vpc_endpoint_service_info.py import-2.7!skip
-plugins/modules/ec2_vpc_endpoint_service_info.py import-3.5!skip
-plugins/modules/ec2_vpc_endpoint_service_info.py import-3.6!skip
-plugins/modules/ec2_vpc_endpoint_service_info.py import-3.7!skip
-plugins/modules/ec2_vpc_endpoint_service_info.py metaclass-boilerplate!skip
-plugins/modules/ec2_vpc_igw.py compile-2.6!skip
-plugins/modules/ec2_vpc_igw.py compile-2.7!skip
-plugins/modules/ec2_vpc_igw.py compile-3.5!skip
-plugins/modules/ec2_vpc_igw.py compile-3.6!skip
-plugins/modules/ec2_vpc_igw.py compile-3.7!skip
-plugins/modules/ec2_vpc_igw.py future-import-boilerplate!skip
-plugins/modules/ec2_vpc_igw.py import-2.6!skip
-plugins/modules/ec2_vpc_igw.py import-2.7!skip
-plugins/modules/ec2_vpc_igw.py import-3.5!skip
-plugins/modules/ec2_vpc_igw.py import-3.6!skip
-plugins/modules/ec2_vpc_igw.py import-3.7!skip
-plugins/modules/ec2_vpc_igw.py metaclass-boilerplate!skip
-plugins/modules/ec2_vpc_igw_info.py compile-2.6!skip
-plugins/modules/ec2_vpc_igw_info.py compile-2.7!skip
-plugins/modules/ec2_vpc_igw_info.py compile-3.5!skip
-plugins/modules/ec2_vpc_igw_info.py compile-3.6!skip
-plugins/modules/ec2_vpc_igw_info.py compile-3.7!skip
-plugins/modules/ec2_vpc_igw_info.py future-import-boilerplate!skip
-plugins/modules/ec2_vpc_igw_info.py import-2.6!skip
-plugins/modules/ec2_vpc_igw_info.py import-2.7!skip
-plugins/modules/ec2_vpc_igw_info.py import-3.5!skip
-plugins/modules/ec2_vpc_igw_info.py import-3.6!skip
-plugins/modules/ec2_vpc_igw_info.py import-3.7!skip
-plugins/modules/ec2_vpc_igw_info.py metaclass-boilerplate!skip
-plugins/modules/ec2_vpc_nacl.py compile-2.6!skip
-plugins/modules/ec2_vpc_nacl.py compile-2.7!skip
-plugins/modules/ec2_vpc_nacl.py compile-3.5!skip
-plugins/modules/ec2_vpc_nacl.py compile-3.6!skip
-plugins/modules/ec2_vpc_nacl.py compile-3.7!skip
-plugins/modules/ec2_vpc_nacl.py future-import-boilerplate!skip
-plugins/modules/ec2_vpc_nacl.py import-2.6!skip
-plugins/modules/ec2_vpc_nacl.py import-2.7!skip
-plugins/modules/ec2_vpc_nacl.py import-3.5!skip
-plugins/modules/ec2_vpc_nacl.py import-3.6!skip
-plugins/modules/ec2_vpc_nacl.py import-3.7!skip
-plugins/modules/ec2_vpc_nacl.py metaclass-boilerplate!skip
-plugins/modules/ec2_vpc_nacl_info.py compile-2.6!skip
-plugins/modules/ec2_vpc_nacl_info.py compile-2.7!skip
-plugins/modules/ec2_vpc_nacl_info.py compile-3.5!skip
-plugins/modules/ec2_vpc_nacl_info.py compile-3.6!skip
-plugins/modules/ec2_vpc_nacl_info.py compile-3.7!skip
-plugins/modules/ec2_vpc_nacl_info.py future-import-boilerplate!skip
-plugins/modules/ec2_vpc_nacl_info.py import-2.6!skip
-plugins/modules/ec2_vpc_nacl_info.py import-2.7!skip
-plugins/modules/ec2_vpc_nacl_info.py import-3.5!skip
-plugins/modules/ec2_vpc_nacl_info.py import-3.6!skip
-plugins/modules/ec2_vpc_nacl_info.py import-3.7!skip
-plugins/modules/ec2_vpc_nacl_info.py metaclass-boilerplate!skip
-plugins/modules/ec2_vpc_nat_gateway.py compile-2.6!skip
-plugins/modules/ec2_vpc_nat_gateway.py compile-2.7!skip
-plugins/modules/ec2_vpc_nat_gateway.py compile-3.5!skip
-plugins/modules/ec2_vpc_nat_gateway.py compile-3.6!skip
-plugins/modules/ec2_vpc_nat_gateway.py compile-3.7!skip
-plugins/modules/ec2_vpc_nat_gateway.py future-import-boilerplate!skip
-plugins/modules/ec2_vpc_nat_gateway.py import-2.6!skip
-plugins/modules/ec2_vpc_nat_gateway.py import-2.7!skip
-plugins/modules/ec2_vpc_nat_gateway.py import-3.5!skip
-plugins/modules/ec2_vpc_nat_gateway.py import-3.6!skip
-plugins/modules/ec2_vpc_nat_gateway.py import-3.7!skip
-plugins/modules/ec2_vpc_nat_gateway.py metaclass-boilerplate!skip
-plugins/modules/ec2_vpc_nat_gateway_info.py compile-2.6!skip
-plugins/modules/ec2_vpc_nat_gateway_info.py compile-2.7!skip
-plugins/modules/ec2_vpc_nat_gateway_info.py compile-3.5!skip
-plugins/modules/ec2_vpc_nat_gateway_info.py compile-3.6!skip
-plugins/modules/ec2_vpc_nat_gateway_info.py compile-3.7!skip
-plugins/modules/ec2_vpc_nat_gateway_info.py future-import-boilerplate!skip
-plugins/modules/ec2_vpc_nat_gateway_info.py import-2.6!skip
-plugins/modules/ec2_vpc_nat_gateway_info.py import-2.7!skip
-plugins/modules/ec2_vpc_nat_gateway_info.py import-3.5!skip
-plugins/modules/ec2_vpc_nat_gateway_info.py import-3.6!skip
-plugins/modules/ec2_vpc_nat_gateway_info.py import-3.7!skip
-plugins/modules/ec2_vpc_nat_gateway_info.py metaclass-boilerplate!skip
-plugins/modules/ec2_vpc_peer.py compile-2.6!skip
-plugins/modules/ec2_vpc_peer.py compile-2.7!skip
-plugins/modules/ec2_vpc_peer.py compile-3.5!skip
-plugins/modules/ec2_vpc_peer.py compile-3.6!skip
-plugins/modules/ec2_vpc_peer.py compile-3.7!skip
-plugins/modules/ec2_vpc_peer.py future-import-boilerplate!skip
-plugins/modules/ec2_vpc_peer.py import-2.6!skip
-plugins/modules/ec2_vpc_peer.py import-2.7!skip
-plugins/modules/ec2_vpc_peer.py import-3.5!skip
-plugins/modules/ec2_vpc_peer.py import-3.6!skip
-plugins/modules/ec2_vpc_peer.py import-3.7!skip
-plugins/modules/ec2_vpc_peer.py metaclass-boilerplate!skip
-plugins/modules/ec2_vpc_peering_info.py compile-2.6!skip
-plugins/modules/ec2_vpc_peering_info.py compile-2.7!skip
-plugins/modules/ec2_vpc_peering_info.py compile-3.5!skip
-plugins/modules/ec2_vpc_peering_info.py compile-3.6!skip
-plugins/modules/ec2_vpc_peering_info.py compile-3.7!skip
-plugins/modules/ec2_vpc_peering_info.py future-import-boilerplate!skip
-plugins/modules/ec2_vpc_peering_info.py import-2.6!skip
-plugins/modules/ec2_vpc_peering_info.py import-2.7!skip
-plugins/modules/ec2_vpc_peering_info.py import-3.5!skip
-plugins/modules/ec2_vpc_peering_info.py import-3.6!skip
-plugins/modules/ec2_vpc_peering_info.py import-3.7!skip
-plugins/modules/ec2_vpc_peering_info.py metaclass-boilerplate!skip
-plugins/modules/ec2_vpc_route_table.py compile-2.6!skip
-plugins/modules/ec2_vpc_route_table.py compile-2.7!skip
-plugins/modules/ec2_vpc_route_table.py compile-3.5!skip
-plugins/modules/ec2_vpc_route_table.py compile-3.6!skip
-plugins/modules/ec2_vpc_route_table.py compile-3.7!skip
-plugins/modules/ec2_vpc_route_table.py future-import-boilerplate!skip
-plugins/modules/ec2_vpc_route_table.py import-2.6!skip
-plugins/modules/ec2_vpc_route_table.py import-2.7!skip
-plugins/modules/ec2_vpc_route_table.py import-3.5!skip
-plugins/modules/ec2_vpc_route_table.py import-3.6!skip
-plugins/modules/ec2_vpc_route_table.py import-3.7!skip
-plugins/modules/ec2_vpc_route_table.py metaclass-boilerplate!skip
-plugins/modules/ec2_vpc_route_table_info.py compile-2.6!skip
-plugins/modules/ec2_vpc_route_table_info.py compile-2.7!skip
-plugins/modules/ec2_vpc_route_table_info.py compile-3.5!skip
-plugins/modules/ec2_vpc_route_table_info.py compile-3.6!skip
-plugins/modules/ec2_vpc_route_table_info.py compile-3.7!skip
-plugins/modules/ec2_vpc_route_table_info.py future-import-boilerplate!skip
-plugins/modules/ec2_vpc_route_table_info.py import-2.6!skip
-plugins/modules/ec2_vpc_route_table_info.py import-2.7!skip
-plugins/modules/ec2_vpc_route_table_info.py import-3.5!skip
-plugins/modules/ec2_vpc_route_table_info.py import-3.6!skip
-plugins/modules/ec2_vpc_route_table_info.py import-3.7!skip
-plugins/modules/ec2_vpc_route_table_info.py metaclass-boilerplate!skip
-plugins/modules/ec2_vpc_vgw.py compile-2.6!skip
-plugins/modules/ec2_vpc_vgw.py compile-2.7!skip
-plugins/modules/ec2_vpc_vgw.py compile-3.5!skip
-plugins/modules/ec2_vpc_vgw.py compile-3.6!skip
-plugins/modules/ec2_vpc_vgw.py compile-3.7!skip
-plugins/modules/ec2_vpc_vgw.py future-import-boilerplate!skip
-plugins/modules/ec2_vpc_vgw.py import-2.6!skip
-plugins/modules/ec2_vpc_vgw.py import-2.7!skip
-plugins/modules/ec2_vpc_vgw.py import-3.5!skip
-plugins/modules/ec2_vpc_vgw.py import-3.6!skip
-plugins/modules/ec2_vpc_vgw.py import-3.7!skip
-plugins/modules/ec2_vpc_vgw.py metaclass-boilerplate!skip
-plugins/modules/ec2_vpc_vgw_info.py compile-2.6!skip
-plugins/modules/ec2_vpc_vgw_info.py compile-2.7!skip
-plugins/modules/ec2_vpc_vgw_info.py compile-3.5!skip
-plugins/modules/ec2_vpc_vgw_info.py compile-3.6!skip
-plugins/modules/ec2_vpc_vgw_info.py compile-3.7!skip
-plugins/modules/ec2_vpc_vgw_info.py future-import-boilerplate!skip
-plugins/modules/ec2_vpc_vgw_info.py import-2.6!skip
-plugins/modules/ec2_vpc_vgw_info.py import-2.7!skip
-plugins/modules/ec2_vpc_vgw_info.py import-3.5!skip
-plugins/modules/ec2_vpc_vgw_info.py import-3.6!skip
-plugins/modules/ec2_vpc_vgw_info.py import-3.7!skip
-plugins/modules/ec2_vpc_vgw_info.py metaclass-boilerplate!skip
-plugins/modules/ec2_vpc_vpn.py compile-2.6!skip
-plugins/modules/ec2_vpc_vpn.py compile-2.7!skip
-plugins/modules/ec2_vpc_vpn.py compile-3.5!skip
-plugins/modules/ec2_vpc_vpn.py compile-3.6!skip
-plugins/modules/ec2_vpc_vpn.py compile-3.7!skip
-plugins/modules/ec2_vpc_vpn.py future-import-boilerplate!skip
-plugins/modules/ec2_vpc_vpn.py import-2.6!skip
-plugins/modules/ec2_vpc_vpn.py import-2.7!skip
-plugins/modules/ec2_vpc_vpn.py import-3.5!skip
-plugins/modules/ec2_vpc_vpn.py import-3.6!skip
-plugins/modules/ec2_vpc_vpn.py import-3.7!skip
-plugins/modules/ec2_vpc_vpn.py metaclass-boilerplate!skip
-plugins/modules/ec2_vpc_vpn_info.py compile-2.6!skip
-plugins/modules/ec2_vpc_vpn_info.py compile-2.7!skip
-plugins/modules/ec2_vpc_vpn_info.py compile-3.5!skip
-plugins/modules/ec2_vpc_vpn_info.py compile-3.6!skip
-plugins/modules/ec2_vpc_vpn_info.py compile-3.7!skip
-plugins/modules/ec2_vpc_vpn_info.py future-import-boilerplate!skip
-plugins/modules/ec2_vpc_vpn_info.py import-2.6!skip
-plugins/modules/ec2_vpc_vpn_info.py import-2.7!skip
-plugins/modules/ec2_vpc_vpn_info.py import-3.5!skip
-plugins/modules/ec2_vpc_vpn_info.py import-3.6!skip
-plugins/modules/ec2_vpc_vpn_info.py import-3.7!skip
-plugins/modules/ec2_vpc_vpn_info.py metaclass-boilerplate!skip
-plugins/modules/ec2_win_password.py compile-2.6!skip
-plugins/modules/ec2_win_password.py compile-2.7!skip
-plugins/modules/ec2_win_password.py compile-3.5!skip
-plugins/modules/ec2_win_password.py compile-3.6!skip
-plugins/modules/ec2_win_password.py compile-3.7!skip
-plugins/modules/ec2_win_password.py future-import-boilerplate!skip
-plugins/modules/ec2_win_password.py import-2.6!skip
-plugins/modules/ec2_win_password.py import-2.7!skip
-plugins/modules/ec2_win_password.py import-3.5!skip
-plugins/modules/ec2_win_password.py import-3.6!skip
-plugins/modules/ec2_win_password.py import-3.7!skip
-plugins/modules/ec2_win_password.py metaclass-boilerplate!skip
-plugins/modules/ecs_attribute.py compile-2.6!skip
-plugins/modules/ecs_attribute.py compile-2.7!skip
-plugins/modules/ecs_attribute.py compile-3.5!skip
-plugins/modules/ecs_attribute.py compile-3.6!skip
-plugins/modules/ecs_attribute.py compile-3.7!skip
-plugins/modules/ecs_attribute.py future-import-boilerplate!skip
-plugins/modules/ecs_attribute.py import-2.6!skip
-plugins/modules/ecs_attribute.py import-2.7!skip
-plugins/modules/ecs_attribute.py import-3.5!skip
-plugins/modules/ecs_attribute.py import-3.6!skip
-plugins/modules/ecs_attribute.py import-3.7!skip
-plugins/modules/ecs_attribute.py metaclass-boilerplate!skip
-plugins/modules/ecs_cluster.py compile-2.6!skip
-plugins/modules/ecs_cluster.py compile-2.7!skip
-plugins/modules/ecs_cluster.py compile-3.5!skip
-plugins/modules/ecs_cluster.py compile-3.6!skip
-plugins/modules/ecs_cluster.py compile-3.7!skip
-plugins/modules/ecs_cluster.py future-import-boilerplate!skip
-plugins/modules/ecs_cluster.py import-2.6!skip
-plugins/modules/ecs_cluster.py import-2.7!skip
-plugins/modules/ecs_cluster.py import-3.5!skip
-plugins/modules/ecs_cluster.py import-3.6!skip
-plugins/modules/ecs_cluster.py import-3.7!skip
-plugins/modules/ecs_cluster.py metaclass-boilerplate!skip
-plugins/modules/ecs_ecr.py compile-2.6!skip
-plugins/modules/ecs_ecr.py compile-2.7!skip
-plugins/modules/ecs_ecr.py compile-3.5!skip
-plugins/modules/ecs_ecr.py compile-3.6!skip
-plugins/modules/ecs_ecr.py compile-3.7!skip
-plugins/modules/ecs_ecr.py future-import-boilerplate!skip
-plugins/modules/ecs_ecr.py import-2.6!skip
-plugins/modules/ecs_ecr.py import-2.7!skip
-plugins/modules/ecs_ecr.py import-3.5!skip
-plugins/modules/ecs_ecr.py import-3.6!skip
-plugins/modules/ecs_ecr.py import-3.7!skip
-plugins/modules/ecs_ecr.py metaclass-boilerplate!skip
-plugins/modules/ecs_service.py compile-2.6!skip
-plugins/modules/ecs_service.py compile-2.7!skip
-plugins/modules/ecs_service.py compile-3.5!skip
-plugins/modules/ecs_service.py compile-3.6!skip
-plugins/modules/ecs_service.py compile-3.7!skip
-plugins/modules/ecs_service.py future-import-boilerplate!skip
-plugins/modules/ecs_service.py import-2.6!skip
-plugins/modules/ecs_service.py import-2.7!skip
-plugins/modules/ecs_service.py import-3.5!skip
-plugins/modules/ecs_service.py import-3.6!skip
-plugins/modules/ecs_service.py import-3.7!skip
-plugins/modules/ecs_service.py metaclass-boilerplate!skip
-plugins/modules/ecs_service_info.py compile-2.6!skip
-plugins/modules/ecs_service_info.py compile-2.7!skip
-plugins/modules/ecs_service_info.py compile-3.5!skip
-plugins/modules/ecs_service_info.py compile-3.6!skip
-plugins/modules/ecs_service_info.py compile-3.7!skip
-plugins/modules/ecs_service_info.py future-import-boilerplate!skip
-plugins/modules/ecs_service_info.py import-2.6!skip
-plugins/modules/ecs_service_info.py import-2.7!skip
-plugins/modules/ecs_service_info.py import-3.5!skip
-plugins/modules/ecs_service_info.py import-3.6!skip
-plugins/modules/ecs_service_info.py import-3.7!skip
-plugins/modules/ecs_service_info.py metaclass-boilerplate!skip
-plugins/modules/ecs_tag.py compile-2.6!skip
-plugins/modules/ecs_tag.py compile-2.7!skip
-plugins/modules/ecs_tag.py compile-3.5!skip
-plugins/modules/ecs_tag.py compile-3.6!skip
-plugins/modules/ecs_tag.py compile-3.7!skip
-plugins/modules/ecs_tag.py future-import-boilerplate!skip
-plugins/modules/ecs_tag.py import-2.6!skip
-plugins/modules/ecs_tag.py import-2.7!skip
-plugins/modules/ecs_tag.py import-3.5!skip
-plugins/modules/ecs_tag.py import-3.6!skip
-plugins/modules/ecs_tag.py import-3.7!skip
-plugins/modules/ecs_tag.py metaclass-boilerplate!skip
-plugins/modules/ecs_task.py compile-2.6!skip
-plugins/modules/ecs_task.py compile-2.7!skip
-plugins/modules/ecs_task.py compile-3.5!skip
-plugins/modules/ecs_task.py compile-3.6!skip
-plugins/modules/ecs_task.py compile-3.7!skip
-plugins/modules/ecs_task.py future-import-boilerplate!skip
-plugins/modules/ecs_task.py import-2.6!skip
-plugins/modules/ecs_task.py import-2.7!skip
-plugins/modules/ecs_task.py import-3.5!skip
-plugins/modules/ecs_task.py import-3.6!skip
-plugins/modules/ecs_task.py import-3.7!skip
-plugins/modules/ecs_task.py metaclass-boilerplate!skip
-plugins/modules/ecs_taskdefinition.py compile-2.6!skip
-plugins/modules/ecs_taskdefinition.py compile-2.7!skip
-plugins/modules/ecs_taskdefinition.py compile-3.5!skip
-plugins/modules/ecs_taskdefinition.py compile-3.6!skip
-plugins/modules/ecs_taskdefinition.py compile-3.7!skip
-plugins/modules/ecs_taskdefinition.py future-import-boilerplate!skip
-plugins/modules/ecs_taskdefinition.py import-2.6!skip
-plugins/modules/ecs_taskdefinition.py import-2.7!skip
-plugins/modules/ecs_taskdefinition.py import-3.5!skip
-plugins/modules/ecs_taskdefinition.py import-3.6!skip
-plugins/modules/ecs_taskdefinition.py import-3.7!skip
-plugins/modules/ecs_taskdefinition.py metaclass-boilerplate!skip
-plugins/modules/ecs_taskdefinition_info.py compile-2.6!skip
-plugins/modules/ecs_taskdefinition_info.py compile-2.7!skip
-plugins/modules/ecs_taskdefinition_info.py compile-3.5!skip
-plugins/modules/ecs_taskdefinition_info.py compile-3.6!skip
-plugins/modules/ecs_taskdefinition_info.py compile-3.7!skip
-plugins/modules/ecs_taskdefinition_info.py future-import-boilerplate!skip
-plugins/modules/ecs_taskdefinition_info.py import-2.6!skip
-plugins/modules/ecs_taskdefinition_info.py import-2.7!skip
-plugins/modules/ecs_taskdefinition_info.py import-3.5!skip
-plugins/modules/ecs_taskdefinition_info.py import-3.6!skip
-plugins/modules/ecs_taskdefinition_info.py import-3.7!skip
-plugins/modules/ecs_taskdefinition_info.py metaclass-boilerplate!skip
-plugins/modules/efs.py compile-2.6!skip
-plugins/modules/efs.py compile-2.7!skip
-plugins/modules/efs.py compile-3.5!skip
-plugins/modules/efs.py compile-3.6!skip
-plugins/modules/efs.py compile-3.7!skip
-plugins/modules/efs.py future-import-boilerplate!skip
-plugins/modules/efs.py import-2.6!skip
-plugins/modules/efs.py import-2.7!skip
-plugins/modules/efs.py import-3.5!skip
-plugins/modules/efs.py import-3.6!skip
-plugins/modules/efs.py import-3.7!skip
-plugins/modules/efs.py metaclass-boilerplate!skip
-plugins/modules/efs_info.py compile-2.6!skip
-plugins/modules/efs_info.py compile-2.7!skip
-plugins/modules/efs_info.py compile-3.5!skip
-plugins/modules/efs_info.py compile-3.6!skip
-plugins/modules/efs_info.py compile-3.7!skip
-plugins/modules/efs_info.py future-import-boilerplate!skip
-plugins/modules/efs_info.py import-2.6!skip
-plugins/modules/efs_info.py import-2.7!skip
-plugins/modules/efs_info.py import-3.5!skip
-plugins/modules/efs_info.py import-3.6!skip
-plugins/modules/efs_info.py import-3.7!skip
-plugins/modules/efs_info.py metaclass-boilerplate!skip
-plugins/modules/elasticache.py compile-2.6!skip
-plugins/modules/elasticache.py compile-2.7!skip
-plugins/modules/elasticache.py compile-3.5!skip
-plugins/modules/elasticache.py compile-3.6!skip
-plugins/modules/elasticache.py compile-3.7!skip
-plugins/modules/elasticache.py future-import-boilerplate!skip
-plugins/modules/elasticache.py import-2.6!skip
-plugins/modules/elasticache.py import-2.7!skip
-plugins/modules/elasticache.py import-3.5!skip
-plugins/modules/elasticache.py import-3.6!skip
-plugins/modules/elasticache.py import-3.7!skip
-plugins/modules/elasticache.py metaclass-boilerplate!skip
-plugins/modules/elasticache_info.py compile-2.6!skip
-plugins/modules/elasticache_info.py compile-2.7!skip
-plugins/modules/elasticache_info.py compile-3.5!skip
-plugins/modules/elasticache_info.py compile-3.6!skip
-plugins/modules/elasticache_info.py compile-3.7!skip
-plugins/modules/elasticache_info.py future-import-boilerplate!skip
-plugins/modules/elasticache_info.py import-2.6!skip
-plugins/modules/elasticache_info.py import-2.7!skip
-plugins/modules/elasticache_info.py import-3.5!skip
-plugins/modules/elasticache_info.py import-3.6!skip
-plugins/modules/elasticache_info.py import-3.7!skip
-plugins/modules/elasticache_info.py metaclass-boilerplate!skip
-plugins/modules/elasticache_parameter_group.py compile-2.6!skip
-plugins/modules/elasticache_parameter_group.py compile-2.7!skip
-plugins/modules/elasticache_parameter_group.py compile-3.5!skip
-plugins/modules/elasticache_parameter_group.py compile-3.6!skip
-plugins/modules/elasticache_parameter_group.py compile-3.7!skip
-plugins/modules/elasticache_parameter_group.py future-import-boilerplate!skip
-plugins/modules/elasticache_parameter_group.py import-2.6!skip
-plugins/modules/elasticache_parameter_group.py import-2.7!skip
-plugins/modules/elasticache_parameter_group.py import-3.5!skip
-plugins/modules/elasticache_parameter_group.py import-3.6!skip
-plugins/modules/elasticache_parameter_group.py import-3.7!skip
-plugins/modules/elasticache_parameter_group.py metaclass-boilerplate!skip
-plugins/modules/elasticache_snapshot.py compile-2.6!skip
-plugins/modules/elasticache_snapshot.py compile-2.7!skip
-plugins/modules/elasticache_snapshot.py compile-3.5!skip
-plugins/modules/elasticache_snapshot.py compile-3.6!skip
-plugins/modules/elasticache_snapshot.py compile-3.7!skip
-plugins/modules/elasticache_snapshot.py future-import-boilerplate!skip
-plugins/modules/elasticache_snapshot.py import-2.6!skip
-plugins/modules/elasticache_snapshot.py import-2.7!skip
-plugins/modules/elasticache_snapshot.py import-3.5!skip
-plugins/modules/elasticache_snapshot.py import-3.6!skip
-plugins/modules/elasticache_snapshot.py import-3.7!skip
-plugins/modules/elasticache_snapshot.py metaclass-boilerplate!skip
-plugins/modules/elasticache_subnet_group.py compile-2.6!skip
-plugins/modules/elasticache_subnet_group.py compile-2.7!skip
-plugins/modules/elasticache_subnet_group.py compile-3.5!skip
-plugins/modules/elasticache_subnet_group.py compile-3.6!skip
-plugins/modules/elasticache_subnet_group.py compile-3.7!skip
-plugins/modules/elasticache_subnet_group.py future-import-boilerplate!skip
-plugins/modules/elasticache_subnet_group.py import-2.6!skip
-plugins/modules/elasticache_subnet_group.py import-2.7!skip
-plugins/modules/elasticache_subnet_group.py import-3.5!skip
-plugins/modules/elasticache_subnet_group.py import-3.6!skip
-plugins/modules/elasticache_subnet_group.py import-3.7!skip
-plugins/modules/elasticache_subnet_group.py metaclass-boilerplate!skip
-plugins/modules/elb_application_lb.py compile-2.6!skip
-plugins/modules/elb_application_lb.py compile-2.7!skip
-plugins/modules/elb_application_lb.py compile-3.5!skip
-plugins/modules/elb_application_lb.py compile-3.6!skip
-plugins/modules/elb_application_lb.py compile-3.7!skip
-plugins/modules/elb_application_lb.py future-import-boilerplate!skip
-plugins/modules/elb_application_lb.py import-2.6!skip
-plugins/modules/elb_application_lb.py import-2.7!skip
-plugins/modules/elb_application_lb.py import-3.5!skip
-plugins/modules/elb_application_lb.py import-3.6!skip
-plugins/modules/elb_application_lb.py import-3.7!skip
-plugins/modules/elb_application_lb.py metaclass-boilerplate!skip
-plugins/modules/elb_application_lb_info.py compile-2.6!skip
-plugins/modules/elb_application_lb_info.py compile-2.7!skip
-plugins/modules/elb_application_lb_info.py compile-3.5!skip
-plugins/modules/elb_application_lb_info.py compile-3.6!skip
-plugins/modules/elb_application_lb_info.py compile-3.7!skip
-plugins/modules/elb_application_lb_info.py future-import-boilerplate!skip
-plugins/modules/elb_application_lb_info.py import-2.6!skip
-plugins/modules/elb_application_lb_info.py import-2.7!skip
-plugins/modules/elb_application_lb_info.py import-3.5!skip
-plugins/modules/elb_application_lb_info.py import-3.6!skip
-plugins/modules/elb_application_lb_info.py import-3.7!skip
-plugins/modules/elb_application_lb_info.py metaclass-boilerplate!skip
-plugins/modules/elb_classic_lb_info.py compile-2.6!skip
-plugins/modules/elb_classic_lb_info.py compile-2.7!skip
-plugins/modules/elb_classic_lb_info.py compile-3.5!skip
-plugins/modules/elb_classic_lb_info.py compile-3.6!skip
-plugins/modules/elb_classic_lb_info.py compile-3.7!skip
-plugins/modules/elb_classic_lb_info.py future-import-boilerplate!skip
-plugins/modules/elb_classic_lb_info.py import-2.6!skip
-plugins/modules/elb_classic_lb_info.py import-2.7!skip
-plugins/modules/elb_classic_lb_info.py import-3.5!skip
-plugins/modules/elb_classic_lb_info.py import-3.6!skip
-plugins/modules/elb_classic_lb_info.py import-3.7!skip
-plugins/modules/elb_classic_lb_info.py metaclass-boilerplate!skip
-plugins/modules/elb_instance.py compile-2.6!skip
-plugins/modules/elb_instance.py compile-2.7!skip
-plugins/modules/elb_instance.py compile-3.5!skip
-plugins/modules/elb_instance.py compile-3.6!skip
-plugins/modules/elb_instance.py compile-3.7!skip
-plugins/modules/elb_instance.py future-import-boilerplate!skip
-plugins/modules/elb_instance.py import-2.6!skip
-plugins/modules/elb_instance.py import-2.7!skip
-plugins/modules/elb_instance.py import-3.5!skip
-plugins/modules/elb_instance.py import-3.6!skip
-plugins/modules/elb_instance.py import-3.7!skip
-plugins/modules/elb_instance.py metaclass-boilerplate!skip
-plugins/modules/elb_network_lb.py compile-2.6!skip
-plugins/modules/elb_network_lb.py compile-2.7!skip
-plugins/modules/elb_network_lb.py compile-3.5!skip
-plugins/modules/elb_network_lb.py compile-3.6!skip
-plugins/modules/elb_network_lb.py compile-3.7!skip
-plugins/modules/elb_network_lb.py future-import-boilerplate!skip
-plugins/modules/elb_network_lb.py import-2.6!skip
-plugins/modules/elb_network_lb.py import-2.7!skip
-plugins/modules/elb_network_lb.py import-3.5!skip
-plugins/modules/elb_network_lb.py import-3.6!skip
-plugins/modules/elb_network_lb.py import-3.7!skip
-plugins/modules/elb_network_lb.py metaclass-boilerplate!skip
-plugins/modules/elb_target.py compile-2.6!skip
-plugins/modules/elb_target.py compile-2.7!skip
-plugins/modules/elb_target.py compile-3.5!skip
-plugins/modules/elb_target.py compile-3.6!skip
-plugins/modules/elb_target.py compile-3.7!skip
-plugins/modules/elb_target.py future-import-boilerplate!skip
-plugins/modules/elb_target.py import-2.6!skip
-plugins/modules/elb_target.py import-2.7!skip
-plugins/modules/elb_target.py import-3.5!skip
-plugins/modules/elb_target.py import-3.6!skip
-plugins/modules/elb_target.py import-3.7!skip
-plugins/modules/elb_target.py metaclass-boilerplate!skip
-plugins/modules/elb_target_group.py compile-2.6!skip
-plugins/modules/elb_target_group.py compile-2.7!skip
-plugins/modules/elb_target_group.py compile-3.5!skip
-plugins/modules/elb_target_group.py compile-3.6!skip
-plugins/modules/elb_target_group.py compile-3.7!skip
-plugins/modules/elb_target_group.py future-import-boilerplate!skip
-plugins/modules/elb_target_group.py import-2.6!skip
-plugins/modules/elb_target_group.py import-2.7!skip
-plugins/modules/elb_target_group.py import-3.5!skip
-plugins/modules/elb_target_group.py import-3.6!skip
-plugins/modules/elb_target_group.py import-3.7!skip
-plugins/modules/elb_target_group.py metaclass-boilerplate!skip
-plugins/modules/elb_target_group_info.py compile-2.6!skip
-plugins/modules/elb_target_group_info.py compile-2.7!skip
-plugins/modules/elb_target_group_info.py compile-3.5!skip
-plugins/modules/elb_target_group_info.py compile-3.6!skip
-plugins/modules/elb_target_group_info.py compile-3.7!skip
-plugins/modules/elb_target_group_info.py future-import-boilerplate!skip
-plugins/modules/elb_target_group_info.py import-2.6!skip
-plugins/modules/elb_target_group_info.py import-2.7!skip
-plugins/modules/elb_target_group_info.py import-3.5!skip
-plugins/modules/elb_target_group_info.py import-3.6!skip
-plugins/modules/elb_target_group_info.py import-3.7!skip
-plugins/modules/elb_target_group_info.py metaclass-boilerplate!skip
-plugins/modules/elb_target_info.py compile-2.6!skip
-plugins/modules/elb_target_info.py compile-2.7!skip
-plugins/modules/elb_target_info.py compile-3.5!skip
-plugins/modules/elb_target_info.py compile-3.6!skip
-plugins/modules/elb_target_info.py compile-3.7!skip
-plugins/modules/elb_target_info.py future-import-boilerplate!skip
-plugins/modules/elb_target_info.py import-2.6!skip
-plugins/modules/elb_target_info.py import-2.7!skip
-plugins/modules/elb_target_info.py import-3.5!skip
-plugins/modules/elb_target_info.py import-3.6!skip
-plugins/modules/elb_target_info.py import-3.7!skip
-plugins/modules/elb_target_info.py metaclass-boilerplate!skip
-plugins/modules/execute_lambda.py compile-2.6!skip
-plugins/modules/execute_lambda.py compile-2.7!skip
-plugins/modules/execute_lambda.py compile-3.5!skip
-plugins/modules/execute_lambda.py compile-3.6!skip
-plugins/modules/execute_lambda.py compile-3.7!skip
-plugins/modules/execute_lambda.py future-import-boilerplate!skip
-plugins/modules/execute_lambda.py import-2.6!skip
-plugins/modules/execute_lambda.py import-2.7!skip
-plugins/modules/execute_lambda.py import-3.5!skip
-plugins/modules/execute_lambda.py import-3.6!skip
-plugins/modules/execute_lambda.py import-3.7!skip
-plugins/modules/execute_lambda.py metaclass-boilerplate!skip
-plugins/modules/iam.py compile-2.6!skip
-plugins/modules/iam.py compile-2.7!skip
-plugins/modules/iam.py compile-3.5!skip
-plugins/modules/iam.py compile-3.6!skip
-plugins/modules/iam.py compile-3.7!skip
-plugins/modules/iam.py future-import-boilerplate!skip
-plugins/modules/iam.py import-2.6!skip
-plugins/modules/iam.py import-2.7!skip
-plugins/modules/iam.py import-3.5!skip
-plugins/modules/iam.py import-3.6!skip
-plugins/modules/iam.py import-3.7!skip
-plugins/modules/iam.py metaclass-boilerplate!skip
-plugins/modules/iam.py pylint:unnecessary-comprehension # iam.py is boto2 so any refactoring can get complex, also it does not have tests
-plugins/modules/iam_cert.py compile-2.6!skip
-plugins/modules/iam_cert.py compile-2.7!skip
-plugins/modules/iam_cert.py compile-3.5!skip
-plugins/modules/iam_cert.py compile-3.6!skip
-plugins/modules/iam_cert.py compile-3.7!skip
-plugins/modules/iam_cert.py future-import-boilerplate!skip
-plugins/modules/iam_cert.py import-2.6!skip
-plugins/modules/iam_cert.py import-2.7!skip
-plugins/modules/iam_cert.py import-3.5!skip
-plugins/modules/iam_cert.py import-3.6!skip
-plugins/modules/iam_cert.py import-3.7!skip
-plugins/modules/iam_cert.py metaclass-boilerplate!skip
-plugins/modules/iam_group.py compile-2.6!skip
-plugins/modules/iam_group.py compile-2.7!skip
-plugins/modules/iam_group.py compile-3.5!skip
-plugins/modules/iam_group.py compile-3.6!skip
-plugins/modules/iam_group.py compile-3.7!skip
-plugins/modules/iam_group.py future-import-boilerplate!skip
-plugins/modules/iam_group.py import-2.6!skip
-plugins/modules/iam_group.py import-2.7!skip
-plugins/modules/iam_group.py import-3.5!skip
-plugins/modules/iam_group.py import-3.6!skip
-plugins/modules/iam_group.py import-3.7!skip
-plugins/modules/iam_group.py metaclass-boilerplate!skip
-plugins/modules/iam_managed_policy.py compile-2.6!skip
-plugins/modules/iam_managed_policy.py compile-2.7!skip
-plugins/modules/iam_managed_policy.py compile-3.5!skip
-plugins/modules/iam_managed_policy.py compile-3.6!skip
-plugins/modules/iam_managed_policy.py compile-3.7!skip
-plugins/modules/iam_managed_policy.py future-import-boilerplate!skip
-plugins/modules/iam_managed_policy.py import-2.6!skip
-plugins/modules/iam_managed_policy.py import-2.7!skip
-plugins/modules/iam_managed_policy.py import-3.5!skip
-plugins/modules/iam_managed_policy.py import-3.6!skip
-plugins/modules/iam_managed_policy.py import-3.7!skip
-plugins/modules/iam_managed_policy.py metaclass-boilerplate!skip
-plugins/modules/iam_mfa_device_info.py compile-2.6!skip
-plugins/modules/iam_mfa_device_info.py compile-2.7!skip
-plugins/modules/iam_mfa_device_info.py compile-3.5!skip
-plugins/modules/iam_mfa_device_info.py compile-3.6!skip
-plugins/modules/iam_mfa_device_info.py compile-3.7!skip
-plugins/modules/iam_mfa_device_info.py future-import-boilerplate!skip
-plugins/modules/iam_mfa_device_info.py import-2.6!skip
-plugins/modules/iam_mfa_device_info.py import-2.7!skip
-plugins/modules/iam_mfa_device_info.py import-3.5!skip
-plugins/modules/iam_mfa_device_info.py import-3.6!skip
-plugins/modules/iam_mfa_device_info.py import-3.7!skip
-plugins/modules/iam_mfa_device_info.py metaclass-boilerplate!skip
-plugins/modules/iam_password_policy.py compile-2.6!skip
-plugins/modules/iam_password_policy.py compile-2.7!skip
-plugins/modules/iam_password_policy.py compile-3.5!skip
-plugins/modules/iam_password_policy.py compile-3.6!skip
-plugins/modules/iam_password_policy.py compile-3.7!skip
-plugins/modules/iam_password_policy.py future-import-boilerplate!skip
-plugins/modules/iam_password_policy.py import-2.6!skip
-plugins/modules/iam_password_policy.py import-2.7!skip
-plugins/modules/iam_password_policy.py import-3.5!skip
-plugins/modules/iam_password_policy.py import-3.6!skip
-plugins/modules/iam_password_policy.py import-3.7!skip
-plugins/modules/iam_password_policy.py metaclass-boilerplate!skip
-plugins/modules/iam_policy.py compile-2.6!skip
-plugins/modules/iam_policy.py compile-2.7!skip
-plugins/modules/iam_policy.py compile-3.5!skip
-plugins/modules/iam_policy.py compile-3.6!skip
-plugins/modules/iam_policy.py compile-3.7!skip
-plugins/modules/iam_policy.py future-import-boilerplate!skip
-plugins/modules/iam_policy.py import-2.6!skip
-plugins/modules/iam_policy.py import-2.7!skip
-plugins/modules/iam_policy.py import-3.5!skip
-plugins/modules/iam_policy.py import-3.6!skip
-plugins/modules/iam_policy.py import-3.7!skip
-plugins/modules/iam_policy.py metaclass-boilerplate!skip
-plugins/modules/iam_policy_info.py compile-2.6!skip
-plugins/modules/iam_policy_info.py compile-2.7!skip
-plugins/modules/iam_policy_info.py compile-3.5!skip
-plugins/modules/iam_policy_info.py compile-3.6!skip
-plugins/modules/iam_policy_info.py compile-3.7!skip
-plugins/modules/iam_policy_info.py future-import-boilerplate!skip
-plugins/modules/iam_policy_info.py import-2.6!skip
-plugins/modules/iam_policy_info.py import-2.7!skip
-plugins/modules/iam_policy_info.py import-3.5!skip
-plugins/modules/iam_policy_info.py import-3.6!skip
-plugins/modules/iam_policy_info.py import-3.7!skip
-plugins/modules/iam_policy_info.py metaclass-boilerplate!skip
-plugins/modules/iam_role.py compile-2.6!skip
-plugins/modules/iam_role.py compile-2.7!skip
-plugins/modules/iam_role.py compile-3.5!skip
-plugins/modules/iam_role.py compile-3.6!skip
-plugins/modules/iam_role.py compile-3.7!skip
-plugins/modules/iam_role.py future-import-boilerplate!skip
-plugins/modules/iam_role.py import-2.6!skip
-plugins/modules/iam_role.py import-2.7!skip
-plugins/modules/iam_role.py import-3.5!skip
-plugins/modules/iam_role.py import-3.6!skip
-plugins/modules/iam_role.py import-3.7!skip
-plugins/modules/iam_role.py metaclass-boilerplate!skip
-plugins/modules/iam_role_info.py compile-2.6!skip
-plugins/modules/iam_role_info.py compile-2.7!skip
-plugins/modules/iam_role_info.py compile-3.5!skip
-plugins/modules/iam_role_info.py compile-3.6!skip
-plugins/modules/iam_role_info.py compile-3.7!skip
-plugins/modules/iam_role_info.py future-import-boilerplate!skip
-plugins/modules/iam_role_info.py import-2.6!skip
-plugins/modules/iam_role_info.py import-2.7!skip
-plugins/modules/iam_role_info.py import-3.5!skip
-plugins/modules/iam_role_info.py import-3.6!skip
-plugins/modules/iam_role_info.py import-3.7!skip
-plugins/modules/iam_role_info.py metaclass-boilerplate!skip
-plugins/modules/iam_saml_federation.py compile-2.6!skip
-plugins/modules/iam_saml_federation.py compile-2.7!skip
-plugins/modules/iam_saml_federation.py compile-3.5!skip
-plugins/modules/iam_saml_federation.py compile-3.6!skip
-plugins/modules/iam_saml_federation.py compile-3.7!skip
-plugins/modules/iam_saml_federation.py future-import-boilerplate!skip
-plugins/modules/iam_saml_federation.py import-2.6!skip
-plugins/modules/iam_saml_federation.py import-2.7!skip
-plugins/modules/iam_saml_federation.py import-3.5!skip
-plugins/modules/iam_saml_federation.py import-3.6!skip
-plugins/modules/iam_saml_federation.py import-3.7!skip
-plugins/modules/iam_saml_federation.py metaclass-boilerplate!skip
-plugins/modules/iam_server_certificate_info.py compile-2.6!skip
-plugins/modules/iam_server_certificate_info.py compile-2.7!skip
-plugins/modules/iam_server_certificate_info.py compile-3.5!skip
-plugins/modules/iam_server_certificate_info.py compile-3.6!skip
-plugins/modules/iam_server_certificate_info.py compile-3.7!skip
-plugins/modules/iam_server_certificate_info.py future-import-boilerplate!skip
-plugins/modules/iam_server_certificate_info.py import-2.6!skip
-plugins/modules/iam_server_certificate_info.py import-2.7!skip
-plugins/modules/iam_server_certificate_info.py import-3.5!skip
-plugins/modules/iam_server_certificate_info.py import-3.6!skip
-plugins/modules/iam_server_certificate_info.py import-3.7!skip
-plugins/modules/iam_server_certificate_info.py metaclass-boilerplate!skip
-plugins/modules/iam_user.py compile-2.6!skip
-plugins/modules/iam_user.py compile-2.7!skip
-plugins/modules/iam_user.py compile-3.5!skip
-plugins/modules/iam_user.py compile-3.6!skip
-plugins/modules/iam_user.py compile-3.7!skip
-plugins/modules/iam_user.py future-import-boilerplate!skip
-plugins/modules/iam_user.py import-2.6!skip
-plugins/modules/iam_user.py import-2.7!skip
-plugins/modules/iam_user.py import-3.5!skip
-plugins/modules/iam_user.py import-3.6!skip
-plugins/modules/iam_user.py import-3.7!skip
-plugins/modules/iam_user.py metaclass-boilerplate!skip
-plugins/modules/iam_user_info.py compile-2.6!skip
-plugins/modules/iam_user_info.py compile-2.7!skip
-plugins/modules/iam_user_info.py compile-3.5!skip
-plugins/modules/iam_user_info.py compile-3.6!skip
-plugins/modules/iam_user_info.py compile-3.7!skip
-plugins/modules/iam_user_info.py future-import-boilerplate!skip
-plugins/modules/iam_user_info.py import-2.6!skip
-plugins/modules/iam_user_info.py import-2.7!skip
-plugins/modules/iam_user_info.py import-3.5!skip
-plugins/modules/iam_user_info.py import-3.6!skip
-plugins/modules/iam_user_info.py import-3.7!skip
-plugins/modules/iam_user_info.py metaclass-boilerplate!skip
-plugins/modules/kinesis_stream.py compile-2.6!skip
-plugins/modules/kinesis_stream.py compile-2.7!skip
-plugins/modules/kinesis_stream.py compile-3.5!skip
-plugins/modules/kinesis_stream.py compile-3.6!skip
-plugins/modules/kinesis_stream.py compile-3.7!skip
-plugins/modules/kinesis_stream.py future-import-boilerplate!skip
-plugins/modules/kinesis_stream.py import-2.6!skip
-plugins/modules/kinesis_stream.py import-2.7!skip
-plugins/modules/kinesis_stream.py import-3.5!skip
-plugins/modules/kinesis_stream.py import-3.6!skip
-plugins/modules/kinesis_stream.py import-3.7!skip
-plugins/modules/kinesis_stream.py metaclass-boilerplate!skip
-plugins/modules/lambda.py compile-2.6!skip
-plugins/modules/lambda.py compile-2.7!skip
-plugins/modules/lambda.py compile-3.5!skip
-plugins/modules/lambda.py compile-3.6!skip
-plugins/modules/lambda.py compile-3.7!skip
-plugins/modules/lambda.py future-import-boilerplate!skip
-plugins/modules/lambda.py import-2.6!skip
-plugins/modules/lambda.py import-2.7!skip
-plugins/modules/lambda.py import-3.5!skip
-plugins/modules/lambda.py import-3.6!skip
-plugins/modules/lambda.py import-3.7!skip
-plugins/modules/lambda.py metaclass-boilerplate!skip
-plugins/modules/lambda_alias.py compile-2.6!skip
-plugins/modules/lambda_alias.py compile-2.7!skip
-plugins/modules/lambda_alias.py compile-3.5!skip
-plugins/modules/lambda_alias.py compile-3.6!skip
-plugins/modules/lambda_alias.py compile-3.7!skip
-plugins/modules/lambda_alias.py future-import-boilerplate!skip
-plugins/modules/lambda_alias.py import-2.6!skip
-plugins/modules/lambda_alias.py import-2.7!skip
-plugins/modules/lambda_alias.py import-3.5!skip
-plugins/modules/lambda_alias.py import-3.6!skip
-plugins/modules/lambda_alias.py import-3.7!skip
-plugins/modules/lambda_alias.py metaclass-boilerplate!skip
-plugins/modules/lambda_event.py compile-2.6!skip
-plugins/modules/lambda_event.py compile-2.7!skip
-plugins/modules/lambda_event.py compile-3.5!skip
-plugins/modules/lambda_event.py compile-3.6!skip
-plugins/modules/lambda_event.py compile-3.7!skip
-plugins/modules/lambda_event.py future-import-boilerplate!skip
-plugins/modules/lambda_event.py import-2.6!skip
-plugins/modules/lambda_event.py import-2.7!skip
-plugins/modules/lambda_event.py import-3.5!skip
-plugins/modules/lambda_event.py import-3.6!skip
-plugins/modules/lambda_event.py import-3.7!skip
-plugins/modules/lambda_event.py metaclass-boilerplate!skip
-plugins/modules/lambda_facts.py compile-2.6!skip
-plugins/modules/lambda_facts.py compile-2.7!skip
-plugins/modules/lambda_facts.py compile-3.5!skip
-plugins/modules/lambda_facts.py compile-3.6!skip
-plugins/modules/lambda_facts.py compile-3.7!skip
-plugins/modules/lambda_facts.py future-import-boilerplate!skip
-plugins/modules/lambda_facts.py import-2.6!skip
-plugins/modules/lambda_facts.py import-2.7!skip
-plugins/modules/lambda_facts.py import-3.5!skip
-plugins/modules/lambda_facts.py import-3.6!skip
-plugins/modules/lambda_facts.py import-3.7!skip
-plugins/modules/lambda_facts.py metaclass-boilerplate!skip
-plugins/modules/lambda_info.py compile-2.6!skip
-plugins/modules/lambda_info.py compile-2.7!skip
-plugins/modules/lambda_info.py compile-3.5!skip
-plugins/modules/lambda_info.py compile-3.6!skip
-plugins/modules/lambda_info.py compile-3.7!skip
-plugins/modules/lambda_info.py future-import-boilerplate!skip
-plugins/modules/lambda_info.py import-2.6!skip
-plugins/modules/lambda_info.py import-2.7!skip
-plugins/modules/lambda_info.py import-3.5!skip
-plugins/modules/lambda_info.py import-3.6!skip
-plugins/modules/lambda_info.py import-3.7!skip
-plugins/modules/lambda_info.py metaclass-boilerplate!skip
-plugins/modules/lambda_policy.py compile-2.6!skip
-plugins/modules/lambda_policy.py compile-2.7!skip
-plugins/modules/lambda_policy.py compile-3.5!skip
-plugins/modules/lambda_policy.py compile-3.6!skip
-plugins/modules/lambda_policy.py compile-3.7!skip
-plugins/modules/lambda_policy.py future-import-boilerplate!skip
-plugins/modules/lambda_policy.py import-2.6!skip
-plugins/modules/lambda_policy.py import-2.7!skip
-plugins/modules/lambda_policy.py import-3.5!skip
-plugins/modules/lambda_policy.py import-3.6!skip
-plugins/modules/lambda_policy.py import-3.7!skip
-plugins/modules/lambda_policy.py metaclass-boilerplate!skip
-plugins/modules/lightsail.py compile-2.6!skip
-plugins/modules/lightsail.py compile-2.7!skip
-plugins/modules/lightsail.py compile-3.5!skip
-plugins/modules/lightsail.py compile-3.6!skip
-plugins/modules/lightsail.py compile-3.7!skip
-plugins/modules/lightsail.py future-import-boilerplate!skip
-plugins/modules/lightsail.py import-2.6!skip
-plugins/modules/lightsail.py import-2.7!skip
-plugins/modules/lightsail.py import-3.5!skip
-plugins/modules/lightsail.py import-3.6!skip
-plugins/modules/lightsail.py import-3.7!skip
-plugins/modules/lightsail.py metaclass-boilerplate!skip
-plugins/modules/rds.py compile-2.6!skip
-plugins/modules/rds.py compile-2.7!skip
-plugins/modules/rds.py compile-3.5!skip
-plugins/modules/rds.py compile-3.6!skip
-plugins/modules/rds.py compile-3.7!skip
-plugins/modules/rds.py future-import-boilerplate!skip
-plugins/modules/rds.py import-2.6!skip
-plugins/modules/rds.py import-2.7!skip
-plugins/modules/rds.py import-3.5!skip
-plugins/modules/rds.py import-3.6!skip
-plugins/modules/rds.py import-3.7!skip
-plugins/modules/rds.py metaclass-boilerplate!skip
-plugins/modules/rds_instance.py compile-2.6!skip
-plugins/modules/rds_instance.py compile-2.7!skip
-plugins/modules/rds_instance.py compile-3.5!skip
-plugins/modules/rds_instance.py compile-3.6!skip
-plugins/modules/rds_instance.py compile-3.7!skip
-plugins/modules/rds_instance.py future-import-boilerplate!skip
-plugins/modules/rds_instance.py import-2.6!skip
-plugins/modules/rds_instance.py import-2.7!skip
-plugins/modules/rds_instance.py import-3.5!skip
-plugins/modules/rds_instance.py import-3.6!skip
-plugins/modules/rds_instance.py import-3.7!skip
-plugins/modules/rds_instance.py metaclass-boilerplate!skip
-plugins/modules/rds_instance_info.py compile-2.6!skip
-plugins/modules/rds_instance_info.py compile-2.7!skip
-plugins/modules/rds_instance_info.py compile-3.5!skip
-plugins/modules/rds_instance_info.py compile-3.6!skip
-plugins/modules/rds_instance_info.py compile-3.7!skip
-plugins/modules/rds_instance_info.py future-import-boilerplate!skip
-plugins/modules/rds_instance_info.py import-2.6!skip
-plugins/modules/rds_instance_info.py import-2.7!skip
-plugins/modules/rds_instance_info.py import-3.5!skip
-plugins/modules/rds_instance_info.py import-3.6!skip
-plugins/modules/rds_instance_info.py import-3.7!skip
-plugins/modules/rds_instance_info.py metaclass-boilerplate!skip
-plugins/modules/rds_param_group.py compile-2.6!skip
-plugins/modules/rds_param_group.py compile-2.7!skip
-plugins/modules/rds_param_group.py compile-3.5!skip
-plugins/modules/rds_param_group.py compile-3.6!skip
-plugins/modules/rds_param_group.py compile-3.7!skip
-plugins/modules/rds_param_group.py future-import-boilerplate!skip
-plugins/modules/rds_param_group.py import-2.6!skip
-plugins/modules/rds_param_group.py import-2.7!skip
-plugins/modules/rds_param_group.py import-3.5!skip
-plugins/modules/rds_param_group.py import-3.6!skip
-plugins/modules/rds_param_group.py import-3.7!skip
-plugins/modules/rds_param_group.py metaclass-boilerplate!skip
-plugins/modules/rds_snapshot.py compile-2.6!skip
-plugins/modules/rds_snapshot.py compile-2.7!skip
-plugins/modules/rds_snapshot.py compile-3.5!skip
-plugins/modules/rds_snapshot.py compile-3.6!skip
-plugins/modules/rds_snapshot.py compile-3.7!skip
-plugins/modules/rds_snapshot.py future-import-boilerplate!skip
-plugins/modules/rds_snapshot.py import-2.6!skip
-plugins/modules/rds_snapshot.py import-2.7!skip
-plugins/modules/rds_snapshot.py import-3.5!skip
-plugins/modules/rds_snapshot.py import-3.6!skip
-plugins/modules/rds_snapshot.py import-3.7!skip
-plugins/modules/rds_snapshot.py metaclass-boilerplate!skip
-plugins/modules/rds_snapshot_info.py compile-2.6!skip
-plugins/modules/rds_snapshot_info.py compile-2.7!skip
-plugins/modules/rds_snapshot_info.py compile-3.5!skip
-plugins/modules/rds_snapshot_info.py compile-3.6!skip
-plugins/modules/rds_snapshot_info.py compile-3.7!skip
-plugins/modules/rds_snapshot_info.py future-import-boilerplate!skip
-plugins/modules/rds_snapshot_info.py import-2.6!skip
-plugins/modules/rds_snapshot_info.py import-2.7!skip
-plugins/modules/rds_snapshot_info.py import-3.5!skip
-plugins/modules/rds_snapshot_info.py import-3.6!skip
-plugins/modules/rds_snapshot_info.py import-3.7!skip
-plugins/modules/rds_snapshot_info.py metaclass-boilerplate!skip
-plugins/modules/rds_subnet_group.py compile-2.6!skip
-plugins/modules/rds_subnet_group.py compile-2.7!skip
-plugins/modules/rds_subnet_group.py compile-3.5!skip
-plugins/modules/rds_subnet_group.py compile-3.6!skip
-plugins/modules/rds_subnet_group.py compile-3.7!skip
-plugins/modules/rds_subnet_group.py future-import-boilerplate!skip
-plugins/modules/rds_subnet_group.py import-2.6!skip
-plugins/modules/rds_subnet_group.py import-2.7!skip
-plugins/modules/rds_subnet_group.py import-3.5!skip
-plugins/modules/rds_subnet_group.py import-3.6!skip
-plugins/modules/rds_subnet_group.py import-3.7!skip
-plugins/modules/rds_subnet_group.py metaclass-boilerplate!skip
-plugins/modules/redshift.py compile-2.6!skip
-plugins/modules/redshift.py compile-2.7!skip
-plugins/modules/redshift.py compile-3.5!skip
-plugins/modules/redshift.py compile-3.6!skip
-plugins/modules/redshift.py compile-3.7!skip
-plugins/modules/redshift.py future-import-boilerplate!skip
-plugins/modules/redshift.py import-2.6!skip
-plugins/modules/redshift.py import-2.7!skip
-plugins/modules/redshift.py import-3.5!skip
-plugins/modules/redshift.py import-3.6!skip
-plugins/modules/redshift.py import-3.7!skip
-plugins/modules/redshift.py metaclass-boilerplate!skip
-plugins/modules/redshift_cross_region_snapshots.py compile-2.6!skip
-plugins/modules/redshift_cross_region_snapshots.py compile-2.7!skip
-plugins/modules/redshift_cross_region_snapshots.py compile-3.5!skip
-plugins/modules/redshift_cross_region_snapshots.py compile-3.6!skip
-plugins/modules/redshift_cross_region_snapshots.py compile-3.7!skip
-plugins/modules/redshift_cross_region_snapshots.py future-import-boilerplate!skip
-plugins/modules/redshift_cross_region_snapshots.py import-2.6!skip
-plugins/modules/redshift_cross_region_snapshots.py import-2.7!skip
-plugins/modules/redshift_cross_region_snapshots.py import-3.5!skip
-plugins/modules/redshift_cross_region_snapshots.py import-3.6!skip
-plugins/modules/redshift_cross_region_snapshots.py import-3.7!skip
-plugins/modules/redshift_cross_region_snapshots.py metaclass-boilerplate!skip
-plugins/modules/redshift_info.py compile-2.6!skip
-plugins/modules/redshift_info.py compile-2.7!skip
-plugins/modules/redshift_info.py compile-3.5!skip
-plugins/modules/redshift_info.py compile-3.6!skip
-plugins/modules/redshift_info.py compile-3.7!skip
-plugins/modules/redshift_info.py future-import-boilerplate!skip
-plugins/modules/redshift_info.py import-2.6!skip
-plugins/modules/redshift_info.py import-2.7!skip
-plugins/modules/redshift_info.py import-3.5!skip
-plugins/modules/redshift_info.py import-3.6!skip
-plugins/modules/redshift_info.py import-3.7!skip
-plugins/modules/redshift_info.py metaclass-boilerplate!skip
-plugins/modules/redshift_subnet_group.py compile-2.6!skip
-plugins/modules/redshift_subnet_group.py compile-2.7!skip
-plugins/modules/redshift_subnet_group.py compile-3.5!skip
-plugins/modules/redshift_subnet_group.py compile-3.6!skip
-plugins/modules/redshift_subnet_group.py compile-3.7!skip
-plugins/modules/redshift_subnet_group.py future-import-boilerplate!skip
-plugins/modules/redshift_subnet_group.py import-2.6!skip
-plugins/modules/redshift_subnet_group.py import-2.7!skip
-plugins/modules/redshift_subnet_group.py import-3.5!skip
-plugins/modules/redshift_subnet_group.py import-3.6!skip
-plugins/modules/redshift_subnet_group.py import-3.7!skip
-plugins/modules/redshift_subnet_group.py metaclass-boilerplate!skip
-plugins/modules/route53.py compile-2.6!skip
-plugins/modules/route53.py compile-2.7!skip
-plugins/modules/route53.py compile-3.5!skip
-plugins/modules/route53.py compile-3.6!skip
-plugins/modules/route53.py compile-3.7!skip
-plugins/modules/route53.py future-import-boilerplate!skip
-plugins/modules/route53.py import-2.6!skip
-plugins/modules/route53.py import-2.7!skip
-plugins/modules/route53.py import-3.5!skip
-plugins/modules/route53.py import-3.6!skip
-plugins/modules/route53.py import-3.7!skip
-plugins/modules/route53.py metaclass-boilerplate!skip
-plugins/modules/route53.py validate-modules:parameter-state-invalid-choice
-plugins/modules/route53_health_check.py compile-2.6!skip
-plugins/modules/route53_health_check.py compile-2.7!skip
-plugins/modules/route53_health_check.py compile-3.5!skip
-plugins/modules/route53_health_check.py compile-3.6!skip
-plugins/modules/route53_health_check.py compile-3.7!skip
-plugins/modules/route53_health_check.py future-import-boilerplate!skip
-plugins/modules/route53_health_check.py import-2.6!skip
-plugins/modules/route53_health_check.py import-2.7!skip
-plugins/modules/route53_health_check.py import-3.5!skip
-plugins/modules/route53_health_check.py import-3.6!skip
-plugins/modules/route53_health_check.py import-3.7!skip
-plugins/modules/route53_health_check.py metaclass-boilerplate!skip
-plugins/modules/route53_info.py compile-2.6!skip
-plugins/modules/route53_info.py compile-2.7!skip
-plugins/modules/route53_info.py compile-3.5!skip
-plugins/modules/route53_info.py compile-3.6!skip
-plugins/modules/route53_info.py compile-3.7!skip
-plugins/modules/route53_info.py future-import-boilerplate!skip
-plugins/modules/route53_info.py import-2.6!skip
-plugins/modules/route53_info.py import-2.7!skip
-plugins/modules/route53_info.py import-3.5!skip
-plugins/modules/route53_info.py import-3.6!skip
-plugins/modules/route53_info.py import-3.7!skip
-plugins/modules/route53_info.py metaclass-boilerplate!skip
-plugins/modules/route53_zone.py compile-2.6!skip
-plugins/modules/route53_zone.py compile-2.7!skip
-plugins/modules/route53_zone.py compile-3.5!skip
-plugins/modules/route53_zone.py compile-3.6!skip
-plugins/modules/route53_zone.py compile-3.7!skip
-plugins/modules/route53_zone.py future-import-boilerplate!skip
-plugins/modules/route53_zone.py import-2.6!skip
-plugins/modules/route53_zone.py import-2.7!skip
-plugins/modules/route53_zone.py import-3.5!skip
-plugins/modules/route53_zone.py import-3.6!skip
-plugins/modules/route53_zone.py import-3.7!skip
-plugins/modules/route53_zone.py metaclass-boilerplate!skip
-plugins/modules/s3_bucket_notification.py compile-2.6!skip
-plugins/modules/s3_bucket_notification.py compile-2.7!skip
-plugins/modules/s3_bucket_notification.py compile-3.5!skip
-plugins/modules/s3_bucket_notification.py compile-3.6!skip
-plugins/modules/s3_bucket_notification.py compile-3.7!skip
-plugins/modules/s3_bucket_notification.py future-import-boilerplate!skip
-plugins/modules/s3_bucket_notification.py import-2.6!skip
-plugins/modules/s3_bucket_notification.py import-2.7!skip
-plugins/modules/s3_bucket_notification.py import-3.5!skip
-plugins/modules/s3_bucket_notification.py import-3.6!skip
-plugins/modules/s3_bucket_notification.py import-3.7!skip
-plugins/modules/s3_bucket_notification.py metaclass-boilerplate!skip
-plugins/modules/s3_lifecycle.py compile-2.6!skip
-plugins/modules/s3_lifecycle.py compile-2.7!skip
-plugins/modules/s3_lifecycle.py compile-3.5!skip
-plugins/modules/s3_lifecycle.py compile-3.6!skip
-plugins/modules/s3_lifecycle.py compile-3.7!skip
-plugins/modules/s3_lifecycle.py future-import-boilerplate!skip
-plugins/modules/s3_lifecycle.py import-2.6!skip
-plugins/modules/s3_lifecycle.py import-2.7!skip
-plugins/modules/s3_lifecycle.py import-3.5!skip
-plugins/modules/s3_lifecycle.py import-3.6!skip
-plugins/modules/s3_lifecycle.py import-3.7!skip
-plugins/modules/s3_lifecycle.py metaclass-boilerplate!skip
-plugins/modules/s3_logging.py compile-2.6!skip
-plugins/modules/s3_logging.py compile-2.7!skip
-plugins/modules/s3_logging.py compile-3.5!skip
-plugins/modules/s3_logging.py compile-3.6!skip
-plugins/modules/s3_logging.py compile-3.7!skip
-plugins/modules/s3_logging.py future-import-boilerplate!skip
-plugins/modules/s3_logging.py import-2.6!skip
-plugins/modules/s3_logging.py import-2.7!skip
-plugins/modules/s3_logging.py import-3.5!skip
-plugins/modules/s3_logging.py import-3.6!skip
-plugins/modules/s3_logging.py import-3.7!skip
-plugins/modules/s3_logging.py metaclass-boilerplate!skip
-plugins/modules/s3_metrics_configuration.py compile-2.6!skip
-plugins/modules/s3_metrics_configuration.py compile-2.7!skip
-plugins/modules/s3_metrics_configuration.py compile-3.5!skip
-plugins/modules/s3_metrics_configuration.py compile-3.6!skip
-plugins/modules/s3_metrics_configuration.py compile-3.7!skip
-plugins/modules/s3_metrics_configuration.py future-import-boilerplate!skip
-plugins/modules/s3_metrics_configuration.py import-2.6!skip
-plugins/modules/s3_metrics_configuration.py import-2.7!skip
-plugins/modules/s3_metrics_configuration.py import-3.5!skip
-plugins/modules/s3_metrics_configuration.py import-3.6!skip
-plugins/modules/s3_metrics_configuration.py import-3.7!skip
-plugins/modules/s3_metrics_configuration.py metaclass-boilerplate!skip
-plugins/modules/s3_sync.py compile-2.6!skip
-plugins/modules/s3_sync.py compile-2.7!skip
-plugins/modules/s3_sync.py compile-3.5!skip
-plugins/modules/s3_sync.py compile-3.6!skip
-plugins/modules/s3_sync.py compile-3.7!skip
-plugins/modules/s3_sync.py future-import-boilerplate!skip
-plugins/modules/s3_sync.py import-2.6!skip
-plugins/modules/s3_sync.py import-2.7!skip
-plugins/modules/s3_sync.py import-3.5!skip
-plugins/modules/s3_sync.py import-3.6!skip
-plugins/modules/s3_sync.py import-3.7!skip
-plugins/modules/s3_sync.py metaclass-boilerplate!skip
-plugins/modules/s3_website.py compile-2.6!skip
-plugins/modules/s3_website.py compile-2.7!skip
-plugins/modules/s3_website.py compile-3.5!skip
-plugins/modules/s3_website.py compile-3.6!skip
-plugins/modules/s3_website.py compile-3.7!skip
-plugins/modules/s3_website.py future-import-boilerplate!skip
-plugins/modules/s3_website.py import-2.6!skip
-plugins/modules/s3_website.py import-2.7!skip
-plugins/modules/s3_website.py import-3.5!skip
-plugins/modules/s3_website.py import-3.6!skip
-plugins/modules/s3_website.py import-3.7!skip
-plugins/modules/s3_website.py metaclass-boilerplate!skip
-plugins/modules/sns.py compile-2.6!skip
-plugins/modules/sns.py compile-2.7!skip
-plugins/modules/sns.py compile-3.5!skip
-plugins/modules/sns.py compile-3.6!skip
-plugins/modules/sns.py compile-3.7!skip
-plugins/modules/sns.py future-import-boilerplate!skip
-plugins/modules/sns.py import-2.6!skip
-plugins/modules/sns.py import-2.7!skip
-plugins/modules/sns.py import-3.5!skip
-plugins/modules/sns.py import-3.6!skip
-plugins/modules/sns.py import-3.7!skip
-plugins/modules/sns.py metaclass-boilerplate!skip
-plugins/modules/sns_topic.py compile-2.6!skip
-plugins/modules/sns_topic.py compile-2.7!skip
-plugins/modules/sns_topic.py compile-3.5!skip
-plugins/modules/sns_topic.py compile-3.6!skip
-plugins/modules/sns_topic.py compile-3.7!skip
-plugins/modules/sns_topic.py future-import-boilerplate!skip
-plugins/modules/sns_topic.py import-2.6!skip
-plugins/modules/sns_topic.py import-2.7!skip
-plugins/modules/sns_topic.py import-3.5!skip
-plugins/modules/sns_topic.py import-3.6!skip
-plugins/modules/sns_topic.py import-3.7!skip
-plugins/modules/sns_topic.py metaclass-boilerplate!skip
-plugins/modules/sqs_queue.py compile-2.6!skip
-plugins/modules/sqs_queue.py compile-2.7!skip
-plugins/modules/sqs_queue.py compile-3.5!skip
-plugins/modules/sqs_queue.py compile-3.6!skip
-plugins/modules/sqs_queue.py compile-3.7!skip
-plugins/modules/sqs_queue.py future-import-boilerplate!skip
-plugins/modules/sqs_queue.py import-2.6!skip
-plugins/modules/sqs_queue.py import-2.7!skip
-plugins/modules/sqs_queue.py import-3.5!skip
-plugins/modules/sqs_queue.py import-3.6!skip
-plugins/modules/sqs_queue.py import-3.7!skip
-plugins/modules/sqs_queue.py metaclass-boilerplate!skip
-plugins/modules/sts_assume_role.py compile-2.6!skip
-plugins/modules/sts_assume_role.py compile-2.7!skip
-plugins/modules/sts_assume_role.py compile-3.5!skip
-plugins/modules/sts_assume_role.py compile-3.6!skip
-plugins/modules/sts_assume_role.py compile-3.7!skip
-plugins/modules/sts_assume_role.py future-import-boilerplate!skip
-plugins/modules/sts_assume_role.py import-2.6!skip
-plugins/modules/sts_assume_role.py import-2.7!skip
-plugins/modules/sts_assume_role.py import-3.5!skip
-plugins/modules/sts_assume_role.py import-3.6!skip
-plugins/modules/sts_assume_role.py import-3.7!skip
-plugins/modules/sts_assume_role.py metaclass-boilerplate!skip
-plugins/modules/sts_session_token.py compile-2.6!skip
-plugins/modules/sts_session_token.py compile-2.7!skip
-plugins/modules/sts_session_token.py compile-3.5!skip
-plugins/modules/sts_session_token.py compile-3.6!skip
-plugins/modules/sts_session_token.py compile-3.7!skip
-plugins/modules/sts_session_token.py future-import-boilerplate!skip
-plugins/modules/sts_session_token.py import-2.6!skip
-plugins/modules/sts_session_token.py import-2.7!skip
-plugins/modules/sts_session_token.py import-3.5!skip
-plugins/modules/sts_session_token.py import-3.6!skip
-plugins/modules/sts_session_token.py import-3.7!skip
-plugins/modules/sts_session_token.py metaclass-boilerplate!skip
-plugins/modules/wafv2_ip_set.py compile-2.6!skip
-plugins/modules/wafv2_ip_set.py compile-2.7!skip
-plugins/modules/wafv2_ip_set.py compile-3.5!skip
-plugins/modules/wafv2_ip_set.py compile-3.6!skip
-plugins/modules/wafv2_ip_set.py compile-3.7!skip
-plugins/modules/wafv2_ip_set.py future-import-boilerplate!skip
-plugins/modules/wafv2_ip_set.py import-2.6!skip
-plugins/modules/wafv2_ip_set.py import-2.7!skip
-plugins/modules/wafv2_ip_set.py import-3.5!skip
-plugins/modules/wafv2_ip_set.py import-3.6!skip
-plugins/modules/wafv2_ip_set.py import-3.7!skip
-plugins/modules/wafv2_ip_set.py metaclass-boilerplate!skip
-plugins/modules/wafv2_ip_set_info.py compile-2.6!skip
-plugins/modules/wafv2_ip_set_info.py compile-2.7!skip
-plugins/modules/wafv2_ip_set_info.py compile-3.5!skip
-plugins/modules/wafv2_ip_set_info.py compile-3.6!skip
-plugins/modules/wafv2_ip_set_info.py compile-3.7!skip
-plugins/modules/wafv2_ip_set_info.py future-import-boilerplate!skip
-plugins/modules/wafv2_ip_set_info.py import-2.6!skip
-plugins/modules/wafv2_ip_set_info.py import-2.7!skip
-plugins/modules/wafv2_ip_set_info.py import-3.5!skip
-plugins/modules/wafv2_ip_set_info.py import-3.6!skip
-plugins/modules/wafv2_ip_set_info.py import-3.7!skip
-plugins/modules/wafv2_ip_set_info.py metaclass-boilerplate!skip
-plugins/modules/wafv2_resources.py compile-2.6!skip
-plugins/modules/wafv2_resources.py compile-2.7!skip
-plugins/modules/wafv2_resources.py compile-3.5!skip
-plugins/modules/wafv2_resources.py compile-3.6!skip
-plugins/modules/wafv2_resources.py compile-3.7!skip
-plugins/modules/wafv2_resources.py future-import-boilerplate!skip
-plugins/modules/wafv2_resources.py import-2.6!skip
-plugins/modules/wafv2_resources.py import-2.7!skip
-plugins/modules/wafv2_resources.py import-3.5!skip
-plugins/modules/wafv2_resources.py import-3.6!skip
-plugins/modules/wafv2_resources.py import-3.7!skip
-plugins/modules/wafv2_resources.py metaclass-boilerplate!skip
-plugins/modules/wafv2_resources_info.py compile-2.6!skip
-plugins/modules/wafv2_resources_info.py compile-2.7!skip
-plugins/modules/wafv2_resources_info.py compile-3.5!skip
-plugins/modules/wafv2_resources_info.py compile-3.6!skip
-plugins/modules/wafv2_resources_info.py compile-3.7!skip
-plugins/modules/wafv2_resources_info.py future-import-boilerplate!skip
-plugins/modules/wafv2_resources_info.py import-2.6!skip
-plugins/modules/wafv2_resources_info.py import-2.7!skip
-plugins/modules/wafv2_resources_info.py import-3.5!skip
-plugins/modules/wafv2_resources_info.py import-3.6!skip
-plugins/modules/wafv2_resources_info.py import-3.7!skip
-plugins/modules/wafv2_resources_info.py metaclass-boilerplate!skip
-plugins/modules/wafv2_rule_group.py compile-2.6!skip
-plugins/modules/wafv2_rule_group.py compile-2.7!skip
-plugins/modules/wafv2_rule_group.py compile-3.5!skip
-plugins/modules/wafv2_rule_group.py compile-3.6!skip
-plugins/modules/wafv2_rule_group.py compile-3.7!skip
-plugins/modules/wafv2_rule_group.py future-import-boilerplate!skip
-plugins/modules/wafv2_rule_group.py import-2.6!skip
-plugins/modules/wafv2_rule_group.py import-2.7!skip
-plugins/modules/wafv2_rule_group.py import-3.5!skip
-plugins/modules/wafv2_rule_group.py import-3.6!skip
-plugins/modules/wafv2_rule_group.py import-3.7!skip
-plugins/modules/wafv2_rule_group.py metaclass-boilerplate!skip
-plugins/modules/wafv2_rule_group_info.py compile-2.6!skip
-plugins/modules/wafv2_rule_group_info.py compile-2.7!skip
-plugins/modules/wafv2_rule_group_info.py compile-3.5!skip
-plugins/modules/wafv2_rule_group_info.py compile-3.6!skip
-plugins/modules/wafv2_rule_group_info.py compile-3.7!skip
-plugins/modules/wafv2_rule_group_info.py future-import-boilerplate!skip
-plugins/modules/wafv2_rule_group_info.py import-2.6!skip
-plugins/modules/wafv2_rule_group_info.py import-2.7!skip
-plugins/modules/wafv2_rule_group_info.py import-3.5!skip
-plugins/modules/wafv2_rule_group_info.py import-3.6!skip
-plugins/modules/wafv2_rule_group_info.py import-3.7!skip
-plugins/modules/wafv2_rule_group_info.py metaclass-boilerplate!skip
-plugins/modules/wafv2_web_acl.py compile-2.6!skip
-plugins/modules/wafv2_web_acl.py compile-2.7!skip
-plugins/modules/wafv2_web_acl.py compile-3.5!skip
-plugins/modules/wafv2_web_acl.py compile-3.6!skip
-plugins/modules/wafv2_web_acl.py compile-3.7!skip
-plugins/modules/wafv2_web_acl.py future-import-boilerplate!skip
-plugins/modules/wafv2_web_acl.py import-2.6!skip
-plugins/modules/wafv2_web_acl.py import-2.7!skip
-plugins/modules/wafv2_web_acl.py import-3.5!skip
-plugins/modules/wafv2_web_acl.py import-3.6!skip
-plugins/modules/wafv2_web_acl.py import-3.7!skip
-plugins/modules/wafv2_web_acl.py metaclass-boilerplate!skip
-plugins/modules/wafv2_web_acl_info.py compile-2.6!skip
-plugins/modules/wafv2_web_acl_info.py compile-2.7!skip
-plugins/modules/wafv2_web_acl_info.py compile-3.5!skip
-plugins/modules/wafv2_web_acl_info.py compile-3.6!skip
-plugins/modules/wafv2_web_acl_info.py compile-3.7!skip
-plugins/modules/wafv2_web_acl_info.py future-import-boilerplate!skip
-plugins/modules/wafv2_web_acl_info.py import-2.6!skip
-plugins/modules/wafv2_web_acl_info.py import-2.7!skip
-plugins/modules/wafv2_web_acl_info.py import-3.5!skip
-plugins/modules/wafv2_web_acl_info.py import-3.6!skip
-plugins/modules/wafv2_web_acl_info.py import-3.7!skip
-plugins/modules/wafv2_web_acl_info.py metaclass-boilerplate!skip
-tests/sanity/refresh_ignore_files shebang!skip
+plugins/modules/cloudfront_info.py pylint:unnecessary-comprehension # (new test) Should be an easy fix, but testing is a challenge - test are broken and aliases require a wildcard cert in ACM
+plugins/modules/iam.py pylint:unnecessary-comprehension # no tests and module is deprecated
+plugins/modules/route53.py validate-modules:parameter-state-invalid-choice # route53_info needs improvements before we can deprecate this
diff --git a/tests/sanity/ignore-2.13.txt b/tests/sanity/ignore-2.13.txt
new file mode 100644
index 00000000000..e5bade76474
--- /dev/null
+++ b/tests/sanity/ignore-2.13.txt
@@ -0,0 +1,3 @@
+plugins/modules/cloudfront_info.py pylint:unnecessary-comprehension # (new test) Should be an easy fix, but testing is a challenge - test are broken and aliases require a wildcard cert in ACM
+plugins/modules/iam.py pylint:unnecessary-comprehension # no tests and module is deprecated
+plugins/modules/route53.py validate-modules:parameter-state-invalid-choice # route53_info needs improvements before we can deprecate this
diff --git a/tests/sanity/ignore-2.9.txt b/tests/sanity/ignore-2.9.txt
index 86e1e2394f9..16062bb5c52 100644
--- a/tests/sanity/ignore-2.9.txt
+++ b/tests/sanity/ignore-2.9.txt
@@ -1,2207 +1,46 @@
-plugins/modules/__init__.py compile-2.6!skip
-plugins/modules/__init__.py compile-2.7!skip
-plugins/modules/__init__.py compile-3.5!skip
-plugins/modules/__init__.py compile-3.6!skip
-plugins/modules/__init__.py compile-3.7!skip
-plugins/modules/__init__.py future-import-boilerplate!skip
-plugins/modules/__init__.py import-2.6!skip
-plugins/modules/__init__.py import-2.7!skip
-plugins/modules/__init__.py import-3.5!skip
-plugins/modules/__init__.py import-3.6!skip
-plugins/modules/__init__.py import-3.7!skip
-plugins/modules/__init__.py metaclass-boilerplate!skip
-plugins/modules/aws_acm.py compile-2.6!skip
-plugins/modules/aws_acm.py compile-2.7!skip
-plugins/modules/aws_acm.py compile-3.5!skip
-plugins/modules/aws_acm.py compile-3.6!skip
-plugins/modules/aws_acm.py compile-3.7!skip
-plugins/modules/aws_acm.py future-import-boilerplate!skip
-plugins/modules/aws_acm.py import-2.6!skip
-plugins/modules/aws_acm.py import-2.7!skip
-plugins/modules/aws_acm.py import-3.5!skip
-plugins/modules/aws_acm.py import-3.6!skip
-plugins/modules/aws_acm.py import-3.7!skip
-plugins/modules/aws_acm.py metaclass-boilerplate!skip
-plugins/modules/aws_acm_info.py compile-2.6!skip
-plugins/modules/aws_acm_info.py compile-2.7!skip
-plugins/modules/aws_acm_info.py compile-3.5!skip
-plugins/modules/aws_acm_info.py compile-3.6!skip
-plugins/modules/aws_acm_info.py compile-3.7!skip
-plugins/modules/aws_acm_info.py future-import-boilerplate!skip
-plugins/modules/aws_acm_info.py import-2.6!skip
-plugins/modules/aws_acm_info.py import-2.7!skip
-plugins/modules/aws_acm_info.py import-3.5!skip
-plugins/modules/aws_acm_info.py import-3.6!skip
-plugins/modules/aws_acm_info.py import-3.7!skip
-plugins/modules/aws_acm_info.py metaclass-boilerplate!skip
plugins/modules/aws_acm_info.py pylint:ansible-deprecated-no-version
-plugins/modules/aws_api_gateway.py compile-2.6!skip
-plugins/modules/aws_api_gateway.py compile-2.7!skip
-plugins/modules/aws_api_gateway.py compile-3.5!skip
-plugins/modules/aws_api_gateway.py compile-3.6!skip
-plugins/modules/aws_api_gateway.py compile-3.7!skip
-plugins/modules/aws_api_gateway.py future-import-boilerplate!skip
-plugins/modules/aws_api_gateway.py import-2.6!skip
-plugins/modules/aws_api_gateway.py import-2.7!skip
-plugins/modules/aws_api_gateway.py import-3.5!skip
-plugins/modules/aws_api_gateway.py import-3.6!skip
-plugins/modules/aws_api_gateway.py import-3.7!skip
-plugins/modules/aws_api_gateway.py metaclass-boilerplate!skip
-plugins/modules/aws_application_scaling_policy.py compile-2.6!skip
-plugins/modules/aws_application_scaling_policy.py compile-2.7!skip
-plugins/modules/aws_application_scaling_policy.py compile-3.5!skip
-plugins/modules/aws_application_scaling_policy.py compile-3.6!skip
-plugins/modules/aws_application_scaling_policy.py compile-3.7!skip
-plugins/modules/aws_application_scaling_policy.py future-import-boilerplate!skip
-plugins/modules/aws_application_scaling_policy.py import-2.6!skip
-plugins/modules/aws_application_scaling_policy.py import-2.7!skip
-plugins/modules/aws_application_scaling_policy.py import-3.5!skip
-plugins/modules/aws_application_scaling_policy.py import-3.6!skip
-plugins/modules/aws_application_scaling_policy.py import-3.7!skip
-plugins/modules/aws_application_scaling_policy.py metaclass-boilerplate!skip
-plugins/modules/aws_batch_compute_environment.py compile-2.6!skip
-plugins/modules/aws_batch_compute_environment.py compile-2.7!skip
-plugins/modules/aws_batch_compute_environment.py compile-3.5!skip
-plugins/modules/aws_batch_compute_environment.py compile-3.6!skip
-plugins/modules/aws_batch_compute_environment.py compile-3.7!skip
-plugins/modules/aws_batch_compute_environment.py future-import-boilerplate!skip
-plugins/modules/aws_batch_compute_environment.py import-2.6!skip
-plugins/modules/aws_batch_compute_environment.py import-2.7!skip
-plugins/modules/aws_batch_compute_environment.py import-3.5!skip
-plugins/modules/aws_batch_compute_environment.py import-3.6!skip
-plugins/modules/aws_batch_compute_environment.py import-3.7!skip
-plugins/modules/aws_batch_compute_environment.py metaclass-boilerplate!skip
-plugins/modules/aws_batch_job_definition.py compile-2.6!skip
-plugins/modules/aws_batch_job_definition.py compile-2.7!skip
-plugins/modules/aws_batch_job_definition.py compile-3.5!skip
-plugins/modules/aws_batch_job_definition.py compile-3.6!skip
-plugins/modules/aws_batch_job_definition.py compile-3.7!skip
-plugins/modules/aws_batch_job_definition.py future-import-boilerplate!skip
-plugins/modules/aws_batch_job_definition.py import-2.6!skip
-plugins/modules/aws_batch_job_definition.py import-2.7!skip
-plugins/modules/aws_batch_job_definition.py import-3.5!skip
-plugins/modules/aws_batch_job_definition.py import-3.6!skip
-plugins/modules/aws_batch_job_definition.py import-3.7!skip
-plugins/modules/aws_batch_job_definition.py metaclass-boilerplate!skip
-plugins/modules/aws_batch_job_queue.py compile-2.6!skip
-plugins/modules/aws_batch_job_queue.py compile-2.7!skip
-plugins/modules/aws_batch_job_queue.py compile-3.5!skip
-plugins/modules/aws_batch_job_queue.py compile-3.6!skip
-plugins/modules/aws_batch_job_queue.py compile-3.7!skip
-plugins/modules/aws_batch_job_queue.py future-import-boilerplate!skip
-plugins/modules/aws_batch_job_queue.py import-2.6!skip
-plugins/modules/aws_batch_job_queue.py import-2.7!skip
-plugins/modules/aws_batch_job_queue.py import-3.5!skip
-plugins/modules/aws_batch_job_queue.py import-3.6!skip
-plugins/modules/aws_batch_job_queue.py import-3.7!skip
-plugins/modules/aws_batch_job_queue.py metaclass-boilerplate!skip
-plugins/modules/aws_codebuild.py compile-2.6!skip
-plugins/modules/aws_codebuild.py compile-2.7!skip
-plugins/modules/aws_codebuild.py compile-3.5!skip
-plugins/modules/aws_codebuild.py compile-3.6!skip
-plugins/modules/aws_codebuild.py compile-3.7!skip
-plugins/modules/aws_codebuild.py future-import-boilerplate!skip
-plugins/modules/aws_codebuild.py import-2.6!skip
-plugins/modules/aws_codebuild.py import-2.7!skip
-plugins/modules/aws_codebuild.py import-3.5!skip
-plugins/modules/aws_codebuild.py import-3.6!skip
-plugins/modules/aws_codebuild.py import-3.7!skip
-plugins/modules/aws_codebuild.py metaclass-boilerplate!skip
-plugins/modules/aws_codecommit.py compile-2.6!skip
-plugins/modules/aws_codecommit.py compile-2.7!skip
-plugins/modules/aws_codecommit.py compile-3.5!skip
-plugins/modules/aws_codecommit.py compile-3.6!skip
-plugins/modules/aws_codecommit.py compile-3.7!skip
-plugins/modules/aws_codecommit.py future-import-boilerplate!skip
-plugins/modules/aws_codecommit.py import-2.6!skip
-plugins/modules/aws_codecommit.py import-2.7!skip
-plugins/modules/aws_codecommit.py import-3.5!skip
-plugins/modules/aws_codecommit.py import-3.6!skip
-plugins/modules/aws_codecommit.py import-3.7!skip
-plugins/modules/aws_codecommit.py metaclass-boilerplate!skip
-plugins/modules/aws_codepipeline.py compile-2.6!skip
-plugins/modules/aws_codepipeline.py compile-2.7!skip
-plugins/modules/aws_codepipeline.py compile-3.5!skip
-plugins/modules/aws_codepipeline.py compile-3.6!skip
-plugins/modules/aws_codepipeline.py compile-3.7!skip
-plugins/modules/aws_codepipeline.py future-import-boilerplate!skip
-plugins/modules/aws_codepipeline.py import-2.6!skip
-plugins/modules/aws_codepipeline.py import-2.7!skip
-plugins/modules/aws_codepipeline.py import-3.5!skip
-plugins/modules/aws_codepipeline.py import-3.6!skip
-plugins/modules/aws_codepipeline.py import-3.7!skip
-plugins/modules/aws_codepipeline.py metaclass-boilerplate!skip
-plugins/modules/aws_config_aggregation_authorization.py compile-2.6!skip
-plugins/modules/aws_config_aggregation_authorization.py compile-2.7!skip
-plugins/modules/aws_config_aggregation_authorization.py compile-3.5!skip
-plugins/modules/aws_config_aggregation_authorization.py compile-3.6!skip
-plugins/modules/aws_config_aggregation_authorization.py compile-3.7!skip
-plugins/modules/aws_config_aggregation_authorization.py future-import-boilerplate!skip
-plugins/modules/aws_config_aggregation_authorization.py import-2.6!skip
-plugins/modules/aws_config_aggregation_authorization.py import-2.7!skip
-plugins/modules/aws_config_aggregation_authorization.py import-3.5!skip
-plugins/modules/aws_config_aggregation_authorization.py import-3.6!skip
-plugins/modules/aws_config_aggregation_authorization.py import-3.7!skip
-plugins/modules/aws_config_aggregation_authorization.py metaclass-boilerplate!skip
-plugins/modules/aws_config_aggregator.py compile-2.6!skip
-plugins/modules/aws_config_aggregator.py compile-2.7!skip
-plugins/modules/aws_config_aggregator.py compile-3.5!skip
-plugins/modules/aws_config_aggregator.py compile-3.6!skip
-plugins/modules/aws_config_aggregator.py compile-3.7!skip
-plugins/modules/aws_config_aggregator.py future-import-boilerplate!skip
-plugins/modules/aws_config_aggregator.py import-2.6!skip
-plugins/modules/aws_config_aggregator.py import-2.7!skip
-plugins/modules/aws_config_aggregator.py import-3.5!skip
-plugins/modules/aws_config_aggregator.py import-3.6!skip
-plugins/modules/aws_config_aggregator.py import-3.7!skip
-plugins/modules/aws_config_aggregator.py metaclass-boilerplate!skip
-plugins/modules/aws_config_delivery_channel.py compile-2.6!skip
-plugins/modules/aws_config_delivery_channel.py compile-2.7!skip
-plugins/modules/aws_config_delivery_channel.py compile-3.5!skip
-plugins/modules/aws_config_delivery_channel.py compile-3.6!skip
-plugins/modules/aws_config_delivery_channel.py compile-3.7!skip
-plugins/modules/aws_config_delivery_channel.py future-import-boilerplate!skip
-plugins/modules/aws_config_delivery_channel.py import-2.6!skip
-plugins/modules/aws_config_delivery_channel.py import-2.7!skip
-plugins/modules/aws_config_delivery_channel.py import-3.5!skip
-plugins/modules/aws_config_delivery_channel.py import-3.6!skip
-plugins/modules/aws_config_delivery_channel.py import-3.7!skip
-plugins/modules/aws_config_delivery_channel.py metaclass-boilerplate!skip
-plugins/modules/aws_config_recorder.py compile-2.6!skip
-plugins/modules/aws_config_recorder.py compile-2.7!skip
-plugins/modules/aws_config_recorder.py compile-3.5!skip
-plugins/modules/aws_config_recorder.py compile-3.6!skip
-plugins/modules/aws_config_recorder.py compile-3.7!skip
-plugins/modules/aws_config_recorder.py future-import-boilerplate!skip
-plugins/modules/aws_config_recorder.py import-2.6!skip
-plugins/modules/aws_config_recorder.py import-2.7!skip
-plugins/modules/aws_config_recorder.py import-3.5!skip
-plugins/modules/aws_config_recorder.py import-3.6!skip
-plugins/modules/aws_config_recorder.py import-3.7!skip
-plugins/modules/aws_config_recorder.py metaclass-boilerplate!skip
-plugins/modules/aws_config_rule.py compile-2.6!skip
-plugins/modules/aws_config_rule.py compile-2.7!skip
-plugins/modules/aws_config_rule.py compile-3.5!skip
-plugins/modules/aws_config_rule.py compile-3.6!skip
-plugins/modules/aws_config_rule.py compile-3.7!skip
-plugins/modules/aws_config_rule.py future-import-boilerplate!skip
-plugins/modules/aws_config_rule.py import-2.6!skip
-plugins/modules/aws_config_rule.py import-2.7!skip
-plugins/modules/aws_config_rule.py import-3.5!skip
-plugins/modules/aws_config_rule.py import-3.6!skip
-plugins/modules/aws_config_rule.py import-3.7!skip
-plugins/modules/aws_config_rule.py metaclass-boilerplate!skip
-plugins/modules/aws_direct_connect_confirm_connection.py compile-2.6!skip
-plugins/modules/aws_direct_connect_confirm_connection.py compile-2.7!skip
-plugins/modules/aws_direct_connect_confirm_connection.py compile-3.5!skip
-plugins/modules/aws_direct_connect_confirm_connection.py compile-3.6!skip
-plugins/modules/aws_direct_connect_confirm_connection.py compile-3.7!skip
-plugins/modules/aws_direct_connect_confirm_connection.py future-import-boilerplate!skip
-plugins/modules/aws_direct_connect_confirm_connection.py import-2.6!skip
-plugins/modules/aws_direct_connect_confirm_connection.py import-2.7!skip
-plugins/modules/aws_direct_connect_confirm_connection.py import-3.5!skip
-plugins/modules/aws_direct_connect_confirm_connection.py import-3.6!skip
-plugins/modules/aws_direct_connect_confirm_connection.py import-3.7!skip
-plugins/modules/aws_direct_connect_confirm_connection.py metaclass-boilerplate!skip
-plugins/modules/aws_direct_connect_connection.py compile-2.6!skip
-plugins/modules/aws_direct_connect_connection.py compile-2.7!skip
-plugins/modules/aws_direct_connect_connection.py compile-3.5!skip
-plugins/modules/aws_direct_connect_connection.py compile-3.6!skip
-plugins/modules/aws_direct_connect_connection.py compile-3.7!skip
-plugins/modules/aws_direct_connect_connection.py future-import-boilerplate!skip
-plugins/modules/aws_direct_connect_connection.py import-2.6!skip
-plugins/modules/aws_direct_connect_connection.py import-2.7!skip
-plugins/modules/aws_direct_connect_connection.py import-3.5!skip
-plugins/modules/aws_direct_connect_connection.py import-3.6!skip
-plugins/modules/aws_direct_connect_connection.py import-3.7!skip
-plugins/modules/aws_direct_connect_connection.py metaclass-boilerplate!skip
-plugins/modules/aws_direct_connect_gateway.py compile-2.6!skip
-plugins/modules/aws_direct_connect_gateway.py compile-2.7!skip
-plugins/modules/aws_direct_connect_gateway.py compile-3.5!skip
-plugins/modules/aws_direct_connect_gateway.py compile-3.6!skip
-plugins/modules/aws_direct_connect_gateway.py compile-3.7!skip
-plugins/modules/aws_direct_connect_gateway.py future-import-boilerplate!skip
-plugins/modules/aws_direct_connect_gateway.py import-2.6!skip
-plugins/modules/aws_direct_connect_gateway.py import-2.7!skip
-plugins/modules/aws_direct_connect_gateway.py import-3.5!skip
-plugins/modules/aws_direct_connect_gateway.py import-3.6!skip
-plugins/modules/aws_direct_connect_gateway.py import-3.7!skip
-plugins/modules/aws_direct_connect_gateway.py metaclass-boilerplate!skip
-plugins/modules/aws_direct_connect_link_aggregation_group.py compile-2.6!skip
-plugins/modules/aws_direct_connect_link_aggregation_group.py compile-2.7!skip
-plugins/modules/aws_direct_connect_link_aggregation_group.py compile-3.5!skip
-plugins/modules/aws_direct_connect_link_aggregation_group.py compile-3.6!skip
-plugins/modules/aws_direct_connect_link_aggregation_group.py compile-3.7!skip
-plugins/modules/aws_direct_connect_link_aggregation_group.py future-import-boilerplate!skip
-plugins/modules/aws_direct_connect_link_aggregation_group.py import-2.6!skip
-plugins/modules/aws_direct_connect_link_aggregation_group.py import-2.7!skip
-plugins/modules/aws_direct_connect_link_aggregation_group.py import-3.5!skip
-plugins/modules/aws_direct_connect_link_aggregation_group.py import-3.6!skip
-plugins/modules/aws_direct_connect_link_aggregation_group.py import-3.7!skip
-plugins/modules/aws_direct_connect_link_aggregation_group.py metaclass-boilerplate!skip
-plugins/modules/aws_direct_connect_virtual_interface.py compile-2.6!skip
-plugins/modules/aws_direct_connect_virtual_interface.py compile-2.7!skip
-plugins/modules/aws_direct_connect_virtual_interface.py compile-3.5!skip
-plugins/modules/aws_direct_connect_virtual_interface.py compile-3.6!skip
-plugins/modules/aws_direct_connect_virtual_interface.py compile-3.7!skip
-plugins/modules/aws_direct_connect_virtual_interface.py future-import-boilerplate!skip
-plugins/modules/aws_direct_connect_virtual_interface.py import-2.6!skip
-plugins/modules/aws_direct_connect_virtual_interface.py import-2.7!skip
-plugins/modules/aws_direct_connect_virtual_interface.py import-3.5!skip
-plugins/modules/aws_direct_connect_virtual_interface.py import-3.6!skip
-plugins/modules/aws_direct_connect_virtual_interface.py import-3.7!skip
-plugins/modules/aws_direct_connect_virtual_interface.py metaclass-boilerplate!skip
-plugins/modules/aws_eks_cluster.py compile-2.6!skip
-plugins/modules/aws_eks_cluster.py compile-2.7!skip
-plugins/modules/aws_eks_cluster.py compile-3.5!skip
-plugins/modules/aws_eks_cluster.py compile-3.6!skip
-plugins/modules/aws_eks_cluster.py compile-3.7!skip
-plugins/modules/aws_eks_cluster.py future-import-boilerplate!skip
-plugins/modules/aws_eks_cluster.py import-2.6!skip
-plugins/modules/aws_eks_cluster.py import-2.7!skip
-plugins/modules/aws_eks_cluster.py import-3.5!skip
-plugins/modules/aws_eks_cluster.py import-3.6!skip
-plugins/modules/aws_eks_cluster.py import-3.7!skip
-plugins/modules/aws_eks_cluster.py metaclass-boilerplate!skip
-plugins/modules/aws_elasticbeanstalk_app.py compile-2.6!skip
-plugins/modules/aws_elasticbeanstalk_app.py compile-2.7!skip
-plugins/modules/aws_elasticbeanstalk_app.py compile-3.5!skip
-plugins/modules/aws_elasticbeanstalk_app.py compile-3.6!skip
-plugins/modules/aws_elasticbeanstalk_app.py compile-3.7!skip
-plugins/modules/aws_elasticbeanstalk_app.py future-import-boilerplate!skip
-plugins/modules/aws_elasticbeanstalk_app.py import-2.6!skip
-plugins/modules/aws_elasticbeanstalk_app.py import-2.7!skip
-plugins/modules/aws_elasticbeanstalk_app.py import-3.5!skip
-plugins/modules/aws_elasticbeanstalk_app.py import-3.6!skip
-plugins/modules/aws_elasticbeanstalk_app.py import-3.7!skip
-plugins/modules/aws_elasticbeanstalk_app.py metaclass-boilerplate!skip
-plugins/modules/aws_glue_connection.py compile-2.6!skip
-plugins/modules/aws_glue_connection.py compile-2.7!skip
-plugins/modules/aws_glue_connection.py compile-3.5!skip
-plugins/modules/aws_glue_connection.py compile-3.6!skip
-plugins/modules/aws_glue_connection.py compile-3.7!skip
-plugins/modules/aws_glue_connection.py future-import-boilerplate!skip
-plugins/modules/aws_glue_connection.py import-2.6!skip
-plugins/modules/aws_glue_connection.py import-2.7!skip
-plugins/modules/aws_glue_connection.py import-3.5!skip
-plugins/modules/aws_glue_connection.py import-3.6!skip
-plugins/modules/aws_glue_connection.py import-3.7!skip
-plugins/modules/aws_glue_connection.py metaclass-boilerplate!skip
-plugins/modules/aws_glue_job.py compile-2.6!skip
-plugins/modules/aws_glue_job.py compile-2.7!skip
-plugins/modules/aws_glue_job.py compile-3.5!skip
-plugins/modules/aws_glue_job.py compile-3.6!skip
-plugins/modules/aws_glue_job.py compile-3.7!skip
-plugins/modules/aws_glue_job.py future-import-boilerplate!skip
-plugins/modules/aws_glue_job.py import-2.6!skip
-plugins/modules/aws_glue_job.py import-2.7!skip
-plugins/modules/aws_glue_job.py import-3.5!skip
-plugins/modules/aws_glue_job.py import-3.6!skip
-plugins/modules/aws_glue_job.py import-3.7!skip
-plugins/modules/aws_glue_job.py metaclass-boilerplate!skip
-plugins/modules/aws_inspector_target.py compile-2.6!skip
-plugins/modules/aws_inspector_target.py compile-2.7!skip
-plugins/modules/aws_inspector_target.py compile-3.5!skip
-plugins/modules/aws_inspector_target.py compile-3.6!skip
-plugins/modules/aws_inspector_target.py compile-3.7!skip
-plugins/modules/aws_inspector_target.py future-import-boilerplate!skip
-plugins/modules/aws_inspector_target.py import-2.6!skip
-plugins/modules/aws_inspector_target.py import-2.7!skip
-plugins/modules/aws_inspector_target.py import-3.5!skip
-plugins/modules/aws_inspector_target.py import-3.6!skip
-plugins/modules/aws_inspector_target.py import-3.7!skip
-plugins/modules/aws_inspector_target.py metaclass-boilerplate!skip
-plugins/modules/aws_kms.py compile-2.6!skip
-plugins/modules/aws_kms.py compile-2.7!skip
-plugins/modules/aws_kms.py compile-3.5!skip
-plugins/modules/aws_kms.py compile-3.6!skip
-plugins/modules/aws_kms.py compile-3.7!skip
-plugins/modules/aws_kms.py future-import-boilerplate!skip
-plugins/modules/aws_kms.py import-2.6!skip
-plugins/modules/aws_kms.py import-2.7!skip
-plugins/modules/aws_kms.py import-3.5!skip
-plugins/modules/aws_kms.py import-3.6!skip
-plugins/modules/aws_kms.py import-3.7!skip
-plugins/modules/aws_kms.py metaclass-boilerplate!skip
plugins/modules/aws_kms.py pylint:ansible-deprecated-no-version
-plugins/modules/aws_kms_info.py compile-2.6!skip
-plugins/modules/aws_kms_info.py compile-2.7!skip
-plugins/modules/aws_kms_info.py compile-3.5!skip
-plugins/modules/aws_kms_info.py compile-3.6!skip
-plugins/modules/aws_kms_info.py compile-3.7!skip
-plugins/modules/aws_kms_info.py future-import-boilerplate!skip
-plugins/modules/aws_kms_info.py import-2.6!skip
-plugins/modules/aws_kms_info.py import-2.7!skip
-plugins/modules/aws_kms_info.py import-3.5!skip
-plugins/modules/aws_kms_info.py import-3.6!skip
-plugins/modules/aws_kms_info.py import-3.7!skip
-plugins/modules/aws_kms_info.py metaclass-boilerplate!skip
plugins/modules/aws_kms_info.py pylint:ansible-deprecated-no-version
-plugins/modules/aws_region_info.py compile-2.6!skip
-plugins/modules/aws_region_info.py compile-2.7!skip
-plugins/modules/aws_region_info.py compile-3.5!skip
-plugins/modules/aws_region_info.py compile-3.6!skip
-plugins/modules/aws_region_info.py compile-3.7!skip
-plugins/modules/aws_region_info.py future-import-boilerplate!skip
-plugins/modules/aws_region_info.py import-2.6!skip
-plugins/modules/aws_region_info.py import-2.7!skip
-plugins/modules/aws_region_info.py import-3.5!skip
-plugins/modules/aws_region_info.py import-3.6!skip
-plugins/modules/aws_region_info.py import-3.7!skip
-plugins/modules/aws_region_info.py metaclass-boilerplate!skip
plugins/modules/aws_region_info.py pylint:ansible-deprecated-no-version
-plugins/modules/aws_s3_bucket_info.py compile-2.6!skip
-plugins/modules/aws_s3_bucket_info.py compile-2.7!skip
-plugins/modules/aws_s3_bucket_info.py compile-3.5!skip
-plugins/modules/aws_s3_bucket_info.py compile-3.6!skip
-plugins/modules/aws_s3_bucket_info.py compile-3.7!skip
-plugins/modules/aws_s3_bucket_info.py future-import-boilerplate!skip
-plugins/modules/aws_s3_bucket_info.py import-2.6!skip
-plugins/modules/aws_s3_bucket_info.py import-2.7!skip
-plugins/modules/aws_s3_bucket_info.py import-3.5!skip
-plugins/modules/aws_s3_bucket_info.py import-3.6!skip
-plugins/modules/aws_s3_bucket_info.py import-3.7!skip
-plugins/modules/aws_s3_bucket_info.py metaclass-boilerplate!skip
plugins/modules/aws_s3_bucket_info.py pylint:ansible-deprecated-no-version
-plugins/modules/aws_s3_cors.py compile-2.6!skip
-plugins/modules/aws_s3_cors.py compile-2.7!skip
-plugins/modules/aws_s3_cors.py compile-3.5!skip
-plugins/modules/aws_s3_cors.py compile-3.6!skip
-plugins/modules/aws_s3_cors.py compile-3.7!skip
-plugins/modules/aws_s3_cors.py future-import-boilerplate!skip
-plugins/modules/aws_s3_cors.py import-2.6!skip
-plugins/modules/aws_s3_cors.py import-2.7!skip
-plugins/modules/aws_s3_cors.py import-3.5!skip
-plugins/modules/aws_s3_cors.py import-3.6!skip
-plugins/modules/aws_s3_cors.py import-3.7!skip
-plugins/modules/aws_s3_cors.py metaclass-boilerplate!skip
-plugins/modules/aws_secret.py compile-2.6!skip
-plugins/modules/aws_secret.py compile-2.7!skip
-plugins/modules/aws_secret.py compile-3.5!skip
-plugins/modules/aws_secret.py compile-3.6!skip
-plugins/modules/aws_secret.py compile-3.7!skip
-plugins/modules/aws_secret.py future-import-boilerplate!skip
-plugins/modules/aws_secret.py import-2.6!skip
-plugins/modules/aws_secret.py import-2.7!skip
-plugins/modules/aws_secret.py import-3.5!skip
-plugins/modules/aws_secret.py import-3.6!skip
-plugins/modules/aws_secret.py import-3.7!skip
-plugins/modules/aws_secret.py metaclass-boilerplate!skip
-plugins/modules/aws_ses_identity.py compile-2.6!skip
-plugins/modules/aws_ses_identity.py compile-2.7!skip
-plugins/modules/aws_ses_identity.py compile-3.5!skip
-plugins/modules/aws_ses_identity.py compile-3.6!skip
-plugins/modules/aws_ses_identity.py compile-3.7!skip
-plugins/modules/aws_ses_identity.py future-import-boilerplate!skip
-plugins/modules/aws_ses_identity.py import-2.6!skip
-plugins/modules/aws_ses_identity.py import-2.7!skip
-plugins/modules/aws_ses_identity.py import-3.5!skip
-plugins/modules/aws_ses_identity.py import-3.6!skip
-plugins/modules/aws_ses_identity.py import-3.7!skip
-plugins/modules/aws_ses_identity.py metaclass-boilerplate!skip
-plugins/modules/aws_ses_identity_policy.py compile-2.6!skip
-plugins/modules/aws_ses_identity_policy.py compile-2.7!skip
-plugins/modules/aws_ses_identity_policy.py compile-3.5!skip
-plugins/modules/aws_ses_identity_policy.py compile-3.6!skip
-plugins/modules/aws_ses_identity_policy.py compile-3.7!skip
-plugins/modules/aws_ses_identity_policy.py future-import-boilerplate!skip
-plugins/modules/aws_ses_identity_policy.py import-2.6!skip
-plugins/modules/aws_ses_identity_policy.py import-2.7!skip
-plugins/modules/aws_ses_identity_policy.py import-3.5!skip
-plugins/modules/aws_ses_identity_policy.py import-3.6!skip
-plugins/modules/aws_ses_identity_policy.py import-3.7!skip
-plugins/modules/aws_ses_identity_policy.py metaclass-boilerplate!skip
-plugins/modules/aws_ses_rule_set.py compile-2.6!skip
-plugins/modules/aws_ses_rule_set.py compile-2.7!skip
-plugins/modules/aws_ses_rule_set.py compile-3.5!skip
-plugins/modules/aws_ses_rule_set.py compile-3.6!skip
-plugins/modules/aws_ses_rule_set.py compile-3.7!skip
-plugins/modules/aws_ses_rule_set.py future-import-boilerplate!skip
-plugins/modules/aws_ses_rule_set.py import-2.6!skip
-plugins/modules/aws_ses_rule_set.py import-2.7!skip
-plugins/modules/aws_ses_rule_set.py import-3.5!skip
-plugins/modules/aws_ses_rule_set.py import-3.6!skip
-plugins/modules/aws_ses_rule_set.py import-3.7!skip
-plugins/modules/aws_ses_rule_set.py metaclass-boilerplate!skip
-plugins/modules/aws_sgw_info.py compile-2.6!skip
-plugins/modules/aws_sgw_info.py compile-2.7!skip
-plugins/modules/aws_sgw_info.py compile-3.5!skip
-plugins/modules/aws_sgw_info.py compile-3.6!skip
-plugins/modules/aws_sgw_info.py compile-3.7!skip
-plugins/modules/aws_sgw_info.py future-import-boilerplate!skip
-plugins/modules/aws_sgw_info.py import-2.6!skip
-plugins/modules/aws_sgw_info.py import-2.7!skip
-plugins/modules/aws_sgw_info.py import-3.5!skip
-plugins/modules/aws_sgw_info.py import-3.6!skip
-plugins/modules/aws_sgw_info.py import-3.7!skip
-plugins/modules/aws_sgw_info.py metaclass-boilerplate!skip
plugins/modules/aws_sgw_info.py pylint:ansible-deprecated-no-version
-plugins/modules/aws_ssm_parameter_store.py compile-2.6!skip
-plugins/modules/aws_ssm_parameter_store.py compile-2.7!skip
-plugins/modules/aws_ssm_parameter_store.py compile-3.5!skip
-plugins/modules/aws_ssm_parameter_store.py compile-3.6!skip
-plugins/modules/aws_ssm_parameter_store.py compile-3.7!skip
-plugins/modules/aws_ssm_parameter_store.py future-import-boilerplate!skip
-plugins/modules/aws_ssm_parameter_store.py import-2.6!skip
-plugins/modules/aws_ssm_parameter_store.py import-2.7!skip
-plugins/modules/aws_ssm_parameter_store.py import-3.5!skip
-plugins/modules/aws_ssm_parameter_store.py import-3.6!skip
-plugins/modules/aws_ssm_parameter_store.py import-3.7!skip
-plugins/modules/aws_ssm_parameter_store.py metaclass-boilerplate!skip
-plugins/modules/aws_step_functions_state_machine.py compile-2.6!skip
-plugins/modules/aws_step_functions_state_machine.py compile-2.7!skip
-plugins/modules/aws_step_functions_state_machine.py compile-3.5!skip
-plugins/modules/aws_step_functions_state_machine.py compile-3.6!skip
-plugins/modules/aws_step_functions_state_machine.py compile-3.7!skip
-plugins/modules/aws_step_functions_state_machine.py future-import-boilerplate!skip
-plugins/modules/aws_step_functions_state_machine.py import-2.6!skip
-plugins/modules/aws_step_functions_state_machine.py import-2.7!skip
-plugins/modules/aws_step_functions_state_machine.py import-3.5!skip
-plugins/modules/aws_step_functions_state_machine.py import-3.6!skip
-plugins/modules/aws_step_functions_state_machine.py import-3.7!skip
-plugins/modules/aws_step_functions_state_machine.py metaclass-boilerplate!skip
-plugins/modules/aws_step_functions_state_machine_execution.py compile-2.6!skip
-plugins/modules/aws_step_functions_state_machine_execution.py compile-2.7!skip
-plugins/modules/aws_step_functions_state_machine_execution.py compile-3.5!skip
-plugins/modules/aws_step_functions_state_machine_execution.py compile-3.6!skip
-plugins/modules/aws_step_functions_state_machine_execution.py compile-3.7!skip
-plugins/modules/aws_step_functions_state_machine_execution.py future-import-boilerplate!skip
-plugins/modules/aws_step_functions_state_machine_execution.py import-2.6!skip
-plugins/modules/aws_step_functions_state_machine_execution.py import-2.7!skip
-plugins/modules/aws_step_functions_state_machine_execution.py import-3.5!skip
-plugins/modules/aws_step_functions_state_machine_execution.py import-3.6!skip
-plugins/modules/aws_step_functions_state_machine_execution.py import-3.7!skip
-plugins/modules/aws_step_functions_state_machine_execution.py metaclass-boilerplate!skip
-plugins/modules/aws_waf_condition.py compile-2.6!skip
-plugins/modules/aws_waf_condition.py compile-2.7!skip
-plugins/modules/aws_waf_condition.py compile-3.5!skip
-plugins/modules/aws_waf_condition.py compile-3.6!skip
-plugins/modules/aws_waf_condition.py compile-3.7!skip
-plugins/modules/aws_waf_condition.py future-import-boilerplate!skip
-plugins/modules/aws_waf_condition.py import-2.6!skip
-plugins/modules/aws_waf_condition.py import-2.7!skip
-plugins/modules/aws_waf_condition.py import-3.5!skip
-plugins/modules/aws_waf_condition.py import-3.6!skip
-plugins/modules/aws_waf_condition.py import-3.7!skip
-plugins/modules/aws_waf_condition.py metaclass-boilerplate!skip
-plugins/modules/aws_waf_info.py compile-2.6!skip
-plugins/modules/aws_waf_info.py compile-2.7!skip
-plugins/modules/aws_waf_info.py compile-3.5!skip
-plugins/modules/aws_waf_info.py compile-3.6!skip
-plugins/modules/aws_waf_info.py compile-3.7!skip
-plugins/modules/aws_waf_info.py future-import-boilerplate!skip
-plugins/modules/aws_waf_info.py import-2.6!skip
-plugins/modules/aws_waf_info.py import-2.7!skip
-plugins/modules/aws_waf_info.py import-3.5!skip
-plugins/modules/aws_waf_info.py import-3.6!skip
-plugins/modules/aws_waf_info.py import-3.7!skip
-plugins/modules/aws_waf_info.py metaclass-boilerplate!skip
plugins/modules/aws_waf_info.py pylint:ansible-deprecated-no-version
-plugins/modules/aws_waf_rule.py compile-2.6!skip
-plugins/modules/aws_waf_rule.py compile-2.7!skip
-plugins/modules/aws_waf_rule.py compile-3.5!skip
-plugins/modules/aws_waf_rule.py compile-3.6!skip
-plugins/modules/aws_waf_rule.py compile-3.7!skip
-plugins/modules/aws_waf_rule.py future-import-boilerplate!skip
-plugins/modules/aws_waf_rule.py import-2.6!skip
-plugins/modules/aws_waf_rule.py import-2.7!skip
-plugins/modules/aws_waf_rule.py import-3.5!skip
-plugins/modules/aws_waf_rule.py import-3.6!skip
-plugins/modules/aws_waf_rule.py import-3.7!skip
-plugins/modules/aws_waf_rule.py metaclass-boilerplate!skip
-plugins/modules/aws_waf_web_acl.py compile-2.6!skip
-plugins/modules/aws_waf_web_acl.py compile-2.7!skip
-plugins/modules/aws_waf_web_acl.py compile-3.5!skip
-plugins/modules/aws_waf_web_acl.py compile-3.6!skip
-plugins/modules/aws_waf_web_acl.py compile-3.7!skip
-plugins/modules/aws_waf_web_acl.py future-import-boilerplate!skip
-plugins/modules/aws_waf_web_acl.py import-2.6!skip
-plugins/modules/aws_waf_web_acl.py import-2.7!skip
-plugins/modules/aws_waf_web_acl.py import-3.5!skip
-plugins/modules/aws_waf_web_acl.py import-3.6!skip
-plugins/modules/aws_waf_web_acl.py import-3.7!skip
-plugins/modules/aws_waf_web_acl.py metaclass-boilerplate!skip
-plugins/modules/cloudformation_exports_info.py compile-2.6!skip
-plugins/modules/cloudformation_exports_info.py compile-2.7!skip
-plugins/modules/cloudformation_exports_info.py compile-3.5!skip
-plugins/modules/cloudformation_exports_info.py compile-3.6!skip
-plugins/modules/cloudformation_exports_info.py compile-3.7!skip
-plugins/modules/cloudformation_exports_info.py future-import-boilerplate!skip
-plugins/modules/cloudformation_exports_info.py import-2.6!skip
-plugins/modules/cloudformation_exports_info.py import-2.7!skip
-plugins/modules/cloudformation_exports_info.py import-3.5!skip
-plugins/modules/cloudformation_exports_info.py import-3.6!skip
-plugins/modules/cloudformation_exports_info.py import-3.7!skip
-plugins/modules/cloudformation_exports_info.py metaclass-boilerplate!skip
-plugins/modules/cloudformation_stack_set.py compile-2.6!skip
-plugins/modules/cloudformation_stack_set.py compile-2.7!skip
-plugins/modules/cloudformation_stack_set.py compile-3.5!skip
-plugins/modules/cloudformation_stack_set.py compile-3.6!skip
-plugins/modules/cloudformation_stack_set.py compile-3.7!skip
-plugins/modules/cloudformation_stack_set.py future-import-boilerplate!skip
-plugins/modules/cloudformation_stack_set.py import-2.6!skip
-plugins/modules/cloudformation_stack_set.py import-2.7!skip
-plugins/modules/cloudformation_stack_set.py import-3.5!skip
-plugins/modules/cloudformation_stack_set.py import-3.6!skip
-plugins/modules/cloudformation_stack_set.py import-3.7!skip
-plugins/modules/cloudformation_stack_set.py metaclass-boilerplate!skip
-plugins/modules/cloudfront_distribution.py compile-2.6!skip
-plugins/modules/cloudfront_distribution.py compile-2.7!skip
-plugins/modules/cloudfront_distribution.py compile-3.5!skip
-plugins/modules/cloudfront_distribution.py compile-3.6!skip
-plugins/modules/cloudfront_distribution.py compile-3.7!skip
-plugins/modules/cloudfront_distribution.py future-import-boilerplate!skip
-plugins/modules/cloudfront_distribution.py import-2.6!skip
-plugins/modules/cloudfront_distribution.py import-2.7!skip
-plugins/modules/cloudfront_distribution.py import-3.5!skip
-plugins/modules/cloudfront_distribution.py import-3.6!skip
-plugins/modules/cloudfront_distribution.py import-3.7!skip
-plugins/modules/cloudfront_distribution.py metaclass-boilerplate!skip
-plugins/modules/cloudfront_info.py compile-2.6!skip
-plugins/modules/cloudfront_info.py compile-2.7!skip
-plugins/modules/cloudfront_info.py compile-3.5!skip
-plugins/modules/cloudfront_info.py compile-3.6!skip
-plugins/modules/cloudfront_info.py compile-3.7!skip
-plugins/modules/cloudfront_info.py future-import-boilerplate!skip
-plugins/modules/cloudfront_info.py import-2.6!skip
-plugins/modules/cloudfront_info.py import-2.7!skip
-plugins/modules/cloudfront_info.py import-3.5!skip
-plugins/modules/cloudfront_info.py import-3.6!skip
-plugins/modules/cloudfront_info.py import-3.7!skip
-plugins/modules/cloudfront_info.py metaclass-boilerplate!skip
plugins/modules/cloudfront_info.py pylint:ansible-deprecated-no-version
-plugins/modules/cloudfront_invalidation.py compile-2.6!skip
-plugins/modules/cloudfront_invalidation.py compile-2.7!skip
-plugins/modules/cloudfront_invalidation.py compile-3.5!skip
-plugins/modules/cloudfront_invalidation.py compile-3.6!skip
-plugins/modules/cloudfront_invalidation.py compile-3.7!skip
-plugins/modules/cloudfront_invalidation.py future-import-boilerplate!skip
-plugins/modules/cloudfront_invalidation.py import-2.6!skip
-plugins/modules/cloudfront_invalidation.py import-2.7!skip
-plugins/modules/cloudfront_invalidation.py import-3.5!skip
-plugins/modules/cloudfront_invalidation.py import-3.6!skip
-plugins/modules/cloudfront_invalidation.py import-3.7!skip
-plugins/modules/cloudfront_invalidation.py metaclass-boilerplate!skip
-plugins/modules/cloudfront_origin_access_identity.py compile-2.6!skip
-plugins/modules/cloudfront_origin_access_identity.py compile-2.7!skip
-plugins/modules/cloudfront_origin_access_identity.py compile-3.5!skip
-plugins/modules/cloudfront_origin_access_identity.py compile-3.6!skip
-plugins/modules/cloudfront_origin_access_identity.py compile-3.7!skip
-plugins/modules/cloudfront_origin_access_identity.py future-import-boilerplate!skip
-plugins/modules/cloudfront_origin_access_identity.py import-2.6!skip
-plugins/modules/cloudfront_origin_access_identity.py import-2.7!skip
-plugins/modules/cloudfront_origin_access_identity.py import-3.5!skip
-plugins/modules/cloudfront_origin_access_identity.py import-3.6!skip
-plugins/modules/cloudfront_origin_access_identity.py import-3.7!skip
-plugins/modules/cloudfront_origin_access_identity.py metaclass-boilerplate!skip
-plugins/modules/cloudtrail.py compile-2.6!skip
-plugins/modules/cloudtrail.py compile-2.7!skip
-plugins/modules/cloudtrail.py compile-3.5!skip
-plugins/modules/cloudtrail.py compile-3.6!skip
-plugins/modules/cloudtrail.py compile-3.7!skip
-plugins/modules/cloudtrail.py future-import-boilerplate!skip
-plugins/modules/cloudtrail.py import-2.6!skip
-plugins/modules/cloudtrail.py import-2.7!skip
-plugins/modules/cloudtrail.py import-3.5!skip
-plugins/modules/cloudtrail.py import-3.6!skip
-plugins/modules/cloudtrail.py import-3.7!skip
-plugins/modules/cloudtrail.py metaclass-boilerplate!skip
-plugins/modules/cloudwatchevent_rule.py compile-2.6!skip
-plugins/modules/cloudwatchevent_rule.py compile-2.7!skip
-plugins/modules/cloudwatchevent_rule.py compile-3.5!skip
-plugins/modules/cloudwatchevent_rule.py compile-3.6!skip
-plugins/modules/cloudwatchevent_rule.py compile-3.7!skip
-plugins/modules/cloudwatchevent_rule.py future-import-boilerplate!skip
-plugins/modules/cloudwatchevent_rule.py import-2.6!skip
-plugins/modules/cloudwatchevent_rule.py import-2.7!skip
-plugins/modules/cloudwatchevent_rule.py import-3.5!skip
-plugins/modules/cloudwatchevent_rule.py import-3.6!skip
-plugins/modules/cloudwatchevent_rule.py import-3.7!skip
-plugins/modules/cloudwatchevent_rule.py metaclass-boilerplate!skip
-plugins/modules/cloudwatchlogs_log_group.py compile-2.6!skip
-plugins/modules/cloudwatchlogs_log_group.py compile-2.7!skip
-plugins/modules/cloudwatchlogs_log_group.py compile-3.5!skip
-plugins/modules/cloudwatchlogs_log_group.py compile-3.6!skip
-plugins/modules/cloudwatchlogs_log_group.py compile-3.7!skip
-plugins/modules/cloudwatchlogs_log_group.py future-import-boilerplate!skip
-plugins/modules/cloudwatchlogs_log_group.py import-2.6!skip
-plugins/modules/cloudwatchlogs_log_group.py import-2.7!skip
-plugins/modules/cloudwatchlogs_log_group.py import-3.5!skip
-plugins/modules/cloudwatchlogs_log_group.py import-3.6!skip
-plugins/modules/cloudwatchlogs_log_group.py import-3.7!skip
-plugins/modules/cloudwatchlogs_log_group.py metaclass-boilerplate!skip
-plugins/modules/cloudwatchlogs_log_group_info.py compile-2.6!skip
-plugins/modules/cloudwatchlogs_log_group_info.py compile-2.7!skip
-plugins/modules/cloudwatchlogs_log_group_info.py compile-3.5!skip
-plugins/modules/cloudwatchlogs_log_group_info.py compile-3.6!skip
-plugins/modules/cloudwatchlogs_log_group_info.py compile-3.7!skip
-plugins/modules/cloudwatchlogs_log_group_info.py future-import-boilerplate!skip
-plugins/modules/cloudwatchlogs_log_group_info.py import-2.6!skip
-plugins/modules/cloudwatchlogs_log_group_info.py import-2.7!skip
-plugins/modules/cloudwatchlogs_log_group_info.py import-3.5!skip
-plugins/modules/cloudwatchlogs_log_group_info.py import-3.6!skip
-plugins/modules/cloudwatchlogs_log_group_info.py import-3.7!skip
-plugins/modules/cloudwatchlogs_log_group_info.py metaclass-boilerplate!skip
plugins/modules/cloudwatchlogs_log_group_info.py pylint:ansible-deprecated-no-version
-plugins/modules/cloudwatchlogs_log_group_metric_filter.py compile-2.6!skip
-plugins/modules/cloudwatchlogs_log_group_metric_filter.py compile-2.7!skip
-plugins/modules/cloudwatchlogs_log_group_metric_filter.py compile-3.5!skip
-plugins/modules/cloudwatchlogs_log_group_metric_filter.py compile-3.6!skip
-plugins/modules/cloudwatchlogs_log_group_metric_filter.py compile-3.7!skip
-plugins/modules/cloudwatchlogs_log_group_metric_filter.py future-import-boilerplate!skip
-plugins/modules/cloudwatchlogs_log_group_metric_filter.py import-2.6!skip
-plugins/modules/cloudwatchlogs_log_group_metric_filter.py import-2.7!skip
-plugins/modules/cloudwatchlogs_log_group_metric_filter.py import-3.5!skip
-plugins/modules/cloudwatchlogs_log_group_metric_filter.py import-3.6!skip
-plugins/modules/cloudwatchlogs_log_group_metric_filter.py import-3.7!skip
-plugins/modules/cloudwatchlogs_log_group_metric_filter.py metaclass-boilerplate!skip
-plugins/modules/data_pipeline.py compile-2.6!skip
-plugins/modules/data_pipeline.py compile-2.7!skip
-plugins/modules/data_pipeline.py compile-3.5!skip
-plugins/modules/data_pipeline.py compile-3.6!skip
-plugins/modules/data_pipeline.py compile-3.7!skip
-plugins/modules/data_pipeline.py future-import-boilerplate!skip
-plugins/modules/data_pipeline.py import-2.6!skip
-plugins/modules/data_pipeline.py import-2.7!skip
-plugins/modules/data_pipeline.py import-3.5!skip
-plugins/modules/data_pipeline.py import-3.6!skip
-plugins/modules/data_pipeline.py import-3.7!skip
-plugins/modules/data_pipeline.py metaclass-boilerplate!skip
-plugins/modules/dms_endpoint.py compile-2.6!skip
-plugins/modules/dms_endpoint.py compile-2.7!skip
-plugins/modules/dms_endpoint.py compile-3.5!skip
-plugins/modules/dms_endpoint.py compile-3.6!skip
-plugins/modules/dms_endpoint.py compile-3.7!skip
-plugins/modules/dms_endpoint.py future-import-boilerplate!skip
-plugins/modules/dms_endpoint.py import-2.6!skip
-plugins/modules/dms_endpoint.py import-2.7!skip
-plugins/modules/dms_endpoint.py import-3.5!skip
-plugins/modules/dms_endpoint.py import-3.6!skip
-plugins/modules/dms_endpoint.py import-3.7!skip
-plugins/modules/dms_endpoint.py metaclass-boilerplate!skip
-plugins/modules/dms_replication_subnet_group.py compile-2.6!skip
-plugins/modules/dms_replication_subnet_group.py compile-2.7!skip
-plugins/modules/dms_replication_subnet_group.py compile-3.5!skip
-plugins/modules/dms_replication_subnet_group.py compile-3.6!skip
-plugins/modules/dms_replication_subnet_group.py compile-3.7!skip
-plugins/modules/dms_replication_subnet_group.py future-import-boilerplate!skip
-plugins/modules/dms_replication_subnet_group.py import-2.6!skip
-plugins/modules/dms_replication_subnet_group.py import-2.7!skip
-plugins/modules/dms_replication_subnet_group.py import-3.5!skip
-plugins/modules/dms_replication_subnet_group.py import-3.6!skip
-plugins/modules/dms_replication_subnet_group.py import-3.7!skip
-plugins/modules/dms_replication_subnet_group.py metaclass-boilerplate!skip
-plugins/modules/dynamodb_table.py compile-2.6!skip
-plugins/modules/dynamodb_table.py compile-2.7!skip
-plugins/modules/dynamodb_table.py compile-3.5!skip
-plugins/modules/dynamodb_table.py compile-3.6!skip
-plugins/modules/dynamodb_table.py compile-3.7!skip
-plugins/modules/dynamodb_table.py future-import-boilerplate!skip
-plugins/modules/dynamodb_table.py import-2.6!skip
-plugins/modules/dynamodb_table.py import-2.7!skip
-plugins/modules/dynamodb_table.py import-3.5!skip
-plugins/modules/dynamodb_table.py import-3.6!skip
-plugins/modules/dynamodb_table.py import-3.7!skip
-plugins/modules/dynamodb_table.py metaclass-boilerplate!skip
-plugins/modules/dynamodb_ttl.py compile-2.6!skip
-plugins/modules/dynamodb_ttl.py compile-2.7!skip
-plugins/modules/dynamodb_ttl.py compile-3.5!skip
-plugins/modules/dynamodb_ttl.py compile-3.6!skip
-plugins/modules/dynamodb_ttl.py compile-3.7!skip
-plugins/modules/dynamodb_ttl.py future-import-boilerplate!skip
-plugins/modules/dynamodb_ttl.py import-2.6!skip
-plugins/modules/dynamodb_ttl.py import-2.7!skip
-plugins/modules/dynamodb_ttl.py import-3.5!skip
-plugins/modules/dynamodb_ttl.py import-3.6!skip
-plugins/modules/dynamodb_ttl.py import-3.7!skip
-plugins/modules/dynamodb_ttl.py metaclass-boilerplate!skip
-plugins/modules/ec2_ami_copy.py compile-2.6!skip
-plugins/modules/ec2_ami_copy.py compile-2.7!skip
-plugins/modules/ec2_ami_copy.py compile-3.5!skip
-plugins/modules/ec2_ami_copy.py compile-3.6!skip
-plugins/modules/ec2_ami_copy.py compile-3.7!skip
-plugins/modules/ec2_ami_copy.py future-import-boilerplate!skip
-plugins/modules/ec2_ami_copy.py import-2.6!skip
-plugins/modules/ec2_ami_copy.py import-2.7!skip
-plugins/modules/ec2_ami_copy.py import-3.5!skip
-plugins/modules/ec2_ami_copy.py import-3.6!skip
-plugins/modules/ec2_ami_copy.py import-3.7!skip
-plugins/modules/ec2_ami_copy.py metaclass-boilerplate!skip
-plugins/modules/ec2_asg.py compile-2.6!skip
-plugins/modules/ec2_asg.py compile-2.7!skip
-plugins/modules/ec2_asg.py compile-3.5!skip
-plugins/modules/ec2_asg.py compile-3.6!skip
-plugins/modules/ec2_asg.py compile-3.7!skip
-plugins/modules/ec2_asg.py future-import-boilerplate!skip
-plugins/modules/ec2_asg.py import-2.6!skip
-plugins/modules/ec2_asg.py import-2.7!skip
-plugins/modules/ec2_asg.py import-3.5!skip
-plugins/modules/ec2_asg.py import-3.6!skip
-plugins/modules/ec2_asg.py import-3.7!skip
-plugins/modules/ec2_asg.py metaclass-boilerplate!skip
-plugins/modules/ec2_asg_info.py compile-2.6!skip
-plugins/modules/ec2_asg_info.py compile-2.7!skip
-plugins/modules/ec2_asg_info.py compile-3.5!skip
-plugins/modules/ec2_asg_info.py compile-3.6!skip
-plugins/modules/ec2_asg_info.py compile-3.7!skip
-plugins/modules/ec2_asg_info.py future-import-boilerplate!skip
-plugins/modules/ec2_asg_info.py import-2.6!skip
-plugins/modules/ec2_asg_info.py import-2.7!skip
-plugins/modules/ec2_asg_info.py import-3.5!skip
-plugins/modules/ec2_asg_info.py import-3.6!skip
-plugins/modules/ec2_asg_info.py import-3.7!skip
-plugins/modules/ec2_asg_info.py metaclass-boilerplate!skip
plugins/modules/ec2_asg_info.py pylint:ansible-deprecated-no-version
-plugins/modules/ec2_asg_lifecycle_hook.py compile-2.6!skip
-plugins/modules/ec2_asg_lifecycle_hook.py compile-2.7!skip
-plugins/modules/ec2_asg_lifecycle_hook.py compile-3.5!skip
-plugins/modules/ec2_asg_lifecycle_hook.py compile-3.6!skip
-plugins/modules/ec2_asg_lifecycle_hook.py compile-3.7!skip
-plugins/modules/ec2_asg_lifecycle_hook.py future-import-boilerplate!skip
-plugins/modules/ec2_asg_lifecycle_hook.py import-2.6!skip
-plugins/modules/ec2_asg_lifecycle_hook.py import-2.7!skip
-plugins/modules/ec2_asg_lifecycle_hook.py import-3.5!skip
-plugins/modules/ec2_asg_lifecycle_hook.py import-3.6!skip
-plugins/modules/ec2_asg_lifecycle_hook.py import-3.7!skip
-plugins/modules/ec2_asg_lifecycle_hook.py metaclass-boilerplate!skip
-plugins/modules/ec2_customer_gateway.py compile-2.6!skip
-plugins/modules/ec2_customer_gateway.py compile-2.7!skip
-plugins/modules/ec2_customer_gateway.py compile-3.5!skip
-plugins/modules/ec2_customer_gateway.py compile-3.6!skip
-plugins/modules/ec2_customer_gateway.py compile-3.7!skip
-plugins/modules/ec2_customer_gateway.py future-import-boilerplate!skip
-plugins/modules/ec2_customer_gateway.py import-2.6!skip
-plugins/modules/ec2_customer_gateway.py import-2.7!skip
-plugins/modules/ec2_customer_gateway.py import-3.5!skip
-plugins/modules/ec2_customer_gateway.py import-3.6!skip
-plugins/modules/ec2_customer_gateway.py import-3.7!skip
-plugins/modules/ec2_customer_gateway.py metaclass-boilerplate!skip
-plugins/modules/ec2_customer_gateway_info.py compile-2.6!skip
-plugins/modules/ec2_customer_gateway_info.py compile-2.7!skip
-plugins/modules/ec2_customer_gateway_info.py compile-3.5!skip
-plugins/modules/ec2_customer_gateway_info.py compile-3.6!skip
-plugins/modules/ec2_customer_gateway_info.py compile-3.7!skip
-plugins/modules/ec2_customer_gateway_info.py future-import-boilerplate!skip
-plugins/modules/ec2_customer_gateway_info.py import-2.6!skip
-plugins/modules/ec2_customer_gateway_info.py import-2.7!skip
-plugins/modules/ec2_customer_gateway_info.py import-3.5!skip
-plugins/modules/ec2_customer_gateway_info.py import-3.6!skip
-plugins/modules/ec2_customer_gateway_info.py import-3.7!skip
-plugins/modules/ec2_customer_gateway_info.py metaclass-boilerplate!skip
plugins/modules/ec2_customer_gateway_info.py pylint:ansible-deprecated-no-version
-plugins/modules/ec2_eip.py compile-2.6!skip
-plugins/modules/ec2_eip.py compile-2.7!skip
-plugins/modules/ec2_eip.py compile-3.5!skip
-plugins/modules/ec2_eip.py compile-3.6!skip
-plugins/modules/ec2_eip.py compile-3.7!skip
-plugins/modules/ec2_eip.py future-import-boilerplate!skip
-plugins/modules/ec2_eip.py import-2.6!skip
-plugins/modules/ec2_eip.py import-2.7!skip
-plugins/modules/ec2_eip.py import-3.5!skip
-plugins/modules/ec2_eip.py import-3.6!skip
-plugins/modules/ec2_eip.py import-3.7!skip
-plugins/modules/ec2_eip.py metaclass-boilerplate!skip
-plugins/modules/ec2_eip_info.py compile-2.6!skip
-plugins/modules/ec2_eip_info.py compile-2.7!skip
-plugins/modules/ec2_eip_info.py compile-3.5!skip
-plugins/modules/ec2_eip_info.py compile-3.6!skip
-plugins/modules/ec2_eip_info.py compile-3.7!skip
-plugins/modules/ec2_eip_info.py future-import-boilerplate!skip
-plugins/modules/ec2_eip_info.py import-2.6!skip
-plugins/modules/ec2_eip_info.py import-2.7!skip
-plugins/modules/ec2_eip_info.py import-3.5!skip
-plugins/modules/ec2_eip_info.py import-3.6!skip
-plugins/modules/ec2_eip_info.py import-3.7!skip
-plugins/modules/ec2_eip_info.py metaclass-boilerplate!skip
plugins/modules/ec2_eip_info.py pylint:ansible-deprecated-no-version
-plugins/modules/ec2_elb_info.py compile-2.6!skip
-plugins/modules/ec2_elb_info.py compile-2.7!skip
-plugins/modules/ec2_elb_info.py compile-3.5!skip
-plugins/modules/ec2_elb_info.py compile-3.6!skip
-plugins/modules/ec2_elb_info.py compile-3.7!skip
-plugins/modules/ec2_elb_info.py future-import-boilerplate!skip
-plugins/modules/ec2_elb_info.py import-2.6!skip
-plugins/modules/ec2_elb_info.py import-2.7!skip
-plugins/modules/ec2_elb_info.py import-3.5!skip
-plugins/modules/ec2_elb_info.py import-3.6!skip
-plugins/modules/ec2_elb_info.py import-3.7!skip
-plugins/modules/ec2_elb_info.py metaclass-boilerplate!skip
plugins/modules/ec2_elb_info.py validate-modules:deprecation-mismatch # Ansible 2.9 docs don't support deprecation properly
plugins/modules/ec2_elb_info.py validate-modules:invalid-documentation # Ansible 2.9 docs don't support deprecation properly
-plugins/modules/ec2_launch_template.py compile-2.6!skip
-plugins/modules/ec2_launch_template.py compile-2.7!skip
-plugins/modules/ec2_launch_template.py compile-3.5!skip
-plugins/modules/ec2_launch_template.py compile-3.6!skip
-plugins/modules/ec2_launch_template.py compile-3.7!skip
-plugins/modules/ec2_launch_template.py future-import-boilerplate!skip
-plugins/modules/ec2_launch_template.py import-2.6!skip
-plugins/modules/ec2_launch_template.py import-2.7!skip
-plugins/modules/ec2_launch_template.py import-3.5!skip
-plugins/modules/ec2_launch_template.py import-3.6!skip
-plugins/modules/ec2_launch_template.py import-3.7!skip
-plugins/modules/ec2_launch_template.py metaclass-boilerplate!skip
-plugins/modules/ec2_lc.py compile-2.6!skip
-plugins/modules/ec2_lc.py compile-2.7!skip
-plugins/modules/ec2_lc.py compile-3.5!skip
-plugins/modules/ec2_lc.py compile-3.6!skip
-plugins/modules/ec2_lc.py compile-3.7!skip
-plugins/modules/ec2_lc.py future-import-boilerplate!skip
-plugins/modules/ec2_lc.py import-2.6!skip
-plugins/modules/ec2_lc.py import-2.7!skip
-plugins/modules/ec2_lc.py import-3.5!skip
-plugins/modules/ec2_lc.py import-3.6!skip
-plugins/modules/ec2_lc.py import-3.7!skip
-plugins/modules/ec2_lc.py metaclass-boilerplate!skip
-plugins/modules/ec2_lc_find.py compile-2.6!skip
-plugins/modules/ec2_lc_find.py compile-2.7!skip
-plugins/modules/ec2_lc_find.py compile-3.5!skip
-plugins/modules/ec2_lc_find.py compile-3.6!skip
-plugins/modules/ec2_lc_find.py compile-3.7!skip
-plugins/modules/ec2_lc_find.py future-import-boilerplate!skip
-plugins/modules/ec2_lc_find.py import-2.6!skip
-plugins/modules/ec2_lc_find.py import-2.7!skip
-plugins/modules/ec2_lc_find.py import-3.5!skip
-plugins/modules/ec2_lc_find.py import-3.6!skip
-plugins/modules/ec2_lc_find.py import-3.7!skip
-plugins/modules/ec2_lc_find.py metaclass-boilerplate!skip
-plugins/modules/ec2_lc_info.py compile-2.6!skip
-plugins/modules/ec2_lc_info.py compile-2.7!skip
-plugins/modules/ec2_lc_info.py compile-3.5!skip
-plugins/modules/ec2_lc_info.py compile-3.6!skip
-plugins/modules/ec2_lc_info.py compile-3.7!skip
-plugins/modules/ec2_lc_info.py future-import-boilerplate!skip
-plugins/modules/ec2_lc_info.py import-2.6!skip
-plugins/modules/ec2_lc_info.py import-2.7!skip
-plugins/modules/ec2_lc_info.py import-3.5!skip
-plugins/modules/ec2_lc_info.py import-3.6!skip
-plugins/modules/ec2_lc_info.py import-3.7!skip
-plugins/modules/ec2_lc_info.py metaclass-boilerplate!skip
plugins/modules/ec2_lc_info.py pylint:ansible-deprecated-no-version
-plugins/modules/ec2_metric_alarm.py compile-2.6!skip
-plugins/modules/ec2_metric_alarm.py compile-2.7!skip
-plugins/modules/ec2_metric_alarm.py compile-3.5!skip
-plugins/modules/ec2_metric_alarm.py compile-3.6!skip
-plugins/modules/ec2_metric_alarm.py compile-3.7!skip
-plugins/modules/ec2_metric_alarm.py future-import-boilerplate!skip
-plugins/modules/ec2_metric_alarm.py import-2.6!skip
-plugins/modules/ec2_metric_alarm.py import-2.7!skip
-plugins/modules/ec2_metric_alarm.py import-3.5!skip
-plugins/modules/ec2_metric_alarm.py import-3.6!skip
-plugins/modules/ec2_metric_alarm.py import-3.7!skip
-plugins/modules/ec2_metric_alarm.py metaclass-boilerplate!skip
plugins/modules/ec2_metric_alarm.py pylint:ansible-deprecated-no-version
-plugins/modules/ec2_placement_group.py compile-2.6!skip
-plugins/modules/ec2_placement_group.py compile-2.7!skip
-plugins/modules/ec2_placement_group.py compile-3.5!skip
-plugins/modules/ec2_placement_group.py compile-3.6!skip
-plugins/modules/ec2_placement_group.py compile-3.7!skip
-plugins/modules/ec2_placement_group.py future-import-boilerplate!skip
-plugins/modules/ec2_placement_group.py import-2.6!skip
-plugins/modules/ec2_placement_group.py import-2.7!skip
-plugins/modules/ec2_placement_group.py import-3.5!skip
-plugins/modules/ec2_placement_group.py import-3.6!skip
-plugins/modules/ec2_placement_group.py import-3.7!skip
-plugins/modules/ec2_placement_group.py metaclass-boilerplate!skip
-plugins/modules/ec2_placement_group_info.py compile-2.6!skip
-plugins/modules/ec2_placement_group_info.py compile-2.7!skip
-plugins/modules/ec2_placement_group_info.py compile-3.5!skip
-plugins/modules/ec2_placement_group_info.py compile-3.6!skip
-plugins/modules/ec2_placement_group_info.py compile-3.7!skip
-plugins/modules/ec2_placement_group_info.py future-import-boilerplate!skip
-plugins/modules/ec2_placement_group_info.py import-2.6!skip
-plugins/modules/ec2_placement_group_info.py import-2.7!skip
-plugins/modules/ec2_placement_group_info.py import-3.5!skip
-plugins/modules/ec2_placement_group_info.py import-3.6!skip
-plugins/modules/ec2_placement_group_info.py import-3.7!skip
-plugins/modules/ec2_placement_group_info.py metaclass-boilerplate!skip
plugins/modules/ec2_placement_group_info.py pylint:ansible-deprecated-no-version
-plugins/modules/ec2_scaling_policy.py compile-2.6!skip
-plugins/modules/ec2_scaling_policy.py compile-2.7!skip
-plugins/modules/ec2_scaling_policy.py compile-3.5!skip
-plugins/modules/ec2_scaling_policy.py compile-3.6!skip
-plugins/modules/ec2_scaling_policy.py compile-3.7!skip
-plugins/modules/ec2_scaling_policy.py future-import-boilerplate!skip
-plugins/modules/ec2_scaling_policy.py import-2.6!skip
-plugins/modules/ec2_scaling_policy.py import-2.7!skip
-plugins/modules/ec2_scaling_policy.py import-3.5!skip
-plugins/modules/ec2_scaling_policy.py import-3.6!skip
-plugins/modules/ec2_scaling_policy.py import-3.7!skip
-plugins/modules/ec2_scaling_policy.py metaclass-boilerplate!skip
-plugins/modules/ec2_snapshot_copy.py compile-2.6!skip
-plugins/modules/ec2_snapshot_copy.py compile-2.7!skip
-plugins/modules/ec2_snapshot_copy.py compile-3.5!skip
-plugins/modules/ec2_snapshot_copy.py compile-3.6!skip
-plugins/modules/ec2_snapshot_copy.py compile-3.7!skip
-plugins/modules/ec2_snapshot_copy.py future-import-boilerplate!skip
-plugins/modules/ec2_snapshot_copy.py import-2.6!skip
-plugins/modules/ec2_snapshot_copy.py import-2.7!skip
-plugins/modules/ec2_snapshot_copy.py import-3.5!skip
-plugins/modules/ec2_snapshot_copy.py import-3.6!skip
-plugins/modules/ec2_snapshot_copy.py import-3.7!skip
-plugins/modules/ec2_snapshot_copy.py metaclass-boilerplate!skip
-plugins/modules/ec2_transit_gateway.py compile-2.6!skip
-plugins/modules/ec2_transit_gateway.py compile-2.7!skip
-plugins/modules/ec2_transit_gateway.py compile-3.5!skip
-plugins/modules/ec2_transit_gateway.py compile-3.6!skip
-plugins/modules/ec2_transit_gateway.py compile-3.7!skip
-plugins/modules/ec2_transit_gateway.py future-import-boilerplate!skip
-plugins/modules/ec2_transit_gateway.py import-2.6!skip
-plugins/modules/ec2_transit_gateway.py import-2.7!skip
-plugins/modules/ec2_transit_gateway.py import-3.5!skip
-plugins/modules/ec2_transit_gateway.py import-3.6!skip
-plugins/modules/ec2_transit_gateway.py import-3.7!skip
-plugins/modules/ec2_transit_gateway.py metaclass-boilerplate!skip
-plugins/modules/ec2_transit_gateway_info.py compile-2.6!skip
-plugins/modules/ec2_transit_gateway_info.py compile-2.7!skip
-plugins/modules/ec2_transit_gateway_info.py compile-3.5!skip
-plugins/modules/ec2_transit_gateway_info.py compile-3.6!skip
-plugins/modules/ec2_transit_gateway_info.py compile-3.7!skip
-plugins/modules/ec2_transit_gateway_info.py future-import-boilerplate!skip
-plugins/modules/ec2_transit_gateway_info.py import-2.6!skip
-plugins/modules/ec2_transit_gateway_info.py import-2.7!skip
-plugins/modules/ec2_transit_gateway_info.py import-3.5!skip
-plugins/modules/ec2_transit_gateway_info.py import-3.6!skip
-plugins/modules/ec2_transit_gateway_info.py import-3.7!skip
-plugins/modules/ec2_transit_gateway_info.py metaclass-boilerplate!skip
-plugins/modules/ec2_vpc_egress_igw.py compile-2.6!skip
-plugins/modules/ec2_vpc_egress_igw.py compile-2.7!skip
-plugins/modules/ec2_vpc_egress_igw.py compile-3.5!skip
-plugins/modules/ec2_vpc_egress_igw.py compile-3.6!skip
-plugins/modules/ec2_vpc_egress_igw.py compile-3.7!skip
-plugins/modules/ec2_vpc_egress_igw.py future-import-boilerplate!skip
-plugins/modules/ec2_vpc_egress_igw.py import-2.6!skip
-plugins/modules/ec2_vpc_egress_igw.py import-2.7!skip
-plugins/modules/ec2_vpc_egress_igw.py import-3.5!skip
-plugins/modules/ec2_vpc_egress_igw.py import-3.6!skip
-plugins/modules/ec2_vpc_egress_igw.py import-3.7!skip
-plugins/modules/ec2_vpc_egress_igw.py metaclass-boilerplate!skip
-plugins/modules/ec2_vpc_endpoint.py compile-2.6!skip
-plugins/modules/ec2_vpc_endpoint.py compile-2.7!skip
-plugins/modules/ec2_vpc_endpoint.py compile-3.5!skip
-plugins/modules/ec2_vpc_endpoint.py compile-3.6!skip
-plugins/modules/ec2_vpc_endpoint.py compile-3.7!skip
-plugins/modules/ec2_vpc_endpoint.py future-import-boilerplate!skip
-plugins/modules/ec2_vpc_endpoint.py import-2.6!skip
-plugins/modules/ec2_vpc_endpoint.py import-2.7!skip
-plugins/modules/ec2_vpc_endpoint.py import-3.5!skip
-plugins/modules/ec2_vpc_endpoint.py import-3.6!skip
-plugins/modules/ec2_vpc_endpoint.py import-3.7!skip
-plugins/modules/ec2_vpc_endpoint.py metaclass-boilerplate!skip
-plugins/modules/ec2_vpc_endpoint.py pylint:ansible-deprecated-no-version
-plugins/modules/ec2_vpc_endpoint_info.py compile-2.6!skip
-plugins/modules/ec2_vpc_endpoint_info.py compile-2.7!skip
-plugins/modules/ec2_vpc_endpoint_info.py compile-3.5!skip
-plugins/modules/ec2_vpc_endpoint_info.py compile-3.6!skip
-plugins/modules/ec2_vpc_endpoint_info.py compile-3.7!skip
-plugins/modules/ec2_vpc_endpoint_info.py future-import-boilerplate!skip
-plugins/modules/ec2_vpc_endpoint_info.py import-2.6!skip
-plugins/modules/ec2_vpc_endpoint_info.py import-2.7!skip
-plugins/modules/ec2_vpc_endpoint_info.py import-3.5!skip
-plugins/modules/ec2_vpc_endpoint_info.py import-3.6!skip
-plugins/modules/ec2_vpc_endpoint_info.py import-3.7!skip
-plugins/modules/ec2_vpc_endpoint_info.py metaclass-boilerplate!skip
-plugins/modules/ec2_vpc_endpoint_info.py pylint:ansible-deprecated-no-version
-plugins/modules/ec2_vpc_endpoint_service_info.py compile-2.6!skip
-plugins/modules/ec2_vpc_endpoint_service_info.py compile-2.7!skip
-plugins/modules/ec2_vpc_endpoint_service_info.py compile-3.5!skip
-plugins/modules/ec2_vpc_endpoint_service_info.py compile-3.6!skip
-plugins/modules/ec2_vpc_endpoint_service_info.py compile-3.7!skip
-plugins/modules/ec2_vpc_endpoint_service_info.py future-import-boilerplate!skip
-plugins/modules/ec2_vpc_endpoint_service_info.py import-2.6!skip
-plugins/modules/ec2_vpc_endpoint_service_info.py import-2.7!skip
-plugins/modules/ec2_vpc_endpoint_service_info.py import-3.5!skip
-plugins/modules/ec2_vpc_endpoint_service_info.py import-3.6!skip
-plugins/modules/ec2_vpc_endpoint_service_info.py import-3.7!skip
-plugins/modules/ec2_vpc_endpoint_service_info.py metaclass-boilerplate!skip
-plugins/modules/ec2_vpc_igw.py compile-2.6!skip
-plugins/modules/ec2_vpc_igw.py compile-2.7!skip
-plugins/modules/ec2_vpc_igw.py compile-3.5!skip
-plugins/modules/ec2_vpc_igw.py compile-3.6!skip
-plugins/modules/ec2_vpc_igw.py compile-3.7!skip
-plugins/modules/ec2_vpc_igw.py future-import-boilerplate!skip
-plugins/modules/ec2_vpc_igw.py import-2.6!skip
-plugins/modules/ec2_vpc_igw.py import-2.7!skip
-plugins/modules/ec2_vpc_igw.py import-3.5!skip
-plugins/modules/ec2_vpc_igw.py import-3.6!skip
-plugins/modules/ec2_vpc_igw.py import-3.7!skip
-plugins/modules/ec2_vpc_igw.py metaclass-boilerplate!skip
-plugins/modules/ec2_vpc_igw_info.py compile-2.6!skip
-plugins/modules/ec2_vpc_igw_info.py compile-2.7!skip
-plugins/modules/ec2_vpc_igw_info.py compile-3.5!skip
-plugins/modules/ec2_vpc_igw_info.py compile-3.6!skip
-plugins/modules/ec2_vpc_igw_info.py compile-3.7!skip
-plugins/modules/ec2_vpc_igw_info.py future-import-boilerplate!skip
-plugins/modules/ec2_vpc_igw_info.py import-2.6!skip
-plugins/modules/ec2_vpc_igw_info.py import-2.7!skip
-plugins/modules/ec2_vpc_igw_info.py import-3.5!skip
-plugins/modules/ec2_vpc_igw_info.py import-3.6!skip
-plugins/modules/ec2_vpc_igw_info.py import-3.7!skip
-plugins/modules/ec2_vpc_igw_info.py metaclass-boilerplate!skip
-plugins/modules/ec2_vpc_igw_info.py pylint:ansible-deprecated-no-version
-plugins/modules/ec2_vpc_nacl.py compile-2.6!skip
-plugins/modules/ec2_vpc_nacl.py compile-2.7!skip
-plugins/modules/ec2_vpc_nacl.py compile-3.5!skip
-plugins/modules/ec2_vpc_nacl.py compile-3.6!skip
-plugins/modules/ec2_vpc_nacl.py compile-3.7!skip
-plugins/modules/ec2_vpc_nacl.py future-import-boilerplate!skip
-plugins/modules/ec2_vpc_nacl.py import-2.6!skip
-plugins/modules/ec2_vpc_nacl.py import-2.7!skip
-plugins/modules/ec2_vpc_nacl.py import-3.5!skip
-plugins/modules/ec2_vpc_nacl.py import-3.6!skip
-plugins/modules/ec2_vpc_nacl.py import-3.7!skip
-plugins/modules/ec2_vpc_nacl.py metaclass-boilerplate!skip
-plugins/modules/ec2_vpc_nacl_info.py compile-2.6!skip
-plugins/modules/ec2_vpc_nacl_info.py compile-2.7!skip
-plugins/modules/ec2_vpc_nacl_info.py compile-3.5!skip
-plugins/modules/ec2_vpc_nacl_info.py compile-3.6!skip
-plugins/modules/ec2_vpc_nacl_info.py compile-3.7!skip
-plugins/modules/ec2_vpc_nacl_info.py future-import-boilerplate!skip
-plugins/modules/ec2_vpc_nacl_info.py import-2.6!skip
-plugins/modules/ec2_vpc_nacl_info.py import-2.7!skip
-plugins/modules/ec2_vpc_nacl_info.py import-3.5!skip
-plugins/modules/ec2_vpc_nacl_info.py import-3.6!skip
-plugins/modules/ec2_vpc_nacl_info.py import-3.7!skip
-plugins/modules/ec2_vpc_nacl_info.py metaclass-boilerplate!skip
plugins/modules/ec2_vpc_nacl_info.py pylint:ansible-deprecated-no-version
-plugins/modules/ec2_vpc_nat_gateway.py compile-2.6!skip
-plugins/modules/ec2_vpc_nat_gateway.py compile-2.7!skip
-plugins/modules/ec2_vpc_nat_gateway.py compile-3.5!skip
-plugins/modules/ec2_vpc_nat_gateway.py compile-3.6!skip
-plugins/modules/ec2_vpc_nat_gateway.py compile-3.7!skip
-plugins/modules/ec2_vpc_nat_gateway.py future-import-boilerplate!skip
-plugins/modules/ec2_vpc_nat_gateway.py import-2.6!skip
-plugins/modules/ec2_vpc_nat_gateway.py import-2.7!skip
-plugins/modules/ec2_vpc_nat_gateway.py import-3.5!skip
-plugins/modules/ec2_vpc_nat_gateway.py import-3.6!skip
-plugins/modules/ec2_vpc_nat_gateway.py import-3.7!skip
-plugins/modules/ec2_vpc_nat_gateway.py metaclass-boilerplate!skip
-plugins/modules/ec2_vpc_nat_gateway_info.py compile-2.6!skip
-plugins/modules/ec2_vpc_nat_gateway_info.py compile-2.7!skip
-plugins/modules/ec2_vpc_nat_gateway_info.py compile-3.5!skip
-plugins/modules/ec2_vpc_nat_gateway_info.py compile-3.6!skip
-plugins/modules/ec2_vpc_nat_gateway_info.py compile-3.7!skip
-plugins/modules/ec2_vpc_nat_gateway_info.py future-import-boilerplate!skip
-plugins/modules/ec2_vpc_nat_gateway_info.py import-2.6!skip
-plugins/modules/ec2_vpc_nat_gateway_info.py import-2.7!skip
-plugins/modules/ec2_vpc_nat_gateway_info.py import-3.5!skip
-plugins/modules/ec2_vpc_nat_gateway_info.py import-3.6!skip
-plugins/modules/ec2_vpc_nat_gateway_info.py import-3.7!skip
-plugins/modules/ec2_vpc_nat_gateway_info.py metaclass-boilerplate!skip
-plugins/modules/ec2_vpc_nat_gateway_info.py pylint:ansible-deprecated-no-version
-plugins/modules/ec2_vpc_peer.py compile-2.6!skip
-plugins/modules/ec2_vpc_peer.py compile-2.7!skip
-plugins/modules/ec2_vpc_peer.py compile-3.5!skip
-plugins/modules/ec2_vpc_peer.py compile-3.6!skip
-plugins/modules/ec2_vpc_peer.py compile-3.7!skip
-plugins/modules/ec2_vpc_peer.py future-import-boilerplate!skip
-plugins/modules/ec2_vpc_peer.py import-2.6!skip
-plugins/modules/ec2_vpc_peer.py import-2.7!skip
-plugins/modules/ec2_vpc_peer.py import-3.5!skip
-plugins/modules/ec2_vpc_peer.py import-3.6!skip
-plugins/modules/ec2_vpc_peer.py import-3.7!skip
-plugins/modules/ec2_vpc_peer.py metaclass-boilerplate!skip
-plugins/modules/ec2_vpc_peering_info.py compile-2.6!skip
-plugins/modules/ec2_vpc_peering_info.py compile-2.7!skip
-plugins/modules/ec2_vpc_peering_info.py compile-3.5!skip
-plugins/modules/ec2_vpc_peering_info.py compile-3.6!skip
-plugins/modules/ec2_vpc_peering_info.py compile-3.7!skip
-plugins/modules/ec2_vpc_peering_info.py future-import-boilerplate!skip
-plugins/modules/ec2_vpc_peering_info.py import-2.6!skip
-plugins/modules/ec2_vpc_peering_info.py import-2.7!skip
-plugins/modules/ec2_vpc_peering_info.py import-3.5!skip
-plugins/modules/ec2_vpc_peering_info.py import-3.6!skip
-plugins/modules/ec2_vpc_peering_info.py import-3.7!skip
-plugins/modules/ec2_vpc_peering_info.py metaclass-boilerplate!skip
plugins/modules/ec2_vpc_peering_info.py pylint:ansible-deprecated-no-version
-plugins/modules/ec2_vpc_route_table.py compile-2.6!skip
-plugins/modules/ec2_vpc_route_table.py compile-2.7!skip
-plugins/modules/ec2_vpc_route_table.py compile-3.5!skip
-plugins/modules/ec2_vpc_route_table.py compile-3.6!skip
-plugins/modules/ec2_vpc_route_table.py compile-3.7!skip
-plugins/modules/ec2_vpc_route_table.py future-import-boilerplate!skip
-plugins/modules/ec2_vpc_route_table.py import-2.6!skip
-plugins/modules/ec2_vpc_route_table.py import-2.7!skip
-plugins/modules/ec2_vpc_route_table.py import-3.5!skip
-plugins/modules/ec2_vpc_route_table.py import-3.6!skip
-plugins/modules/ec2_vpc_route_table.py import-3.7!skip
-plugins/modules/ec2_vpc_route_table.py metaclass-boilerplate!skip
-plugins/modules/ec2_vpc_route_table_info.py compile-2.6!skip
-plugins/modules/ec2_vpc_route_table_info.py compile-2.7!skip
-plugins/modules/ec2_vpc_route_table_info.py compile-3.5!skip
-plugins/modules/ec2_vpc_route_table_info.py compile-3.6!skip
-plugins/modules/ec2_vpc_route_table_info.py compile-3.7!skip
-plugins/modules/ec2_vpc_route_table_info.py future-import-boilerplate!skip
-plugins/modules/ec2_vpc_route_table_info.py import-2.6!skip
-plugins/modules/ec2_vpc_route_table_info.py import-2.7!skip
-plugins/modules/ec2_vpc_route_table_info.py import-3.5!skip
-plugins/modules/ec2_vpc_route_table_info.py import-3.6!skip
-plugins/modules/ec2_vpc_route_table_info.py import-3.7!skip
-plugins/modules/ec2_vpc_route_table_info.py metaclass-boilerplate!skip
plugins/modules/ec2_vpc_route_table_info.py pylint:ansible-deprecated-no-version
-plugins/modules/ec2_vpc_vgw.py compile-2.6!skip
-plugins/modules/ec2_vpc_vgw.py compile-2.7!skip
-plugins/modules/ec2_vpc_vgw.py compile-3.5!skip
-plugins/modules/ec2_vpc_vgw.py compile-3.6!skip
-plugins/modules/ec2_vpc_vgw.py compile-3.7!skip
-plugins/modules/ec2_vpc_vgw.py future-import-boilerplate!skip
-plugins/modules/ec2_vpc_vgw.py import-2.6!skip
-plugins/modules/ec2_vpc_vgw.py import-2.7!skip
-plugins/modules/ec2_vpc_vgw.py import-3.5!skip
-plugins/modules/ec2_vpc_vgw.py import-3.6!skip
-plugins/modules/ec2_vpc_vgw.py import-3.7!skip
-plugins/modules/ec2_vpc_vgw.py metaclass-boilerplate!skip
-plugins/modules/ec2_vpc_vgw_info.py compile-2.6!skip
-plugins/modules/ec2_vpc_vgw_info.py compile-2.7!skip
-plugins/modules/ec2_vpc_vgw_info.py compile-3.5!skip
-plugins/modules/ec2_vpc_vgw_info.py compile-3.6!skip
-plugins/modules/ec2_vpc_vgw_info.py compile-3.7!skip
-plugins/modules/ec2_vpc_vgw_info.py future-import-boilerplate!skip
-plugins/modules/ec2_vpc_vgw_info.py import-2.6!skip
-plugins/modules/ec2_vpc_vgw_info.py import-2.7!skip
-plugins/modules/ec2_vpc_vgw_info.py import-3.5!skip
-plugins/modules/ec2_vpc_vgw_info.py import-3.6!skip
-plugins/modules/ec2_vpc_vgw_info.py import-3.7!skip
-plugins/modules/ec2_vpc_vgw_info.py metaclass-boilerplate!skip
plugins/modules/ec2_vpc_vgw_info.py pylint:ansible-deprecated-no-version
-plugins/modules/ec2_vpc_vpn.py compile-2.6!skip
-plugins/modules/ec2_vpc_vpn.py compile-2.7!skip
-plugins/modules/ec2_vpc_vpn.py compile-3.5!skip
-plugins/modules/ec2_vpc_vpn.py compile-3.6!skip
-plugins/modules/ec2_vpc_vpn.py compile-3.7!skip
-plugins/modules/ec2_vpc_vpn.py future-import-boilerplate!skip
-plugins/modules/ec2_vpc_vpn.py import-2.6!skip
-plugins/modules/ec2_vpc_vpn.py import-2.7!skip
-plugins/modules/ec2_vpc_vpn.py import-3.5!skip
-plugins/modules/ec2_vpc_vpn.py import-3.6!skip
-plugins/modules/ec2_vpc_vpn.py import-3.7!skip
-plugins/modules/ec2_vpc_vpn.py metaclass-boilerplate!skip
-plugins/modules/ec2_vpc_vpn_info.py compile-2.6!skip
-plugins/modules/ec2_vpc_vpn_info.py compile-2.7!skip
-plugins/modules/ec2_vpc_vpn_info.py compile-3.5!skip
-plugins/modules/ec2_vpc_vpn_info.py compile-3.6!skip
-plugins/modules/ec2_vpc_vpn_info.py compile-3.7!skip
-plugins/modules/ec2_vpc_vpn_info.py future-import-boilerplate!skip
-plugins/modules/ec2_vpc_vpn_info.py import-2.6!skip
-plugins/modules/ec2_vpc_vpn_info.py import-2.7!skip
-plugins/modules/ec2_vpc_vpn_info.py import-3.5!skip
-plugins/modules/ec2_vpc_vpn_info.py import-3.6!skip
-plugins/modules/ec2_vpc_vpn_info.py import-3.7!skip
-plugins/modules/ec2_vpc_vpn_info.py metaclass-boilerplate!skip
plugins/modules/ec2_vpc_vpn_info.py pylint:ansible-deprecated-no-version
-plugins/modules/ec2_win_password.py compile-2.6!skip
-plugins/modules/ec2_win_password.py compile-2.7!skip
-plugins/modules/ec2_win_password.py compile-3.5!skip
-plugins/modules/ec2_win_password.py compile-3.6!skip
-plugins/modules/ec2_win_password.py compile-3.7!skip
-plugins/modules/ec2_win_password.py future-import-boilerplate!skip
-plugins/modules/ec2_win_password.py import-2.6!skip
-plugins/modules/ec2_win_password.py import-2.7!skip
-plugins/modules/ec2_win_password.py import-3.5!skip
-plugins/modules/ec2_win_password.py import-3.6!skip
-plugins/modules/ec2_win_password.py import-3.7!skip
-plugins/modules/ec2_win_password.py metaclass-boilerplate!skip
-plugins/modules/ecs_attribute.py compile-2.6!skip
-plugins/modules/ecs_attribute.py compile-2.7!skip
-plugins/modules/ecs_attribute.py compile-3.5!skip
-plugins/modules/ecs_attribute.py compile-3.6!skip
-plugins/modules/ecs_attribute.py compile-3.7!skip
-plugins/modules/ecs_attribute.py future-import-boilerplate!skip
-plugins/modules/ecs_attribute.py import-2.6!skip
-plugins/modules/ecs_attribute.py import-2.7!skip
-plugins/modules/ecs_attribute.py import-3.5!skip
-plugins/modules/ecs_attribute.py import-3.6!skip
-plugins/modules/ecs_attribute.py import-3.7!skip
-plugins/modules/ecs_attribute.py metaclass-boilerplate!skip
-plugins/modules/ecs_cluster.py compile-2.6!skip
-plugins/modules/ecs_cluster.py compile-2.7!skip
-plugins/modules/ecs_cluster.py compile-3.5!skip
-plugins/modules/ecs_cluster.py compile-3.6!skip
-plugins/modules/ecs_cluster.py compile-3.7!skip
-plugins/modules/ecs_cluster.py future-import-boilerplate!skip
-plugins/modules/ecs_cluster.py import-2.6!skip
-plugins/modules/ecs_cluster.py import-2.7!skip
-plugins/modules/ecs_cluster.py import-3.5!skip
-plugins/modules/ecs_cluster.py import-3.6!skip
-plugins/modules/ecs_cluster.py import-3.7!skip
-plugins/modules/ecs_cluster.py metaclass-boilerplate!skip
-plugins/modules/ecs_ecr.py compile-2.6!skip
-plugins/modules/ecs_ecr.py compile-2.7!skip
-plugins/modules/ecs_ecr.py compile-3.5!skip
-plugins/modules/ecs_ecr.py compile-3.6!skip
-plugins/modules/ecs_ecr.py compile-3.7!skip
-plugins/modules/ecs_ecr.py future-import-boilerplate!skip
-plugins/modules/ecs_ecr.py import-2.6!skip
-plugins/modules/ecs_ecr.py import-2.7!skip
-plugins/modules/ecs_ecr.py import-3.5!skip
-plugins/modules/ecs_ecr.py import-3.6!skip
-plugins/modules/ecs_ecr.py import-3.7!skip
-plugins/modules/ecs_ecr.py metaclass-boilerplate!skip
-plugins/modules/ecs_service.py compile-2.6!skip
-plugins/modules/ecs_service.py compile-2.7!skip
-plugins/modules/ecs_service.py compile-3.5!skip
-plugins/modules/ecs_service.py compile-3.6!skip
-plugins/modules/ecs_service.py compile-3.7!skip
-plugins/modules/ecs_service.py future-import-boilerplate!skip
-plugins/modules/ecs_service.py import-2.6!skip
-plugins/modules/ecs_service.py import-2.7!skip
-plugins/modules/ecs_service.py import-3.5!skip
-plugins/modules/ecs_service.py import-3.6!skip
-plugins/modules/ecs_service.py import-3.7!skip
-plugins/modules/ecs_service.py metaclass-boilerplate!skip
-plugins/modules/ecs_service_info.py compile-2.6!skip
-plugins/modules/ecs_service_info.py compile-2.7!skip
-plugins/modules/ecs_service_info.py compile-3.5!skip
-plugins/modules/ecs_service_info.py compile-3.6!skip
-plugins/modules/ecs_service_info.py compile-3.7!skip
-plugins/modules/ecs_service_info.py future-import-boilerplate!skip
-plugins/modules/ecs_service_info.py import-2.6!skip
-plugins/modules/ecs_service_info.py import-2.7!skip
-plugins/modules/ecs_service_info.py import-3.5!skip
-plugins/modules/ecs_service_info.py import-3.6!skip
-plugins/modules/ecs_service_info.py import-3.7!skip
-plugins/modules/ecs_service_info.py metaclass-boilerplate!skip
plugins/modules/ecs_service_info.py pylint:ansible-deprecated-no-version
-plugins/modules/ecs_tag.py compile-2.6!skip
-plugins/modules/ecs_tag.py compile-2.7!skip
-plugins/modules/ecs_tag.py compile-3.5!skip
-plugins/modules/ecs_tag.py compile-3.6!skip
-plugins/modules/ecs_tag.py compile-3.7!skip
-plugins/modules/ecs_tag.py future-import-boilerplate!skip
-plugins/modules/ecs_tag.py import-2.6!skip
-plugins/modules/ecs_tag.py import-2.7!skip
-plugins/modules/ecs_tag.py import-3.5!skip
-plugins/modules/ecs_tag.py import-3.6!skip
-plugins/modules/ecs_tag.py import-3.7!skip
-plugins/modules/ecs_tag.py metaclass-boilerplate!skip
-plugins/modules/ecs_task.py compile-2.6!skip
-plugins/modules/ecs_task.py compile-2.7!skip
-plugins/modules/ecs_task.py compile-3.5!skip
-plugins/modules/ecs_task.py compile-3.6!skip
-plugins/modules/ecs_task.py compile-3.7!skip
-plugins/modules/ecs_task.py future-import-boilerplate!skip
-plugins/modules/ecs_task.py import-2.6!skip
-plugins/modules/ecs_task.py import-2.7!skip
-plugins/modules/ecs_task.py import-3.5!skip
-plugins/modules/ecs_task.py import-3.6!skip
-plugins/modules/ecs_task.py import-3.7!skip
-plugins/modules/ecs_task.py metaclass-boilerplate!skip
-plugins/modules/ecs_taskdefinition.py compile-2.6!skip
-plugins/modules/ecs_taskdefinition.py compile-2.7!skip
-plugins/modules/ecs_taskdefinition.py compile-3.5!skip
-plugins/modules/ecs_taskdefinition.py compile-3.6!skip
-plugins/modules/ecs_taskdefinition.py compile-3.7!skip
-plugins/modules/ecs_taskdefinition.py future-import-boilerplate!skip
-plugins/modules/ecs_taskdefinition.py import-2.6!skip
-plugins/modules/ecs_taskdefinition.py import-2.7!skip
-plugins/modules/ecs_taskdefinition.py import-3.5!skip
-plugins/modules/ecs_taskdefinition.py import-3.6!skip
-plugins/modules/ecs_taskdefinition.py import-3.7!skip
-plugins/modules/ecs_taskdefinition.py metaclass-boilerplate!skip
-plugins/modules/ecs_taskdefinition_info.py compile-2.6!skip
-plugins/modules/ecs_taskdefinition_info.py compile-2.7!skip
-plugins/modules/ecs_taskdefinition_info.py compile-3.5!skip
-plugins/modules/ecs_taskdefinition_info.py compile-3.6!skip
-plugins/modules/ecs_taskdefinition_info.py compile-3.7!skip
-plugins/modules/ecs_taskdefinition_info.py future-import-boilerplate!skip
-plugins/modules/ecs_taskdefinition_info.py import-2.6!skip
-plugins/modules/ecs_taskdefinition_info.py import-2.7!skip
-plugins/modules/ecs_taskdefinition_info.py import-3.5!skip
-plugins/modules/ecs_taskdefinition_info.py import-3.6!skip
-plugins/modules/ecs_taskdefinition_info.py import-3.7!skip
-plugins/modules/ecs_taskdefinition_info.py metaclass-boilerplate!skip
plugins/modules/ecs_taskdefinition_info.py pylint:ansible-deprecated-no-version
-plugins/modules/efs.py compile-2.6!skip
-plugins/modules/efs.py compile-2.7!skip
-plugins/modules/efs.py compile-3.5!skip
-plugins/modules/efs.py compile-3.6!skip
-plugins/modules/efs.py compile-3.7!skip
-plugins/modules/efs.py future-import-boilerplate!skip
-plugins/modules/efs.py import-2.6!skip
-plugins/modules/efs.py import-2.7!skip
-plugins/modules/efs.py import-3.5!skip
-plugins/modules/efs.py import-3.6!skip
-plugins/modules/efs.py import-3.7!skip
-plugins/modules/efs.py metaclass-boilerplate!skip
-plugins/modules/efs_info.py compile-2.6!skip
-plugins/modules/efs_info.py compile-2.7!skip
-plugins/modules/efs_info.py compile-3.5!skip
-plugins/modules/efs_info.py compile-3.6!skip
-plugins/modules/efs_info.py compile-3.7!skip
-plugins/modules/efs_info.py future-import-boilerplate!skip
-plugins/modules/efs_info.py import-2.6!skip
-plugins/modules/efs_info.py import-2.7!skip
-plugins/modules/efs_info.py import-3.5!skip
-plugins/modules/efs_info.py import-3.6!skip
-plugins/modules/efs_info.py import-3.7!skip
-plugins/modules/efs_info.py metaclass-boilerplate!skip
plugins/modules/efs_info.py pylint:ansible-deprecated-no-version
-plugins/modules/elasticache.py compile-2.6!skip
-plugins/modules/elasticache.py compile-2.7!skip
-plugins/modules/elasticache.py compile-3.5!skip
-plugins/modules/elasticache.py compile-3.6!skip
-plugins/modules/elasticache.py compile-3.7!skip
-plugins/modules/elasticache.py future-import-boilerplate!skip
-plugins/modules/elasticache.py import-2.6!skip
-plugins/modules/elasticache.py import-2.7!skip
-plugins/modules/elasticache.py import-3.5!skip
-plugins/modules/elasticache.py import-3.6!skip
-plugins/modules/elasticache.py import-3.7!skip
-plugins/modules/elasticache.py metaclass-boilerplate!skip
-plugins/modules/elasticache_info.py compile-2.6!skip
-plugins/modules/elasticache_info.py compile-2.7!skip
-plugins/modules/elasticache_info.py compile-3.5!skip
-plugins/modules/elasticache_info.py compile-3.6!skip
-plugins/modules/elasticache_info.py compile-3.7!skip
-plugins/modules/elasticache_info.py future-import-boilerplate!skip
-plugins/modules/elasticache_info.py import-2.6!skip
-plugins/modules/elasticache_info.py import-2.7!skip
-plugins/modules/elasticache_info.py import-3.5!skip
-plugins/modules/elasticache_info.py import-3.6!skip
-plugins/modules/elasticache_info.py import-3.7!skip
-plugins/modules/elasticache_info.py metaclass-boilerplate!skip
plugins/modules/elasticache_info.py pylint:ansible-deprecated-no-version
-plugins/modules/elasticache_parameter_group.py compile-2.6!skip
-plugins/modules/elasticache_parameter_group.py compile-2.7!skip
-plugins/modules/elasticache_parameter_group.py compile-3.5!skip
-plugins/modules/elasticache_parameter_group.py compile-3.6!skip
-plugins/modules/elasticache_parameter_group.py compile-3.7!skip
-plugins/modules/elasticache_parameter_group.py future-import-boilerplate!skip
-plugins/modules/elasticache_parameter_group.py import-2.6!skip
-plugins/modules/elasticache_parameter_group.py import-2.7!skip
-plugins/modules/elasticache_parameter_group.py import-3.5!skip
-plugins/modules/elasticache_parameter_group.py import-3.6!skip
-plugins/modules/elasticache_parameter_group.py import-3.7!skip
-plugins/modules/elasticache_parameter_group.py metaclass-boilerplate!skip
-plugins/modules/elasticache_snapshot.py compile-2.6!skip
-plugins/modules/elasticache_snapshot.py compile-2.7!skip
-plugins/modules/elasticache_snapshot.py compile-3.5!skip
-plugins/modules/elasticache_snapshot.py compile-3.6!skip
-plugins/modules/elasticache_snapshot.py compile-3.7!skip
-plugins/modules/elasticache_snapshot.py future-import-boilerplate!skip
-plugins/modules/elasticache_snapshot.py import-2.6!skip
-plugins/modules/elasticache_snapshot.py import-2.7!skip
-plugins/modules/elasticache_snapshot.py import-3.5!skip
-plugins/modules/elasticache_snapshot.py import-3.6!skip
-plugins/modules/elasticache_snapshot.py import-3.7!skip
-plugins/modules/elasticache_snapshot.py metaclass-boilerplate!skip
-plugins/modules/elasticache_subnet_group.py compile-2.6!skip
-plugins/modules/elasticache_subnet_group.py compile-2.7!skip
-plugins/modules/elasticache_subnet_group.py compile-3.5!skip
-plugins/modules/elasticache_subnet_group.py compile-3.6!skip
-plugins/modules/elasticache_subnet_group.py compile-3.7!skip
-plugins/modules/elasticache_subnet_group.py future-import-boilerplate!skip
-plugins/modules/elasticache_subnet_group.py import-2.6!skip
-plugins/modules/elasticache_subnet_group.py import-2.7!skip
-plugins/modules/elasticache_subnet_group.py import-3.5!skip
-plugins/modules/elasticache_subnet_group.py import-3.6!skip
-plugins/modules/elasticache_subnet_group.py import-3.7!skip
-plugins/modules/elasticache_subnet_group.py metaclass-boilerplate!skip
-plugins/modules/elb_application_lb.py compile-2.6!skip
-plugins/modules/elb_application_lb.py compile-2.7!skip
-plugins/modules/elb_application_lb.py compile-3.5!skip
-plugins/modules/elb_application_lb.py compile-3.6!skip
-plugins/modules/elb_application_lb.py compile-3.7!skip
-plugins/modules/elb_application_lb.py future-import-boilerplate!skip
-plugins/modules/elb_application_lb.py import-2.6!skip
-plugins/modules/elb_application_lb.py import-2.7!skip
-plugins/modules/elb_application_lb.py import-3.5!skip
-plugins/modules/elb_application_lb.py import-3.6!skip
-plugins/modules/elb_application_lb.py import-3.7!skip
-plugins/modules/elb_application_lb.py metaclass-boilerplate!skip
-plugins/modules/elb_application_lb_info.py compile-2.6!skip
-plugins/modules/elb_application_lb_info.py compile-2.7!skip
-plugins/modules/elb_application_lb_info.py compile-3.5!skip
-plugins/modules/elb_application_lb_info.py compile-3.6!skip
-plugins/modules/elb_application_lb_info.py compile-3.7!skip
-plugins/modules/elb_application_lb_info.py future-import-boilerplate!skip
-plugins/modules/elb_application_lb_info.py import-2.6!skip
-plugins/modules/elb_application_lb_info.py import-2.7!skip
-plugins/modules/elb_application_lb_info.py import-3.5!skip
-plugins/modules/elb_application_lb_info.py import-3.6!skip
-plugins/modules/elb_application_lb_info.py import-3.7!skip
-plugins/modules/elb_application_lb_info.py metaclass-boilerplate!skip
plugins/modules/elb_application_lb_info.py pylint:ansible-deprecated-no-version
-plugins/modules/elb_classic_lb_info.py compile-2.6!skip
-plugins/modules/elb_classic_lb_info.py compile-2.7!skip
-plugins/modules/elb_classic_lb_info.py compile-3.5!skip
-plugins/modules/elb_classic_lb_info.py compile-3.6!skip
-plugins/modules/elb_classic_lb_info.py compile-3.7!skip
-plugins/modules/elb_classic_lb_info.py future-import-boilerplate!skip
-plugins/modules/elb_classic_lb_info.py import-2.6!skip
-plugins/modules/elb_classic_lb_info.py import-2.7!skip
-plugins/modules/elb_classic_lb_info.py import-3.5!skip
-plugins/modules/elb_classic_lb_info.py import-3.6!skip
-plugins/modules/elb_classic_lb_info.py import-3.7!skip
-plugins/modules/elb_classic_lb_info.py metaclass-boilerplate!skip
plugins/modules/elb_classic_lb_info.py pylint:ansible-deprecated-no-version
-plugins/modules/elb_instance.py compile-2.6!skip
-plugins/modules/elb_instance.py compile-2.7!skip
-plugins/modules/elb_instance.py compile-3.5!skip
-plugins/modules/elb_instance.py compile-3.6!skip
-plugins/modules/elb_instance.py compile-3.7!skip
-plugins/modules/elb_instance.py future-import-boilerplate!skip
-plugins/modules/elb_instance.py import-2.6!skip
-plugins/modules/elb_instance.py import-2.7!skip
-plugins/modules/elb_instance.py import-3.5!skip
-plugins/modules/elb_instance.py import-3.6!skip
-plugins/modules/elb_instance.py import-3.7!skip
-plugins/modules/elb_instance.py metaclass-boilerplate!skip
-plugins/modules/elb_network_lb.py compile-2.6!skip
-plugins/modules/elb_network_lb.py compile-2.7!skip
-plugins/modules/elb_network_lb.py compile-3.5!skip
-plugins/modules/elb_network_lb.py compile-3.6!skip
-plugins/modules/elb_network_lb.py compile-3.7!skip
-plugins/modules/elb_network_lb.py future-import-boilerplate!skip
-plugins/modules/elb_network_lb.py import-2.6!skip
-plugins/modules/elb_network_lb.py import-2.7!skip
-plugins/modules/elb_network_lb.py import-3.5!skip
-plugins/modules/elb_network_lb.py import-3.6!skip
-plugins/modules/elb_network_lb.py import-3.7!skip
-plugins/modules/elb_network_lb.py metaclass-boilerplate!skip
plugins/modules/elb_network_lb.py pylint:ansible-deprecated-no-version
-plugins/modules/elb_target.py compile-2.6!skip
-plugins/modules/elb_target.py compile-2.7!skip
-plugins/modules/elb_target.py compile-3.5!skip
-plugins/modules/elb_target.py compile-3.6!skip
-plugins/modules/elb_target.py compile-3.7!skip
-plugins/modules/elb_target.py future-import-boilerplate!skip
-plugins/modules/elb_target.py import-2.6!skip
-plugins/modules/elb_target.py import-2.7!skip
-plugins/modules/elb_target.py import-3.5!skip
-plugins/modules/elb_target.py import-3.6!skip
-plugins/modules/elb_target.py import-3.7!skip
-plugins/modules/elb_target.py metaclass-boilerplate!skip
-plugins/modules/elb_target_group.py compile-2.6!skip
-plugins/modules/elb_target_group.py compile-2.7!skip
-plugins/modules/elb_target_group.py compile-3.5!skip
-plugins/modules/elb_target_group.py compile-3.6!skip
-plugins/modules/elb_target_group.py compile-3.7!skip
-plugins/modules/elb_target_group.py future-import-boilerplate!skip
-plugins/modules/elb_target_group.py import-2.6!skip
-plugins/modules/elb_target_group.py import-2.7!skip
-plugins/modules/elb_target_group.py import-3.5!skip
-plugins/modules/elb_target_group.py import-3.6!skip
-plugins/modules/elb_target_group.py import-3.7!skip
-plugins/modules/elb_target_group.py metaclass-boilerplate!skip
-plugins/modules/elb_target_group_info.py compile-2.6!skip
-plugins/modules/elb_target_group_info.py compile-2.7!skip
-plugins/modules/elb_target_group_info.py compile-3.5!skip
-plugins/modules/elb_target_group_info.py compile-3.6!skip
-plugins/modules/elb_target_group_info.py compile-3.7!skip
-plugins/modules/elb_target_group_info.py future-import-boilerplate!skip
-plugins/modules/elb_target_group_info.py import-2.6!skip
-plugins/modules/elb_target_group_info.py import-2.7!skip
-plugins/modules/elb_target_group_info.py import-3.5!skip
-plugins/modules/elb_target_group_info.py import-3.6!skip
-plugins/modules/elb_target_group_info.py import-3.7!skip
-plugins/modules/elb_target_group_info.py metaclass-boilerplate!skip
plugins/modules/elb_target_group_info.py pylint:ansible-deprecated-no-version
-plugins/modules/elb_target_info.py compile-2.6!skip
-plugins/modules/elb_target_info.py compile-2.7!skip
-plugins/modules/elb_target_info.py compile-3.5!skip
-plugins/modules/elb_target_info.py compile-3.6!skip
-plugins/modules/elb_target_info.py compile-3.7!skip
-plugins/modules/elb_target_info.py future-import-boilerplate!skip
-plugins/modules/elb_target_info.py import-2.6!skip
-plugins/modules/elb_target_info.py import-2.7!skip
-plugins/modules/elb_target_info.py import-3.5!skip
-plugins/modules/elb_target_info.py import-3.6!skip
-plugins/modules/elb_target_info.py import-3.7!skip
-plugins/modules/elb_target_info.py metaclass-boilerplate!skip
plugins/modules/elb_target_info.py pylint:ansible-deprecated-no-version
-plugins/modules/execute_lambda.py compile-2.6!skip
-plugins/modules/execute_lambda.py compile-2.7!skip
-plugins/modules/execute_lambda.py compile-3.5!skip
-plugins/modules/execute_lambda.py compile-3.6!skip
-plugins/modules/execute_lambda.py compile-3.7!skip
-plugins/modules/execute_lambda.py future-import-boilerplate!skip
-plugins/modules/execute_lambda.py import-2.6!skip
-plugins/modules/execute_lambda.py import-2.7!skip
-plugins/modules/execute_lambda.py import-3.5!skip
-plugins/modules/execute_lambda.py import-3.6!skip
-plugins/modules/execute_lambda.py import-3.7!skip
-plugins/modules/execute_lambda.py metaclass-boilerplate!skip
-plugins/modules/iam.py compile-2.6!skip
-plugins/modules/iam.py compile-2.7!skip
-plugins/modules/iam.py compile-3.5!skip
-plugins/modules/iam.py compile-3.6!skip
-plugins/modules/iam.py compile-3.7!skip
-plugins/modules/iam.py future-import-boilerplate!skip
-plugins/modules/iam.py import-2.6!skip
-plugins/modules/iam.py import-2.7!skip
-plugins/modules/iam.py import-3.5!skip
-plugins/modules/iam.py import-3.6!skip
-plugins/modules/iam.py import-3.7!skip
-plugins/modules/iam.py metaclass-boilerplate!skip
-plugins/modules/iam_cert.py compile-2.6!skip
-plugins/modules/iam_cert.py compile-2.7!skip
-plugins/modules/iam_cert.py compile-3.5!skip
-plugins/modules/iam_cert.py compile-3.6!skip
-plugins/modules/iam_cert.py compile-3.7!skip
-plugins/modules/iam_cert.py future-import-boilerplate!skip
-plugins/modules/iam_cert.py import-2.6!skip
-plugins/modules/iam_cert.py import-2.7!skip
-plugins/modules/iam_cert.py import-3.5!skip
-plugins/modules/iam_cert.py import-3.6!skip
-plugins/modules/iam_cert.py import-3.7!skip
-plugins/modules/iam_cert.py metaclass-boilerplate!skip
-plugins/modules/iam_group.py compile-2.6!skip
-plugins/modules/iam_group.py compile-2.7!skip
-plugins/modules/iam_group.py compile-3.5!skip
-plugins/modules/iam_group.py compile-3.6!skip
-plugins/modules/iam_group.py compile-3.7!skip
-plugins/modules/iam_group.py future-import-boilerplate!skip
-plugins/modules/iam_group.py import-2.6!skip
-plugins/modules/iam_group.py import-2.7!skip
-plugins/modules/iam_group.py import-3.5!skip
-plugins/modules/iam_group.py import-3.6!skip
-plugins/modules/iam_group.py import-3.7!skip
-plugins/modules/iam_group.py metaclass-boilerplate!skip
-plugins/modules/iam_managed_policy.py compile-2.6!skip
-plugins/modules/iam_managed_policy.py compile-2.7!skip
-plugins/modules/iam_managed_policy.py compile-3.5!skip
-plugins/modules/iam_managed_policy.py compile-3.6!skip
-plugins/modules/iam_managed_policy.py compile-3.7!skip
-plugins/modules/iam_managed_policy.py future-import-boilerplate!skip
-plugins/modules/iam_managed_policy.py import-2.6!skip
-plugins/modules/iam_managed_policy.py import-2.7!skip
-plugins/modules/iam_managed_policy.py import-3.5!skip
-plugins/modules/iam_managed_policy.py import-3.6!skip
-plugins/modules/iam_managed_policy.py import-3.7!skip
-plugins/modules/iam_managed_policy.py metaclass-boilerplate!skip
-plugins/modules/iam_mfa_device_info.py compile-2.6!skip
-plugins/modules/iam_mfa_device_info.py compile-2.7!skip
-plugins/modules/iam_mfa_device_info.py compile-3.5!skip
-plugins/modules/iam_mfa_device_info.py compile-3.6!skip
-plugins/modules/iam_mfa_device_info.py compile-3.7!skip
-plugins/modules/iam_mfa_device_info.py future-import-boilerplate!skip
-plugins/modules/iam_mfa_device_info.py import-2.6!skip
-plugins/modules/iam_mfa_device_info.py import-2.7!skip
-plugins/modules/iam_mfa_device_info.py import-3.5!skip
-plugins/modules/iam_mfa_device_info.py import-3.6!skip
-plugins/modules/iam_mfa_device_info.py import-3.7!skip
-plugins/modules/iam_mfa_device_info.py metaclass-boilerplate!skip
+plugins/modules/iam.py validate-modules:deprecation-mismatch # Ansible 2.9 docs don't support deprecation properly
+plugins/modules/iam.py validate-modules:invalid-documentation # Ansible 2.9 docs don't support deprecation properly
plugins/modules/iam_mfa_device_info.py pylint:ansible-deprecated-no-version
-plugins/modules/iam_password_policy.py compile-2.6!skip
-plugins/modules/iam_password_policy.py compile-2.7!skip
-plugins/modules/iam_password_policy.py compile-3.5!skip
-plugins/modules/iam_password_policy.py compile-3.6!skip
-plugins/modules/iam_password_policy.py compile-3.7!skip
-plugins/modules/iam_password_policy.py future-import-boilerplate!skip
-plugins/modules/iam_password_policy.py import-2.6!skip
-plugins/modules/iam_password_policy.py import-2.7!skip
-plugins/modules/iam_password_policy.py import-3.5!skip
-plugins/modules/iam_password_policy.py import-3.6!skip
-plugins/modules/iam_password_policy.py import-3.7!skip
-plugins/modules/iam_password_policy.py metaclass-boilerplate!skip
-plugins/modules/iam_policy.py compile-2.6!skip
-plugins/modules/iam_policy.py compile-2.7!skip
-plugins/modules/iam_policy.py compile-3.5!skip
-plugins/modules/iam_policy.py compile-3.6!skip
-plugins/modules/iam_policy.py compile-3.7!skip
-plugins/modules/iam_policy.py future-import-boilerplate!skip
-plugins/modules/iam_policy.py import-2.6!skip
-plugins/modules/iam_policy.py import-2.7!skip
-plugins/modules/iam_policy.py import-3.5!skip
-plugins/modules/iam_policy.py import-3.6!skip
-plugins/modules/iam_policy.py import-3.7!skip
-plugins/modules/iam_policy.py metaclass-boilerplate!skip
plugins/modules/iam_policy.py pylint:ansible-deprecated-no-version
-plugins/modules/iam_policy_info.py compile-2.6!skip
-plugins/modules/iam_policy_info.py compile-2.7!skip
-plugins/modules/iam_policy_info.py compile-3.5!skip
-plugins/modules/iam_policy_info.py compile-3.6!skip
-plugins/modules/iam_policy_info.py compile-3.7!skip
-plugins/modules/iam_policy_info.py future-import-boilerplate!skip
-plugins/modules/iam_policy_info.py import-2.6!skip
-plugins/modules/iam_policy_info.py import-2.7!skip
-plugins/modules/iam_policy_info.py import-3.5!skip
-plugins/modules/iam_policy_info.py import-3.6!skip
-plugins/modules/iam_policy_info.py import-3.7!skip
-plugins/modules/iam_policy_info.py metaclass-boilerplate!skip
-plugins/modules/iam_role.py compile-2.6!skip
-plugins/modules/iam_role.py compile-2.7!skip
-plugins/modules/iam_role.py compile-3.5!skip
-plugins/modules/iam_role.py compile-3.6!skip
-plugins/modules/iam_role.py compile-3.7!skip
-plugins/modules/iam_role.py future-import-boilerplate!skip
-plugins/modules/iam_role.py import-2.6!skip
-plugins/modules/iam_role.py import-2.7!skip
-plugins/modules/iam_role.py import-3.5!skip
-plugins/modules/iam_role.py import-3.6!skip
-plugins/modules/iam_role.py import-3.7!skip
-plugins/modules/iam_role.py metaclass-boilerplate!skip
plugins/modules/iam_role.py pylint:ansible-deprecated-no-version
-plugins/modules/iam_role_info.py compile-2.6!skip
-plugins/modules/iam_role_info.py compile-2.7!skip
-plugins/modules/iam_role_info.py compile-3.5!skip
-plugins/modules/iam_role_info.py compile-3.6!skip
-plugins/modules/iam_role_info.py compile-3.7!skip
-plugins/modules/iam_role_info.py future-import-boilerplate!skip
-plugins/modules/iam_role_info.py import-2.6!skip
-plugins/modules/iam_role_info.py import-2.7!skip
-plugins/modules/iam_role_info.py import-3.5!skip
-plugins/modules/iam_role_info.py import-3.6!skip
-plugins/modules/iam_role_info.py import-3.7!skip
-plugins/modules/iam_role_info.py metaclass-boilerplate!skip
plugins/modules/iam_role_info.py pylint:ansible-deprecated-no-version
-plugins/modules/iam_saml_federation.py compile-2.6!skip
-plugins/modules/iam_saml_federation.py compile-2.7!skip
-plugins/modules/iam_saml_federation.py compile-3.5!skip
-plugins/modules/iam_saml_federation.py compile-3.6!skip
-plugins/modules/iam_saml_federation.py compile-3.7!skip
-plugins/modules/iam_saml_federation.py future-import-boilerplate!skip
-plugins/modules/iam_saml_federation.py import-2.6!skip
-plugins/modules/iam_saml_federation.py import-2.7!skip
-plugins/modules/iam_saml_federation.py import-3.5!skip
-plugins/modules/iam_saml_federation.py import-3.6!skip
-plugins/modules/iam_saml_federation.py import-3.7!skip
-plugins/modules/iam_saml_federation.py metaclass-boilerplate!skip
-plugins/modules/iam_server_certificate_info.py compile-2.6!skip
-plugins/modules/iam_server_certificate_info.py compile-2.7!skip
-plugins/modules/iam_server_certificate_info.py compile-3.5!skip
-plugins/modules/iam_server_certificate_info.py compile-3.6!skip
-plugins/modules/iam_server_certificate_info.py compile-3.7!skip
-plugins/modules/iam_server_certificate_info.py future-import-boilerplate!skip
-plugins/modules/iam_server_certificate_info.py import-2.6!skip
-plugins/modules/iam_server_certificate_info.py import-2.7!skip
-plugins/modules/iam_server_certificate_info.py import-3.5!skip
-plugins/modules/iam_server_certificate_info.py import-3.6!skip
-plugins/modules/iam_server_certificate_info.py import-3.7!skip
-plugins/modules/iam_server_certificate_info.py metaclass-boilerplate!skip
plugins/modules/iam_server_certificate_info.py pylint:ansible-deprecated-no-version
-plugins/modules/iam_user.py compile-2.6!skip
-plugins/modules/iam_user.py compile-2.7!skip
-plugins/modules/iam_user.py compile-3.5!skip
-plugins/modules/iam_user.py compile-3.6!skip
-plugins/modules/iam_user.py compile-3.7!skip
-plugins/modules/iam_user.py future-import-boilerplate!skip
-plugins/modules/iam_user.py import-2.6!skip
-plugins/modules/iam_user.py import-2.7!skip
-plugins/modules/iam_user.py import-3.5!skip
-plugins/modules/iam_user.py import-3.6!skip
-plugins/modules/iam_user.py import-3.7!skip
-plugins/modules/iam_user.py metaclass-boilerplate!skip
-plugins/modules/iam_user_info.py compile-2.6!skip
-plugins/modules/iam_user_info.py compile-2.7!skip
-plugins/modules/iam_user_info.py compile-3.5!skip
-plugins/modules/iam_user_info.py compile-3.6!skip
-plugins/modules/iam_user_info.py compile-3.7!skip
-plugins/modules/iam_user_info.py future-import-boilerplate!skip
-plugins/modules/iam_user_info.py import-2.6!skip
-plugins/modules/iam_user_info.py import-2.7!skip
-plugins/modules/iam_user_info.py import-3.5!skip
-plugins/modules/iam_user_info.py import-3.6!skip
-plugins/modules/iam_user_info.py import-3.7!skip
-plugins/modules/iam_user_info.py metaclass-boilerplate!skip
-plugins/modules/kinesis_stream.py compile-2.6!skip
-plugins/modules/kinesis_stream.py compile-2.7!skip
-plugins/modules/kinesis_stream.py compile-3.5!skip
-plugins/modules/kinesis_stream.py compile-3.6!skip
-plugins/modules/kinesis_stream.py compile-3.7!skip
-plugins/modules/kinesis_stream.py future-import-boilerplate!skip
-plugins/modules/kinesis_stream.py import-2.6!skip
-plugins/modules/kinesis_stream.py import-2.7!skip
-plugins/modules/kinesis_stream.py import-3.5!skip
-plugins/modules/kinesis_stream.py import-3.6!skip
-plugins/modules/kinesis_stream.py import-3.7!skip
-plugins/modules/kinesis_stream.py metaclass-boilerplate!skip
-plugins/modules/lambda.py compile-2.6!skip
-plugins/modules/lambda.py compile-2.7!skip
-plugins/modules/lambda.py compile-3.5!skip
-plugins/modules/lambda.py compile-3.6!skip
-plugins/modules/lambda.py compile-3.7!skip
-plugins/modules/lambda.py future-import-boilerplate!skip
-plugins/modules/lambda.py import-2.6!skip
-plugins/modules/lambda.py import-2.7!skip
-plugins/modules/lambda.py import-3.5!skip
-plugins/modules/lambda.py import-3.6!skip
-plugins/modules/lambda.py import-3.7!skip
-plugins/modules/lambda.py metaclass-boilerplate!skip
-plugins/modules/lambda_alias.py compile-2.6!skip
-plugins/modules/lambda_alias.py compile-2.7!skip
-plugins/modules/lambda_alias.py compile-3.5!skip
-plugins/modules/lambda_alias.py compile-3.6!skip
-plugins/modules/lambda_alias.py compile-3.7!skip
-plugins/modules/lambda_alias.py future-import-boilerplate!skip
-plugins/modules/lambda_alias.py import-2.6!skip
-plugins/modules/lambda_alias.py import-2.7!skip
-plugins/modules/lambda_alias.py import-3.5!skip
-plugins/modules/lambda_alias.py import-3.6!skip
-plugins/modules/lambda_alias.py import-3.7!skip
-plugins/modules/lambda_alias.py metaclass-boilerplate!skip
-plugins/modules/lambda_event.py compile-2.6!skip
-plugins/modules/lambda_event.py compile-2.7!skip
-plugins/modules/lambda_event.py compile-3.5!skip
-plugins/modules/lambda_event.py compile-3.6!skip
-plugins/modules/lambda_event.py compile-3.7!skip
-plugins/modules/lambda_event.py future-import-boilerplate!skip
-plugins/modules/lambda_event.py import-2.6!skip
-plugins/modules/lambda_event.py import-2.7!skip
-plugins/modules/lambda_event.py import-3.5!skip
-plugins/modules/lambda_event.py import-3.6!skip
-plugins/modules/lambda_event.py import-3.7!skip
-plugins/modules/lambda_event.py metaclass-boilerplate!skip
-plugins/modules/lambda_facts.py compile-2.6!skip
-plugins/modules/lambda_facts.py compile-2.7!skip
-plugins/modules/lambda_facts.py compile-3.5!skip
-plugins/modules/lambda_facts.py compile-3.6!skip
-plugins/modules/lambda_facts.py compile-3.7!skip
-plugins/modules/lambda_facts.py future-import-boilerplate!skip
-plugins/modules/lambda_facts.py import-2.6!skip
-plugins/modules/lambda_facts.py import-2.7!skip
-plugins/modules/lambda_facts.py import-3.5!skip
-plugins/modules/lambda_facts.py import-3.6!skip
-plugins/modules/lambda_facts.py import-3.7!skip
-plugins/modules/lambda_facts.py metaclass-boilerplate!skip
plugins/modules/lambda_facts.py validate-modules:deprecation-mismatch
plugins/modules/lambda_facts.py validate-modules:invalid-documentation
-plugins/modules/lambda_info.py compile-2.6!skip
-plugins/modules/lambda_info.py compile-2.7!skip
-plugins/modules/lambda_info.py compile-3.5!skip
-plugins/modules/lambda_info.py compile-3.6!skip
-plugins/modules/lambda_info.py compile-3.7!skip
-plugins/modules/lambda_info.py future-import-boilerplate!skip
-plugins/modules/lambda_info.py import-2.6!skip
-plugins/modules/lambda_info.py import-2.7!skip
-plugins/modules/lambda_info.py import-3.5!skip
-plugins/modules/lambda_info.py import-3.6!skip
-plugins/modules/lambda_info.py import-3.7!skip
-plugins/modules/lambda_info.py metaclass-boilerplate!skip
-plugins/modules/lambda_policy.py compile-2.6!skip
-plugins/modules/lambda_policy.py compile-2.7!skip
-plugins/modules/lambda_policy.py compile-3.5!skip
-plugins/modules/lambda_policy.py compile-3.6!skip
-plugins/modules/lambda_policy.py compile-3.7!skip
-plugins/modules/lambda_policy.py future-import-boilerplate!skip
-plugins/modules/lambda_policy.py import-2.6!skip
-plugins/modules/lambda_policy.py import-2.7!skip
-plugins/modules/lambda_policy.py import-3.5!skip
-plugins/modules/lambda_policy.py import-3.6!skip
-plugins/modules/lambda_policy.py import-3.7!skip
-plugins/modules/lambda_policy.py metaclass-boilerplate!skip
-plugins/modules/lightsail.py compile-2.6!skip
-plugins/modules/lightsail.py compile-2.7!skip
-plugins/modules/lightsail.py compile-3.5!skip
-plugins/modules/lightsail.py compile-3.6!skip
-plugins/modules/lightsail.py compile-3.7!skip
-plugins/modules/lightsail.py future-import-boilerplate!skip
-plugins/modules/lightsail.py import-2.6!skip
-plugins/modules/lightsail.py import-2.7!skip
-plugins/modules/lightsail.py import-3.5!skip
-plugins/modules/lightsail.py import-3.6!skip
-plugins/modules/lightsail.py import-3.7!skip
-plugins/modules/lightsail.py metaclass-boilerplate!skip
-plugins/modules/rds.py compile-2.6!skip
-plugins/modules/rds.py compile-2.7!skip
-plugins/modules/rds.py compile-3.5!skip
-plugins/modules/rds.py compile-3.6!skip
-plugins/modules/rds.py compile-3.7!skip
-plugins/modules/rds.py future-import-boilerplate!skip
-plugins/modules/rds.py import-2.6!skip
-plugins/modules/rds.py import-2.7!skip
-plugins/modules/rds.py import-3.5!skip
-plugins/modules/rds.py import-3.6!skip
-plugins/modules/rds.py import-3.7!skip
-plugins/modules/rds.py metaclass-boilerplate!skip
-plugins/modules/rds_instance.py compile-2.6!skip
-plugins/modules/rds_instance.py compile-2.7!skip
-plugins/modules/rds_instance.py compile-3.5!skip
-plugins/modules/rds_instance.py compile-3.6!skip
-plugins/modules/rds_instance.py compile-3.7!skip
-plugins/modules/rds_instance.py future-import-boilerplate!skip
-plugins/modules/rds_instance.py import-2.6!skip
-plugins/modules/rds_instance.py import-2.7!skip
-plugins/modules/rds_instance.py import-3.5!skip
-plugins/modules/rds_instance.py import-3.6!skip
-plugins/modules/rds_instance.py import-3.7!skip
-plugins/modules/rds_instance.py metaclass-boilerplate!skip
-plugins/modules/rds_instance_info.py compile-2.6!skip
-plugins/modules/rds_instance_info.py compile-2.7!skip
-plugins/modules/rds_instance_info.py compile-3.5!skip
-plugins/modules/rds_instance_info.py compile-3.6!skip
-plugins/modules/rds_instance_info.py compile-3.7!skip
-plugins/modules/rds_instance_info.py future-import-boilerplate!skip
-plugins/modules/rds_instance_info.py import-2.6!skip
-plugins/modules/rds_instance_info.py import-2.7!skip
-plugins/modules/rds_instance_info.py import-3.5!skip
-plugins/modules/rds_instance_info.py import-3.6!skip
-plugins/modules/rds_instance_info.py import-3.7!skip
-plugins/modules/rds_instance_info.py metaclass-boilerplate!skip
+plugins/modules/rds.py validate-modules:deprecation-mismatch # Ansible 2.9 docs don't support deprecation properly
+plugins/modules/rds.py validate-modules:invalid-documentation # Ansible 2.9 docs don't support deprecation properly
plugins/modules/rds_instance_info.py pylint:ansible-deprecated-no-version
-plugins/modules/rds_param_group.py compile-2.6!skip
-plugins/modules/rds_param_group.py compile-2.7!skip
-plugins/modules/rds_param_group.py compile-3.5!skip
-plugins/modules/rds_param_group.py compile-3.6!skip
-plugins/modules/rds_param_group.py compile-3.7!skip
-plugins/modules/rds_param_group.py future-import-boilerplate!skip
-plugins/modules/rds_param_group.py import-2.6!skip
-plugins/modules/rds_param_group.py import-2.7!skip
-plugins/modules/rds_param_group.py import-3.5!skip
-plugins/modules/rds_param_group.py import-3.6!skip
-plugins/modules/rds_param_group.py import-3.7!skip
-plugins/modules/rds_param_group.py metaclass-boilerplate!skip
-plugins/modules/rds_snapshot.py compile-2.6!skip
-plugins/modules/rds_snapshot.py compile-2.7!skip
-plugins/modules/rds_snapshot.py compile-3.5!skip
-plugins/modules/rds_snapshot.py compile-3.6!skip
-plugins/modules/rds_snapshot.py compile-3.7!skip
-plugins/modules/rds_snapshot.py future-import-boilerplate!skip
-plugins/modules/rds_snapshot.py import-2.6!skip
-plugins/modules/rds_snapshot.py import-2.7!skip
-plugins/modules/rds_snapshot.py import-3.5!skip
-plugins/modules/rds_snapshot.py import-3.6!skip
-plugins/modules/rds_snapshot.py import-3.7!skip
-plugins/modules/rds_snapshot.py metaclass-boilerplate!skip
-plugins/modules/rds_snapshot_info.py compile-2.6!skip
-plugins/modules/rds_snapshot_info.py compile-2.7!skip
-plugins/modules/rds_snapshot_info.py compile-3.5!skip
-plugins/modules/rds_snapshot_info.py compile-3.6!skip
-plugins/modules/rds_snapshot_info.py compile-3.7!skip
-plugins/modules/rds_snapshot_info.py future-import-boilerplate!skip
-plugins/modules/rds_snapshot_info.py import-2.6!skip
-plugins/modules/rds_snapshot_info.py import-2.7!skip
-plugins/modules/rds_snapshot_info.py import-3.5!skip
-plugins/modules/rds_snapshot_info.py import-3.6!skip
-plugins/modules/rds_snapshot_info.py import-3.7!skip
-plugins/modules/rds_snapshot_info.py metaclass-boilerplate!skip
plugins/modules/rds_snapshot_info.py pylint:ansible-deprecated-no-version
-plugins/modules/rds_subnet_group.py compile-2.6!skip
-plugins/modules/rds_subnet_group.py compile-2.7!skip
-plugins/modules/rds_subnet_group.py compile-3.5!skip
-plugins/modules/rds_subnet_group.py compile-3.6!skip
-plugins/modules/rds_subnet_group.py compile-3.7!skip
-plugins/modules/rds_subnet_group.py future-import-boilerplate!skip
-plugins/modules/rds_subnet_group.py import-2.6!skip
-plugins/modules/rds_subnet_group.py import-2.7!skip
-plugins/modules/rds_subnet_group.py import-3.5!skip
-plugins/modules/rds_subnet_group.py import-3.6!skip
-plugins/modules/rds_subnet_group.py import-3.7!skip
-plugins/modules/rds_subnet_group.py metaclass-boilerplate!skip
-plugins/modules/redshift.py compile-2.6!skip
-plugins/modules/redshift.py compile-2.7!skip
-plugins/modules/redshift.py compile-3.5!skip
-plugins/modules/redshift.py compile-3.6!skip
-plugins/modules/redshift.py compile-3.7!skip
-plugins/modules/redshift.py future-import-boilerplate!skip
-plugins/modules/redshift.py import-2.6!skip
-plugins/modules/redshift.py import-2.7!skip
-plugins/modules/redshift.py import-3.5!skip
-plugins/modules/redshift.py import-3.6!skip
-plugins/modules/redshift.py import-3.7!skip
-plugins/modules/redshift.py metaclass-boilerplate!skip
-plugins/modules/redshift_cross_region_snapshots.py compile-2.6!skip
-plugins/modules/redshift_cross_region_snapshots.py compile-2.7!skip
-plugins/modules/redshift_cross_region_snapshots.py compile-3.5!skip
-plugins/modules/redshift_cross_region_snapshots.py compile-3.6!skip
-plugins/modules/redshift_cross_region_snapshots.py compile-3.7!skip
-plugins/modules/redshift_cross_region_snapshots.py future-import-boilerplate!skip
-plugins/modules/redshift_cross_region_snapshots.py import-2.6!skip
-plugins/modules/redshift_cross_region_snapshots.py import-2.7!skip
-plugins/modules/redshift_cross_region_snapshots.py import-3.5!skip
-plugins/modules/redshift_cross_region_snapshots.py import-3.6!skip
-plugins/modules/redshift_cross_region_snapshots.py import-3.7!skip
-plugins/modules/redshift_cross_region_snapshots.py metaclass-boilerplate!skip
-plugins/modules/redshift_info.py compile-2.6!skip
-plugins/modules/redshift_info.py compile-2.7!skip
-plugins/modules/redshift_info.py compile-3.5!skip
-plugins/modules/redshift_info.py compile-3.6!skip
-plugins/modules/redshift_info.py compile-3.7!skip
-plugins/modules/redshift_info.py future-import-boilerplate!skip
-plugins/modules/redshift_info.py import-2.6!skip
-plugins/modules/redshift_info.py import-2.7!skip
-plugins/modules/redshift_info.py import-3.5!skip
-plugins/modules/redshift_info.py import-3.6!skip
-plugins/modules/redshift_info.py import-3.7!skip
-plugins/modules/redshift_info.py metaclass-boilerplate!skip
plugins/modules/redshift_info.py pylint:ansible-deprecated-no-version
-plugins/modules/redshift_subnet_group.py compile-2.6!skip
-plugins/modules/redshift_subnet_group.py compile-2.7!skip
-plugins/modules/redshift_subnet_group.py compile-3.5!skip
-plugins/modules/redshift_subnet_group.py compile-3.6!skip
-plugins/modules/redshift_subnet_group.py compile-3.7!skip
-plugins/modules/redshift_subnet_group.py future-import-boilerplate!skip
-plugins/modules/redshift_subnet_group.py import-2.6!skip
-plugins/modules/redshift_subnet_group.py import-2.7!skip
-plugins/modules/redshift_subnet_group.py import-3.5!skip
-plugins/modules/redshift_subnet_group.py import-3.6!skip
-plugins/modules/redshift_subnet_group.py import-3.7!skip
-plugins/modules/redshift_subnet_group.py metaclass-boilerplate!skip
-plugins/modules/route53.py compile-2.6!skip
-plugins/modules/route53.py compile-2.7!skip
-plugins/modules/route53.py compile-3.5!skip
-plugins/modules/route53.py compile-3.6!skip
-plugins/modules/route53.py compile-3.7!skip
-plugins/modules/route53.py future-import-boilerplate!skip
-plugins/modules/route53.py import-2.6!skip
-plugins/modules/route53.py import-2.7!skip
-plugins/modules/route53.py import-3.5!skip
-plugins/modules/route53.py import-3.6!skip
-plugins/modules/route53.py import-3.7!skip
-plugins/modules/route53.py metaclass-boilerplate!skip
-plugins/modules/route53_health_check.py compile-2.6!skip
-plugins/modules/route53_health_check.py compile-2.7!skip
-plugins/modules/route53_health_check.py compile-3.5!skip
-plugins/modules/route53_health_check.py compile-3.6!skip
-plugins/modules/route53_health_check.py compile-3.7!skip
-plugins/modules/route53_health_check.py future-import-boilerplate!skip
-plugins/modules/route53_health_check.py import-2.6!skip
-plugins/modules/route53_health_check.py import-2.7!skip
-plugins/modules/route53_health_check.py import-3.5!skip
-plugins/modules/route53_health_check.py import-3.6!skip
-plugins/modules/route53_health_check.py import-3.7!skip
-plugins/modules/route53_health_check.py metaclass-boilerplate!skip
-plugins/modules/route53_info.py compile-2.6!skip
-plugins/modules/route53_info.py compile-2.7!skip
-plugins/modules/route53_info.py compile-3.5!skip
-plugins/modules/route53_info.py compile-3.6!skip
-plugins/modules/route53_info.py compile-3.7!skip
-plugins/modules/route53_info.py future-import-boilerplate!skip
-plugins/modules/route53_info.py import-2.6!skip
-plugins/modules/route53_info.py import-2.7!skip
-plugins/modules/route53_info.py import-3.5!skip
-plugins/modules/route53_info.py import-3.6!skip
-plugins/modules/route53_info.py import-3.7!skip
-plugins/modules/route53_info.py metaclass-boilerplate!skip
plugins/modules/route53_info.py pylint:ansible-deprecated-no-version
-plugins/modules/route53_zone.py compile-2.6!skip
-plugins/modules/route53_zone.py compile-2.7!skip
-plugins/modules/route53_zone.py compile-3.5!skip
-plugins/modules/route53_zone.py compile-3.6!skip
-plugins/modules/route53_zone.py compile-3.7!skip
-plugins/modules/route53_zone.py future-import-boilerplate!skip
-plugins/modules/route53_zone.py import-2.6!skip
-plugins/modules/route53_zone.py import-2.7!skip
-plugins/modules/route53_zone.py import-3.5!skip
-plugins/modules/route53_zone.py import-3.6!skip
-plugins/modules/route53_zone.py import-3.7!skip
-plugins/modules/route53_zone.py metaclass-boilerplate!skip
-plugins/modules/s3_bucket_notification.py compile-2.6!skip
-plugins/modules/s3_bucket_notification.py compile-2.7!skip
-plugins/modules/s3_bucket_notification.py compile-3.5!skip
-plugins/modules/s3_bucket_notification.py compile-3.6!skip
-plugins/modules/s3_bucket_notification.py compile-3.7!skip
-plugins/modules/s3_bucket_notification.py future-import-boilerplate!skip
-plugins/modules/s3_bucket_notification.py import-2.6!skip
-plugins/modules/s3_bucket_notification.py import-2.7!skip
-plugins/modules/s3_bucket_notification.py import-3.5!skip
-plugins/modules/s3_bucket_notification.py import-3.6!skip
-plugins/modules/s3_bucket_notification.py import-3.7!skip
-plugins/modules/s3_bucket_notification.py metaclass-boilerplate!skip
-plugins/modules/s3_lifecycle.py compile-2.6!skip
-plugins/modules/s3_lifecycle.py compile-2.7!skip
-plugins/modules/s3_lifecycle.py compile-3.5!skip
-plugins/modules/s3_lifecycle.py compile-3.6!skip
-plugins/modules/s3_lifecycle.py compile-3.7!skip
-plugins/modules/s3_lifecycle.py future-import-boilerplate!skip
-plugins/modules/s3_lifecycle.py import-2.6!skip
-plugins/modules/s3_lifecycle.py import-2.7!skip
-plugins/modules/s3_lifecycle.py import-3.5!skip
-plugins/modules/s3_lifecycle.py import-3.6!skip
-plugins/modules/s3_lifecycle.py import-3.7!skip
-plugins/modules/s3_lifecycle.py metaclass-boilerplate!skip
-plugins/modules/s3_logging.py compile-2.6!skip
-plugins/modules/s3_logging.py compile-2.7!skip
-plugins/modules/s3_logging.py compile-3.5!skip
-plugins/modules/s3_logging.py compile-3.6!skip
-plugins/modules/s3_logging.py compile-3.7!skip
-plugins/modules/s3_logging.py future-import-boilerplate!skip
-plugins/modules/s3_logging.py import-2.6!skip
-plugins/modules/s3_logging.py import-2.7!skip
-plugins/modules/s3_logging.py import-3.5!skip
-plugins/modules/s3_logging.py import-3.6!skip
-plugins/modules/s3_logging.py import-3.7!skip
-plugins/modules/s3_logging.py metaclass-boilerplate!skip
-plugins/modules/s3_metrics_configuration.py compile-2.6!skip
-plugins/modules/s3_metrics_configuration.py compile-2.7!skip
-plugins/modules/s3_metrics_configuration.py compile-3.5!skip
-plugins/modules/s3_metrics_configuration.py compile-3.6!skip
-plugins/modules/s3_metrics_configuration.py compile-3.7!skip
-plugins/modules/s3_metrics_configuration.py future-import-boilerplate!skip
-plugins/modules/s3_metrics_configuration.py import-2.6!skip
-plugins/modules/s3_metrics_configuration.py import-2.7!skip
-plugins/modules/s3_metrics_configuration.py import-3.5!skip
-plugins/modules/s3_metrics_configuration.py import-3.6!skip
-plugins/modules/s3_metrics_configuration.py import-3.7!skip
-plugins/modules/s3_metrics_configuration.py metaclass-boilerplate!skip
-plugins/modules/s3_sync.py compile-2.6!skip
-plugins/modules/s3_sync.py compile-2.7!skip
-plugins/modules/s3_sync.py compile-3.5!skip
-plugins/modules/s3_sync.py compile-3.6!skip
-plugins/modules/s3_sync.py compile-3.7!skip
-plugins/modules/s3_sync.py future-import-boilerplate!skip
-plugins/modules/s3_sync.py import-2.6!skip
-plugins/modules/s3_sync.py import-2.7!skip
-plugins/modules/s3_sync.py import-3.5!skip
-plugins/modules/s3_sync.py import-3.6!skip
-plugins/modules/s3_sync.py import-3.7!skip
-plugins/modules/s3_sync.py metaclass-boilerplate!skip
-plugins/modules/s3_website.py compile-2.6!skip
-plugins/modules/s3_website.py compile-2.7!skip
-plugins/modules/s3_website.py compile-3.5!skip
-plugins/modules/s3_website.py compile-3.6!skip
-plugins/modules/s3_website.py compile-3.7!skip
-plugins/modules/s3_website.py future-import-boilerplate!skip
-plugins/modules/s3_website.py import-2.6!skip
-plugins/modules/s3_website.py import-2.7!skip
-plugins/modules/s3_website.py import-3.5!skip
-plugins/modules/s3_website.py import-3.6!skip
-plugins/modules/s3_website.py import-3.7!skip
-plugins/modules/s3_website.py metaclass-boilerplate!skip
-plugins/modules/sns.py compile-2.6!skip
-plugins/modules/sns.py compile-2.7!skip
-plugins/modules/sns.py compile-3.5!skip
-plugins/modules/sns.py compile-3.6!skip
-plugins/modules/sns.py compile-3.7!skip
-plugins/modules/sns.py future-import-boilerplate!skip
-plugins/modules/sns.py import-2.6!skip
-plugins/modules/sns.py import-2.7!skip
-plugins/modules/sns.py import-3.5!skip
-plugins/modules/sns.py import-3.6!skip
-plugins/modules/sns.py import-3.7!skip
-plugins/modules/sns.py metaclass-boilerplate!skip
-plugins/modules/sns_topic.py compile-2.6!skip
-plugins/modules/sns_topic.py compile-2.7!skip
-plugins/modules/sns_topic.py compile-3.5!skip
-plugins/modules/sns_topic.py compile-3.6!skip
-plugins/modules/sns_topic.py compile-3.7!skip
-plugins/modules/sns_topic.py future-import-boilerplate!skip
-plugins/modules/sns_topic.py import-2.6!skip
-plugins/modules/sns_topic.py import-2.7!skip
-plugins/modules/sns_topic.py import-3.5!skip
-plugins/modules/sns_topic.py import-3.6!skip
-plugins/modules/sns_topic.py import-3.7!skip
-plugins/modules/sns_topic.py metaclass-boilerplate!skip
-plugins/modules/sqs_queue.py compile-2.6!skip
-plugins/modules/sqs_queue.py compile-2.7!skip
-plugins/modules/sqs_queue.py compile-3.5!skip
-plugins/modules/sqs_queue.py compile-3.6!skip
-plugins/modules/sqs_queue.py compile-3.7!skip
-plugins/modules/sqs_queue.py future-import-boilerplate!skip
-plugins/modules/sqs_queue.py import-2.6!skip
-plugins/modules/sqs_queue.py import-2.7!skip
-plugins/modules/sqs_queue.py import-3.5!skip
-plugins/modules/sqs_queue.py import-3.6!skip
-plugins/modules/sqs_queue.py import-3.7!skip
-plugins/modules/sqs_queue.py metaclass-boilerplate!skip
-plugins/modules/sts_assume_role.py compile-2.6!skip
-plugins/modules/sts_assume_role.py compile-2.7!skip
-plugins/modules/sts_assume_role.py compile-3.5!skip
-plugins/modules/sts_assume_role.py compile-3.6!skip
-plugins/modules/sts_assume_role.py compile-3.7!skip
-plugins/modules/sts_assume_role.py future-import-boilerplate!skip
-plugins/modules/sts_assume_role.py import-2.6!skip
-plugins/modules/sts_assume_role.py import-2.7!skip
-plugins/modules/sts_assume_role.py import-3.5!skip
-plugins/modules/sts_assume_role.py import-3.6!skip
-plugins/modules/sts_assume_role.py import-3.7!skip
-plugins/modules/sts_assume_role.py metaclass-boilerplate!skip
-plugins/modules/sts_session_token.py compile-2.6!skip
-plugins/modules/sts_session_token.py compile-2.7!skip
-plugins/modules/sts_session_token.py compile-3.5!skip
-plugins/modules/sts_session_token.py compile-3.6!skip
-plugins/modules/sts_session_token.py compile-3.7!skip
-plugins/modules/sts_session_token.py future-import-boilerplate!skip
-plugins/modules/sts_session_token.py import-2.6!skip
-plugins/modules/sts_session_token.py import-2.7!skip
-plugins/modules/sts_session_token.py import-3.5!skip
-plugins/modules/sts_session_token.py import-3.6!skip
-plugins/modules/sts_session_token.py import-3.7!skip
-plugins/modules/sts_session_token.py metaclass-boilerplate!skip
-plugins/modules/wafv2_ip_set.py compile-2.6!skip
-plugins/modules/wafv2_ip_set.py compile-2.7!skip
-plugins/modules/wafv2_ip_set.py compile-3.5!skip
-plugins/modules/wafv2_ip_set.py compile-3.6!skip
-plugins/modules/wafv2_ip_set.py compile-3.7!skip
-plugins/modules/wafv2_ip_set.py future-import-boilerplate!skip
-plugins/modules/wafv2_ip_set.py import-2.6!skip
-plugins/modules/wafv2_ip_set.py import-2.7!skip
-plugins/modules/wafv2_ip_set.py import-3.5!skip
-plugins/modules/wafv2_ip_set.py import-3.6!skip
-plugins/modules/wafv2_ip_set.py import-3.7!skip
-plugins/modules/wafv2_ip_set.py metaclass-boilerplate!skip
-plugins/modules/wafv2_ip_set_info.py compile-2.6!skip
-plugins/modules/wafv2_ip_set_info.py compile-2.7!skip
-plugins/modules/wafv2_ip_set_info.py compile-3.5!skip
-plugins/modules/wafv2_ip_set_info.py compile-3.6!skip
-plugins/modules/wafv2_ip_set_info.py compile-3.7!skip
-plugins/modules/wafv2_ip_set_info.py future-import-boilerplate!skip
-plugins/modules/wafv2_ip_set_info.py import-2.6!skip
-plugins/modules/wafv2_ip_set_info.py import-2.7!skip
-plugins/modules/wafv2_ip_set_info.py import-3.5!skip
-plugins/modules/wafv2_ip_set_info.py import-3.6!skip
-plugins/modules/wafv2_ip_set_info.py import-3.7!skip
-plugins/modules/wafv2_ip_set_info.py metaclass-boilerplate!skip
-plugins/modules/wafv2_resources.py compile-2.6!skip
-plugins/modules/wafv2_resources.py compile-2.7!skip
-plugins/modules/wafv2_resources.py compile-3.5!skip
-plugins/modules/wafv2_resources.py compile-3.6!skip
-plugins/modules/wafv2_resources.py compile-3.7!skip
-plugins/modules/wafv2_resources.py future-import-boilerplate!skip
-plugins/modules/wafv2_resources.py import-2.6!skip
-plugins/modules/wafv2_resources.py import-2.7!skip
-plugins/modules/wafv2_resources.py import-3.5!skip
-plugins/modules/wafv2_resources.py import-3.6!skip
-plugins/modules/wafv2_resources.py import-3.7!skip
-plugins/modules/wafv2_resources.py metaclass-boilerplate!skip
-plugins/modules/wafv2_resources_info.py compile-2.6!skip
-plugins/modules/wafv2_resources_info.py compile-2.7!skip
-plugins/modules/wafv2_resources_info.py compile-3.5!skip
-plugins/modules/wafv2_resources_info.py compile-3.6!skip
-plugins/modules/wafv2_resources_info.py compile-3.7!skip
-plugins/modules/wafv2_resources_info.py future-import-boilerplate!skip
-plugins/modules/wafv2_resources_info.py import-2.6!skip
-plugins/modules/wafv2_resources_info.py import-2.7!skip
-plugins/modules/wafv2_resources_info.py import-3.5!skip
-plugins/modules/wafv2_resources_info.py import-3.6!skip
-plugins/modules/wafv2_resources_info.py import-3.7!skip
-plugins/modules/wafv2_resources_info.py metaclass-boilerplate!skip
-plugins/modules/wafv2_rule_group.py compile-2.6!skip
-plugins/modules/wafv2_rule_group.py compile-2.7!skip
-plugins/modules/wafv2_rule_group.py compile-3.5!skip
-plugins/modules/wafv2_rule_group.py compile-3.6!skip
-plugins/modules/wafv2_rule_group.py compile-3.7!skip
-plugins/modules/wafv2_rule_group.py future-import-boilerplate!skip
-plugins/modules/wafv2_rule_group.py import-2.6!skip
-plugins/modules/wafv2_rule_group.py import-2.7!skip
-plugins/modules/wafv2_rule_group.py import-3.5!skip
-plugins/modules/wafv2_rule_group.py import-3.6!skip
-plugins/modules/wafv2_rule_group.py import-3.7!skip
-plugins/modules/wafv2_rule_group.py metaclass-boilerplate!skip
-plugins/modules/wafv2_rule_group_info.py compile-2.6!skip
-plugins/modules/wafv2_rule_group_info.py compile-2.7!skip
-plugins/modules/wafv2_rule_group_info.py compile-3.5!skip
-plugins/modules/wafv2_rule_group_info.py compile-3.6!skip
-plugins/modules/wafv2_rule_group_info.py compile-3.7!skip
-plugins/modules/wafv2_rule_group_info.py future-import-boilerplate!skip
-plugins/modules/wafv2_rule_group_info.py import-2.6!skip
-plugins/modules/wafv2_rule_group_info.py import-2.7!skip
-plugins/modules/wafv2_rule_group_info.py import-3.5!skip
-plugins/modules/wafv2_rule_group_info.py import-3.6!skip
-plugins/modules/wafv2_rule_group_info.py import-3.7!skip
-plugins/modules/wafv2_rule_group_info.py metaclass-boilerplate!skip
-plugins/modules/wafv2_web_acl.py compile-2.6!skip
-plugins/modules/wafv2_web_acl.py compile-2.7!skip
-plugins/modules/wafv2_web_acl.py compile-3.5!skip
-plugins/modules/wafv2_web_acl.py compile-3.6!skip
-plugins/modules/wafv2_web_acl.py compile-3.7!skip
-plugins/modules/wafv2_web_acl.py future-import-boilerplate!skip
-plugins/modules/wafv2_web_acl.py import-2.6!skip
-plugins/modules/wafv2_web_acl.py import-2.7!skip
-plugins/modules/wafv2_web_acl.py import-3.5!skip
-plugins/modules/wafv2_web_acl.py import-3.6!skip
-plugins/modules/wafv2_web_acl.py import-3.7!skip
-plugins/modules/wafv2_web_acl.py metaclass-boilerplate!skip
-plugins/modules/wafv2_web_acl_info.py compile-2.6!skip
-plugins/modules/wafv2_web_acl_info.py compile-2.7!skip
-plugins/modules/wafv2_web_acl_info.py compile-3.5!skip
-plugins/modules/wafv2_web_acl_info.py compile-3.6!skip
-plugins/modules/wafv2_web_acl_info.py compile-3.7!skip
-plugins/modules/wafv2_web_acl_info.py future-import-boilerplate!skip
-plugins/modules/wafv2_web_acl_info.py import-2.6!skip
-plugins/modules/wafv2_web_acl_info.py import-2.7!skip
-plugins/modules/wafv2_web_acl_info.py import-3.5!skip
-plugins/modules/wafv2_web_acl_info.py import-3.6!skip
-plugins/modules/wafv2_web_acl_info.py import-3.7!skip
-plugins/modules/wafv2_web_acl_info.py metaclass-boilerplate!skip
-tests/sanity/refresh_ignore_files shebang!skip
diff --git a/tests/sanity/refresh_ignore_files b/tests/sanity/refresh_ignore_files
deleted file mode 100755
index 41b97639ed6..00000000000
--- a/tests/sanity/refresh_ignore_files
+++ /dev/null
@@ -1,42 +0,0 @@
-#!/usr/bin/env python3
-
-from pathlib import Path
-
-target_dir = Path('.')
-
-ignore_dir = target_dir / "tests" / "sanity"
-module_dir = target_dir / "plugins" / "modules"
-module_utils_dir = target_dir / "plugins" / "module_utilss"
-ignore_dir.mkdir(parents=True, exist_ok=True)
-
-for version in ["2.9", "2.10", "2.11", "2.12"]:
- ignore_file = ignore_dir / f"ignore-{version}.txt"
- ignore_content = ignore_file.read_text().split("\n")
- ignore_content.append(f"tests/sanity/refresh_ignore_files shebang!skip")
- skip_list = [
- "compile-2.6!skip", # Py3.8+
- "compile-2.7!skip", # Py3.8+
- "compile-3.5!skip", # Py3.8+
- "compile-3.6!skip", # Py3.8+
- "compile-3.7!skip", # Py3.8+
- "import-2.6!skip", # Py3.8+
- "import-2.7!skip", # Py3.8+
- "import-3.5!skip", # Py3.8+
- "import-3.6!skip", # Py3.8+
- "import-3.7!skip", # Py3.8+
- "future-import-boilerplate!skip", # Py2 only
- "metaclass-boilerplate!skip", # Py2 only
- ]
-
- for f in module_dir.glob("*.py"):
- if f.is_symlink():
- continue
- for test in skip_list:
- ignore_content.append(f"{f} {test}")
- for f in module_utils_dir.glob("*.py"):
- if f.is_symlink():
- continue
- for test in skip_list:
- ignore_content.append(f"{f} {test}")
- ignore_file = ignore_dir / f"ignore-{version}.txt"
- ignore_file.write_text("\n".join(sorted(set(ignore_content))).lstrip("\n"))
diff --git a/tests/unit/constraints.txt b/tests/unit/constraints.txt
new file mode 100644
index 00000000000..bd95eb26733
--- /dev/null
+++ b/tests/unit/constraints.txt
@@ -0,0 +1,7 @@
+# Specifically run tests against the oldest versions that we support
+boto3==1.15.0
+botocore==1.18.0
+
+# AWS CLI has `botocore==` dependencies, provide the one that matches botocore
+# to avoid needing to download over a years worth of awscli wheels.
+awscli==1.18.141
diff --git a/tests/unit/mock/loader.py b/tests/unit/mock/loader.py
index 0ee47fbb9f5..00a5841274b 100644
--- a/tests/unit/mock/loader.py
+++ b/tests/unit/mock/loader.py
@@ -46,12 +46,12 @@ def load_from_file(self, path, cache=True, unsafe=False):
# TODO: the real _get_file_contents returns a bytestring, so we actually convert the
# unicode/text it's created with to utf-8
- def _get_file_contents(self, path):
- path = to_text(path)
- if path in self._file_mapping:
- return (to_bytes(self._file_mapping[path]), False)
+ def _get_file_contents(self, file_name):
+ file_name = to_text(file_name)
+ if file_name in self._file_mapping:
+ return (to_bytes(self._file_mapping[file_name]), False)
else:
- raise AnsibleParserError("file not found: %s" % path)
+ raise AnsibleParserError("file not found: %s" % file_name)
def path_exists(self, path):
path = to_text(path)
diff --git a/tests/unit/plugins/modules/test_ec2_win_password.py b/tests/unit/plugins/modules/test_ec2_win_password.py
index c572378ccb1..58082f6cc4a 100644
--- a/tests/unit/plugins/modules/test_ec2_win_password.py
+++ b/tests/unit/plugins/modules/test_ec2_win_password.py
@@ -17,6 +17,8 @@
string_cipher = base64.b64encode(base64_cipher)
'''
+import datetime
+
from ansible.module_utils._text import to_bytes
from ansible.module_utils._text import to_text
from ansible_collections.community.aws.tests.unit.compat.mock import patch
@@ -31,25 +33,37 @@
class TestEc2WinPasswordModule(ModuleTestCase):
- @patch('ansible_collections.community.aws.plugins.modules.ec2_win_password.ec2_connect')
- def test_decryption(self, mock_connect):
- path = fixture_prefix + '/ec2_win_password.pem'
+ # Future: It would be good to generate this data on the fly and use a
+ # temporary certificate and password.
+ PEM_PATH = fixture_prefix + '/ec2_win_password.pem'
+ UNENCRYPTED_DATA = 'Ansible_AWS_EC2_Win_Password'
+ ENCRYPTED_DATA = 'L2k1iFiu/TRrjGr6Rwco/T3C7xkWxUw4+YPYpGGOmP3KDdy3hT1' \
+ '8RvdDJ2i0e+y7wUcH43DwbRYSlkSyALY/nzjSV9R5NChUyVs3W5' \
+ '5oiVuyTKsk0lor8dFJ9z9unq14tScZHvyQ3Nx1ggOtS18S9Pk55q' \
+ 'IaCXfx26ucH76VRho='
+ INSTANCE_ID = 'i-12345'
+
+ @patch('ansible_collections.community.aws.plugins.modules.s3_bucket_notification.AnsibleAWSModule.client')
+ def test_decryption(self, mock_client):
+
+ path = self.PEM_PATH
with open(path, 'r') as f:
pem = to_text(f.read())
with self.assertRaises(AnsibleExitJson) as exec_info:
- set_module_args({'instance_id': 'i-12345',
- 'key_data': pem
+ set_module_args({'instance_id': self.INSTANCE_ID,
+ 'key_data': pem,
})
module = setup_module_object()
- mock_connect().get_password_data.return_value = 'L2k1iFiu/TRrjGr6Rwco/T3C7xkWxUw4+YPYpGGOmP3KDdy3hT1' \
- '8RvdDJ2i0e+y7wUcH43DwbRYSlkSyALY/nzjSV9R5NChUyVs3W5' \
- '5oiVuyTKsk0lor8dFJ9z9unq14tScZHvyQ3Nx1ggOtS18S9Pk55q' \
- 'IaCXfx26ucH76VRho='
+ mock_client().get_password_data.return_value = {
+ 'InstanceId': self.INSTANCE_ID,
+ 'PasswordData': self.ENCRYPTED_DATA,
+ 'Timestamp': datetime.datetime.now(),
+ }
ec2_win_password(module)
self.assertEqual(
exec_info.exception.args[0]['win_password'],
- to_bytes('Ansible_AWS_EC2_Win_Password'),
+ to_bytes(self.UNENCRYPTED_DATA),
)
diff --git a/tests/unit/requirements.txt b/tests/unit/requirements.txt
index 4b10ff777a4..4c5b1ce9282 100644
--- a/tests/unit/requirements.txt
+++ b/tests/unit/requirements.txt
@@ -1,3 +1,7 @@
+# Our code is based on the AWS SDKs
+botocore
+boto3
+boto
+
placebo
-botocore>=1.16.0
-boto3>=1.13.0
+cryptography