ELBv2 - Support create_listener with ForwardConfig param (#4704)
This commit is contained in:
parent
82d18443d3
commit
43269fc8af
@ -821,6 +821,17 @@ class ELBv2Backend(BaseBackend):
|
|||||||
"A 'QueryStringConfig' must be specified with 'query-string'"
|
"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):
|
def _validate_actions(self, actions):
|
||||||
# validate Actions
|
# validate Actions
|
||||||
target_group_arns = [
|
target_group_arns = [
|
||||||
@ -829,10 +840,11 @@ class ELBv2Backend(BaseBackend):
|
|||||||
for i, action in enumerate(actions):
|
for i, action in enumerate(actions):
|
||||||
index = i + 1
|
index = i + 1
|
||||||
action_type = action.type
|
action_type = action.type
|
||||||
if action_type == "forward" and "TargetGroupArn" in action.data:
|
if action_type == "forward":
|
||||||
action_target_group_arn = action.data["TargetGroupArn"]
|
found_arns = self._get_target_group_arns_from(action_data=action.data)
|
||||||
if action_target_group_arn not in target_group_arns:
|
for target_group_arn in found_arns:
|
||||||
raise ActionTargetGroupNotFoundError(action_target_group_arn)
|
if target_group_arn not in target_group_arns:
|
||||||
|
raise ActionTargetGroupNotFoundError(target_group_arn)
|
||||||
elif action_type == "fixed-response":
|
elif action_type == "fixed-response":
|
||||||
self._validate_fixed_response_action(action, i, index)
|
self._validate_fixed_response_action(action, i, index)
|
||||||
elif action_type in ["redirect", "authenticate-cognito"]:
|
elif action_type in ["redirect", "authenticate-cognito"]:
|
||||||
@ -998,8 +1010,10 @@ Member must satisfy regular expression pattern: {}".format(
|
|||||||
balancer.listeners[listener.arn] = listener
|
balancer.listeners[listener.arn] = listener
|
||||||
for action in default_actions:
|
for action in default_actions:
|
||||||
if action.type == "forward":
|
if action.type == "forward":
|
||||||
target_group = self.target_groups[action.data["TargetGroupArn"]]
|
found_arns = self._get_target_group_arns_from(action_data=action.data)
|
||||||
target_group.load_balancer_arns.append(load_balancer_arn)
|
for arn in found_arns:
|
||||||
|
target_group = self.target_groups[arn]
|
||||||
|
target_group.load_balancer_arns.append(load_balancer_arn)
|
||||||
|
|
||||||
return listener
|
return listener
|
||||||
|
|
||||||
@ -1432,7 +1446,10 @@ Member must satisfy regular expression pattern: {}".format(
|
|||||||
for listener in load_balancer.listeners.values():
|
for listener in load_balancer.listeners.values():
|
||||||
for rule in listener.rules.values():
|
for rule in listener.rules.values():
|
||||||
for action in rule.actions:
|
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 True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
@ -187,7 +187,7 @@ class ELBV2Response(BaseResponse):
|
|||||||
healthcheck_enabled = self._get_param("HealthCheckEnabled")
|
healthcheck_enabled = self._get_param("HealthCheckEnabled")
|
||||||
healthy_threshold_count = self._get_param("HealthyThresholdCount")
|
healthy_threshold_count = self._get_param("HealthyThresholdCount")
|
||||||
unhealthy_threshold_count = self._get_param("UnhealthyThresholdCount")
|
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_type = self._get_param("TargetType")
|
||||||
|
|
||||||
target_group = self.elbv2_backend.create_target_group(
|
target_group = self.elbv2_backend.create_target_group(
|
||||||
|
@ -447,10 +447,12 @@ def test_describe_target_groups_no_arguments():
|
|||||||
HealthCheckTimeoutSeconds=5,
|
HealthCheckTimeoutSeconds=5,
|
||||||
HealthyThresholdCount=5,
|
HealthyThresholdCount=5,
|
||||||
UnhealthyThresholdCount=2,
|
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
|
@mock_elbv2
|
||||||
@ -570,3 +572,123 @@ def test_delete_target_group_after_modifying_listener():
|
|||||||
default_actions.should.equal(
|
default_actions.should.equal(
|
||||||
[{"Type": "forward", "TargetGroupArn": target_group_arn2}]
|
[{"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)
|
||||||
|
Loading…
Reference in New Issue
Block a user