diff --git a/changelogs/fragments/27800-ec2_vpc_net-ipv6-support.yml b/changelogs/fragments/27800-ec2_vpc_net-ipv6-support.yml new file mode 100644 index 00000000000..402a055b10d --- /dev/null +++ b/changelogs/fragments/27800-ec2_vpc_net-ipv6-support.yml @@ -0,0 +1,2 @@ +minor_changes: + - ec2_vpc_net - Enable IPv6 CIDR assignment diff --git a/lib/ansible/modules/cloud/amazon/ec2_vpc_net.py b/lib/ansible/modules/cloud/amazon/ec2_vpc_net.py index f06738ac0fa..1d9a3e96c47 100644 --- a/lib/ansible/modules/cloud/amazon/ec2_vpc_net.py +++ b/lib/ansible/modules/cloud/amazon/ec2_vpc_net.py @@ -31,6 +31,13 @@ options: - The primary CIDR of the VPC. After 2.5 a list of CIDRs can be provided. The first in the list will be used as the primary CIDR and is used in conjunction with the C(name) to ensure idempotence. required: yes + ipv6_cidr: + description: + - Request an Amazon-provided IPv6 CIDR block with /56 prefix length. You cannot specify the range of IPv6 addresses, + or the size of the CIDR block. + default: False + type: bool + version_added: '2.10' purge_cidrs: description: - Remove CIDRs that are associated with the VPC and are not specified in C(cidr_block). @@ -91,6 +98,14 @@ EXAMPLES = ''' module: ec2_vpc_net this: works tenancy: dedicated + +- name: create a VPC with dedicated tenancy and request an IPv6 CIDR + ec2_vpc_net: + name: Module_dev2 + cidr_block: 10.10.0.0/16 + ipv6_cidr: True + region: us-east-1 + tenancy: dedicated ''' RETURN = ''' @@ -138,6 +153,20 @@ vpc: returned: always type: str sample: default + ipv6_cidr_block_association_set: + description: IPv6 CIDR blocks associated with the VPC + returned: success + type: list + sample: + "ipv6_cidr_block_association_set": [ + { + "association_id": "vpc-cidr-assoc-97aeeefd", + "ipv6_cidr_block": "2001:db8::/56", + "ipv6_cidr_block_state": { + "state": "associated" + } + } + ] is_default: description: indicates whether this is the default VPC returned: always @@ -337,6 +366,7 @@ def main(): argument_spec = dict( name=dict(required=True), cidr_block=dict(type='list', required=True), + ipv6_cidr=dict(type='bool', default=False), tenancy=dict(choices=['default', 'dedicated'], default='default'), dns_support=dict(type='bool', default=True), dns_hostnames=dict(type='bool', default=True), @@ -354,6 +384,7 @@ def main(): name = module.params.get('name') cidr_block = get_cidr_network_bits(module, module.params.get('cidr_block')) + ipv6_cidr = module.params.get('ipv6_cidr') purge_cidrs = module.params.get('purge_cidrs') tenancy = module.params.get('tenancy') dns_support = module.params.get('dns_support') @@ -395,7 +426,21 @@ def main(): if len(cidr_block) > 1: for cidr in to_add: changed = True - connection.associate_vpc_cidr_block(CidrBlock=cidr, VpcId=vpc_id) + try: + connection.associate_vpc_cidr_block(CidrBlock=cidr, VpcId=vpc_id) + except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: + module.fail_json_aws(e, "Unable to associate CIDR {0}.".format(ipv6_cidr)) + if ipv6_cidr: + if 'Ipv6CidrBlockAssociationSet' in vpc_obj.keys(): + module.warn("Only one IPv6 CIDR is permitted per VPC, {0} already has CIDR {1}".format( + vpc_id, + vpc_obj['Ipv6CidrBlockAssociationSet'][0]['Ipv6CidrBlock'])) + else: + try: + connection.associate_vpc_cidr_block(AmazonProvidedIpv6CidrBlock=ipv6_cidr, VpcId=vpc_id) + changed = True + except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: + module.fail_json_aws(e, "Unable to associate CIDR {0}.".format(ipv6_cidr)) if purge_cidrs: for association_id in to_remove: diff --git a/test/integration/targets/ec2_vpc_net/tasks/main.yml b/test/integration/targets/ec2_vpc_net/tasks/main.yml index 74edfe7d02c..4429b4e39a3 100644 --- a/test/integration/targets/ec2_vpc_net/tasks/main.yml +++ b/test/integration/targets/ec2_vpc_net/tasks/main.yml @@ -63,6 +63,7 @@ - name: create a VPC ec2_vpc_net: cidr_block: 20.0.0.0/24 + ipv6_cidr: True name: "{{ resource_prefix }}" state: present <<: *aws_connection_info @@ -78,6 +79,7 @@ assert: that: - '"cidr_block" in result.vpc' + - '"ipv6_cidr_block_association_set" in result.vpc' - '"classic_link_enabled" in result.vpc' - '"dhcp_options_id" in result.vpc' - '"id" in result.vpc' @@ -86,9 +88,10 @@ - '"state" in result.vpc' - '"tags" in result.vpc' - - name: set the first VPC as a fact for comparison and cleanup + - name: set the first VPC's details as facts for comparison and cleanup set_fact: vpc_1: "{{ result.vpc.id }}" + vpc_1_ipv6_cidr: "{{ result.vpc.ipv6_cidr_block_association_set.0.ipv6_cidr_block }}" - name: save default dhcp_options_id for later comparison set_fact: @@ -96,9 +99,28 @@ # ============================================================ + - name: Try to add IPv6 CIDR when one already exists + ec2_vpc_net: + cidr_block: 20.0.0.0/24 + ipv6_cidr: True + name: "{{ resource_prefix }}" + state: present + multi_ok: no + <<: *aws_connection_info + register: result + + - name: Assert no changes made + assert: + that: + - '"Only one IPv6 CIDR is permitted per VPC, {{ result.vpc.id }} already has CIDR {{ vpc_1_ipv6_cidr }}" in result.warnings' + - 'not result.changed' + + # ============================================================ + - name: test check mode creating an identical VPC ec2_vpc_net: cidr_block: 20.0.0.0/24 + ipv6_cidr: True name: "{{ resource_prefix }}" state: present multi_ok: yes @@ -117,6 +139,7 @@ ec2_vpc_net: cidr_block: 20.0.0.0/24 name: "{{ resource_prefix }}" + ipv6_cidr: True tenancy: dedicated state: present multi_ok: yes @@ -136,6 +159,7 @@ - name: attempt to create another VPC with the same CIDR and name without multi_ok ec2_vpc_net: cidr_block: 20.0.0.0/24 + ipv6_cidr: True name: "{{ resource_prefix }}" state: present multi_ok: no diff --git a/test/integration/targets/ec2_vpc_subnet/tasks/main.yml b/test/integration/targets/ec2_vpc_subnet/tasks/main.yml index f246c25faaf..fa79901db08 100644 --- a/test/integration/targets/ec2_vpc_subnet/tasks/main.yml +++ b/test/integration/targets/ec2_vpc_subnet/tasks/main.yml @@ -21,11 +21,15 @@ name: "{{ resource_prefix }}-vpc" state: present cidr_block: "10.232.232.128/26" + ipv6_cidr: True tags: Name: "{{ resource_prefix }}-vpc" Description: "Created by ansible-test" register: vpc_result + - set_fact: + vpc_ipv6_cidr: "{{ vpc_result.vpc.ipv6_cidr_block_association_set[0].ipv6_cidr_block }}" + # ============================================================ - name: create subnet (expected changed=true) (CHECK MODE) ec2_vpc_subnet: @@ -371,35 +375,6 @@ that: - result is changed - # ============================================================ - # FIXME - Replace by creating IPv6 enabled VPC once ec2_vpc_net module supports it. - # See Also https://github.com/ansible/ansible/pull/60983 - - name: - set_fact: - aws_connection_env: - AWS_ACCESS_KEY_ID: "{{ aws_access_key }}" - AWS_SECRET_ACCESS_KEY: "{{ aws_secret_key }}" - AWS_SESSION_TOKEN: "{{ security_token | default(omit) }}" - AWS_DEFAULT_REGION: "{{ aws_region }}" - no_log: yes - - - name: install aws cli - FIXME temporary this should go for a lighterweight solution - command: pip install awscli - - - name: Assign an Amazon provided IPv6 CIDR block to the VPC - command: aws ec2 associate-vpc-cidr-block --amazon-provided-ipv6-cidr-block --vpc-id '{{ vpc_result.vpc.id }}' - environment: '{{ aws_connection_env }}' - - - name: wait for the IPv6 CIDR to be assigned - command: sleep 5 - - - name: Get the assigned IPv6 CIDR - command: aws ec2 describe-vpcs --vpc-ids '{{ vpc_result.vpc.id }}' - environment: '{{ aws_connection_env }}' - register: vpc_ipv6 - - - set_fact: - vpc_ipv6_cidr: "{{ vpc_ipv6.stdout | from_json | json_query('Vpcs[0].Ipv6CidrBlockAssociationSet[0].Ipv6CidrBlock') }}" # ============================================================ - name: create subnet with IPv6 (expected changed=true) (CHECK MODE)