Skip to content

Commit

Permalink
ELBv2: Improve Target Group validation (#6818)
Browse files Browse the repository at this point in the history
  • Loading branch information
bblommers authored Sep 16, 2023
1 parent fb9023a commit 55293b3
Show file tree
Hide file tree
Showing 3 changed files with 65 additions and 6 deletions.
16 changes: 15 additions & 1 deletion moto/elbv2/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,12 @@ def __init__(
"slow_start.duration_seconds": 0,
"waf.fail_open.enabled": "false",
}
if target_type == "lambda":
self.attributes["lambda.multi_value_headers.enabled"] = "false"
if self.protocol in ["HTTP", "HTTPS"]:
self.attributes["stickiness.type"] = "lb_cookie"
if self.protocol in ["TCP", "UDP", "TCP_UDP"]:
self.attributes["stickiness.type"] = "source_ip"

self.targets: Dict[str, Dict[str, Any]] = OrderedDict()

Expand Down Expand Up @@ -1201,6 +1207,7 @@ def create_target_group(self, name: str, **kwargs: Any) -> FakeTargetGroup:
{k: kwargs.get(k) or v for k, v in conditions["target_alb"].items()}
)

original_kwargs = dict(kwargs)
kwargs.update(kwargs_patch)

healthcheck_timeout_seconds = int(
Expand All @@ -1219,7 +1226,14 @@ def create_target_group(self, name: str, **kwargs: Any) -> FakeTargetGroup:
raise ValidationError(
"Health check interval must be greater than the timeout."
)
if healthcheck_interval_seconds == healthcheck_timeout_seconds:
both_values_supplied = (
original_kwargs.get("healthcheck_timeout_seconds") is not None
and original_kwargs.get("healthcheck_interval_seconds") is not None
)
if (
both_values_supplied
and healthcheck_interval_seconds == healthcheck_timeout_seconds
):
raise ValidationError(
f"Health check timeout '{healthcheck_timeout_seconds}' must be smaller than the interval '{healthcheck_interval_seconds}'"
)
Expand Down
6 changes: 6 additions & 0 deletions tests/terraformtests/terraform-tests.success.txt
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,12 @@ elbv2:
- TestAccELBV2ListenerCertificate
- TestAccELBV2TargetGroupAttachment
- TestAccELBV2TargetGroupDataSource
- TestAccELBV2TargetGroup_ALBAlias
- TestAccELBV2TargetGroup_networkLB
- TestAccELBV2TargetGroup_NetworkLB
- TestAccELBV2TargetGroup_Stickiness_defaultALB
- TestAccELBV2TargetGroup_Stickiness_valid
- TestAccELBV2TargetGroup_Stickiness_update
events:
- TestAccEventsAPIDestination
- TestAccEventsArchive
Expand Down
49 changes: 44 additions & 5 deletions tests/test_elbv2/test_elbv2_target_groups.py
Original file line number Diff line number Diff line change
Expand Up @@ -380,9 +380,9 @@ def test_target_group_attributes():
assert len(response["TargetGroups"]) == 1
target_group_arn = target_group["TargetGroupArn"]

# The attributes should start with the two defaults
# The attributes should start with the defaults
response = conn.describe_target_group_attributes(TargetGroupArn=target_group_arn)
assert len(response["Attributes"]) == 6
assert len(response["Attributes"]) == 7
attributes = {attr["Key"]: attr["Value"] for attr in response["Attributes"]}
assert attributes["deregistration_delay.timeout_seconds"] == "300"
assert attributes["stickiness.enabled"] == "false"
Expand All @@ -397,21 +397,21 @@ def test_target_group_attributes():
TargetGroupArn=target_group_arn,
Attributes=[
{"Key": "stickiness.enabled", "Value": "true"},
{"Key": "stickiness.type", "Value": "lb_cookie"},
{"Key": "stickiness.type", "Value": "app_cookie"},
],
)

# The response should have only the keys updated
assert len(response["Attributes"]) == 2
attributes = {attr["Key"]: attr["Value"] for attr in response["Attributes"]}
assert attributes["stickiness.type"] == "lb_cookie"
assert attributes["stickiness.type"] == "app_cookie"
assert attributes["stickiness.enabled"] == "true"

# These new values should be in the full attribute list
response = conn.describe_target_group_attributes(TargetGroupArn=target_group_arn)
assert len(response["Attributes"]) == 7
attributes = {attr["Key"]: attr["Value"] for attr in response["Attributes"]}
assert attributes["stickiness.type"] == "lb_cookie"
assert attributes["stickiness.type"] == "app_cookie"
assert attributes["stickiness.enabled"] == "true"


Expand Down Expand Up @@ -828,9 +828,11 @@ def test_delete_target_group_while_listener_still_exists():
client.delete_target_group(TargetGroupArn=target_group_arn1)


@mock_ec2
@mock_elbv2
def test_create_target_group_validation_error():
elbv2 = boto3.client("elbv2", region_name="us-east-1")
_, vpc, _, _, _, _ = create_load_balancer()

with pytest.raises(ClientError) as ex:
elbv2.create_target_group(
Expand Down Expand Up @@ -896,6 +898,43 @@ def test_create_target_group_validation_error():
assert err["Code"] == "ValidationError"
assert err["Message"] == "Health check interval must be greater than the timeout."

# When providing both values:
# Health check timeout '5' must be smaller than the interval '5'
#
# When only the Interval is supplied, it can be the same value as the default
group = elbv2.create_target_group(
Name="target1",
Port=443,
Protocol="TLS",
VpcId=vpc.id,
TargetType="ip",
IpAddressType="ipv6",
HealthCheckIntervalSeconds=10,
HealthCheckPort="traffic-port",
HealthCheckProtocol="TCP",
HealthyThresholdCount=3,
UnhealthyThresholdCount=3,
)["TargetGroups"][0]
assert group["HealthCheckIntervalSeconds"] == 10
assert group["HealthCheckTimeoutSeconds"] == 10

# Same idea goes the other way around
group = elbv2.create_target_group(
Name="target2",
Port=443,
Protocol="TLS",
VpcId=vpc.id,
TargetType="ip",
IpAddressType="ipv6",
HealthCheckTimeoutSeconds=30,
HealthCheckPort="traffic-port",
HealthCheckProtocol="TCP",
HealthyThresholdCount=3,
UnhealthyThresholdCount=3,
)["TargetGroups"][0]
assert group["HealthCheckIntervalSeconds"] == 30
assert group["HealthCheckTimeoutSeconds"] == 30

with pytest.raises(ClientError) as ex:
elbv2.create_target_group(Name="a-target", TargetType="lambda", Port=8080)
err = ex.value.response["Error"]
Expand Down

0 comments on commit 55293b3

Please sign in to comment.