ELBv2 - Support create_listener with ForwardConfig param (#4704)

This commit is contained in:
Bert Blommers 2021-12-20 16:06:57 -01:00 committed by GitHub
parent 82d18443d3
commit 43269fc8af
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 149 additions and 10 deletions

View File

@ -821,6 +821,17 @@ class ELBv2Backend(BaseBackend):
"A 'QueryStringConfig' must be specified with 'query-string'"
)
def _get_target_group_arns_from(self, action_data):
if "TargetGroupArn" in action_data:
return [action_data["TargetGroupArn"]]
elif "ForwardConfig" in action_data:
return [
tg["TargetGroupArn"]
for tg in action_data["ForwardConfig"].get("TargetGroups", [])
]
else:
return []
def _validate_actions(self, actions):
# validate Actions
target_group_arns = [
@ -829,10 +840,11 @@ class ELBv2Backend(BaseBackend):
for i, action in enumerate(actions):
index = i + 1
action_type = action.type
if action_type == "forward" and "TargetGroupArn" in action.data:
action_target_group_arn = action.data["TargetGroupArn"]
if action_target_group_arn not in target_group_arns:
raise ActionTargetGroupNotFoundError(action_target_group_arn)
if action_type == "forward":
found_arns = self._get_target_group_arns_from(action_data=action.data)
for target_group_arn in found_arns:
if target_group_arn not in target_group_arns:
raise ActionTargetGroupNotFoundError(target_group_arn)
elif action_type == "fixed-response":
self._validate_fixed_response_action(action, i, index)
elif action_type in ["redirect", "authenticate-cognito"]:
@ -998,8 +1010,10 @@ Member must satisfy regular expression pattern: {}".format(
balancer.listeners[listener.arn] = listener
for action in default_actions:
if action.type == "forward":
target_group = self.target_groups[action.data["TargetGroupArn"]]
target_group.load_balancer_arns.append(load_balancer_arn)
found_arns = self._get_target_group_arns_from(action_data=action.data)
for arn in found_arns:
target_group = self.target_groups[arn]
target_group.load_balancer_arns.append(load_balancer_arn)
return listener
@ -1432,7 +1446,10 @@ Member must satisfy regular expression pattern: {}".format(
for listener in load_balancer.listeners.values():
for rule in listener.rules.values():
for action in rule.actions:
if action.data.get("TargetGroupArn") == target_group_arn:
found_arns = self._get_target_group_arns_from(
action_data=action.data
)
if target_group_arn in found_arns:
return True
return False

View File

@ -187,7 +187,7 @@ class ELBV2Response(BaseResponse):
healthcheck_enabled = self._get_param("HealthCheckEnabled")
healthy_threshold_count = self._get_param("HealthyThresholdCount")
unhealthy_threshold_count = self._get_param("UnhealthyThresholdCount")
matcher = self._get_param("Matcher")
matcher = self._get_params().get("Matcher")
target_type = self._get_param("TargetType")
target_group = self.elbv2_backend.create_target_group(

View File

@ -447,10 +447,12 @@ def test_describe_target_groups_no_arguments():
HealthCheckTimeoutSeconds=5,
HealthyThresholdCount=5,
UnhealthyThresholdCount=2,
Matcher={"HttpCode": "200"},
Matcher={"HttpCode": "201"},
)
conn.describe_target_groups()["TargetGroups"].should.have.length_of(1)
groups = conn.describe_target_groups()["TargetGroups"]
groups.should.have.length_of(1)
groups[0].should.have.key("Matcher").equals({"HttpCode": "201"})
@mock_elbv2
@ -570,3 +572,123 @@ def test_delete_target_group_after_modifying_listener():
default_actions.should.equal(
[{"Type": "forward", "TargetGroupArn": target_group_arn2}]
)
@mock_elbv2
@mock_ec2
def test_create_listener_with_multiple_target_groups():
client = boto3.client("elbv2", region_name="us-east-1")
response, vpc, _, _, _, conn = create_load_balancer()
load_balancer_arn = response.get("LoadBalancers")[0].get("LoadBalancerArn")
response = client.create_target_group(
Name="a-target", Protocol="HTTP", Port=8080, VpcId=vpc.id,
)
target_group_arn1 = response.get("TargetGroups")[0]["TargetGroupArn"]
response = client.create_target_group(
Name="a-target-2", Protocol="HTTPS", Port=8081, VpcId=vpc.id,
)
target_group_arn2 = response.get("TargetGroups")[0]["TargetGroupArn"]
conn.create_listener(
LoadBalancerArn=load_balancer_arn,
Protocol="HTTP",
Port=80,
DefaultActions=[
{
"Type": "forward",
"ForwardConfig": {
"TargetGroups": [
{"TargetGroupArn": target_group_arn1, "Weight": 100},
{"TargetGroupArn": target_group_arn2, "Weight": 0},
],
"TargetGroupStickinessConfig": {
"Enabled": False,
"DurationSeconds": 300,
},
},
}
],
)
response = conn.describe_listeners(LoadBalancerArn=load_balancer_arn)
listener = response["Listeners"][0]
groups = listener["DefaultActions"][0]["ForwardConfig"]["TargetGroups"]
groups.should.have.length_of(2)
groups.should.contain({"TargetGroupArn": target_group_arn1, "Weight": 100})
groups.should.contain({"TargetGroupArn": target_group_arn2, "Weight": 0})
@mock_elbv2
@mock_ec2
def test_create_listener_with_invalid_target_group():
response, _, _, _, _, conn = create_load_balancer()
load_balancer_arn = response.get("LoadBalancers")[0].get("LoadBalancerArn")
with pytest.raises(ClientError) as exc:
conn.create_listener(
LoadBalancerArn=load_balancer_arn,
Protocol="HTTP",
Port=80,
DefaultActions=[
{
"Type": "forward",
"ForwardConfig": {
"TargetGroups": [{"TargetGroupArn": "unknown", "Weight": 100}]
},
}
],
)
err = exc.value.response["Error"]
err["Code"].should.equal("TargetGroupNotFound")
err["Message"].should.equal("Target group 'unknown' not found")
@mock_elbv2
@mock_ec2
def test_delete_target_group_while_listener_still_exists():
client = boto3.client("elbv2", region_name="us-east-1")
response, vpc, _, _, _, conn = create_load_balancer()
load_balancer_arn = response.get("LoadBalancers")[0].get("LoadBalancerArn")
response = client.create_target_group(
Name="a-target", Protocol="HTTP", Port=8080, VpcId=vpc.id,
)
target_group_arn1 = response.get("TargetGroups")[0]["TargetGroupArn"]
response = conn.create_listener(
LoadBalancerArn=load_balancer_arn,
Protocol="HTTP",
Port=80,
DefaultActions=[
{
"Type": "forward",
"ForwardConfig": {
"TargetGroups": [
{"TargetGroupArn": target_group_arn1, "Weight": 100}
]
},
}
],
)
listener_arn = response["Listeners"][0]["ListenerArn"]
# Deletion does not succeed if the Listener still exists
with pytest.raises(ClientError) as exc:
client.delete_target_group(TargetGroupArn=target_group_arn1)
err = exc.value.response["Error"]
err["Code"].should.equal("ResourceInUse")
err["Message"].should.equal(
f"The target group '{target_group_arn1}' is currently in use by a listener or a rule"
)
client.delete_listener(ListenerArn=listener_arn)
# Deletion does succeed now that the listener is deleted
client.delete_target_group(TargetGroupArn=target_group_arn1)