summaryrefslogtreecommitdiffstats
path: root/ansible_collections/amazon/aws/tests
diff options
context:
space:
mode:
Diffstat (limited to 'ansible_collections/amazon/aws/tests')
-rw-r--r--ansible_collections/amazon/aws/tests/integration/targets/ec2_ami/tasks/main.yml4
-rw-r--r--ansible_collections/amazon/aws/tests/integration/targets/ec2_security_group/tasks/multi_nested_target.yml18
-rw-r--r--ansible_collections/amazon/aws/tests/integration/targets/inventory_aws_ec2/playbooks/create_inventory_config.yml5
-rw-r--r--ansible_collections/amazon/aws/tests/integration/targets/inventory_aws_ec2/templates/config.ini.j23
-rw-r--r--ansible_collections/amazon/aws/tests/integration/targets/inventory_aws_ec2/templates/inventory_with_template.yml.j22
-rw-r--r--ansible_collections/amazon/aws/tests/integration/targets/s3_object/aliases1
-rw-r--r--ansible_collections/amazon/aws/tests/integration/targets/s3_object/tasks/copy_object.yml71
-rw-r--r--ansible_collections/amazon/aws/tests/integration/targets/s3_object/tasks/main.yml4
-rw-r--r--ansible_collections/amazon/aws/tests/unit/module_utils/iam/test_iam_resource_transforms.py583
-rw-r--r--ansible_collections/amazon/aws/tests/unit/module_utils/transformation/test_boto3_resource_to_ansible_dict.py140
-rw-r--r--ansible_collections/amazon/aws/tests/unit/plugin_utils/inventory/test_inventory_base.py131
-rw-r--r--ansible_collections/amazon/aws/tests/unit/plugins/inventory/test_aws_ec2.py1
12 files changed, 948 insertions, 15 deletions
diff --git a/ansible_collections/amazon/aws/tests/integration/targets/ec2_ami/tasks/main.yml b/ansible_collections/amazon/aws/tests/integration/targets/ec2_ami/tasks/main.yml
index a9289b3c1..267e52abb 100644
--- a/ansible_collections/amazon/aws/tests/integration/targets/ec2_ami/tasks/main.yml
+++ b/ansible_collections/amazon/aws/tests/integration/targets/ec2_ami/tasks/main.yml
@@ -708,8 +708,8 @@
tags:
Name: "{{ ec2_ami_name }}_permissions"
launch_permissions:
- org_arns: [arn:aws:organizations::123456789012:organization/o-123ab4cdef]
- org_unit_arns: [arn:aws:organizations::123456789012:ou/o-123example/ou-1234-5exampld]
+ org_arns: ["arn:aws:organizations::123456789012:organization/o-123ab4cdef"]
+ org_unit_arns: ["arn:aws:organizations::123456789012:ou/o-123example/ou-1234-5exampld"]
register: permissions_update_result
- name: Get ami info
diff --git a/ansible_collections/amazon/aws/tests/integration/targets/ec2_security_group/tasks/multi_nested_target.yml b/ansible_collections/amazon/aws/tests/integration/targets/ec2_security_group/tasks/multi_nested_target.yml
index dcb7ac7bb..02057003a 100644
--- a/ansible_collections/amazon/aws/tests/integration/targets/ec2_security_group/tasks/multi_nested_target.yml
+++ b/ansible_collections/amazon/aws/tests/integration/targets/ec2_security_group/tasks/multi_nested_target.yml
@@ -12,7 +12,7 @@
to_port: 8182
cidr_ipv6:
- 64:ff9b::/96
- - [2620::/32]
+ - ["2620::/32"]
- proto: tcp
ports: 5665
cidr_ip:
@@ -38,7 +38,7 @@
to_port: 8182
cidr_ipv6:
- 64:ff9b::/96
- - [2620::/32]
+ - ["2620::/32"]
- proto: tcp
ports: 5665
cidr_ip:
@@ -66,7 +66,7 @@
to_port: 8182
cidr_ipv6:
- 64:ff9b::/96
- - [2620::/32]
+ - ["2620::/32"]
- proto: tcp
ports: 5665
cidr_ip:
@@ -92,7 +92,7 @@
to_port: 8182
cidr_ipv6:
- 64:ff9b::/96
- - [2620::/32]
+ - ["2620::/32"]
- proto: tcp
ports: 5665
cidr_ip:
@@ -117,7 +117,7 @@
to_port: 8182
cidr_ipv6:
- 64:ff9b::/96
- - [2620::/32]
+ - ["2620::/32"]
- proto: tcp
ports: 5665
cidr_ip:
@@ -142,7 +142,7 @@
to_port: 8182
cidr_ipv6:
- 64:ff9b::/96
- - [2620::/32]
+ - ["2620::/32"]
- proto: tcp
ports: 5665
cidr_ip:
@@ -167,7 +167,7 @@
from_port: 8182
to_port: 8182
cidr_ipv6:
- - [2620::/32, 64:ff9b::/96]
+ - ["2620::/32", "64:ff9b::/96"]
- proto: tcp
ports: 5665
cidr_ip:
@@ -190,8 +190,8 @@
from_port: 8182
to_port: 8182
cidr_ipv6:
- - [2620::/32, 64:ff9b::/96]
- - [2001:DB8:A0B:12F0::1/64]
+ - ["2620::/32", "64:ff9b::/96"]
+ - ["2001:DB8:A0B:12F0::1/64"]
- proto: tcp
ports: 5665
cidr_ip:
diff --git a/ansible_collections/amazon/aws/tests/integration/targets/inventory_aws_ec2/playbooks/create_inventory_config.yml b/ansible_collections/amazon/aws/tests/integration/targets/inventory_aws_ec2/playbooks/create_inventory_config.yml
index 232911d24..282ca43ee 100644
--- a/ansible_collections/amazon/aws/tests/integration/targets/inventory_aws_ec2/playbooks/create_inventory_config.yml
+++ b/ansible_collections/amazon/aws/tests/integration/targets/inventory_aws_ec2/playbooks/create_inventory_config.yml
@@ -9,3 +9,8 @@
ansible.builtin.copy:
dest: ../test.aws_ec2.yml
content: "{{ lookup('template', template_name) }}"
+
+ - name: write ini configuration
+ ansible.builtin.copy:
+ dest: ../config.ini
+ content: "{{ lookup('template', '../templates/config.ini.j2') }}"
diff --git a/ansible_collections/amazon/aws/tests/integration/targets/inventory_aws_ec2/templates/config.ini.j2 b/ansible_collections/amazon/aws/tests/integration/targets/inventory_aws_ec2/templates/config.ini.j2
new file mode 100644
index 000000000..f7320a7fb
--- /dev/null
+++ b/ansible_collections/amazon/aws/tests/integration/targets/inventory_aws_ec2/templates/config.ini.j2
@@ -0,0 +1,3 @@
+[ansible-test]
+
+region = {{ aws_region }} \ No newline at end of file
diff --git a/ansible_collections/amazon/aws/tests/integration/targets/inventory_aws_ec2/templates/inventory_with_template.yml.j2 b/ansible_collections/amazon/aws/tests/integration/targets/inventory_aws_ec2/templates/inventory_with_template.yml.j2
index 44a132c1c..dee7422a9 100644
--- a/ansible_collections/amazon/aws/tests/integration/targets/inventory_aws_ec2/templates/inventory_with_template.yml.j2
+++ b/ansible_collections/amazon/aws/tests/integration/targets/inventory_aws_ec2/templates/inventory_with_template.yml.j2
@@ -5,7 +5,7 @@ secret_key: '{{ aws_secret_key }}'
session_token: '{{ security_token }}'
{% endif %}
regions:
-- '{{ aws_region }}'
+- '{{ '{{ lookup("ansible.builtin.ini", "region", section="ansible-test", file="config.ini") }}' }}'
filters:
tag:Name:
- '{{ resource_prefix }}'
diff --git a/ansible_collections/amazon/aws/tests/integration/targets/s3_object/aliases b/ansible_collections/amazon/aws/tests/integration/targets/s3_object/aliases
index d34fac48d..2a1c5ccb6 100644
--- a/ansible_collections/amazon/aws/tests/integration/targets/s3_object/aliases
+++ b/ansible_collections/amazon/aws/tests/integration/targets/s3_object/aliases
@@ -1,3 +1,4 @@
cloud/aws
aws_s3
s3_object_info
+time=12m
diff --git a/ansible_collections/amazon/aws/tests/integration/targets/s3_object/tasks/copy_object.yml b/ansible_collections/amazon/aws/tests/integration/targets/s3_object/tasks/copy_object.yml
index 9ae36b952..994733d81 100644
--- a/ansible_collections/amazon/aws/tests/integration/targets/s3_object/tasks/copy_object.yml
+++ b/ansible_collections/amazon/aws/tests/integration/targets/s3_object/tasks/copy_object.yml
@@ -1,5 +1,12 @@
---
-- block:
+- vars:
+ withmeta_data:
+ something: exists
+ version: "1.0.2"
+ metacopy_data:
+ name: metacopy
+ version: "1.0.3"
+ block:
- name: define bucket name used for tests
ansible.builtin.set_fact:
copy_bucket:
@@ -142,6 +149,68 @@
- result is not changed
- result.msg == "Key this_key_does_not_exist.txt does not exist in bucket "+copy_bucket.src+"."
+ # Copy with metadata
+ - name: Set fact for bucket name
+ ansible.builtin.set_fact:
+ bucket_name: "{{ copy_bucket.dst }}"
+
+ - name: Create test bucket
+ amazon.aws.s3_bucket:
+ name: "{{ bucket_name }}"
+ state: present
+
+ - name: Create test object
+ amazon.aws.s3_object:
+ bucket: "{{ bucket_name }}"
+ object: nometa
+ mode: put
+ content: "some content"
+
+ - name: Copy and add metadata
+ amazon.aws.s3_object:
+ bucket: "{{ bucket_name }}"
+ object: metacopy
+ mode: copy
+ copy_src:
+ bucket: "{{ bucket_name }}"
+ object: nometa
+ metadata: "{{ metacopy_data }}"
+
+ - name: Create test object with metadata
+ amazon.aws.s3_object:
+ bucket: "{{ bucket_name }}"
+ object: withmeta
+ mode: put
+ content: "another content"
+ metadata: "{{ withmeta_data }}"
+
+ - name: Copy and preserve metadata
+ amazon.aws.s3_object:
+ bucket: "{{ bucket_name }}"
+ object: copywithmeta
+ mode: copy
+ copy_src:
+ bucket: "{{ bucket_name }}"
+ object: withmeta
+
+ - name: Get objects info
+ amazon.aws.s3_object_info:
+ bucket_name: "{{ bucket_name }}"
+ object_name: "{{ item }}"
+ loop:
+ - nometa
+ - metacopy
+ - withmeta
+ - copywithmeta
+ register: obj_info
+
+ - assert:
+ that:
+ - obj_info.results | selectattr('item', 'equalto', 'nometa') | map(attribute='object_info.0.object_data.metadata') | first == {}
+ - obj_info.results | selectattr('item', 'equalto', 'withmeta') | map(attribute='object_info.0.object_data.metadata') | first == withmeta_data
+ - obj_info.results | selectattr('item', 'equalto', 'metacopy') | map(attribute='object_info.0.object_data.metadata') | first == metacopy_data
+ - obj_info.results | selectattr('item', 'equalto', 'copywithmeta') | map(attribute='object_info.0.object_data.metadata') | first == withmeta_data
+
always:
- ansible.builtin.include_tasks: delete_bucket.yml
with_items:
diff --git a/ansible_collections/amazon/aws/tests/integration/targets/s3_object/tasks/main.yml b/ansible_collections/amazon/aws/tests/integration/targets/s3_object/tasks/main.yml
index ed65fe31f..7a8a585de 100644
--- a/ansible_collections/amazon/aws/tests/integration/targets/s3_object/tasks/main.yml
+++ b/ansible_collections/amazon/aws/tests/integration/targets/s3_object/tasks/main.yml
@@ -837,8 +837,6 @@
that:
- binary_files.results[0].stat.checksum == binary_files.results[1].stat.checksum
- - ansible.builtin.include_tasks: copy_object.yml
- - ansible.builtin.include_tasks: copy_object_acl_disabled_bucket.yml
- name: Run tagging tests
block:
# ============================================================
@@ -1074,6 +1072,8 @@
- (result.tags | length) == 0
- ansible.builtin.include_tasks: copy_recursively.yml
+ - ansible.builtin.include_tasks: copy_object.yml
+ - ansible.builtin.include_tasks: copy_object_acl_disabled_bucket.yml
always:
- name: delete temporary files
file:
diff --git a/ansible_collections/amazon/aws/tests/unit/module_utils/iam/test_iam_resource_transforms.py b/ansible_collections/amazon/aws/tests/unit/module_utils/iam/test_iam_resource_transforms.py
new file mode 100644
index 000000000..28090f993
--- /dev/null
+++ b/ansible_collections/amazon/aws/tests/unit/module_utils/iam/test_iam_resource_transforms.py
@@ -0,0 +1,583 @@
+# -*- coding: utf-8 -*-
+
+# Copyright: Contributors to the Ansible project
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+
+import dateutil
+
+from ansible_collections.amazon.aws.plugins.module_utils.iam import normalize_iam_access_key
+from ansible_collections.amazon.aws.plugins.module_utils.iam import normalize_iam_access_keys
+from ansible_collections.amazon.aws.plugins.module_utils.iam import normalize_iam_group
+from ansible_collections.amazon.aws.plugins.module_utils.iam import normalize_iam_instance_profile
+from ansible_collections.amazon.aws.plugins.module_utils.iam import normalize_iam_mfa_device
+from ansible_collections.amazon.aws.plugins.module_utils.iam import normalize_iam_mfa_devices
+from ansible_collections.amazon.aws.plugins.module_utils.iam import normalize_iam_policy
+from ansible_collections.amazon.aws.plugins.module_utils.iam import normalize_iam_role
+from ansible_collections.amazon.aws.plugins.module_utils.iam import normalize_iam_user
+
+# The various normalize_ functions are based upon ..transformation.boto3_resource_to_ansible_dict
+# As such these tests will be relatively light touch.
+
+example_date1_txt = "2020-12-30T00:00:00.000Z"
+example_date2_txt = "2021-04-26T01:23:58.000Z"
+example_date1_iso = "2020-12-30T00:00:00+00:00"
+example_date2_iso = "2021-04-26T01:23:58+00:00"
+example_date1 = dateutil.parser.parse(example_date1_txt)
+example_date2 = dateutil.parser.parse(example_date2_txt)
+
+
+class TestIamResourceToAnsibleDict:
+ def setup_method(self):
+ pass
+
+ def test_normalize_iam_mfa_device(self):
+ INPUT = {
+ "UserName": "ExampleUser",
+ "SerialNumber": "arn:aws:iam::123456789012:mfa/ExampleUser",
+ "EnableDate": example_date1,
+ }
+ OUTPUT = {
+ "user_name": "ExampleUser",
+ "serial_number": "arn:aws:iam::123456789012:mfa/ExampleUser",
+ "enable_date": example_date1_iso,
+ "tags": {},
+ }
+
+ assert OUTPUT == normalize_iam_mfa_device(INPUT)
+
+ def test_normalize_iam_mfa_devices(self):
+ INPUT = [
+ {
+ "UserName": "ExampleUser",
+ "SerialNumber": "arn:aws:iam::123456789012:mfa/ExampleUser",
+ "EnableDate": example_date1,
+ }
+ ]
+ OUTPUT = [
+ {
+ "user_name": "ExampleUser",
+ "serial_number": "arn:aws:iam::123456789012:mfa/ExampleUser",
+ "enable_date": example_date1_iso,
+ "tags": {},
+ }
+ ]
+
+ assert OUTPUT == normalize_iam_mfa_devices(INPUT)
+
+ def test_normalize_iam_user(self):
+ INPUT = {
+ "Path": "/MyPath/",
+ "UserName": "ExampleUser",
+ "UserId": "AIDU12345EXAMPLE12345",
+ "Arn": "arn:aws:iam::123456789012:user/MyPath/ExampleUser",
+ "CreateDate": example_date1,
+ "PasswordLastUsed": example_date2,
+ "PermissionsBoundary": {
+ "PermissionsBoundaryType": "PermissionsBoundaryPolicy",
+ "PermissionsBoundaryArn": "arn:aws:iam::123456789012:policy/ExamplePolicy",
+ },
+ "Tags": [
+ {"Key": "MyKey", "Value": "Example Value"},
+ ],
+ }
+
+ OUTPUT = {
+ "path": "/MyPath/",
+ "user_name": "ExampleUser",
+ "user_id": "AIDU12345EXAMPLE12345",
+ "arn": "arn:aws:iam::123456789012:user/MyPath/ExampleUser",
+ "create_date": example_date1_iso,
+ "password_last_used": example_date2_iso,
+ "permissions_boundary": {
+ "permissions_boundary_type": "PermissionsBoundaryPolicy",
+ "permissions_boundary_arn": "arn:aws:iam::123456789012:policy/ExamplePolicy",
+ },
+ "tags": {"MyKey": "Example Value"},
+ }
+
+ assert OUTPUT == normalize_iam_user(INPUT)
+
+ def test_normalize_iam_policy(self):
+ INPUT = {
+ "PolicyName": "AnsibleIntegratation-CI-ApplicationServices",
+ "PolicyId": "ANPA12345EXAMPLE12345",
+ "Arn": "arn:aws:iam::123456789012:policy/AnsibleIntegratation-CI-ApplicationServices",
+ "Path": "/examples/",
+ "DefaultVersionId": "v6",
+ "AttachmentCount": 2,
+ "PermissionsBoundaryUsageCount": 0,
+ "IsAttachable": True,
+ "CreateDate": example_date1,
+ "UpdateDate": example_date2,
+ "Tags": [
+ {"Key": "MyKey", "Value": "Example Value"},
+ ],
+ }
+
+ OUTPUT = {
+ "policy_name": "AnsibleIntegratation-CI-ApplicationServices",
+ "policy_id": "ANPA12345EXAMPLE12345",
+ "arn": "arn:aws:iam::123456789012:policy/AnsibleIntegratation-CI-ApplicationServices",
+ "path": "/examples/",
+ "default_version_id": "v6",
+ "attachment_count": 2,
+ "permissions_boundary_usage_count": 0,
+ "is_attachable": True,
+ "create_date": example_date1_iso,
+ "update_date": example_date2_iso,
+ "tags": {"MyKey": "Example Value"},
+ }
+
+ assert OUTPUT == normalize_iam_policy(INPUT)
+
+ def test_normalize_iam_group(self):
+ INPUT = {
+ "Users": [
+ {
+ "Path": "/",
+ "UserName": "ansible_test",
+ "UserId": "AIDA12345EXAMPLE12345",
+ "Arn": "arn:aws:iam::123456789012:user/ansible_test",
+ "CreateDate": example_date1,
+ "PasswordLastUsed": example_date2,
+ }
+ ],
+ "Group": {
+ "Path": "/",
+ "GroupName": "ansible-integration-ci",
+ "GroupId": "AGPA01234EXAMPLE01234",
+ "Arn": "arn:aws:iam::123456789012:group/ansible-integration-ci",
+ "CreateDate": example_date1,
+ },
+ "AttachedPolicies": [
+ {
+ "PolicyName": "AnsibleIntegratation-CI-Paas",
+ "PolicyArn": "arn:aws:iam::123456789012:policy/AnsibleIntegratation-CI-Paas",
+ },
+ {
+ "PolicyName": "AnsibleIntegratation-CI-ApplicationServices",
+ "PolicyArn": "arn:aws:iam::123456789012:policy/AnsibleIntegratation-CI-ApplicationServices",
+ },
+ ],
+ }
+
+ OUTPUT = {
+ "users": [
+ {
+ "path": "/",
+ "user_name": "ansible_test",
+ "user_id": "AIDA12345EXAMPLE12345",
+ "arn": "arn:aws:iam::123456789012:user/ansible_test",
+ "create_date": example_date1_iso,
+ "password_last_used": example_date2_iso,
+ }
+ ],
+ "group": {
+ "path": "/",
+ "group_name": "ansible-integration-ci",
+ "group_id": "AGPA01234EXAMPLE01234",
+ "arn": "arn:aws:iam::123456789012:group/ansible-integration-ci",
+ "create_date": example_date1_iso,
+ },
+ "attached_policies": [
+ {
+ "policy_name": "AnsibleIntegratation-CI-Paas",
+ "policy_arn": "arn:aws:iam::123456789012:policy/AnsibleIntegratation-CI-Paas",
+ },
+ {
+ "policy_name": "AnsibleIntegratation-CI-ApplicationServices",
+ "policy_arn": "arn:aws:iam::123456789012:policy/AnsibleIntegratation-CI-ApplicationServices",
+ },
+ ],
+ }
+
+ assert OUTPUT == normalize_iam_group(INPUT)
+
+ def test_normalize_access_key(self):
+ INPUT = {
+ "UserName": "ansible_test",
+ "AccessKeyId": "AKIA12345EXAMPLE1234",
+ "Status": "Active",
+ "CreateDate": example_date1,
+ }
+
+ OUTPUT = {
+ "user_name": "ansible_test",
+ "access_key_id": "AKIA12345EXAMPLE1234",
+ "status": "Active",
+ "create_date": example_date1_iso,
+ }
+
+ assert OUTPUT == normalize_iam_access_key(INPUT)
+
+ def test_normalize_access_keys(self):
+ INPUT = [
+ {
+ "UserName": "ansible_test",
+ "AccessKeyId": "AKIA12345EXAMPLE1234",
+ "Status": "Active",
+ "CreateDate": example_date1,
+ },
+ {
+ "UserName": "ansible_test",
+ "AccessKeyId": "AKIA01234EXAMPLE4321",
+ "Status": "Active",
+ "CreateDate": example_date2,
+ },
+ ]
+
+ OUTPUT = [
+ {
+ "access_key_id": "AKIA12345EXAMPLE1234",
+ "create_date": example_date1_iso,
+ "status": "Active",
+ "user_name": "ansible_test",
+ },
+ {
+ "access_key_id": "AKIA01234EXAMPLE4321",
+ "create_date": example_date2_iso,
+ "status": "Active",
+ "user_name": "ansible_test",
+ },
+ ]
+
+ assert OUTPUT == normalize_iam_access_keys(INPUT)
+
+ # Switch order to test that they're sorted by Creation Date
+ INPUT = [
+ {
+ "UserName": "ansible_test",
+ "AccessKeyId": "AKIA12345EXAMPLE1234",
+ "Status": "Active",
+ "CreateDate": example_date2,
+ },
+ {
+ "UserName": "ansible_test",
+ "AccessKeyId": "AKIA01234EXAMPLE4321",
+ "Status": "Active",
+ "CreateDate": example_date1,
+ },
+ ]
+
+ OUTPUT = [
+ {
+ "access_key_id": "AKIA01234EXAMPLE4321",
+ "create_date": example_date1_iso,
+ "status": "Active",
+ "user_name": "ansible_test",
+ },
+ {
+ "access_key_id": "AKIA12345EXAMPLE1234",
+ "create_date": example_date2_iso,
+ "status": "Active",
+ "user_name": "ansible_test",
+ },
+ ]
+
+ assert OUTPUT == normalize_iam_access_keys(INPUT)
+
+ def test_normalize_role(self):
+ INPUT = {
+ "Arn": "arn:aws:iam::123456789012:role/ansible-test-76640355",
+ "AssumeRolePolicyDocument": {
+ "Statement": [
+ {"Action": "sts:AssumeRole", "Effect": "Deny", "Principal": {"Service": "ec2.amazonaws.com"}}
+ ],
+ "Version": "2012-10-17",
+ },
+ "CreateDate": example_date1,
+ "Description": "Ansible Test Role (updated) ansible-test-76640355",
+ "InlinePolicies": ["inline-policy-a", "inline-policy-b"],
+ "InstanceProfiles": [
+ {
+ "Arn": "arn:aws:iam::123456789012:instance-profile/ansible-test-76640355",
+ "CreateDate": example_date2,
+ "InstanceProfileId": "AIPA12345EXAMPLE12345",
+ "InstanceProfileName": "ansible-test-76640355",
+ "Path": "/",
+ "Roles": [
+ {
+ "Arn": "arn:aws:iam::123456789012:role/ansible-test-76640355",
+ "AssumeRolePolicyDocument": {
+ "Statement": [
+ {
+ "Action": "sts:AssumeRole",
+ "Effect": "Deny",
+ "Principal": {"Service": "ec2.amazonaws.com"},
+ }
+ ],
+ "Version": "2012-10-17",
+ },
+ "CreateDate": example_date1,
+ "Path": "/",
+ "RoleId": "AROA12345EXAMPLE12345",
+ "RoleName": "ansible-test-76640355",
+ # XXX Bug in iam_role_info - Tags should have been in here.
+ "Tags": [{"Key": "TagB", "Value": "ValueB"}],
+ }
+ ],
+ "Tags": [{"Key": "TagA", "Value": "Value A"}],
+ }
+ ],
+ "ManagedPolicies": [
+ {
+ "PolicyArn": "arn:aws:iam::123456789012:policy/ansible-test-76640355",
+ "PolicyName": "ansible-test-76640355",
+ }
+ ],
+ "MaxSessionDuration": 43200,
+ "Path": "/",
+ "RoleId": "AROA12345EXAMPLE12345",
+ "RoleLastUsed": {},
+ "RoleName": "ansible-test-76640355",
+ "Tags": [{"Key": "TagB", "Value": "ValueB"}],
+ }
+
+ OUTPUT = {
+ "arn": "arn:aws:iam::123456789012:role/ansible-test-76640355",
+ "assume_role_policy_document": {
+ "Statement": [
+ {"Action": "sts:AssumeRole", "Effect": "Deny", "Principal": {"Service": "ec2.amazonaws.com"}}
+ ],
+ "Version": "2012-10-17",
+ },
+ "create_date": example_date1_iso,
+ "description": "Ansible Test Role (updated) ansible-test-76640355",
+ "inline_policies": ["inline-policy-a", "inline-policy-b"],
+ "instance_profiles": [
+ {
+ "arn": "arn:aws:iam::123456789012:instance-profile/ansible-test-76640355",
+ "create_date": example_date2_iso,
+ "instance_profile_id": "AIPA12345EXAMPLE12345",
+ "instance_profile_name": "ansible-test-76640355",
+ "path": "/",
+ "roles": [
+ {
+ "arn": "arn:aws:iam::123456789012:role/ansible-test-76640355",
+ "assume_role_policy_document": {
+ "Statement": [
+ {
+ "Action": "sts:AssumeRole",
+ "Effect": "Deny",
+ "Principal": {"Service": "ec2.amazonaws.com"},
+ }
+ ],
+ "Version": "2012-10-17",
+ },
+ "create_date": example_date1_iso,
+ "path": "/",
+ "role_id": "AROA12345EXAMPLE12345",
+ "role_name": "ansible-test-76640355",
+ "tags": {"TagB": "ValueB"},
+ }
+ ],
+ "tags": {"TagA": "Value A"},
+ }
+ ],
+ "managed_policies": [
+ {
+ "policy_arn": "arn:aws:iam::123456789012:policy/ansible-test-76640355",
+ "policy_name": "ansible-test-76640355",
+ }
+ ],
+ "max_session_duration": 43200,
+ "path": "/",
+ "role_id": "AROA12345EXAMPLE12345",
+ "role_last_used": {},
+ "role_name": "ansible-test-76640355",
+ "tags": {"TagB": "ValueB"},
+ }
+
+ assert OUTPUT == normalize_iam_role(INPUT)
+
+ def test_normalize_role_compat(self):
+ INPUT = {
+ "Arn": "arn:aws:iam::123456789012:role/ansible-test-76640355",
+ "AssumeRolePolicyDocument": {
+ "Statement": [
+ {"Action": "sts:AssumeRole", "Effect": "Deny", "Principal": {"Service": "ec2.amazonaws.com"}}
+ ],
+ "Version": "2012-10-17",
+ },
+ "CreateDate": example_date1,
+ "Description": "Ansible Test Role (updated) ansible-test-76640355",
+ "InlinePolicies": ["inline-policy-a", "inline-policy-b"],
+ "InstanceProfiles": [
+ {
+ "Arn": "arn:aws:iam::123456789012:instance-profile/ansible-test-76640355",
+ "CreateDate": example_date2,
+ "InstanceProfileId": "AIPA12345EXAMPLE12345",
+ "InstanceProfileName": "ansible-test-76640355",
+ "Path": "/",
+ "Roles": [
+ {
+ "Arn": "arn:aws:iam::123456789012:role/ansible-test-76640355",
+ "AssumeRolePolicyDocument": {
+ "Statement": [
+ {
+ "Action": "sts:AssumeRole",
+ "Effect": "Deny",
+ "Principal": {"Service": "ec2.amazonaws.com"},
+ }
+ ],
+ "Version": "2012-10-17",
+ },
+ "CreateDate": example_date1,
+ "Path": "/",
+ "RoleId": "AROA12345EXAMPLE12345",
+ "RoleName": "ansible-test-76640355",
+ # XXX Bug in iam_role_info - Tags should have been in here.
+ "Tags": [{"Key": "TagB", "Value": "ValueB"}],
+ }
+ ],
+ "Tags": [{"Key": "TagA", "Value": "Value A"}],
+ }
+ ],
+ "ManagedPolicies": [
+ {
+ "PolicyArn": "arn:aws:iam::123456789012:policy/ansible-test-76640355",
+ "PolicyName": "ansible-test-76640355",
+ }
+ ],
+ "MaxSessionDuration": 43200,
+ "Path": "/",
+ "RoleId": "AROA12345EXAMPLE12345",
+ "RoleLastUsed": {},
+ "RoleName": "ansible-test-76640355",
+ "Tags": [{"Key": "TagB", "Value": "ValueB"}],
+ }
+
+ OUTPUT = {
+ "arn": "arn:aws:iam::123456789012:role/ansible-test-76640355",
+ "assume_role_policy_document": {
+ "statement": [
+ {"action": "sts:AssumeRole", "effect": "Deny", "principal": {"service": "ec2.amazonaws.com"}}
+ ],
+ "version": "2012-10-17",
+ },
+ "assume_role_policy_document_raw": {
+ "Statement": [
+ {"Action": "sts:AssumeRole", "Effect": "Deny", "Principal": {"Service": "ec2.amazonaws.com"}}
+ ],
+ "Version": "2012-10-17",
+ },
+ "create_date": example_date1_iso,
+ "description": "Ansible Test Role (updated) ansible-test-76640355",
+ "inline_policies": ["inline-policy-a", "inline-policy-b"],
+ "instance_profiles": [
+ {
+ "arn": "arn:aws:iam::123456789012:instance-profile/ansible-test-76640355",
+ "create_date": example_date2_iso,
+ "instance_profile_id": "AIPA12345EXAMPLE12345",
+ "instance_profile_name": "ansible-test-76640355",
+ "path": "/",
+ "roles": [
+ {
+ "arn": "arn:aws:iam::123456789012:role/ansible-test-76640355",
+ "assume_role_policy_document": {
+ "Statement": [
+ {
+ "Action": "sts:AssumeRole",
+ "Effect": "Deny",
+ "Principal": {"Service": "ec2.amazonaws.com"},
+ }
+ ],
+ "Version": "2012-10-17",
+ },
+ "create_date": example_date1_iso,
+ "path": "/",
+ "role_id": "AROA12345EXAMPLE12345",
+ "role_name": "ansible-test-76640355",
+ "tags": {"TagB": "ValueB"},
+ }
+ ],
+ "tags": {"TagA": "Value A"},
+ }
+ ],
+ "managed_policies": [
+ {
+ "policy_arn": "arn:aws:iam::123456789012:policy/ansible-test-76640355",
+ "policy_name": "ansible-test-76640355",
+ }
+ ],
+ "max_session_duration": 43200,
+ "path": "/",
+ "role_id": "AROA12345EXAMPLE12345",
+ "role_last_used": {},
+ "role_name": "ansible-test-76640355",
+ "tags": {"TagB": "ValueB"},
+ }
+
+ assert OUTPUT == normalize_iam_role(INPUT, _v7_compat=True)
+
+ def test_normalize_instance_profile(self):
+ INPUT = {
+ "Arn": "arn:aws:iam::123456789012:instance-profile/ansible-test-40050922/ansible-test-40050922",
+ "CreateDate": example_date1,
+ "InstanceProfileId": "AIPA12345EXAMPLE12345",
+ "InstanceProfileName": "ansible-test-40050922",
+ "Path": "/ansible-test-40050922/",
+ "Roles": [
+ {
+ "Arn": "arn:aws:iam::123456789012:role/ansible-test-40050922/ansible-test-40050922",
+ "AssumeRolePolicyDocument": {
+ "Statement": [
+ {
+ "Action": "sts:AssumeRole",
+ "Effect": "Deny",
+ "Principal": {"Service": "ec2.amazonaws.com"},
+ }
+ ],
+ "Version": "2012-10-17",
+ },
+ "CreateDate": example_date2,
+ "Path": "/ansible-test-40050922/",
+ "RoleId": "AROA12345EXAMPLE12345",
+ "RoleName": "ansible-test-40050922",
+ "Tags": [{"Key": "TagC", "Value": "ValueC"}],
+ }
+ ],
+ "Tags": [
+ {"Key": "Key with Spaces", "Value": "Value with spaces"},
+ {"Key": "snake_case_key", "Value": "snake_case_value"},
+ {"Key": "CamelCaseKey", "Value": "CamelCaseValue"},
+ {"Key": "pascalCaseKey", "Value": "pascalCaseValue"},
+ ],
+ }
+
+ OUTPUT = {
+ "arn": "arn:aws:iam::123456789012:instance-profile/ansible-test-40050922/ansible-test-40050922",
+ "create_date": "2020-12-30T00:00:00+00:00",
+ "instance_profile_id": "AIPA12345EXAMPLE12345",
+ "instance_profile_name": "ansible-test-40050922",
+ "path": "/ansible-test-40050922/",
+ "roles": [
+ {
+ "arn": "arn:aws:iam::123456789012:role/ansible-test-40050922/ansible-test-40050922",
+ "assume_role_policy_document": {
+ "Statement": [
+ {
+ "Action": "sts:AssumeRole",
+ "Effect": "Deny",
+ "Principal": {"Service": "ec2.amazonaws.com"},
+ }
+ ],
+ "Version": "2012-10-17",
+ },
+ "create_date": "2021-04-26T01:23:58+00:00",
+ "path": "/ansible-test-40050922/",
+ "role_id": "AROA12345EXAMPLE12345",
+ "role_name": "ansible-test-40050922",
+ "tags": {"TagC": "ValueC"},
+ }
+ ],
+ "tags": {
+ "CamelCaseKey": "CamelCaseValue",
+ "Key with Spaces": "Value with spaces",
+ "pascalCaseKey": "pascalCaseValue",
+ "snake_case_key": "snake_case_value",
+ },
+ }
+
+ assert OUTPUT == normalize_iam_instance_profile(INPUT)
diff --git a/ansible_collections/amazon/aws/tests/unit/module_utils/transformation/test_boto3_resource_to_ansible_dict.py b/ansible_collections/amazon/aws/tests/unit/module_utils/transformation/test_boto3_resource_to_ansible_dict.py
new file mode 100644
index 000000000..89a0a837c
--- /dev/null
+++ b/ansible_collections/amazon/aws/tests/unit/module_utils/transformation/test_boto3_resource_to_ansible_dict.py
@@ -0,0 +1,140 @@
+# (c) 2017 Red Hat Inc.
+#
+# 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 copy import deepcopy
+from unittest.mock import sentinel
+
+import dateutil
+import pytest
+
+from ansible.module_utils.common.dict_transformations import camel_dict_to_snake_dict
+
+from ansible_collections.amazon.aws.plugins.module_utils.transformation import boto3_resource_to_ansible_dict
+
+example_date_txt = "2020-12-30T00:00:00.000Z"
+example_date_iso = "2020-12-30T00:00:00+00:00"
+example_date = dateutil.parser.parse(example_date_txt)
+
+EXAMPLE_BOTO3 = [
+ None,
+ {},
+ {"ExampleDate": example_date},
+ {"ExampleTxtDate": example_date_txt},
+ {"Tags": [{"Key": "MyKey", "Value": "MyValue"}, {"Key": "Normal case", "Value": "Normal Value"}]},
+ {
+ "Name": "ExampleResource",
+ "ExampleDate": example_date,
+ "Tags": [{"Key": "MyKey", "Value": "MyValue"}, {"Key": "Normal case", "Value": "Normal Value"}],
+ },
+ {"ExampleNested": {"ExampleKey": "Example Value"}},
+]
+
+EXAMPLE_DICT = [
+ None,
+ {},
+ {"example_date": example_date_iso, "tags": {}},
+ {"example_txt_date": example_date_txt, "tags": {}},
+ {"tags": {"MyKey": "MyValue", "Normal case": "Normal Value"}},
+ {
+ "name": "ExampleResource",
+ "example_date": example_date_iso,
+ "tags": {"MyKey": "MyValue", "Normal case": "Normal Value"},
+ },
+ {"example_nested": {"example_key": "Example Value"}, "tags": {}},
+]
+
+TEST_DATA = zip(EXAMPLE_BOTO3, EXAMPLE_DICT)
+
+NESTED_DATA = {"sentinal": sentinel.MY_VALUE}
+
+
+def do_transform_nested(resource):
+ return {"sentinal": sentinel.MY_VALUE}
+
+
+class TestBoto3ResourceToAnsibleDict:
+ def setup_method(self):
+ pass
+
+ @pytest.mark.parametrize("input_params, output_params", deepcopy(TEST_DATA))
+ def test_default_conversion(self, input_params, output_params):
+ # Test default behaviour
+ assert boto3_resource_to_ansible_dict(input_params) == output_params
+
+ @pytest.mark.parametrize("input_params, output_params", deepcopy(TEST_DATA))
+ def test_normalize(self, input_params, output_params):
+ # Test with normalize explicitly enabled
+ assert boto3_resource_to_ansible_dict(input_params, normalize=True) == output_params
+
+ @pytest.mark.parametrize("input_params, output_params", deepcopy(TEST_DATA))
+ def test_no_normalize(self, input_params, output_params):
+ # Test with normalize explicitly disabled
+ expected_value = deepcopy(output_params)
+ if input_params and "ExampleDate" in input_params:
+ expected_value["example_date"] = example_date
+ assert expected_value == boto3_resource_to_ansible_dict(input_params, normalize=False)
+
+ @pytest.mark.parametrize("input_params, output_params", deepcopy(TEST_DATA))
+ def test_no_skip(self, input_params, output_params):
+ # Test with ignore_list explicitly set to []
+ assert boto3_resource_to_ansible_dict(input_params, ignore_list=[]) == output_params
+ assert boto3_resource_to_ansible_dict(input_params, ignore_list=["NotUsed"]) == output_params
+
+ @pytest.mark.parametrize("input_params, output_params", deepcopy(TEST_DATA))
+ def test_skip(self, input_params, output_params):
+ # Test with ignore_list explicitly set
+ expected_value = deepcopy(output_params)
+ if input_params and "ExampleNested" in input_params:
+ expected_value["example_nested"] = input_params["ExampleNested"]
+ assert expected_value == boto3_resource_to_ansible_dict(input_params, ignore_list=["ExampleNested"])
+ assert expected_value == boto3_resource_to_ansible_dict(input_params, ignore_list=["NotUsed", "ExampleNested"])
+ assert expected_value == boto3_resource_to_ansible_dict(input_params, ignore_list=["ExampleNested", "NotUsed"])
+
+ @pytest.mark.parametrize("input_params, output_params", deepcopy(TEST_DATA))
+ def test_tags(self, input_params, output_params):
+ # Test with transform_tags explicitly enabled
+ assert boto3_resource_to_ansible_dict(input_params, transform_tags=True) == output_params
+
+ @pytest.mark.parametrize("input_params, output_params", deepcopy(TEST_DATA))
+ def test_no_tags(self, input_params, output_params):
+ # Test with transform_tags explicitly disabled
+ expected_value = deepcopy(output_params)
+ if input_params and "Tags" in input_params:
+ camel_tags = camel_dict_to_snake_dict({"tags": input_params["Tags"]})
+ expected_value.update(camel_tags)
+ assert expected_value == boto3_resource_to_ansible_dict(input_params, transform_tags=False)
+
+ @pytest.mark.parametrize("input_params, output_params", deepcopy(TEST_DATA))
+ def test_no_nested(self, input_params, output_params):
+ # Test with transform_nested explicitly set to an empty dictionary
+ assert boto3_resource_to_ansible_dict(input_params, nested_transforms={}) == output_params
+
+ @pytest.mark.parametrize("input_params, output_params", deepcopy(TEST_DATA))
+ def test_nested(self, input_params, output_params):
+ # Test with a custom transformation of nested resources
+ transform_map = {"ExampleNested": do_transform_nested}
+ expected_value = deepcopy(output_params)
+
+ actual_value = boto3_resource_to_ansible_dict(input_params, nested_transforms=transform_map)
+
+ if input_params and "ExampleNested" in input_params:
+ assert actual_value["example_nested"] == NESTED_DATA
+ del actual_value["example_nested"]
+ del expected_value["example_nested"]
+
+ assert expected_value == actual_value
+
+ @pytest.mark.parametrize("input_params, output_params", deepcopy(TEST_DATA))
+ def test_force_tags(self, input_params, output_params):
+ # Test with force_tags explicitly enabled
+ assert boto3_resource_to_ansible_dict(input_params, force_tags=True) == output_params
+
+ @pytest.mark.parametrize("input_params, output_params", deepcopy(TEST_DATA))
+ def test_no_force_tags(self, input_params, output_params):
+ # Test with force_tags explicitly enabled
+ expected_value = deepcopy(output_params)
+ if input_params and "Tags" not in input_params:
+ del expected_value["tags"]
+ assert boto3_resource_to_ansible_dict(input_params, force_tags=False) == expected_value
diff --git a/ansible_collections/amazon/aws/tests/unit/plugin_utils/inventory/test_inventory_base.py b/ansible_collections/amazon/aws/tests/unit/plugin_utils/inventory/test_inventory_base.py
index 32eb3f7ab..4da5792a8 100644
--- a/ansible_collections/amazon/aws/tests/unit/plugin_utils/inventory/test_inventory_base.py
+++ b/ansible_collections/amazon/aws/tests/unit/plugin_utils/inventory/test_inventory_base.py
@@ -3,6 +3,7 @@
# This file is part of Ansible
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+import re
from unittest.mock import MagicMock
from unittest.mock import call
from unittest.mock import patch
@@ -11,6 +12,8 @@ from unittest.mock import sentinel
import pytest
import ansible.plugins.inventory as base_inventory
+from ansible.errors import AnsibleError
+from ansible.module_utils.six import string_types
import ansible_collections.amazon.aws.plugins.plugin_utils.inventory as utils_inventory
@@ -65,3 +68,131 @@ def test_inventory_verify_file(monkeypatch, filename, result):
assert inventory_plugin.verify_file(filename) is result
base_verify.return_value = False
assert inventory_plugin.verify_file(filename) is False
+
+
+class AwsUnitTestTemplar:
+ def __init__(self, config):
+ self.config = config
+
+ def is_template_string(self, key):
+ m = re.findall("{{([ ]*[a-zA-Z0-9_]*[ ]*)}}", key)
+ return bool(m)
+
+ def is_template(self, data):
+ if isinstance(data, string_types):
+ return self.is_template_string(data)
+ elif isinstance(data, (list, tuple)):
+ for v in data:
+ if self.is_template(v):
+ return True
+ elif isinstance(data, dict):
+ for k in data:
+ if self.is_template(k) or self.is_template(data[k]):
+ return True
+ return False
+
+ def template(self, variable, disable_lookups):
+ for k, v in self.config.items():
+ variable = re.sub("{{([ ]*%s[ ]*)}}" % k, v, variable)
+ if self.is_template_string(variable):
+ m = re.findall("{{([ ]*[a-zA-Z0-9_]*[ ]*)}}", variable)
+ raise AnsibleError(f"Missing variables: {','.join([k.replace(' ', '') for k in m])}")
+ return variable
+
+
+@pytest.fixture
+def aws_inventory_base():
+ inventory = utils_inventory.AWSInventoryBase()
+ inventory._options = {}
+ inventory.templar = None
+ return inventory
+
+
+@pytest.mark.parametrize(
+ "option,value",
+ [
+ ("access_key", "amazon_ansible_access_key_001"),
+ ("secret_key", "amazon_ansible_secret_key_890"),
+ ("session_token", None),
+ ("use_ssm_inventory", False),
+ ("This_field_is_undefined", None),
+ ("assume_role_arn", "arn:aws:iam::123456789012:role/ansible-test-inventory"),
+ ("region", "us-east-2"),
+ ],
+)
+def test_inventory_get_options_without_templar(aws_inventory_base, mocker, option, value):
+ inventory_options = {
+ "access_key": "amazon_ansible_access_key_001",
+ "secret_key": "amazon_ansible_secret_key_890",
+ "endpoint": "http//ansible.amazon.com",
+ "assume_role_arn": "arn:aws:iam::123456789012:role/ansible-test-inventory",
+ "region": "us-east-2",
+ "use_ssm_inventory": False,
+ }
+ aws_inventory_base._options = inventory_options
+
+ super_get_options_patch = mocker.patch(
+ "ansible_collections.amazon.aws.plugins.plugin_utils.inventory.BaseInventoryPlugin.get_options"
+ )
+ super_get_options_patch.return_value = aws_inventory_base._options
+
+ options = aws_inventory_base.get_options()
+ assert value == options.get(option)
+
+
+@pytest.mark.parametrize(
+ "option,value,error",
+ [
+ ("access_key", "amazon_ansible_access_key_001", None),
+ ("session_token", None, None),
+ ("use_ssm_inventory", "{{ aws_inventory_use_ssm }}", None),
+ ("This_field_is_undefined", None, None),
+ ("region", "us-east-1", None),
+ ("profile", None, "Missing variables: ansible_version"),
+ ],
+)
+def test_inventory_get_options_with_templar(aws_inventory_base, mocker, option, value, error):
+ inventory_options = {
+ "access_key": "amazon_ansible_access_key_001",
+ "profile": "ansbile_{{ ansible_os }}_{{ ansible_version }}",
+ "endpoint": "{{ aws_endpoint }}",
+ "region": "{{ aws_region_country }}-east-{{ aws_region_id }}",
+ "use_ssm_inventory": "{{ aws_inventory_use_ssm }}",
+ }
+ aws_inventory_base._options = inventory_options
+ templar_config = {
+ "ansible_os": "RedHat",
+ "aws_region_country": "us",
+ "aws_region_id": "1",
+ "aws_endpoint": "http//ansible.amazon.com",
+ }
+ aws_inventory_base.templar = AwsUnitTestTemplar(templar_config)
+
+ super_get_options_patch = mocker.patch(
+ "ansible_collections.amazon.aws.plugins.plugin_utils.inventory.BaseInventoryPlugin.get_options"
+ )
+ super_get_options_patch.return_value = aws_inventory_base._options
+
+ super_get_option_patch = mocker.patch(
+ "ansible_collections.amazon.aws.plugins.plugin_utils.inventory.BaseInventoryPlugin.get_option"
+ )
+ super_get_option_patch.side_effect = lambda x, hostvars=None: aws_inventory_base._options.get(x)
+
+ if error:
+ # test using get_options()
+ with pytest.raises(AnsibleError) as exc:
+ options = aws_inventory_base.get_options()
+ options.get(option)
+ assert error == str(exc.value)
+
+ # test using get_option()
+ with pytest.raises(AnsibleError) as exc:
+ aws_inventory_base.get_option(option)
+ assert error == str(exc.value)
+ else:
+ # test using get_options()
+ options = aws_inventory_base.get_options()
+ assert value == options.get(option)
+
+ # test using get_option()
+ assert value == aws_inventory_base.get_option(option)
diff --git a/ansible_collections/amazon/aws/tests/unit/plugins/inventory/test_aws_ec2.py b/ansible_collections/amazon/aws/tests/unit/plugins/inventory/test_aws_ec2.py
index 8cced1662..e33b78c51 100644
--- a/ansible_collections/amazon/aws/tests/unit/plugins/inventory/test_aws_ec2.py
+++ b/ansible_collections/amazon/aws/tests/unit/plugins/inventory/test_aws_ec2.py
@@ -240,6 +240,7 @@ def test_get_tag_hostname(preference, instance, expected):
)
def test_inventory_build_include_filters(inventory, _options, expected):
inventory._options = _options
+ inventory.templar = None
assert inventory.build_include_filters() == expected