New module: AWS Network load balancer (#33808)

* New module - elb_network_lb

* Fix creating a load balancer without tags

* Linter

Fix purging tags

Remove extra imports

* add support for cross zone lb, doc update and fix tagging

* pep8 fixes

* Add integration tests for elb_network_lb module

* more pep8

* Remove non-applicable option for NLBs

* fix target protocol

* pep8
This commit is contained in:
Rob
2018-05-25 06:38:34 +10:00
committed by Ryan Brown
parent 529ef6446e
commit 858f0fc000
12 changed files with 1095 additions and 8 deletions

View File

@@ -0,0 +1,2 @@
cloud/aws
unsupported

View File

@@ -0,0 +1,6 @@
---
# load balancer and target group names have to be less than 32 characters
# the 8 digit identifier at the end of resource_prefix helps determine during which test something
# was created and allows tests to be run in parallel
nlb_name: "my-nlb-{{ resource_prefix | regex_search('([0-9]+)$') }}"
tg_name: "my-tg-{{ resource_prefix | regex_search('([0-9]+)$') }}"

View File

@@ -0,0 +1,3 @@
dependencies:
- prepare_tests
- setup_ec2

View File

@@ -0,0 +1,205 @@
- block:
- name: set connection information for all tasks
set_fact:
aws_connection_info: &aws_connection_info
aws_access_key: "{{ aws_access_key }}"
aws_secret_key: "{{ aws_secret_key }}"
security_token: "{{ security_token }}"
region: "{{ aws_region }}"
no_log: yes
- name: create VPC
ec2_vpc_net:
cidr_block: 10.228.228.0/22
name: "{{ resource_prefix }}_vpc"
state: present
<<: *aws_connection_info
register: vpc
- name: create internet gateway
ec2_vpc_igw:
vpc_id: "{{ vpc.vpc.id }}"
state: present
tags:
Name: "{{ resource_prefix }}"
<<: *aws_connection_info
register: igw
- name: create subnets
ec2_vpc_subnet:
cidr: "{{ item.cidr }}"
az: "{{ aws_region}}{{ item.az }}"
vpc_id: "{{ vpc.vpc.id }}"
state: present
tags:
Created_By: "{{ resource_prefix }}"
Public: "{{ item.public }}"
<<: *aws_connection_info
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_facts:
filters:
vpc-id: "{{ vpc.vpc.id }}"
<<: *aws_connection_info
register: vpc_subnets
- name: create list of subnet ids
set_fact:
nlb_subnets: "{{ vpc_subnets|json_query('subnets[?tags.Public == `True`].id') }}"
private_subnets: "{{ vpc_subnets|json_query('subnets[?tags.Public != `True`].id') }}"
- name: create a route table
ec2_vpc_route_table:
vpc_id: "{{ vpc.vpc.id }}"
<<: *aws_connection_info
tags:
Name: igw-route
Created: "{{ resource_prefix }}"
subnets: "{{ nlb_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 NLB 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
- proto: all
ports: 80
cidr_ip: 10.228.228.0/22
<<: *aws_connection_info
register: sec_group
- name: create a target group for testing
elb_target_group:
name: "{{ tg_name }}"
protocol: tcp
port: 80
vpc_id: "{{ vpc.vpc.id }}"
state: present
<<: *aws_connection_info
register: tg
- include_tasks: test_nlb_bad_listener_options.yml
- include_tasks: test_nlb_tags.yml
- include_tasks: test_creating_nlb.yml
- include_tasks: test_nlb_with_asg.yml
- include_tasks: test_modifying_nlb_listeners.yml
- include_tasks: test_deleting_nlb.yml
always:
- name: destroy NLB
elb_network_lb:
name: "{{ nlb_name }}"
state: absent
wait: yes
wait_timeout: 600
<<: *aws_connection_info
ignore_errors: yes
- name: destroy target group if it was created
elb_target_group:
name: "{{ tg_name }}"
protocol: tcp
port: 80
vpc_id: "{{ vpc.vpc.id }}"
state: absent
wait: yes
wait_timeout: 600
<<: *aws_connection_info
register: remove_tg
retries: 5
delay: 3
until: remove_tg is success
when: tg is defined
ignore_errors: yes
- name: destroy sec group
ec2_group:
name: "{{ sec_group.group_name }}"
description: "security group for Ansible NLB integration tests"
state: absent
vpc_id: "{{ vpc.vpc.id }}"
<<: *aws_connection_info
register: remove_sg
retries: 10
delay: 5
until: remove_sg is success
ignore_errors: yes
- 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
<<: *aws_connection_info
register: remove_rt
retries: 10
delay: 5
until: remove_rt is success
ignore_errors: yes
- name: destroy subnets
ec2_vpc_subnet:
cidr: "{{ item.cidr }}"
vpc_id: "{{ vpc.vpc.id }}"
state: absent
<<: *aws_connection_info
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: yes
- name: destroy internet gateway
ec2_vpc_igw:
vpc_id: "{{ vpc.vpc.id }}"
tags:
Name: "{{ resource_prefix }}"
state: absent
<<: *aws_connection_info
register: remove_igw
retries: 10
delay: 5
until: remove_igw is success
ignore_errors: yes
- name: destroy VPC
ec2_vpc_net:
cidr_block: 10.228.228.0/22
name: "{{ resource_prefix }}_vpc"
state: absent
<<: *aws_connection_info
register: remove_vpc
retries: 10
delay: 5
until: remove_vpc is success
ignore_errors: yes

View File

@@ -0,0 +1,48 @@
- block:
- name: set connection information for all tasks
set_fact:
aws_connection_info: &aws_connection_info
aws_access_key: "{{ aws_access_key }}"
aws_secret_key: "{{ aws_secret_key }}"
security_token: "{{ security_token }}"
region: "{{ aws_region }}"
no_log: yes
- name: create NLB with a listener
elb_network_lb:
name: "{{ nlb_name }}"
subnets: "{{ nlb_subnets }}"
state: present
listeners:
- Protocol: TCP
Port: 80
DefaultActions:
- Type: forward
TargetGroupName: "{{ tg_name }}"
<<: *aws_connection_info
register: nlb
- assert:
that:
- nlb.changed
- nlb.listeners|length == 1
- name: test idempotence creating NLB with a listener
elb_network_lb:
name: "{{ nlb_name }}"
subnets: "{{ nlb_subnets }}"
state: present
listeners:
- Protocol: TCP
Port: 80
DefaultActions:
- Type: forward
TargetGroupName: "{{ tg_name }}"
<<: *aws_connection_info
register: nlb
- assert:
that:
- not nlb.changed
- nlb.listeners|length == 1

View File

@@ -0,0 +1,50 @@
- block:
- name: set connection information for all tasks
set_fact:
aws_connection_info: &aws_connection_info
aws_access_key: "{{ aws_access_key }}"
aws_secret_key: "{{ aws_secret_key }}"
security_token: "{{ security_token }}"
region: "{{ aws_region }}"
no_log: yes
- name: destroy NLB with listener
elb_network_lb:
name: "{{ nlb_name }}"
subnets: "{{ nlb_subnets }}"
state: absent
listeners:
- Protocol: TCP
Port: 80
DefaultActions:
- Type: forward
TargetGroupName: "{{ tg_name }}"
<<: *aws_connection_info
wait: yes
wait_timeout: 300
register: nlb
- assert:
that:
- nlb.changed
- name: test idempotence
elb_network_lb:
name: "{{ nlb_name }}"
subnets: "{{ nlb_subnets }}"
state: absent
listeners:
- Protocol: TCP
Port: 80
DefaultActions:
- Type: forward
TargetGroupName: "{{ tg_name }}"
<<: *aws_connection_info
wait: yes
wait_timeout: 300
register: nlb
- assert:
that:
- not nlb.changed

View File

@@ -0,0 +1,88 @@
- block:
- name: set connection information for all tasks
set_fact:
aws_connection_info: &aws_connection_info
aws_access_key: "{{ aws_access_key }}"
aws_secret_key: "{{ aws_secret_key }}"
security_token: "{{ security_token }}"
region: "{{ aws_region }}"
no_log: yes
- name: add a listener
elb_network_lb:
name: "{{ nlb_name }}"
subnets: "{{ nlb_subnets }}"
state: present
listeners:
- Protocol: TCP
Port: 80
DefaultActions:
- Type: forward
TargetGroupName: "{{ tg_name }}"
- Protocol: TCP
Port: 443
DefaultActions:
- Type: forward
TargetGroupName: "{{ tg_name }}"
<<: *aws_connection_info
register: nlb
- assert:
that:
- nlb.changed
- nlb.listeners|length == 2
- name: test an omitted listener will not be removed without purge_listeners
elb_network_lb:
name: "{{ nlb_name }}"
subnets: "{{ nlb_subnets }}"
state: present
purge_listeners: false
listeners:
- Protocol: TCP
Port: 80
DefaultActions:
- Type: forward
TargetGroupName: "{{ tg_name }}"
<<: *aws_connection_info
register: nlb
- assert:
that:
- not nlb.changed
- nlb.listeners|length == 2
- name: remove the rule
elb_network_lb:
name: "{{ nlb_name }}"
subnets: "{{ nlb_subnets }}"
state: present
purge_listeners: true
listeners:
- Protocol: TCP
Port: 80
DefaultActions:
- Type: forward
TargetGroupName: "{{ tg_name }}"
<<: *aws_connection_info
register: nlb
- assert:
that:
- nlb.changed
- nlb.listeners|length == 1
- name: remove listener from NLB
elb_network_lb:
name: "{{ nlb_name }}"
subnets: "{{ nlb_subnets }}"
state: present
listeners: []
<<: *aws_connection_info
register: nlb
- assert:
that:
- nlb.changed
- not nlb.listeners

View File

@@ -0,0 +1,72 @@
- block:
- name: set connection information for all tasks
set_fact:
aws_connection_info: &aws_connection_info
aws_access_key: "{{ aws_access_key }}"
aws_secret_key: "{{ aws_secret_key }}"
security_token: "{{ security_token }}"
region: "{{ aws_region }}"
no_log: yes
- name: test creating an NLB with invalid listener options
elb_network_lb:
name: "{{ nlb_name }}"
subnets: "{{ nlb_subnets }}"
#security_groups: "{{ sec_group.group_id }}"
state: present
listeners:
- Protocol: TCP
Port: 80
Certificates: {'CertificateArn': 'test', 'IsDefault': 'True'}
DefaultActions:
- Type: forward
TargetGroupName: "{{ tg_name }}"
<<: *aws_connection_info
ignore_errors: yes
register: nlb
- assert:
that:
- nlb is failed
- "'unable to convert to list' in nlb.msg"
- name: test creating an NLB without providing required listener options
elb_network_lb:
name: "{{ nlb_name }}"
subnets: "{{ nlb_subnets }}"
#security_groups: "{{ sec_group.group_id }}"
state: present
listeners:
- Port: 80
<<: *aws_connection_info
ignore_errors: yes
register: nlb
- assert:
that:
- nlb is failed
- '"missing required arguments" in nlb.msg'
- '"Protocol" in nlb.msg'
- '"DefaultActions" in nlb.msg'
- name: test creating an NLB providing an invalid listener option type
elb_network_lb:
name: "{{ nlb_name }}"
subnets: "{{ nlb_subnets }}"
#security_groups: "{{ sec_group.group_id }}"
state: present
listeners:
- Protocol: TCP
Port: "bad type"
DefaultActions:
- Type: forward
TargetGroupName: "{{ tg_name }}"
<<: *aws_connection_info
ignore_errors: yes
register: nlb
- assert:
that:
- nlb is failed
- "'unable to convert to int' in nlb.msg"

View File

@@ -0,0 +1,101 @@
- block:
- name: set connection information for all tasks
set_fact:
aws_connection_info: &aws_connection_info
aws_access_key: "{{ aws_access_key }}"
aws_secret_key: "{{ aws_secret_key }}"
security_token: "{{ security_token }}"
region: "{{ aws_region }}"
no_log: yes
- name: create NLB with no listeners
elb_network_lb:
name: "{{ nlb_name }}"
subnets: "{{ nlb_subnets }}"
state: present
<<: *aws_connection_info
register: nlb
- assert:
that:
- nlb.changed
- name: re-create NLB with no listeners
elb_network_lb:
name: "{{ nlb_name }}"
subnets: "{{ nlb_subnets }}"
state: present
<<: *aws_connection_info
register: nlb
- assert:
that:
- not nlb.changed
- name: add tags to NLB
elb_network_lb:
name: "{{ nlb_name }}"
subnets: "{{ nlb_subnets }}"
state: present
tags:
created_by: "NLB test {{ resource_prefix }}"
<<: *aws_connection_info
register: nlb
- assert:
that:
- nlb.changed
- 'nlb.tags.created_by == "NLB test {{ resource_prefix }}"'
- name: test tags are not removed if unspecified
elb_network_lb:
name: "{{ nlb_name }}"
subnets: "{{ nlb_subnets }}"
state: present
<<: *aws_connection_info
register: nlb
- assert:
that:
- not nlb.changed
- 'nlb.tags.created_by == "NLB test {{ resource_prefix }}"'
- name: remove tags from NLB
elb_network_lb:
name: "{{ nlb_name }}"
subnets: "{{ nlb_subnets }}"
state: present
tags: {}
<<: *aws_connection_info
register: nlb
- assert:
that:
- nlb.changed
- not nlb.tags
- name: test idempotence
elb_network_lb:
name: "{{ nlb_name }}"
subnets: "{{ nlb_subnets }}"
state: present
tags: {}
<<: *aws_connection_info
register: nlb
- assert:
that:
- not nlb.changed
- not nlb.tags
- name: destroy NLB with no listeners
elb_network_lb:
name: "{{ nlb_name }}"
state: absent
<<: *aws_connection_info
register: nlb
- assert:
that:
- nlb.changed

View File

@@ -0,0 +1,90 @@
- block:
# create instances
- name: set connection information for all tasks
set_fact:
aws_connection_info: &aws_connection_info
aws_access_key: "{{ aws_access_key }}"
aws_secret_key: "{{ aws_secret_key }}"
security_token: "{{ security_token }}"
region: "{{ aws_region }}"
no_log: yes
- ec2_ami_facts:
<<: *aws_connection_info
filters:
architecture: x86_64
virtualization-type: hvm
root-device-type: ebs
name: "amzn-ami-hvm*"
register: amis
- set_fact:
latest_amazon_linux: "{{ amis.images | sort(attribute='creation_date') | last }}"
- ec2_asg:
<<: *aws_connection_info
state: absent
name: "{{ resource_prefix }}-webservers"
wait_timeout: 900
- ec2_lc:
<<: *aws_connection_info
name: "{{ resource_prefix }}-web-lcfg"
state: absent
- name: Create launch config for testing
ec2_lc:
<<: *aws_connection_info
name: "{{ resource_prefix }}-web-lcfg"
assign_public_ip: true
image_id: "{{ latest_amazon_linux.image_id }}"
security_groups: "{{ sec_group.group_id }}"
instance_type: t2.micro
user_data: |
#!/bin/bash
set -x
yum update -y --nogpgcheck
yum install -y --nogpgcheck httpd
echo "Hello Ansiblings!" >> /var/www/html/index.html
service httpd start
volumes:
- device_name: /dev/xvda
volume_size: 10
volume_type: gp2
delete_on_termination: true
- name: Create autoscaling group for app server fleet
ec2_asg:
<<: *aws_connection_info
name: "{{ resource_prefix }}-webservers"
vpc_zone_identifier: "{{ nlb_subnets }}"
launch_config_name: "{{ resource_prefix }}-web-lcfg"
termination_policies:
- OldestLaunchConfiguration
- Default
health_check_period: 600
health_check_type: EC2
replace_all_instances: true
min_size: 0
max_size: 2
desired_capacity: 1
wait_for_instances: true
target_group_arns:
- "{{ tg.target_group_arn }}"
always:
- ec2_asg:
<<: *aws_connection_info
state: absent
name: "{{ resource_prefix }}-webservers"
wait_timeout: 900
ignore_errors: yes
- ec2_lc:
<<: *aws_connection_info
name: "{{ resource_prefix }}-web-lcfg"
state: absent
ignore_errors: yes