From 65a56412655c4a3c4149b5614678fde0c9511940 Mon Sep 17 00:00:00 2001 From: abikouo Date: Thu, 25 Mar 2021 14:23:46 +0100 Subject: [PATCH 01/11] update elb modules adding ip_address_type parameters --- plugins/modules/elb_application_lb.py | 16 +++- plugins/modules/elb_application_lb_info.py | 31 +++---- plugins/modules/elb_network_lb.py | 19 +++- .../elb_application_lb/tasks/full_test.yml | 32 +++++-- .../test_alb_ip_address_type_options.yml | 93 +++++++++++++++++++ .../targets/elb_application_lb_info/aliases | 2 + .../elb_application_lb_info/defaults/main.yml | 4 + .../elb_application_lb_info/meta/main.yml | 2 + .../tasks/full_test.yml | 11 +++ .../elb_application_lb_info/tasks/main.yml | 40 ++++++++ .../elb_application_lb_info/tasks/setup.yml | 83 +++++++++++++++++ .../tasks/teardown.yml | 83 +++++++++++++++++ .../tasks/test_elb_application_lb_info.yml | 41 ++++++++ .../targets/elb_network_lb/tasks/main.yml | 31 +++++-- .../tasks/test_nlb_ip_address_type_option.yml | 92 ++++++++++++++++++ 15 files changed, 542 insertions(+), 38 deletions(-) create mode 100644 tests/integration/targets/elb_application_lb/tasks/test_alb_ip_address_type_options.yml create mode 100644 tests/integration/targets/elb_application_lb_info/aliases create mode 100644 tests/integration/targets/elb_application_lb_info/defaults/main.yml create mode 100644 tests/integration/targets/elb_application_lb_info/meta/main.yml create mode 100644 tests/integration/targets/elb_application_lb_info/tasks/full_test.yml create mode 100644 tests/integration/targets/elb_application_lb_info/tasks/main.yml create mode 100644 tests/integration/targets/elb_application_lb_info/tasks/setup.yml create mode 100644 tests/integration/targets/elb_application_lb_info/tasks/teardown.yml create mode 100644 tests/integration/targets/elb_application_lb_info/tasks/test_elb_application_lb_info.yml create mode 100644 tests/integration/targets/elb_network_lb/tasks/test_nlb_ip_address_type_option.yml diff --git a/plugins/modules/elb_application_lb.py b/plugins/modules/elb_application_lb.py index f154c8803ff..9dcab533c9c 100644 --- a/plugins/modules/elb_application_lb.py +++ b/plugins/modules/elb_application_lb.py @@ -179,6 +179,12 @@ - When set to C(no), keep the existing load balancer rules in place. Will modify and add, but will not delete. default: yes type: bool + ip_address_type: + description: + - Sets the type of IP addresses used by the subnets of the specified Application Load Balancer. + default: "ipv4" + choices: [ 'ipv4', 'dualstack' ] + type: str extends_documentation_fragment: - amazon.aws.aws - amazon.aws.ec2 @@ -476,7 +482,6 @@ def create_or_update_elb(elb_obj): """Create ELB or modify main attributes. json_exit here""" - if elb_obj.elb: # ELB exists so check subnets, security groups and tags match what has been passed @@ -562,6 +567,9 @@ def create_or_update_elb(elb_obj): rule_obj.modify() elb_obj.changed = True + # Update ELB ip address type only if option has been provided + if elb_obj.module.params.get('ip_address_type') is not None : + elb_obj.modify_ip_address_type(elb_obj.module.params.get('ip_address_type')) # Get the ELB again elb_obj.update() @@ -583,6 +591,9 @@ def create_or_update_elb(elb_obj): # Change tags to ansible friendly dict snaked_elb['tags'] = boto3_tag_list_to_ansible_dict(snaked_elb['tags']) + # ip address type + snaked_elb['ip_address_type']=elb_obj.get_elb_ip_address_type() + elb_obj.module.exit_json(changed=elb_obj.changed, **snaked_elb) @@ -629,7 +640,8 @@ def main(): tags=dict(type='dict'), wait_timeout=dict(type='int'), wait=dict(default=False, type='bool'), - purge_rules=dict(default=True, type='bool') + purge_rules=dict(default=True, type='bool'), + ip_address_type=dict(type='str', choices=['ipv4', 'dualstack']) ) module = AnsibleAWSModule(argument_spec=argument_spec, diff --git a/plugins/modules/elb_application_lb_info.py b/plugins/modules/elb_application_lb_info.py index e3003789911..9d3ad385556 100644 --- a/plugins/modules/elb_application_lb_info.py +++ b/plugins/modules/elb_application_lb_info.py @@ -70,96 +70,82 @@ contains: access_logs_s3_bucket: description: The name of the S3 bucket for the access logs. - returned: when status is present type: str sample: mys3bucket access_logs_s3_enabled: description: Indicates whether access logs stored in Amazon S3 are enabled. - returned: when status is present type: str sample: true access_logs_s3_prefix: description: The prefix for the location in the S3 bucket. - returned: when status is present type: str sample: /my/logs availability_zones: description: The Availability Zones for the load balancer. - returned: when status is present type: list sample: "[{'subnet_id': 'subnet-aabbccddff', 'zone_name': 'ap-southeast-2a'}]" canonical_hosted_zone_id: description: The ID of the Amazon Route 53 hosted zone associated with the load balancer. - returned: when status is present type: str sample: ABCDEF12345678 created_time: description: The date and time the load balancer was created. - returned: when status is present type: str sample: "2015-02-12T02:14:02+00:00" deletion_protection_enabled: description: Indicates whether deletion protection is enabled. - returned: when status is present type: str sample: true dns_name: description: The public DNS name of the load balancer. - returned: when status is present type: str sample: internal-my-elb-123456789.ap-southeast-2.elb.amazonaws.com idle_timeout_timeout_seconds: description: The idle timeout value, in seconds. - returned: when status is present type: str sample: 60 ip_address_type: description: The type of IP addresses used by the subnets for the load balancer. - returned: when status is present type: str sample: ipv4 load_balancer_arn: description: The Amazon Resource Name (ARN) of the load balancer. - returned: when status is present type: str sample: arn:aws:elasticloadbalancing:ap-southeast-2:0123456789:loadbalancer/app/my-elb/001122334455 load_balancer_name: description: The name of the load balancer. - returned: when status is present type: str sample: my-elb scheme: description: Internet-facing or internal load balancer. - returned: when status is present type: str sample: internal security_groups: description: The IDs of the security groups for the load balancer. - returned: when status is present type: list sample: ['sg-0011223344'] state: description: The state of the load balancer. - returned: when status is present type: dict sample: "{'code': 'active'}" tags: description: The tags attached to the load balancer. - returned: when status is present type: dict sample: "{ 'Tag': 'Example' }" type: description: The type of load balancer. - returned: when status is present type: str sample: application vpc_id: description: The ID of the VPC for the load balancer. - returned: when status is present type: str sample: vpc-0011223344 + ip_address_type: + description: The type of IP addresses used by the subnets for the load balancer. + type: str + sample: ipv4 ''' try: @@ -213,6 +199,12 @@ def get_load_balancer_tags(connection, module, load_balancer_arn): module.fail_json_aws(e, msg="Failed to describe load balancer tags") +def get_load_balancer_ipaddresstype(connection, load_balancer_arn) : + try: + return connection.describe_load_balancers(LoadBalancerArns=[load_balancer_arn])['LoadBalancers'][0]['IpAddressType'] + except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: + module.fail_json_aws(e, msg="Failed to describe load balancer tags") + def list_load_balancers(connection, module): load_balancer_arns = module.params.get("load_balancer_arns") @@ -242,6 +234,9 @@ def list_load_balancers(connection, module): for listener in load_balancer['listeners']: listener['rules'] = get_listener_rules(connection, module, listener['ListenerArn']) + # Get ELB ip address type + load_balancer['IpAddressType']=get_load_balancer_ipaddresstype(connection, load_balancer['LoadBalancerArn']) + # Turn the boto3 result in to ansible_friendly_snaked_names snaked_load_balancers = [camel_dict_to_snake_dict(load_balancer) for load_balancer in load_balancers['LoadBalancers']] diff --git a/plugins/modules/elb_network_lb.py b/plugins/modules/elb_network_lb.py index 5e34c527276..d0d2d82f14f 100644 --- a/plugins/modules/elb_network_lb.py +++ b/plugins/modules/elb_network_lb.py @@ -125,6 +125,12 @@ description: - The duration in seconds to wait, used in conjunction with I(wait). type: int + ip_address_type: + description: + - Sets the type of IP addresses used by the subnets of the specified Application Load Balancer. + default: "ipv4" + choices: [ 'ipv4', 'dualstack' ] + type: str extends_documentation_fragment: - amazon.aws.aws - amazon.aws.ec2 @@ -311,10 +317,8 @@ from ansible_collections.amazon.aws.plugins.module_utils.ec2 import camel_dict_to_snake_dict, boto3_tag_list_to_ansible_dict, compare_aws_tags from ansible_collections.amazon.aws.plugins.module_utils.elbv2 import NetworkLoadBalancer, ELBListeners, ELBListener - def create_or_update_elb(elb_obj): """Create ELB or modify main attributes. json_exit here""" - if elb_obj.elb: # ELB exists so check subnets, security groups and tags match what has been passed @@ -339,6 +343,7 @@ def create_or_update_elb(elb_obj): # Create load balancer elb_obj.create_elb() + # ELB attributes elb_obj.update_elb_attributes() elb_obj.modify_elb_attributes() @@ -379,6 +384,10 @@ def create_or_update_elb(elb_obj): # Update the ELB attributes elb_obj.update_elb_attributes() + # Update ELB ip address type only if option has been provided + if elb_obj.module.params.get('ip_address_type') is not None : + elb_obj.modify_ip_address_type(elb_obj.module.params.get('ip_address_type')) + # Convert to snake_case and merge in everything we want to return to the user snaked_elb = camel_dict_to_snake_dict(elb_obj.elb) snaked_elb.update(camel_dict_to_snake_dict(elb_obj.elb_attributes)) @@ -389,6 +398,9 @@ def create_or_update_elb(elb_obj): # Change tags to ansible friendly dict snaked_elb['tags'] = boto3_tag_list_to_ansible_dict(snaked_elb['tags']) + # ip address type + snaked_elb['ip_address_type']=elb_obj.get_elb_ip_address_type() + elb_obj.module.exit_json(changed=elb_obj.changed, **snaked_elb) @@ -425,7 +437,8 @@ def main(): state=dict(choices=['present', 'absent'], type='str'), tags=dict(type='dict'), wait_timeout=dict(type='int'), - wait=dict(type='bool') + wait=dict(type='bool'), + ip_address_type=dict(type='str', choices=['ipv4', 'dualstack']) ) ) 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 28386fa4844..bf68f93aefa 100644 --- a/tests/integration/targets/elb_application_lb/tasks/full_test.yml +++ b/tests/integration/targets/elb_application_lb/tasks/full_test.yml @@ -6,6 +6,7 @@ cidr_block: 10.228.228.0/22 name: '{{ resource_prefix }}_vpc' state: present + ipv6_cidr: true register: vpc - name: create internet gateway ec2_vpc_igw: @@ -14,7 +15,7 @@ tags: Name: '{{ resource_prefix }}' register: igw - - name: create public subnet + - name: create private subnet ec2_vpc_subnet: cidr: '{{ item.cidr }}' az: '{{ aws_region}}{{ item.az }}' @@ -24,19 +25,33 @@ Public: '{{ item.public|string }}' Name: '{{ item.public|ternary(''public'', ''private'') }}-{{ item.az }}' with_items: - - cidr: 10.228.228.0/24 - az: a - public: 'True' - - cidr: 10.228.229.0/24 - az: b - public: 'True' - cidr: 10.228.230.0/24 az: a public: 'False' - cidr: 10.228.231.0/24 az: b public: 'False' - register: subnets + + - name: create public subnets with ipv6 + ec2_vpc_subnet: + cidr: '{{ item.cidr }}' + az: '{{ aws_region}}{{ item.az }}' + vpc_id: '{{ vpc.vpc.id }}' + state: present + ipv6_cidr: '{{ item.vpc_ipv6_cidr }}' + tags: + Public: '{{ item.public|string }}' + Name: '{{ item.public|ternary(''public'', ''private'') }}-{{ item.az }}' + with_items: + - cidr: 10.228.228.0/24 + az: a + public: 'True' + vpc_ipv6_cidr: "{{ vpc.vpc.ipv6_cidr_block_association_set[0].ipv6_cidr_block | replace('0::/56','0::/64') }}" + - cidr: 10.228.229.0/24 + az: b + public: 'True' + vpc_ipv6_cidr: "{{ vpc.vpc.ipv6_cidr_block_association_set[0].ipv6_cidr_block | replace('0::/56','1::/64') }}" + - ec2_vpc_subnet_info: filters: vpc-id: '{{ vpc.vpc.id }}' @@ -83,6 +98,7 @@ # Run main tests - include_tasks: test_alb_bad_listener_options.yml + - include_tasks: test_alb_ip_address_type_options.yml - include_tasks: test_alb_tags.yml - include_tasks: test_creating_alb.yml - include_tasks: test_alb_with_asg.yml diff --git a/tests/integration/targets/elb_application_lb/tasks/test_alb_ip_address_type_options.yml b/tests/integration/targets/elb_application_lb/tasks/test_alb_ip_address_type_options.yml new file mode 100644 index 00000000000..788befe2765 --- /dev/null +++ b/tests/integration/targets/elb_application_lb/tasks/test_alb_ip_address_type_options.yml @@ -0,0 +1,93 @@ +- block: + - name: set elb name for ipv6 + set_fact: + elb_name_ipv6: "{{ alb_name ~ 'ipv6' }}" + + - name: test creating an ELB with invalid ip address type + elb_application_lb: + name: "{{ elb_name_ipv6 }}" + subnets: "{{ alb_subnets }}" + security_groups: "{{ sec_group.group_id }}" + state: present + listeners: + - Protocol: HTTP + Port: 80 + DefaultActions: + - Type: forward + TargetGroupName: "{{ tg_name }}" + ip_address_type: "ipv6" + ignore_errors: yes + register: elb + + - assert: + that: + - elb is failed + + - name: test creating an ELB with dualstack ip adress type + elb_application_lb: + name: "{{ elb_name_ipv6 }}" + subnets: "{{ alb_subnets }}" + security_groups: "{{ sec_group.group_id }}" + state: present + listeners: + - Protocol: HTTP + Port: 80 + DefaultActions: + - Type: forward + TargetGroupName: "{{ tg_name }}" + ip_address_type: "dualstack" + register: elb + + - assert: + that: + - elb.ip_address_type == "dualstack" + + - name: test updating an ELB with ipv4 adress type + elb_application_lb: + name: "{{ elb_name_ipv6 }}" + subnets: "{{ alb_subnets }}" + security_groups: "{{ sec_group.group_id }}" + state: present + listeners: + - Protocol: HTTP + Port: 80 + DefaultActions: + - Type: forward + TargetGroupName: "{{ tg_name }}" + ip_address_type: "ipv4" + register: elb + + - assert: + that: + - elb.changed + - elb.ip_address_type == "ipv4" + + - name: test idempotence updating an ELB with ipv4 adress type + elb_application_lb: + name: "{{ elb_name_ipv6 }}" + subnets: "{{ alb_subnets }}" + security_groups: "{{ sec_group.group_id }}" + state: present + listeners: + - Protocol: HTTP + Port: 80 + DefaultActions: + - Type: forward + TargetGroupName: "{{ tg_name }}" + ip_address_type: "ipv4" + register: elb + + - assert: + that: + - not elb.changed + - elb.ip_address_type == "ipv4" + + always: + # Cleanup + - name: destroy ALB if created + elb_application_lb: + name: '{{ elb_name_ipv6 }}' + state: absent + wait: true + wait_timeout: 600 + ignore_errors: true diff --git a/tests/integration/targets/elb_application_lb_info/aliases b/tests/integration/targets/elb_application_lb_info/aliases new file mode 100644 index 00000000000..6e3860bee23 --- /dev/null +++ b/tests/integration/targets/elb_application_lb_info/aliases @@ -0,0 +1,2 @@ +cloud/aws +shippable/aws/group2 diff --git a/tests/integration/targets/elb_application_lb_info/defaults/main.yml b/tests/integration/targets/elb_application_lb_info/defaults/main.yml new file mode 100644 index 00000000000..d0c601c6a04 --- /dev/null +++ b/tests/integration/targets/elb_application_lb_info/defaults/main.yml @@ -0,0 +1,4 @@ +--- +resource_short: "{{ '%0.8x'%((16**8) | random(seed=resource_prefix)) }}" +alb_name: "alb-test-{{ resource_short }}" +tg_name: "alb-test-{{ resource_short }}" diff --git a/tests/integration/targets/elb_application_lb_info/meta/main.yml b/tests/integration/targets/elb_application_lb_info/meta/main.yml new file mode 100644 index 00000000000..bc4ebde80b9 --- /dev/null +++ b/tests/integration/targets/elb_application_lb_info/meta/main.yml @@ -0,0 +1,2 @@ +dependencies: + - setup_remote_tmp_dir \ No newline at end of file diff --git a/tests/integration/targets/elb_application_lb_info/tasks/full_test.yml b/tests/integration/targets/elb_application_lb_info/tasks/full_test.yml new file mode 100644 index 00000000000..c74c2b958de --- /dev/null +++ b/tests/integration/targets/elb_application_lb_info/tasks/full_test.yml @@ -0,0 +1,11 @@ +- name: elb_application_lb full_test + block: + # setup + - include_tasks: setup.yml + + # Run main tests + - include_tasks: test_elb_application_lb_info.yml + + always: + # Cleanup + - include_tasks: teardown.yml \ No newline at end of file diff --git a/tests/integration/targets/elb_application_lb_info/tasks/main.yml b/tests/integration/targets/elb_application_lb_info/tasks/main.yml new file mode 100644 index 00000000000..4ec0660c237 --- /dev/null +++ b/tests/integration/targets/elb_application_lb_info/tasks/main.yml @@ -0,0 +1,40 @@ +- name: 'elb_application_lb_info integration 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: + + # 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_info/tasks/setup.yml b/tests/integration/targets/elb_application_lb_info/tasks/setup.yml new file mode 100644 index 00000000000..5dc4122b128 --- /dev/null +++ b/tests/integration/targets/elb_application_lb_info/tasks/setup.yml @@ -0,0 +1,83 @@ +- name: elb_application_lb_info setup + block: + - name: create VPC + ec2_vpc_net: + cidr_block: 10.228.228.0/22 + name: '{{ resource_prefix }}_vpc' + state: present + register: vpc + + - name: create internet gateway + ec2_vpc_igw: + vpc_id: '{{ vpc.vpc.id }}' + state: present + tags: + Name: '{{ resource_prefix }}' + register: igw + + - name: create public subnet + ec2_vpc_subnet: + cidr: '{{ item.cidr }}' + az: '{{ aws_region}}{{ item.az }}' + vpc_id: '{{ vpc.vpc.id }}' + state: present + tags: + Public: '{{ item.public|string }}' + Name: '{{ item.public|ternary(''public'', ''private'') }}-{{ item.az }}' + with_items: + - cidr: 10.228.228.0/24 + az: a + public: 'True' + - cidr: 10.228.229.0/24 + az: b + public: 'True' + - cidr: 10.228.230.0/24 + az: a + public: 'False' + - cidr: 10.228.231.0/24 + az: b + public: 'False' + register: subnets + + - ec2_vpc_subnet_info: + filters: + vpc-id: '{{ vpc.vpc.id }}' + register: vpc_subnets + + - name: create list of subnet ids + set_fact: + alb_subnets: '{{ vpc_subnets|community.general.json_query(''subnets[?tags.Public == `True`].id'') }}' + private_subnets: '{{ vpc_subnets|community.general.json_query(''subnets[?tags.Public != `True`].id'') }}' + + - name: create a route table + ec2_vpc_route_table: + vpc_id: '{{ vpc.vpc.id }}' + tags: + Name: igw-route + Created: '{{ resource_prefix }}' + subnets: '{{ alb_subnets + private_subnets }}' + routes: + - dest: 0.0.0.0/0 + gateway_id: '{{ igw.gateway_id }}' + register: route_table + + - ec2_group: + name: '{{ resource_prefix }}' + description: security group for Ansible ALB integration tests + state: present + vpc_id: '{{ vpc.vpc.id }}' + rules: + - proto: tcp + from_port: 1 + to_port: 65535 + cidr_ip: 0.0.0.0/0 + register: sec_group + + - name: create a target group for testing + elb_target_group: + name: '{{ tg_name }}' + protocol: http + port: 80 + vpc_id: '{{ vpc.vpc.id }}' + state: present + register: tg \ No newline at end of file diff --git a/tests/integration/targets/elb_application_lb_info/tasks/teardown.yml b/tests/integration/targets/elb_application_lb_info/tasks/teardown.yml new file mode 100644 index 00000000000..24326e343a6 --- /dev/null +++ b/tests/integration/targets/elb_application_lb_info/tasks/teardown.yml @@ -0,0 +1,83 @@ +- name: elb_application_lb_info teardown + block: + - name: destroy ALB + elb_application_lb: + name: '{{ alb_name }}' + state: absent + wait: true + wait_timeout: 600 + ignore_errors: true + + - name: destroy target group if it was created + elb_target_group: + name: '{{ tg_name }}' + protocol: http + port: 80 + vpc_id: '{{ vpc.vpc.id }}' + state: absent + wait: true + wait_timeout: 600 + register: remove_tg + retries: 5 + delay: 3 + until: remove_tg is success + when: tg is defined + ignore_errors: true + - name: destroy sec group + ec2_group: + name: '{{ sec_group.group_name }}' + description: security group for Ansible ALB integration tests + state: absent + vpc_id: '{{ vpc.vpc.id }}' + register: remove_sg + retries: 10 + delay: 5 + until: remove_sg is success + ignore_errors: true + - name: remove route table + ec2_vpc_route_table: + vpc_id: '{{ vpc.vpc.id }}' + route_table_id: '{{ route_table.route_table.route_table_id }}' + lookup: id + state: absent + register: remove_rt + retries: 10 + delay: 5 + until: remove_rt is success + ignore_errors: true + - name: destroy subnets + ec2_vpc_subnet: + cidr: '{{ item.cidr }}' + vpc_id: '{{ vpc.vpc.id }}' + state: absent + register: remove_subnet + retries: 10 + delay: 5 + until: remove_subnet is success + with_items: + - cidr: 10.228.228.0/24 + - cidr: 10.228.229.0/24 + - cidr: 10.228.230.0/24 + - cidr: 10.228.231.0/24 + ignore_errors: true + - name: destroy internet gateway + ec2_vpc_igw: + vpc_id: '{{ vpc.vpc.id }}' + tags: + Name: '{{ resource_prefix }}' + state: absent + register: remove_igw + retries: 10 + delay: 5 + until: remove_igw is success + ignore_errors: true + - name: destroy VPC + ec2_vpc_net: + cidr_block: 10.228.228.0/22 + name: '{{ resource_prefix }}_vpc' + state: absent + register: remove_vpc + retries: 10 + delay: 5 + until: remove_vpc is success + ignore_errors: true diff --git a/tests/integration/targets/elb_application_lb_info/tasks/test_elb_application_lb_info.yml b/tests/integration/targets/elb_application_lb_info/tasks/test_elb_application_lb_info.yml new file mode 100644 index 00000000000..229ac43001b --- /dev/null +++ b/tests/integration/targets/elb_application_lb_info/tasks/test_elb_application_lb_info.yml @@ -0,0 +1,41 @@ +- block: + + - name: create ALB with a listener + 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 }}" + register: alb + + - assert: + that: + - alb.changed + - alb.listeners|length == 1 + - alb.listeners[0].rules|length == 1 + + - name: ELB applicaiton info using load balancer arn + elb_application_lb_info: + load_balancer_arns: + - "{{ alb.load_balancer_arn }}" + register: elb_app_lb_info + + - assert: + that: + - elb_app_lb_info.load_balancers[0].ip_address_type == 'ipv4' + + - name: ELB applicaiton info using load balancer name + elb_application_lb_info: + names: + - "{{ alb.load_balancer_name }}" + register: elb_app_lb_info + + - assert: + that: + - elb_app_lb_info.load_balancers[0].ip_address_type == 'ipv4' diff --git a/tests/integration/targets/elb_network_lb/tasks/main.yml b/tests/integration/targets/elb_network_lb/tasks/main.yml index 896697018bc..5a45fc389b7 100644 --- a/tests/integration/targets/elb_network_lb/tasks/main.yml +++ b/tests/integration/targets/elb_network_lb/tasks/main.yml @@ -22,6 +22,7 @@ ec2_vpc_net: cidr_block: 10.228.228.0/22 name: "{{ resource_prefix }}_vpc" + ipv6_cidr: true state: present register: vpc @@ -33,7 +34,7 @@ Name: "{{ resource_prefix }}" register: igw - - name: create subnets + - name: create private subnets ec2_vpc_subnet: cidr: "{{ item.cidr }}" az: "{{ aws_region}}{{ item.az }}" @@ -43,12 +44,6 @@ Created_By: "{{ resource_prefix }}" Public: "{{ item.public }}" with_items: - - cidr: 10.228.228.0/24 - az: "a" - public: True - - cidr: 10.228.229.0/24 - az: "b" - public: True - cidr: 10.228.230.0/24 az: "a" public: False @@ -57,6 +52,27 @@ public: False register: subnets + - name: create public subnets with ipv6 + ec2_vpc_subnet: + cidr: '{{ item.cidr }}' + az: '{{ aws_region}}{{ item.az }}' + vpc_id: '{{ vpc.vpc.id }}' + state: present + ipv6_cidr: '{{ item.vpc_ipv6_cidr }}' + tags: + Public: '{{ item.public|string }}' + Name: '{{ item.public|ternary(''public'', ''private'') }}-{{ item.az }}' + Created_By: "{{ resource_prefix }}" + with_items: + - cidr: 10.228.228.0/24 + az: "a" + public: True + vpc_ipv6_cidr: "{{ vpc.vpc.ipv6_cidr_block_association_set[0].ipv6_cidr_block | replace('0::/56','0::/64') }}" + - cidr: 10.228.229.0/24 + az: "b" + public: True + vpc_ipv6_cidr: "{{ vpc.vpc.ipv6_cidr_block_association_set[0].ipv6_cidr_block | replace('0::/56','1::/64') }}" + - ec2_vpc_subnet_info: filters: vpc-id: "{{ vpc.vpc.id }}" @@ -113,6 +129,7 @@ register: tg_tcpudp - include_tasks: test_nlb_bad_listener_options.yml + - include_tasks: test_nlb_ip_address_type_option.yml - include_tasks: test_nlb_tags.yml - include_tasks: test_creating_nlb.yml - include_tasks: test_nlb_with_asg.yml diff --git a/tests/integration/targets/elb_network_lb/tasks/test_nlb_ip_address_type_option.yml b/tests/integration/targets/elb_network_lb/tasks/test_nlb_ip_address_type_option.yml new file mode 100644 index 00000000000..3baa453ac82 --- /dev/null +++ b/tests/integration/targets/elb_network_lb/tasks/test_nlb_ip_address_type_option.yml @@ -0,0 +1,92 @@ +- block: + - name: set NLB name for ipv6 + set_fact: + nlb_name_ipv6: "{{ nlb_name ~ 'ipv6' }}" + + - name: Create NLB with invalid ip address type + elb_network_lb: + name: "{{ nlb_name_ipv6 }}" + subnets: "{{ nlb_subnets }}" + state: present + listeners: + - Protocol: TCP + Port: 80 + DefaultActions: + - Type: forward + TargetGroupName: "{{ tg_name }}" + ip_address_type: "ipv6" + ignore_errors: true + register: nlb + + - assert: + that: + - nlb is failed + + - name: Create NLB with dualstack ip address type + elb_network_lb: + name: "{{ nlb_name_ipv6 }}" + subnets: "{{ nlb_subnets }}" + state: present + listeners: + - Protocol: TCP + Port: 80 + DefaultActions: + - Type: forward + TargetGroupName: "{{ tg_name }}" + ip_address_type: "dualstack" + ignore_errors: true + register: nlb + + - assert: + that: + - nlb.ip_address_type == "dualstack" + + - name: Update NLB with ipv4 address type + elb_network_lb: + name: "{{ nlb_name_ipv6 }}" + subnets: "{{ nlb_subnets }}" + state: present + listeners: + - Protocol: TCP + Port: 80 + DefaultActions: + - Type: forward + TargetGroupName: "{{ tg_name }}" + ip_address_type: "ipv4" + ignore_errors: true + register: nlb + + - assert: + that: + - nlb.changed + - nlb.ip_address_type == "ipv4" + + - name: Test idempotence when updating NLB + elb_network_lb: + name: "{{ nlb_name_ipv6 }}" + subnets: "{{ nlb_subnets }}" + state: present + listeners: + - Protocol: TCP + Port: 80 + DefaultActions: + - Type: forward + TargetGroupName: "{{ tg_name }}" + ip_address_type: "ipv4" + ignore_errors: true + register: nlb + + - assert: + that: + - not nlb.changed + - nlb.ip_address_type == "ipv4" + + always: + # Cleanup + - name: destroy NLB if created + elb_network_lb: + name: '{{ nlb_name_ipv6 }}' + state: absent + wait: true + wait_timeout: 600 + ignore_errors: true From a5126b887d307a1cc7a63f5208cb741c8d41a35e Mon Sep 17 00:00:00 2001 From: abikouo Date: Thu, 25 Mar 2021 14:38:06 +0100 Subject: [PATCH 02/11] change log --- changelogs/499-elb-module-add-ip_address_type_option.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 changelogs/499-elb-module-add-ip_address_type_option.yml diff --git a/changelogs/499-elb-module-add-ip_address_type_option.yml b/changelogs/499-elb-module-add-ip_address_type_option.yml new file mode 100644 index 00000000000..afc1f939be0 --- /dev/null +++ b/changelogs/499-elb-module-add-ip_address_type_option.yml @@ -0,0 +1,4 @@ +minor_changes: +- elb_application_lb - added ``ip_address_type`` parameter to support changing application load balancer configuration (https://github.com/ansible-collections/community.aws/pull/499). +- elb_network_lb - added ``ip_address_type`` parameter to support changing network load balancer configuration (https://github.com/ansible-collections/community.aws/pull/499). +- elb_application_lb_info - added ``ip_address_type`` in output when gathering application load balancer parameters (https://github.com/ansible-collections/community.aws/pull/499). From 86bd49b995423fd7ced57df72b895eb7fcee2afd Mon Sep 17 00:00:00 2001 From: abikouo Date: Mon, 29 Mar 2021 15:04:09 +0200 Subject: [PATCH 03/11] lint validation --- plugins/modules/elb_application_lb.py | 1 - plugins/modules/elb_application_lb_info.py | 8 ++------ plugins/modules/elb_network_lb.py | 5 ++--- 3 files changed, 4 insertions(+), 10 deletions(-) diff --git a/plugins/modules/elb_application_lb.py b/plugins/modules/elb_application_lb.py index 9dcab533c9c..0d0695a0352 100644 --- a/plugins/modules/elb_application_lb.py +++ b/plugins/modules/elb_application_lb.py @@ -182,7 +182,6 @@ ip_address_type: description: - Sets the type of IP addresses used by the subnets of the specified Application Load Balancer. - default: "ipv4" choices: [ 'ipv4', 'dualstack' ] type: str extends_documentation_fragment: diff --git a/plugins/modules/elb_application_lb_info.py b/plugins/modules/elb_application_lb_info.py index 9d3ad385556..17fd1324683 100644 --- a/plugins/modules/elb_application_lb_info.py +++ b/plugins/modules/elb_application_lb_info.py @@ -142,10 +142,6 @@ description: The ID of the VPC for the load balancer. type: str sample: vpc-0011223344 - ip_address_type: - description: The type of IP addresses used by the subnets for the load balancer. - type: str - sample: ipv4 ''' try: @@ -199,7 +195,7 @@ def get_load_balancer_tags(connection, module, load_balancer_arn): module.fail_json_aws(e, msg="Failed to describe load balancer tags") -def get_load_balancer_ipaddresstype(connection, load_balancer_arn) : +def get_load_balancer_ipaddresstype(connection, module, load_balancer_arn) : try: return connection.describe_load_balancers(LoadBalancerArns=[load_balancer_arn])['LoadBalancers'][0]['IpAddressType'] except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: @@ -235,7 +231,7 @@ def list_load_balancers(connection, module): listener['rules'] = get_listener_rules(connection, module, listener['ListenerArn']) # Get ELB ip address type - load_balancer['IpAddressType']=get_load_balancer_ipaddresstype(connection, load_balancer['LoadBalancerArn']) + load_balancer['IpAddressType']=get_load_balancer_ipaddresstype(connection,module,load_balancer['LoadBalancerArn']) # Turn the boto3 result in to ansible_friendly_snaked_names snaked_load_balancers = [camel_dict_to_snake_dict(load_balancer) for load_balancer in load_balancers['LoadBalancers']] diff --git a/plugins/modules/elb_network_lb.py b/plugins/modules/elb_network_lb.py index d0d2d82f14f..70942bbf8ee 100644 --- a/plugins/modules/elb_network_lb.py +++ b/plugins/modules/elb_network_lb.py @@ -128,7 +128,6 @@ ip_address_type: description: - Sets the type of IP addresses used by the subnets of the specified Application Load Balancer. - default: "ipv4" choices: [ 'ipv4', 'dualstack' ] type: str extends_documentation_fragment: @@ -385,7 +384,7 @@ def create_or_update_elb(elb_obj): elb_obj.update_elb_attributes() # Update ELB ip address type only if option has been provided - if elb_obj.module.params.get('ip_address_type') is not None : + if elb_obj.module.params.get('ip_address_type') is not None: elb_obj.modify_ip_address_type(elb_obj.module.params.get('ip_address_type')) # Convert to snake_case and merge in everything we want to return to the user @@ -399,7 +398,7 @@ def create_or_update_elb(elb_obj): snaked_elb['tags'] = boto3_tag_list_to_ansible_dict(snaked_elb['tags']) # ip address type - snaked_elb['ip_address_type']=elb_obj.get_elb_ip_address_type() + snaked_elb['ip_address_type'] = elb_obj.get_elb_ip_address_type() elb_obj.module.exit_json(changed=elb_obj.changed, **snaked_elb) From 222db35579c6570ca8bd165d94db1928e2d8d47f Mon Sep 17 00:00:00 2001 From: abikouo Date: Mon, 29 Mar 2021 15:58:27 +0200 Subject: [PATCH 04/11] pep8 linting --- plugins/modules/elb_application_lb.py | 6 +++--- plugins/modules/elb_application_lb_info.py | 6 +++--- plugins/modules/elb_network_lb.py | 4 ++-- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/plugins/modules/elb_application_lb.py b/plugins/modules/elb_application_lb.py index 0d0695a0352..284d392891f 100644 --- a/plugins/modules/elb_application_lb.py +++ b/plugins/modules/elb_application_lb.py @@ -567,8 +567,8 @@ def create_or_update_elb(elb_obj): elb_obj.changed = True # Update ELB ip address type only if option has been provided - if elb_obj.module.params.get('ip_address_type') is not None : - elb_obj.modify_ip_address_type(elb_obj.module.params.get('ip_address_type')) + if elb_obj.module.params.get('ip_address_type') is not None: + elb_obj.modify_ip_address_type(elb_obj.module.params.get('ip_address_type')) # Get the ELB again elb_obj.update() @@ -591,7 +591,7 @@ def create_or_update_elb(elb_obj): snaked_elb['tags'] = boto3_tag_list_to_ansible_dict(snaked_elb['tags']) # ip address type - snaked_elb['ip_address_type']=elb_obj.get_elb_ip_address_type() + snaked_elb['ip_address_type'] = elb_obj.get_elb_ip_address_type() elb_obj.module.exit_json(changed=elb_obj.changed, **snaked_elb) diff --git a/plugins/modules/elb_application_lb_info.py b/plugins/modules/elb_application_lb_info.py index 17fd1324683..fcf06e1473c 100644 --- a/plugins/modules/elb_application_lb_info.py +++ b/plugins/modules/elb_application_lb_info.py @@ -195,14 +195,14 @@ def get_load_balancer_tags(connection, module, load_balancer_arn): module.fail_json_aws(e, msg="Failed to describe load balancer tags") -def get_load_balancer_ipaddresstype(connection, module, load_balancer_arn) : +def get_load_balancer_ipaddresstype(connection, module, load_balancer_arn): try: return connection.describe_load_balancers(LoadBalancerArns=[load_balancer_arn])['LoadBalancers'][0]['IpAddressType'] except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: module.fail_json_aws(e, msg="Failed to describe load balancer tags") -def list_load_balancers(connection, module): +def list_load_balancers(connection, module): load_balancer_arns = module.params.get("load_balancer_arns") names = module.params.get("names") @@ -231,7 +231,7 @@ def list_load_balancers(connection, module): listener['rules'] = get_listener_rules(connection, module, listener['ListenerArn']) # Get ELB ip address type - load_balancer['IpAddressType']=get_load_balancer_ipaddresstype(connection,module,load_balancer['LoadBalancerArn']) + load_balancer['IpAddressType'] = get_load_balancer_ipaddresstype(connection, module, load_balancer['LoadBalancerArn']) # Turn the boto3 result in to ansible_friendly_snaked_names snaked_load_balancers = [camel_dict_to_snake_dict(load_balancer) for load_balancer in load_balancers['LoadBalancers']] diff --git a/plugins/modules/elb_network_lb.py b/plugins/modules/elb_network_lb.py index 70942bbf8ee..5eeb2ec6220 100644 --- a/plugins/modules/elb_network_lb.py +++ b/plugins/modules/elb_network_lb.py @@ -316,6 +316,7 @@ from ansible_collections.amazon.aws.plugins.module_utils.ec2 import camel_dict_to_snake_dict, boto3_tag_list_to_ansible_dict, compare_aws_tags from ansible_collections.amazon.aws.plugins.module_utils.elbv2 import NetworkLoadBalancer, ELBListeners, ELBListener + def create_or_update_elb(elb_obj): """Create ELB or modify main attributes. json_exit here""" if elb_obj.elb: @@ -342,7 +343,6 @@ def create_or_update_elb(elb_obj): # Create load balancer elb_obj.create_elb() - # ELB attributes elb_obj.update_elb_attributes() elb_obj.modify_elb_attributes() @@ -385,7 +385,7 @@ def create_or_update_elb(elb_obj): # Update ELB ip address type only if option has been provided if elb_obj.module.params.get('ip_address_type') is not None: - elb_obj.modify_ip_address_type(elb_obj.module.params.get('ip_address_type')) + elb_obj.modify_ip_address_type(elb_obj.module.params.get('ip_address_type')) # Convert to snake_case and merge in everything we want to return to the user snaked_elb = camel_dict_to_snake_dict(elb_obj.elb) From ec2caa6c39a13c7feb7db3265fd0b83f40810a40 Mon Sep 17 00:00:00 2001 From: abikouo <79859644+abikouo@users.noreply.github.com> Date: Tue, 20 Apr 2021 11:07:35 +0200 Subject: [PATCH 05/11] Update main.yml --- tests/integration/targets/elb_application_lb_info/meta/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/integration/targets/elb_application_lb_info/meta/main.yml b/tests/integration/targets/elb_application_lb_info/meta/main.yml index bc4ebde80b9..1810d4bec98 100644 --- a/tests/integration/targets/elb_application_lb_info/meta/main.yml +++ b/tests/integration/targets/elb_application_lb_info/meta/main.yml @@ -1,2 +1,2 @@ dependencies: - - setup_remote_tmp_dir \ No newline at end of file + - setup_remote_tmp_dir From dabefd3c7a82a1988e5db0c8ffdbb6da0afdf943 Mon Sep 17 00:00:00 2001 From: abikouo <79859644+abikouo@users.noreply.github.com> Date: Tue, 20 Apr 2021 11:07:49 +0200 Subject: [PATCH 06/11] Update full_test.yml --- .../targets/elb_application_lb_info/tasks/full_test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/integration/targets/elb_application_lb_info/tasks/full_test.yml b/tests/integration/targets/elb_application_lb_info/tasks/full_test.yml index c74c2b958de..7603a0454ab 100644 --- a/tests/integration/targets/elb_application_lb_info/tasks/full_test.yml +++ b/tests/integration/targets/elb_application_lb_info/tasks/full_test.yml @@ -8,4 +8,4 @@ always: # Cleanup - - include_tasks: teardown.yml \ No newline at end of file + - include_tasks: teardown.yml From 9a970998ba3c66cd917f08afdb2efdf998bed65e Mon Sep 17 00:00:00 2001 From: abikouo <79859644+abikouo@users.noreply.github.com> Date: Tue, 20 Apr 2021 11:08:10 +0200 Subject: [PATCH 07/11] Update setup.yml --- .../targets/elb_application_lb_info/tasks/setup.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/integration/targets/elb_application_lb_info/tasks/setup.yml b/tests/integration/targets/elb_application_lb_info/tasks/setup.yml index 5dc4122b128..f2304b44e7e 100644 --- a/tests/integration/targets/elb_application_lb_info/tasks/setup.yml +++ b/tests/integration/targets/elb_application_lb_info/tasks/setup.yml @@ -80,4 +80,5 @@ port: 80 vpc_id: '{{ vpc.vpc.id }}' state: present - register: tg \ No newline at end of file + register: tg + From cdc1d40439db7228fcb2f24349ed532aaf7b97bf Mon Sep 17 00:00:00 2001 From: abikouo <79859644+abikouo@users.noreply.github.com> Date: Fri, 23 Apr 2021 08:29:47 +0200 Subject: [PATCH 08/11] Update plugins/modules/elb_application_lb_info.py Co-authored-by: Jill R <4121322+jillr@users.noreply.github.com> --- plugins/modules/elb_application_lb_info.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/modules/elb_application_lb_info.py b/plugins/modules/elb_application_lb_info.py index fcf06e1473c..3848bc4766b 100644 --- a/plugins/modules/elb_application_lb_info.py +++ b/plugins/modules/elb_application_lb_info.py @@ -199,7 +199,7 @@ def get_load_balancer_ipaddresstype(connection, module, load_balancer_arn): try: return connection.describe_load_balancers(LoadBalancerArns=[load_balancer_arn])['LoadBalancers'][0]['IpAddressType'] except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: - module.fail_json_aws(e, msg="Failed to describe load balancer tags") + module.fail_json_aws(e, msg="Failed to describe load balancer ip address type") def list_load_balancers(connection, module): From 185ec77e33a83c7c4bdb448d1ef8a09b8bb41e9e Mon Sep 17 00:00:00 2001 From: abikouo <79859644+abikouo@users.noreply.github.com> Date: Fri, 23 Apr 2021 08:32:15 +0200 Subject: [PATCH 09/11] Update test_alb_ip_address_type_options.yml --- .../tasks/test_alb_ip_address_type_options.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/integration/targets/elb_application_lb/tasks/test_alb_ip_address_type_options.yml b/tests/integration/targets/elb_application_lb/tasks/test_alb_ip_address_type_options.yml index 788befe2765..9249d1161c0 100644 --- a/tests/integration/targets/elb_application_lb/tasks/test_alb_ip_address_type_options.yml +++ b/tests/integration/targets/elb_application_lb/tasks/test_alb_ip_address_type_options.yml @@ -15,7 +15,7 @@ DefaultActions: - Type: forward TargetGroupName: "{{ tg_name }}" - ip_address_type: "ipv6" + ip_address_type: "ip_addr_v4_v6" ignore_errors: yes register: elb From 8f0ef45c1b4a1f60a7394eceb08b9f6adc835f51 Mon Sep 17 00:00:00 2001 From: abikouo <79859644+abikouo@users.noreply.github.com> Date: Fri, 23 Apr 2021 08:39:41 +0200 Subject: [PATCH 10/11] Update setup.yml --- .../targets/elb_application_lb_info/tasks/setup.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/integration/targets/elb_application_lb_info/tasks/setup.yml b/tests/integration/targets/elb_application_lb_info/tasks/setup.yml index f2304b44e7e..8e19ca76e14 100644 --- a/tests/integration/targets/elb_application_lb_info/tasks/setup.yml +++ b/tests/integration/targets/elb_application_lb_info/tasks/setup.yml @@ -46,8 +46,8 @@ - name: create list of subnet ids set_fact: - alb_subnets: '{{ vpc_subnets|community.general.json_query(''subnets[?tags.Public == `True`].id'') }}' - private_subnets: '{{ vpc_subnets|community.general.json_query(''subnets[?tags.Public != `True`].id'') }}' + alb_subnets: '{{ ( vpc_subnets.subnets | selectattr('tags.Public', 'equalto', 'True') | map(attribute='id') | list ) }}' + private_subnets: '{{ ( vpc_subnets.subnets | rejectattr('tags.Public', 'equalto', 'True') | map(attribute='id') | list ) }}' - name: create a route table ec2_vpc_route_table: From 2dbb8d198a3eec1713b0543f318daaa906c8e48c Mon Sep 17 00:00:00 2001 From: aubin Date: Fri, 23 Apr 2021 09:46:12 +0200 Subject: [PATCH 11/11] sanity --- .../targets/elb_application_lb_info/tasks/setup.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/integration/targets/elb_application_lb_info/tasks/setup.yml b/tests/integration/targets/elb_application_lb_info/tasks/setup.yml index 8e19ca76e14..26289d230d0 100644 --- a/tests/integration/targets/elb_application_lb_info/tasks/setup.yml +++ b/tests/integration/targets/elb_application_lb_info/tasks/setup.yml @@ -46,8 +46,8 @@ - name: create list of subnet ids set_fact: - alb_subnets: '{{ ( vpc_subnets.subnets | selectattr('tags.Public', 'equalto', 'True') | map(attribute='id') | list ) }}' - private_subnets: '{{ ( vpc_subnets.subnets | rejectattr('tags.Public', 'equalto', 'True') | map(attribute='id') | list ) }}' + alb_subnets: "{{ ( vpc_subnets.subnets | selectattr('tags.Public', 'equalto', 'True') | map(attribute='id') | list ) }}" + private_subnets: "{{ ( vpc_subnets.subnets | rejectattr('tags.Public', 'equalto', 'True') | map(attribute='id') | list ) }}" - name: create a route table ec2_vpc_route_table: