From 55293b3668df0454f0f5855fa97578bc50d72dea Mon Sep 17 00:00:00 2001 From: Bert Blommers Date: Sat, 16 Sep 2023 08:54:51 +0000 Subject: [PATCH] ELBv2: Improve Target Group validation (#6818) --- moto/elbv2/models.py | 16 +++++- .../terraform-tests.success.txt | 6 +++ tests/test_elbv2/test_elbv2_target_groups.py | 49 +++++++++++++++++-- 3 files changed, 65 insertions(+), 6 deletions(-) diff --git a/moto/elbv2/models.py b/moto/elbv2/models.py index 69c1f13ac..81ea9740f 100644 --- a/moto/elbv2/models.py +++ b/moto/elbv2/models.py @@ -132,6 +132,12 @@ class FakeTargetGroup(CloudFormationModel): "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() @@ -1201,6 +1207,7 @@ Member must satisfy regular expression pattern: {expression}" {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( @@ -1219,7 +1226,14 @@ Member must satisfy regular expression pattern: {expression}" 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}'" ) diff --git a/tests/terraformtests/terraform-tests.success.txt b/tests/terraformtests/terraform-tests.success.txt index b3c0f2f87..6a2020df2 100644 --- a/tests/terraformtests/terraform-tests.success.txt +++ b/tests/terraformtests/terraform-tests.success.txt @@ -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 diff --git a/tests/test_elbv2/test_elbv2_target_groups.py b/tests/test_elbv2/test_elbv2_target_groups.py index 347c7f211..0bbce2355 100644 --- a/tests/test_elbv2/test_elbv2_target_groups.py +++ b/tests/test_elbv2/test_elbv2_target_groups.py @@ -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" @@ -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" @@ -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( @@ -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"]