diff --git a/changelogs/fragments/826-inventory-aws_ec2-allow-literal-string-in-hostname.yml b/changelogs/fragments/826-inventory-aws_ec2-allow-literal-string-in-hostname.yml new file mode 100644 index 00000000000..7c0ffa00fa3 --- /dev/null +++ b/changelogs/fragments/826-inventory-aws_ec2-allow-literal-string-in-hostname.yml @@ -0,0 +1,2 @@ +minor_changes: + - aws_ec2 inventory - Allow for literal strings in hostname that don't match filter parameters in ec2 describe-instances (https://github.com/ansible-collections/amazon.aws/pull/826). diff --git a/plugins/inventory/aws_ec2.py b/plugins/inventory/aws_ec2.py index 0e2aead1fd7..9efaf6802f7 100644 --- a/plugins/inventory/aws_ec2.py +++ b/plugins/inventory/aws_ec2.py @@ -39,11 +39,31 @@ hostnames: description: - A list in order of precedence for hostname variables. - - You can use the options specified in U(http://docs.aws.amazon.com/cli/latest/reference/ec2/describe-instances.html#options). - - To use tags as hostnames use the syntax tag:Name=Value to use the hostname Name_Value, or tag:Name to use the value of the Name tag. type: list elements: dict default: [] + suboptions: + name: + description: + - Name of the host. + - Can be one of the options specified in U(http://docs.aws.amazon.com/cli/latest/reference/ec2/describe-instances.html#options). + - To use tags as hostnames use the syntax tag:Name=Value to use the hostname Name_Value, or tag:Name to use the value of the Name tag. + - If value provided does not exist in the above options, it will be used as a literal string. + type: str + required: True + prefix: + description: + - Prefix to prepend to I(name). Same options as I(name). + - If I(prefix) is specified, final hostname will be I(prefix) + I(separator) + I(name). + type: str + default: '' + required: False + separator: + description: + - Value to separate I(prefix) and I(name) when I(prefix) is specified. + type: str + default: '_' + required: False filters: description: - A dictionary of filter value pairs. @@ -149,6 +169,9 @@ - name: 'private-ip-address' separator: '_' prefix: 'tag:Name' + - name: 'test_literal' # Using literal values for hostname + separator: '-' # Hostname will be aws-test_literal + prefix: 'aws' # Example using constructed features to create groups and set ansible_host plugin: aws_ec2 @@ -387,9 +410,11 @@ def _get_boto_attr_chain(self, filter_name, instance): :param instance: instance dict returned by boto3 ec2 describe_instances() ''' allowed_filters = sorted(list(instance_data_filter_to_boto_attr.keys()) + list(instance_meta_filter_to_boto_attr.keys())) + + # If filter not in allow_filters -> use it as a literal string if filter_name not in allowed_filters: - raise AnsibleError("Invalid filter '%s' provided; filter must be one of %s." % (filter_name, - allowed_filters)) + return filter_name + if filter_name in instance_data_filter_to_boto_attr: boto_attr_list = instance_data_filter_to_boto_attr[filter_name] else: diff --git a/tests/integration/targets/inventory_aws_ec2/playbooks/test_populating_inventory_with_literal_string.yml b/tests/integration/targets/inventory_aws_ec2/playbooks/test_populating_inventory_with_literal_string.yml new file mode 100644 index 00000000000..8ba065eaf8e --- /dev/null +++ b/tests/integration/targets/inventory_aws_ec2/playbooks/test_populating_inventory_with_literal_string.yml @@ -0,0 +1,56 @@ +--- +- 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 }}' + tags: + OtherTag: value + instance_type: t2.micro + security_groups: '{{ sg_id }}' + vpc_subnet_id: '{{ subnet_id }}' + wait: no + register: setup_instance + + - meta: refresh_inventory + + - name: register the current hostname + set_fact: + expected_hostname: "aws-{{ resource_prefix }}" + + - name: "Ensure we've got a hostvars entry for the new host" + assert: + that: + - expected_hostname in hostvars + + always: + + - name: remove setup ec2 instance + ec2_instance: + instance_type: t2.micro + instance_ids: '{{ setup_instance.instance_ids }}' + state: absent + name: '{{ resource_prefix }}' + security_groups: "{{ sg_id }}" + vpc_subnet_id: "{{ subnet_id }}" + ignore_errors: yes + when: setup_instance 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 index a43b6968680..216994672f3 100755 --- a/tests/integration/targets/inventory_aws_ec2/runme.sh +++ b/tests/integration/targets/inventory_aws_ec2/runme.sh @@ -38,6 +38,9 @@ ansible-playbook playbooks/create_inventory_config.yml -e "template='inventory_w ansible-playbook playbooks/test_populating_inventory_with_constructed.yml "$@" ansible-playbook playbooks/create_inventory_config.yml -e "template='inventory_with_concatenation.yml.j2'" "$@" ansible-playbook playbooks/test_populating_inventory_with_concatenation.yml "$@" +ansible-playbook playbooks/create_inventory_config.yml -e "template='inventory_with_literal_string.yml.j2'" "$@" +ansible-playbook playbooks/test_populating_inventory_with_literal_string.yml "$@" + # generate inventory config with includes_entries_matching and prepare the tests 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 "$@" diff --git a/tests/integration/targets/inventory_aws_ec2/templates/inventory_with_literal_string.yml.j2 b/tests/integration/targets/inventory_aws_ec2/templates/inventory_with_literal_string.yml.j2 new file mode 100644 index 00000000000..0dbddcb82bf --- /dev/null +++ b/tests/integration/targets/inventory_aws_ec2/templates/inventory_with_literal_string.yml.j2 @@ -0,0 +1,15 @@ +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 }}' +hostnames: + - name: 'tag:Name' + separator: '-' + prefix: 'aws'