Repository: ansible-collections/amazon.aws

Issue:
aws_ec2 and aws_rds inventories: An option to prefix hostvar names to prevent accidental collisions
### Summary

aws_ec2 and aws_rds inventory plugins 'pollute' hostvars with key-values which ansible has not control over. There are two problems with this:
- there is no easy way to know which variables come from aws and which from static inventories
- aws variables may accidentally overlap with other variables and this is very difficult to catch and debug

It would be useful to have an option of enabling prefixes for host variable names coming from AWS (e.g. `aws_ec2_state` instead of `state`).

### Issue Type

Feature Idea

### Component Name

aws_ec2 inventory (plugins/inventory/aws_ec2.py), aws_rds inventory (plugins/inventory/aws_rds.py)

### Additional Information

### Examples

#### EC2 instance variables without prefixes (without the proposed change)
```
[
  "ami_launch_index",
  "ansible_check_mode",
  "ansible_config_file",
  "ansible_dependent_role_names",
  "ansible_diff_mode",
  "ansible_facts",
  "ansible_forks",
  "ansible_host",
  "ansible_inventory_sources",
  "ansible_play_batch",
  "ansible_play_hosts",
  "ansible_play_hosts_all",
  "ansible_play_name",
  "ansible_play_role_names",
  "ansible_playbook_python",
  "ansible_role_names",
  "ansible_verbosity",
  "ansible_version",
  "architecture",
  "block_device_mappings",
  "capacity_reservation_specification",
  "client_token",
  "cpu_options",
  "ebs_optimized",
  "ena_support",
  "enclave_options",
  "environment",
  "group_names",
  "groups",
  "hibernation_options",
  "hostvars",
  "hypervisor",
  "iam_instance_profile",
  "image_id",
  "instance_id",
  "instance_type",
  "inventory_dir",
  "inventory_file",
  "inventory_hostname",
  "inventory_hostname_short",
  "key_name",
  "launch_time",
  "metadata_options",
  "monitoring",
  "network_interfaces",
  "omit",
  "owner_id",
  "placement",
  "play_hosts",
  "playbook_dir",
  "private_dns_name",
  "private_ip_address",
  "product_codes",
  "public_dns_name",
  "requester_id",
  "reservation_id",
  "role_names",
  "root_device_name",
  "root_device_type",
  "security_groups",
  "source_dest_check",
  "state",
  "state_transition_reason",
  "subnet_id",
  "tags",
  "virtualization_type",
  "vpc_id"
]
```
#### EC2 instance variables with prefixes (with the proposed change)
```
[
  "ansible_check_mode",
  "ansible_config_file",
  "ansible_dependent_role_names",
  "ansible_diff_mode",
  "ansible_facts",
  "ansible_forks",
  "ansible_host",
  "ansible_inventory_sources",
  "ansible_play_batch",
  "ansible_play_hosts",
  "ansible_play_hosts_all",
  "ansible_play_name",
  "ansible_play_role_names",
  "ansible_playbook_python",
  "ansible_role_names",
  "ansible_verbosity",
  "ansible_version",
  "aws_ec2_ami_launch_index",
  "aws_ec2_architecture",
  "aws_ec2_block_device_mappings",
  "aws_ec2_capacity_reservation_specification",
  "aws_ec2_client_token",
  "aws_ec2_cpu_options",
  "aws_ec2_ebs_optimized",
  "aws_ec2_ena_support",
  "aws_ec2_enclave_options",
  "aws_ec2_hibernation_options",
  "aws_ec2_hypervisor",
  "aws_ec2_iam_instance_profile",
  "aws_ec2_image_id",
  "aws_ec2_instance_id",
  "aws_ec2_instance_type",
  "aws_ec2_key_name",
  "aws_ec2_launch_time",
  "aws_ec2_metadata_options",
  "aws_ec2_monitoring",
  "aws_ec2_network_interfaces",
  "aws_ec2_owner_id",
  "aws_ec2_placement",
  "aws_ec2_private_dns_name",
  "aws_ec2_private_ip_address",
  "aws_ec2_product_codes",
  "aws_ec2_public_dns_name",
  "aws_ec2_requester_id",
  "aws_ec2_reservation_id",
  "aws_ec2_root_device_name",
  "aws_ec2_root_device_type",
  "aws_ec2_security_groups",
  "aws_ec2_source_dest_check",
  "aws_ec2_state",
  "aws_ec2_state_transition_reason",
  "aws_ec2_subnet_id",
  "aws_ec2_tags",
  "aws_ec2_virtualization_type",
  "aws_ec2_vpc_id",
  "environment",
  "group_names",
  "groups",
  "hostvars",
  "inventory_dir",
  "inventory_file",
  "inventory_hostname",
  "inventory_hostname_short",
  "omit",
  "play_hosts",
  "playbook_dir",
  "private_ip_address",
  "role_names"
]
```
#### RDS instance variables without prefixes (without the proposed change)
```
[
  "allocated_storage",
  "ansible_check_mode",
  "ansible_config_file",
  "ansible_dependent_role_names",
  "ansible_diff_mode",
  "ansible_facts",
  "ansible_forks",
  "ansible_inventory_sources",
  "ansible_play_batch",
  "ansible_play_hosts",
  "ansible_play_hosts_all",
  "ansible_play_name",
  "ansible_play_role_names",
  "ansible_playbook_python",
  "ansible_role_names",
  "ansible_verbosity",
  "ansible_version",
  "associated_roles",
  "auto_minor_version_upgrade",
  "availability_zone",
  "backup_retention_period",
  "ca_certificate_identifier",
  "copy_tags_to_snapshot",
  "customer_owned_ip_enabled",
  "db_cluster_identifier",
  "db_instance_arn",
  "db_instance_class",
  "db_instance_identifier",
  "db_instance_port",
  "db_instance_status",
  "db_parameter_groups",
  "db_security_groups",
  "db_subnet_group",
  "dbi_resource_id",
  "deletion_protection",
  "domain_memberships",
  "enabled_cloudwatch_logs_exports",
  "endpoint",
  "engine",
  "engine_version",
  "enhanced_monitoring_resource_arn",
  "environment",
  "group_names",
  "groups",
  "hostvars",
  "iam_database_authentication_enabled",
  "instance_create_time",
  "inventory_dir",
  "inventory_file",
  "inventory_hostname",
  "inventory_hostname_short",
  "kms_key_id",
  "license_model",
  "master_username",
  "monitoring_interval",
  "monitoring_role_arn",
  "multi_az",
  "omit",
  "option_group_memberships",
  "pending_modified_values",
  "performance_insights_enabled",
  "play_hosts",
  "playbook_dir",
  "preferred_backup_window",
  "preferred_maintenance_window",
  "private_host",
  "promotion_tier",
  "publicly_accessible",
  "read_replica_db_instance_identifiers",
  "region",
  "role_names",
  "storage_encrypted",
  "storage_type",
  "tag_list",
  "tags",
  "vpc_security_groups"
]
```
#### RDS instance variables with prefixes (with the proposed change)
```
[
  "ansible_check_mode",
  "ansible_config_file",
  "ansible_dependent_role_names",
  "ansible_diff_mode",
  "ansible_facts",
  "ansible_forks",
  "ansible_inventory_sources",
  "ansible_play_batch",
  "ansible_play_hosts",
  "ansible_play_hosts_all",
  "ansible_play_name",
  "ansible_play_role_names",
  "ansible_playbook_python",
  "ansible_role_names",
  "ansible_verbosity",
  "ansible_version",
  "aws_rds_allocated_storage",
  "aws_rds_associated_roles",
  "aws_rds_auto_minor_version_upgrade",
  "aws_rds_availability_zone",
  "aws_rds_backup_retention_period",
  "aws_rds_ca_certificate_identifier",
  "aws_rds_copy_tags_to_snapshot",
  "aws_rds_customer_owned_ip_enabled",
  "aws_rds_db_cluster_identifier",
  "aws_rds_db_instance_arn",
  "aws_rds_db_instance_class",
  "aws_rds_db_instance_identifier",
  "aws_rds_db_instance_port",
  "aws_rds_db_instance_status",
  "aws_rds_db_parameter_groups",
  "aws_rds_db_security_groups",
  "aws_rds_db_subnet_group",
  "aws_rds_dbi_resource_id",
  "aws_rds_deletion_protection",
  "aws_rds_domain_memberships",
  "aws_rds_enabled_cloudwatch_logs_exports",
  "aws_rds_endpoint",
  "aws_rds_engine",
  "aws_rds_engine_version",
  "aws_rds_enhanced_monitoring_resource_arn",
  "aws_rds_iam_database_authentication_enabled",
  "aws_rds_instance_create_time",
  "aws_rds_kms_key_id",
  "aws_rds_license_model",
  "aws_rds_master_username",
  "aws_rds_monitoring_interval",
  "aws_rds_monitoring_role_arn",
  "aws_rds_multi_az",
  "aws_rds_option_group_memberships",
  "aws_rds_pending_modified_values",
  "aws_rds_performance_insights_enabled",
  "aws_rds_preferred_backup_window",
  "aws_rds_preferred_maintenance_window",
  "aws_rds_promotion_tier",
  "aws_rds_publicly_accessible",
  "aws_rds_read_replica_db_instance_identifiers",
  "aws_rds_region",
  "aws_rds_storage_encrypted",
  "aws_rds_storage_type",
  "aws_rds_tag_list",
  "aws_rds_tags",
  "aws_rds_vpc_security_groups",
  "environment",
  "group_names",
  "groups",
  "hostvars",
  "inventory_dir",
  "inventory_file",
  "inventory_hostname",
  "inventory_hostname_short",
  "omit",
  "play_hosts",
  "playbook_dir",
  "private_host",
  "role_names"
]
```

### Code of Conduct

- [x] I agree to follow the Ansible Code of Conduct


Discussion:
Files identified in the description:
* [`plugins/modules/aws_s3.py`](https://github.com/['ansible-collections/amazon.aws', 'ansible-collections/community.aws', 'ansible-collections/community.vmware']/blob/main/plugins/modules/aws_s3.py)

If these files are inaccurate, please update the `component name` section of the description or use the `!component` bot command.

[click here for bot help](https://github.com/ansible/ansibullbot/blob/master/ISSUE_HELP.md)
<!--- boilerplate: components_banner --->
cc @jillr @linabuzachis @lwade @s-hertel @tremble @wimnat
[click here for bot help](https://github.com/ansible/ansibullbot/blob/master/ISSUE_HELP.md)
<!--- boilerplate: notify --->
Files identified in the description:
* [`lib/ansible/vars/hostvars.py`](https://github.com/['ansible-collections/amazon.aws', 'ansible-collections/community.aws', 'ansible-collections/community.vmware']/blob/main/lib/ansible/vars/hostvars.py)

If these files are inaccurate, please update the `component name` section of the description or use the `!component` bot command.

[click here for bot help](https://github.com/ansible/ansibullbot/blob/master/ISSUE_HELP.md)
<!--- boilerplate: components_banner --->
Hi @giner Could you give us an example of a use case?  Is this something that you could use `compose` for?
Hi @jillr, let me illustrate by an example.

There are two machines, somehost1 - AWS EC2 instance (from dynamic inventory) and somehost2 - statically defined instance. Please take a look at the playbook and the results below. `somehost1` is skipped (wrong behaviour) and `somehost2` is not (correct behaviour).

```yaml
$ cat play.yml
- hosts: somehost1  # AWS EC2 instance
  gather_facts: no
  tasks:
  - name: Perform this action
    debug:
      msg: Performing the action
    when: state is not defined or state is in ['started']

- hosts: somehost2  # Statically defined instance
  gather_facts: no
  tasks:
  - name: Perform another action
    debug:
      msg: Performing another action
    when: state is not defined or state is in ['started']
```

```bash
$ ansible-playbook -i inventory play.yml

PLAY [somehost1] ***********************************************************************************************************

TASK [Perform this action] *************************************************************************************************
skipping: [somehost1]

PLAY [somehost2] ***********************************************************************************************************

TASK [Perform another action] **********************************************************************************************
ok: [somehost2] =>
  msg: Performing another action

PLAY RECAP *****************************************************************************************************************
somehost1                  : ok=0    changed=0    unreachable=0    failed=0    skipped=1    rescued=0    ignored=0
somehost2                  : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
```

```bash
$ ansible -i inventory -m debug -a "var=state" somehost1

PLAY [Ansible Ad-Hoc] ******************************************************************************************************

TASK [debug] ***************************************************************************************************************
ok: [somehost1] =>
  state:
    code: 16
    name: running

PLAY RECAP *****************************************************************************************************************
somehost1                  : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
```

Resolving patch:
diff --git a/plugins/inventory/aws_ec2.py b/plugins/inventory/aws_ec2.py
--- a/plugins/inventory/aws_ec2.py
+++ b/plugins/inventory/aws_ec2.py
@@ -99,6 +99,16 @@
             - The use of this feature is discouraged and we advise to migrate to the new ``tags`` structure.
           type: bool
           default: False
+        hostvars_prefix:
+          description:
+            - The prefix for host variables names coming from AWS.
+          type: str
+          version_added: 3.1.0
+        hostvars_suffix:
+          description:
+            - The suffix for host variables names coming from AWS.
+          type: str
+          version_added: 3.1.0
 '''
 
 EXAMPLES = '''
@@ -205,6 +215,12 @@
   ansible_host: public_dns_name
 groups:
   libvpc: vpc_id == 'vpc-####'
+# Define prefix and suffix for host variables coming from AWS.
+plugin: aws_ec2
+regions:
+  - us-east-1
+hostvars_prefix: 'aws_'
+hostvars_suffix: '_ec2'
 '''
 
 import re
@@ -647,8 +663,17 @@ def _add_hosts(self, hosts, group, hostnames):
             if not hostname:
                 continue
             self.inventory.add_host(hostname, group=group)
+            hostvars_prefix = self.get_option("hostvars_prefix")
+            hostvars_suffix = self.get_option("hostvars_suffix")
+            new_vars = dict()
             for hostvar, hostval in host.items():
+                if hostvars_prefix:
+                    hostvar = hostvars_prefix + hostvar
+                if hostvars_suffix:
+                    hostvar = hostvar + hostvars_suffix
+                new_vars[hostvar] = hostval
                 self.inventory.set_variable(hostname, hostvar, hostval)
+            host.update(new_vars)
 
             # Use constructed if applicable
 
diff --git a/plugins/inventory/aws_rds.py b/plugins/inventory/aws_rds.py
--- a/plugins/inventory/aws_rds.py
+++ b/plugins/inventory/aws_rds.py
@@ -39,6 +39,16 @@
         iam_role_arn:
           description: The ARN of the IAM role to assume to perform the inventory lookup. You should still provide
               AWS credentials with enough privilege to perform the AssumeRole action.
+        hostvars_prefix:
+          description:
+            - The prefix for host variables names coming from AWS.
+          type: str
+          version_added: 3.1.0
+        hostvars_suffix:
+          description:
+            - The suffix for host variables names coming from AWS.
+          type: str
+          version_added: 3.1.0
     note:
         Ansible versions prior to 2.10 should use the fully qualified plugin name 'amazon.aws.aws_rds'.
     extends_documentation_fragment:
@@ -64,6 +74,8 @@
     prefix: rds
   - key: tags
   - key: region
+hostvars_prefix: aws_
+hostvars_suffix: _rds
 '''
 
 try:
@@ -280,8 +292,17 @@ def _add_hosts(self, hosts, group):
                 host['region'] = host['availability_zones'][0][:-1]
 
             self.inventory.add_host(hostname, group=group)
+            hostvars_prefix = self.get_option("hostvars_prefix")
+            hostvars_suffix = self.get_option("hostvars_suffix")
+            new_vars = dict()
             for hostvar, hostval in host.items():
+                if hostvars_prefix:
+                    hostvar = hostvars_prefix + hostvar
+                if hostvars_suffix:
+                    hostvar = hostvar + hostvars_suffix
+                new_vars[hostvar] = hostval
                 self.inventory.set_variable(hostname, hostvar, hostval)
+            host.update(new_vars)
 
             # Use constructed if applicable
             strict = self.get_option('strict')


Test patch:
diff --git a/tests/integration/targets/inventory_aws_ec2/playbooks/test_populating_inventory_with_hostvars_prefix_suffix.yml b/tests/integration/targets/inventory_aws_ec2/playbooks/test_populating_inventory_with_hostvars_prefix_suffix.yml
new file mode 100644
--- /dev/null
+++ b/tests/integration/targets/inventory_aws_ec2/playbooks/test_populating_inventory_with_hostvars_prefix_suffix.yml
@@ -0,0 +1,65 @@
+---
+- hosts: 127.0.0.1
+  connection: local
+  gather_facts: no
+  environment: "{{ ansible_test.environment }}"
+  tasks:
+
+    - 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:
+
+        # Create VPC, subnet, security group, and find image_id to create instance
+
+        - include_tasks: setup.yml
+
+        # Create new host, refresh inventory
+        - name: create a new host
+          ec2_instance:
+            image_id: '{{ image_id }}'
+            name: '{{ resource_prefix }}_1'
+            tags:
+              tag_instance1: foo
+            instance_type: t2.micro
+            security_groups: '{{ sg_id }}'
+            vpc_subnet_id: '{{ subnet_id }}'
+            wait: no
+          register: setup_instance_1
+
+        - meta: refresh_inventory
+
+        - name: assert the hostvars are defined with prefix and/or suffix
+          assert:
+            that:
+              - "hostvars['{{ resource_prefix }}_1'].{{ vars_prefix }}instance_type{{ vars_suffix }} == 't2.micro'"
+              - "'{{ vars_prefix }}instance_type{{ vars_suffix }}' in hostvars['{{ resource_prefix }}_1']"
+              - "'{{ vars_prefix }}image_id{{ vars_suffix }}' in hostvars['{{ resource_prefix }}_1']"
+              - "'{{ vars_prefix }}instance_id{{ vars_suffix }}' in hostvars['{{ resource_prefix }}_1']"
+              - "'instance_type' not in hostvars['{{ resource_prefix }}_1']"
+              - "'image_id' not in hostvars['{{ resource_prefix }}_1']"
+              - "'instance_id' not in hostvars['{{ resource_prefix }}_1']"
+              - "'ansible_diff_mode' in hostvars['{{ resource_prefix }}_1']"
+              - "'ansible_forks' in hostvars['{{ resource_prefix }}_1']"
+              - "'ansible_version' in hostvars['{{ resource_prefix }}_1']"
+          vars:
+            vars_prefix: "{{ hostvars_prefix | default('') }}"
+            vars_suffix: "{{ hostvars_suffix | default('') }}"
+
+      always:
+
+        - name: remove setup ec2 instance
+          ec2_instance:
+            instance_type: t2.micro
+            instance_ids: '{{ setup_instance_1.instance_ids }}'
+            state: absent
+            name: '{{ resource_prefix }}_1'
+            security_groups: "{{ sg_id }}"
+            vpc_subnet_id: "{{ subnet_id }}"
+          ignore_errors: yes
+          when: setup_instance_1 is defined
+
+        - include_tasks: tear_down.yml
diff --git a/tests/integration/targets/inventory_aws_ec2/runme.sh b/tests/integration/targets/inventory_aws_ec2/runme.sh
--- a/tests/integration/targets/inventory_aws_ec2/runme.sh
+++ b/tests/integration/targets/inventory_aws_ec2/runme.sh
@@ -42,6 +42,16 @@ ansible-playbook playbooks/test_populating_inventory_with_concatenation.yml "$@"
 ansible-playbook playbooks/create_inventory_config.yml -e "template='inventory_with_include_or_exclude_filters.yml.j2'" "$@"
 ansible-playbook playbooks/test_populating_inventory_with_include_or_exclude_filters.yml "$@"
 
+# generate inventory config with hostvars_prefix
+ansible-playbook playbooks/create_inventory_config.yml -e "template='inventory_with_hostvars_prefix_suffix.yml.j2'" -e "hostvars_prefix='aws_ec2_'" "$@"
+ansible-playbook playbooks/test_populating_inventory_with_hostvars_prefix_suffix.yml -e "hostvars_prefix='aws_ec2_'" "$@"
+# generate inventory config with hostvars_suffix
+ansible-playbook playbooks/create_inventory_config.yml -e "template='inventory_with_hostvars_prefix_suffix.yml.j2'" -e "hostvars_suffix='_aws_ec2'" "$@"
+ansible-playbook playbooks/test_populating_inventory_with_hostvars_prefix_suffix.yml -e "hostvars_suffix='_aws_ec2'" "$@"
+# generate inventory config with hostvars_prefix and hostvars_suffix
+ansible-playbook playbooks/create_inventory_config.yml -e "template='inventory_with_hostvars_prefix_suffix.yml.j2'" -e "hostvars_prefix='aws_'" -e "hostvars_suffix='_ec2'" "$@"
+ansible-playbook playbooks/test_populating_inventory_with_hostvars_prefix_suffix.yml -e "hostvars_prefix='aws_'" -e "hostvars_suffix='_ec2'" "$@"
+
 # generate inventory config with caching and test using it
 ansible-playbook playbooks/create_inventory_config.yml -e "template='inventory_with_use_contrib_script_keys.yml.j2'" "$@"
 ANSIBLE_TRANSFORM_INVALID_GROUP_CHARS=never ansible-playbook playbooks/test_populating_inventory_with_use_contrib_script_keys.yml "$@"
diff --git a/tests/integration/targets/inventory_aws_ec2/templates/inventory_with_hostvars_prefix_suffix.yml.j2 b/tests/integration/targets/inventory_aws_ec2/templates/inventory_with_hostvars_prefix_suffix.yml.j2
new file mode 100644
--- /dev/null
+++ b/tests/integration/targets/inventory_aws_ec2/templates/inventory_with_hostvars_prefix_suffix.yml.j2
@@ -0,0 +1,19 @@
+plugin: amazon.aws.aws_ec2
+aws_access_key_id: '{{ aws_access_key }}'
+aws_secret_access_key: '{{ aws_secret_key }}'
+{% if security_token | default(false) %}
+aws_security_token: '{{ security_token }}'
+{% endif %}
+regions:
+- '{{ aws_region }}'
+filters:
+  tag:Name:
+  - '{{ resource_prefix }}_*'
+{% if hostvars_prefix | default(false) %}
+hostvars_prefix: '{{ hostvars_prefix }}'
+{% endif %}
+{% if hostvars_suffix | default(false) %}
+hostvars_suffix: '{{ hostvars_suffix }}'
+{% endif %}
+hostnames:
+- tag:Name
diff --git a/tests/integration/targets/inventory_aws_rds/playbooks/test_inventory_with_hostvars_prefix_suffix.yml b/tests/integration/targets/inventory_aws_rds/playbooks/test_inventory_with_hostvars_prefix_suffix.yml
new file mode 100644
--- /dev/null
+++ b/tests/integration/targets/inventory_aws_rds/playbooks/test_inventory_with_hostvars_prefix_suffix.yml
@@ -0,0 +1,62 @@
+---
+- hosts: 127.0.0.1
+  connection: local
+  gather_facts: no
+  environment: "{{ ansible_test.environment }}"
+  collections:
+    - community.aws
+  tasks:
+
+    - 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:
+
+        - set_fact:
+            instance_id: "{{ resource_prefix }}-mariadb"
+
+        - name: create minimal mariadb instance in default VPC and default subnet group
+          rds_instance:
+            state: present
+            engine: mariadb
+            db_instance_class: db.t2.micro
+            allocated_storage: 20
+            instance_id: '{{ resource_prefix }}-mariadb'
+            master_username: 'ansibletestuser'
+            master_user_password: 'password-{{ resource_prefix | regex_findall(".{8}$") | first }}'
+            tags:
+              workload_type: other
+          register: setup_instance
+
+        - meta: refresh_inventory
+
+        - name: assert the hostvars are defined with prefix and/or suffix
+          assert:
+            that:
+              - "hostvars[host_instance_name].{{ vars_prefix }}db_instance_class{{ vars_suffix }} == 'db.t2.micro'"
+              - "hostvars[host_instance_name].{{ vars_prefix }}engine{{ vars_suffix }} == 'mariadb'"
+              - "hostvars[host_instance_name].{{ vars_prefix }}db_instance_status{{ vars_suffix }} == 'available'"
+              - "'db_instance_class' not in hostvars[host_instance_name]"
+              - "'engine' not in hostvars[host_instance_name]"
+              - "'db_instance_status' not in hostvars[host_instance_name]"
+              - "'ansible_diff_mode' in hostvars[host_instance_name]"
+              - "'ansible_forks' in hostvars[host_instance_name]"
+              - "'ansible_version' in hostvars[host_instance_name]"
+          vars:
+            host_instance_name: "{{ resource_prefix }}-mariadb"
+            vars_prefix: "{{ inventory_prefix | default('') }}"
+            vars_suffix: "{{ inventory_suffix | default('') }}"
+
+      always:
+
+        - name: remove mariadb instance
+          rds_instance:
+            state: absent
+            engine: mariadb
+            skip_final_snapshot: yes
+            instance_id: '{{ instance_id }}'
+          ignore_errors: yes
+          when: setup_instance is defined
diff --git a/tests/integration/targets/inventory_aws_rds/runme.sh b/tests/integration/targets/inventory_aws_rds/runme.sh
--- a/tests/integration/targets/inventory_aws_rds/runme.sh
+++ b/tests/integration/targets/inventory_aws_rds/runme.sh
@@ -31,5 +31,17 @@ rm -r aws_rds_cache_dir/
 ansible-playbook playbooks/create_inventory_config.yml -e "template='inventory_with_constructed.j2'" "$@"
 ansible-playbook playbooks/test_populating_inventory_with_constructed.yml "$@"
 
+# generate inventory config with hostvars_prefix features and test using it
+ansible-playbook playbooks/create_inventory_config.yml -e "template='inventory_with_hostvars_prefix_suffix.j2'" -e "inventory_prefix='aws_rds_'" "$@"
+ansible-playbook playbooks/test_inventory_with_hostvars_prefix_suffix.yml -e "inventory_prefix='aws_rds_'" "$@"
+
+# generate inventory config with hostvars_suffix features and test using it
+ansible-playbook playbooks/create_inventory_config.yml -e "template='inventory_with_hostvars_prefix_suffix.j2'" -e "inventory_suffix='_aws_rds'" "$@"
+ansible-playbook playbooks/test_inventory_with_hostvars_prefix_suffix.yml -e "inventory_suffix='_aws_rds'" "$@"
+
+# generate inventory config with hostvars_prefix and hostvars_suffix features and test using it
+ansible-playbook playbooks/create_inventory_config.yml -e "template='inventory_with_hostvars_prefix_suffix.j2'" -e "inventory_prefix='aws_'" -e "inventory_suffix='_rds'" "$@"
+ansible-playbook playbooks/test_inventory_with_hostvars_prefix_suffix.yml -e "inventory_prefix='aws_'" -e "inventory_suffix='_rds'" "$@"
+
 # cleanup inventory config
 ansible-playbook playbooks/empty_inventory_config.yml "$@"
diff --git a/tests/integration/targets/inventory_aws_rds/templates/inventory_with_hostvars_prefix_suffix.j2 b/tests/integration/targets/inventory_aws_rds/templates/inventory_with_hostvars_prefix_suffix.j2
new file mode 100644
--- /dev/null
+++ b/tests/integration/targets/inventory_aws_rds/templates/inventory_with_hostvars_prefix_suffix.j2
@@ -0,0 +1,16 @@
+plugin: amazon.aws.aws_rds
+aws_access_key_id: '{{ aws_access_key }}'
+aws_secret_access_key: '{{ aws_secret_key }}'
+{% if security_token | default(false) %}
+aws_security_token: '{{ security_token }}'
+{% endif %}
+regions:
+  - '{{ aws_region }}'
+{% if inventory_prefix | default(false) %}
+hostvars_prefix: '{{ inventory_prefix }}'
+{% endif %}
+{% if inventory_suffix | default(false) %}
+hostvars_suffix: '{{ inventory_suffix }}'
+{% endif %}
+filters:
+  db-instance-id: "{{ resource_prefix }}-mariadb"