Skip to content

Commit

Permalink
AWS ELB: Return empty list when no load balancer name was found (#215)
Browse files Browse the repository at this point in the history
When trying to describe a LoadBalancer that doesn't exist, the module crash. Instead of that behavior, this commit will return an empty list when no load balancer is found, allowing to deal next tasks by reading the output of the module.

Co-authored-by: Pedro Magalhães <[email protected]>
  • Loading branch information
pjrm and pjrm authored Mar 14, 2021
1 parent 7c1b49f commit 3d5ffdc
Show file tree
Hide file tree
Showing 4 changed files with 150 additions and 13 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
minor_changes:
- elb_classic_info - If the provided load balancer doesn't exist, return an empty list instead of throwing an error. (https://github.com/ansible-collections/community.aws/pull/215).
32 changes: 21 additions & 11 deletions plugins/modules/elb_classic_lb_info.py
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@
vpc_id: vpc-c248fda4
'''

from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule, is_boto3_error_code
from ansible_collections.amazon.aws.plugins.module_utils.ec2 import (
AWSRetry,
camel_dict_to_snake_dict,
Expand All @@ -154,14 +154,17 @@
except ImportError:
pass # caught by AnsibleAWSModule

MAX_AWS_RETRIES = 5
MAX_AWS_DELAY = 5

@AWSRetry.backoff(tries=5, delay=5, backoff=2.0)
def list_elbs(connection, names):
paginator = connection.get_paginator('describe_load_balancers')
load_balancers = paginator.paginate(LoadBalancerNames=names).build_full_result().get('LoadBalancerDescriptions', [])

def list_elbs(connection, load_balancer_names):
results = []

for lb in load_balancers:
for load_balancer_name in load_balancer_names:
lb = get_lb(connection, load_balancer_name)
if not lb:
continue
description = camel_dict_to_snake_dict(lb)
name = lb['LoadBalancerName']
instances = lb.get('Instances', [])
Expand All @@ -174,13 +177,20 @@ def list_elbs(connection, names):
return results


def get_lb_attributes(connection, name):
attributes = connection.describe_load_balancer_attributes(LoadBalancerName=name).get('LoadBalancerAttributes', {})
def get_lb(connection, load_balancer_name):
try:
return connection.describe_load_balancers(aws_retry=True, LoadBalancerNames=[load_balancer_name])['LoadBalancerDescriptions'][0]
except is_boto3_error_code('LoadBalancerNotFound'):
return []


def get_lb_attributes(connection, load_balancer_name):
attributes = connection.describe_load_balancer_attributes(aws_retry=True, LoadBalancerName=load_balancer_name).get('LoadBalancerAttributes', {})
return camel_dict_to_snake_dict(attributes)


def get_tags(connection, load_balancer_name):
tags = connection.describe_tags(LoadBalancerNames=[load_balancer_name])['TagDescriptions']
tags = connection.describe_tags(aws_retry=True, LoadBalancerNames=[load_balancer_name])['TagDescriptions']
if not tags:
return {}
return boto3_tag_list_to_ansible_dict(tags[0]['Tags'])
Expand All @@ -194,14 +204,14 @@ def lb_instance_health(connection, load_balancer_name, instances, state):

def main():
argument_spec = dict(
names={'default': [], 'type': 'list', 'elements': 'str'}
names=dict(default=[], type='list', elements='str')
)
module = AnsibleAWSModule(argument_spec=argument_spec,
supports_check_mode=True)
if module._name == 'elb_classic_lb_facts':
module.deprecate("The 'elb_classic_lb_facts' module has been renamed to 'elb_classic_lb_info'", date='2021-12-01', collection_name='community.aws')

connection = module.client('elb')
connection = module.client('elb', retry_decorator=AWSRetry.jittered_backoff(retries=MAX_AWS_RETRIES, delay=MAX_AWS_DELAY))

try:
elbs = list_elbs(connection, module.params.get('names'))
Expand Down
2 changes: 2 additions & 0 deletions tests/integration/targets/elb_classic_lb/aliases
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,5 @@ unstable

cloud/aws
shippable/aws/group2

elb_classic_lb_info
127 changes: 125 additions & 2 deletions tests/integration/targets/elb_classic_lb/tasks/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@
# remove listeners
# remove elb

# __elb_classic_lb_info_
# get nonexistent load balancer

# __ec2-common__
# test environment variable EC2_REGION
# test with no parameters
Expand Down Expand Up @@ -71,6 +74,32 @@
- '[80, 80, "HTTP", "HTTP"] in info.elb.listeners'
- '[8080, 8080, "HTTP", "HTTP"] in info.elb.listeners'

- name: Get ELB info
elb_classic_lb_info:
names: "{{ tag_prefix }}"
region: "{{ ec2_region }}"
ec2_access_key: "{{ ec2_access_key }}"
ec2_secret_key: "{{ ec2_secret_key }}"
security_token: "{{ security_token }}"
register: info

- assert:
that:
- 'info.elbs|length == 1'
- 'elb.availability_zones|length == 2'
- '"{{ ec2_region }}a" in elb.availability_zones'
- '"{{ ec2_region }}b" in elb.availability_zones'
- 'elb.health_check.healthy_threshold == 10'
- 'elb.health_check.interval == 30'
- 'elb.health_check.target == "HTTP:80/index.html"'
- 'elb.health_check.timeout == 5'
- 'elb.health_check.unhealthy_threshold == 2'
- '{"instance_port": 80, "instance_protocol": "HTTP", "load_balancer_port": 80, "protocol": "HTTP"} == listeners[0]'
- '{"instance_port": 8080, "instance_protocol": "HTTP", "load_balancer_port": 8080, "protocol": "HTTP"} == listeners[1]'
vars:
elb: "{{ info.elbs[0] }}"
listeners: "{{ elb.listener_descriptions|map(attribute='listener')|sort(attribute='load_balancer_port') }}"

# ============================================================

# check ports, would be cool, but we are at the mercy of AWS
Expand Down Expand Up @@ -119,14 +148,28 @@
healthy_threshold: 10
register: info



- assert:
that:
- 'info.elb.status == "ok"'
- 'info.changed'
- 'info.elb.zones[0] == "{{ ec2_region }}c"'

- name: Get ELB info after changing AZ's
elb_classic_lb_info:
names: "{{ tag_prefix }}"
region: "{{ ec2_region }}"
ec2_access_key: "{{ ec2_access_key }}"
ec2_secret_key: "{{ ec2_secret_key }}"
security_token: "{{ security_token }}"
register: info

- assert:
that:
- 'elb.availability_zones|length == 1'
- '"{{ ec2_region }}c" in elb.availability_zones[0]'
vars:
elb: "{{ info.elbs[0] }}"

# ============================================================

# Update AZ's
Expand Down Expand Up @@ -158,6 +201,23 @@
- '"{{ ec2_region }}b" in info.elb.zones'
- '"{{ ec2_region }}c" in info.elb.zones'

- name: Get ELB info after updating AZ's
elb_classic_lb_info:
names: "{{ tag_prefix }}"
region: "{{ ec2_region }}"
ec2_access_key: "{{ ec2_access_key }}"
ec2_secret_key: "{{ ec2_secret_key }}"
security_token: "{{ security_token }}"
register: info

- assert:
that:
- 'elb.availability_zones|length == 3'
- '"{{ ec2_region }}a" in elb.availability_zones'
- '"{{ ec2_region }}b" in elb.availability_zones'
- '"{{ ec2_region }}c" in elb.availability_zones'
vars:
elb: "{{ info.elbs[0] }}"

# ============================================================

Expand Down Expand Up @@ -189,6 +249,21 @@
- '[80, 81, "HTTP", "HTTP"] in info.elb.listeners'
- 'info.elb.listeners|length == 1'

- name: Get ELB info after purging listeners
elb_classic_lb_info:
names: "{{ tag_prefix }}"
region: "{{ ec2_region }}"
ec2_access_key: "{{ ec2_access_key }}"
ec2_secret_key: "{{ ec2_secret_key }}"
security_token: "{{ security_token }}"
register: info

- assert:
that:
- 'elb.listener_descriptions|length == 1'
- '{"instance_port": 81, "instance_protocol": "HTTP", "load_balancer_port": 80, "protocol": "HTTP"} == elb.listener_descriptions[0].listener'
vars:
elb: "{{ info.elbs[0] }}"


# ============================================================
Expand Down Expand Up @@ -222,6 +297,54 @@
- '[8081, 8081, "HTTP", "HTTP"] in info.elb.listeners'
- 'info.elb.listeners|length == 2'

- name: Get ELB info after adding listeners
elb_classic_lb_info:
names: "{{ tag_prefix }}"
region: "{{ ec2_region }}"
ec2_access_key: "{{ ec2_access_key }}"
ec2_secret_key: "{{ ec2_secret_key }}"
security_token: "{{ security_token }}"
register: info

- assert:
that:
- 'elb.listener_descriptions|length == 2'
- '{"instance_port": 81, "instance_protocol": "HTTP", "load_balancer_port": 80, "protocol": "HTTP"} == listeners[0]'
- '{"instance_port": 8081, "instance_protocol": "HTTP", "load_balancer_port": 8081, "protocol": "HTTP"} == listeners[1]'
vars:
elb: "{{ info.elbs[0] }}"
listeners: "{{ elb.listener_descriptions|map(attribute='listener')|sort(attribute='load_balancer_port') }}"

# ============================================================

# Test getting nonexistent load balancer
- name: get nonexistent load balancer
elb_classic_lb_info:
names: "invalid-elb"
region: "{{ ec2_region }}"
ec2_access_key: "{{ ec2_access_key }}"
ec2_secret_key: "{{ ec2_secret_key }}"
security_token: "{{ security_token }}"
register: info

- assert:
that:
- 'info.elbs|length==0'

# Test getting a valid and nonexistent load balancer
- name: get nonexistent load balancer
elb_classic_lb_info:
names: ["{{ tag_prefix }}", "invalid-elb"]
region: "{{ ec2_region }}"
ec2_access_key: "{{ ec2_access_key }}"
ec2_secret_key: "{{ ec2_secret_key }}"
security_token: "{{ security_token }}"
register: info

- assert:
that:
- 'info.elbs|length==1'
- 'info.elbs[0].load_balancer_name == "{{ tag_prefix }}"'

# ============================================================

Expand Down

0 comments on commit 3d5ffdc

Please sign in to comment.