Skip to content

Commit

Permalink
resource/aws_lb: Enable ALB connection logs
Browse files Browse the repository at this point in the history
  • Loading branch information
dpirotte committed Dec 11, 2023
1 parent 4f16b25 commit ac57c8e
Show file tree
Hide file tree
Showing 5 changed files with 304 additions and 0 deletions.
109 changes: 109 additions & 0 deletions internal/service/elbv2/load_balancer.go
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,35 @@ func ResourceLoadBalancer() *schema.Resource {
Type: schema.TypeString,
Computed: true,
},
"connection_logs": {
Type: schema.TypeList,
Optional: true,
MaxItems: 1,
DiffSuppressFunc: verify.SuppressMissingOptionalConfigurationBlock,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"bucket": {
Type: schema.TypeString,
Required: true,
DiffSuppressFunc: func(k, old, new string, d *schema.ResourceData) bool {
return !d.Get("connection_logs.0.enabled").(bool)
},
},
"enabled": {
Type: schema.TypeBool,
Optional: true,
Default: false,
},
"prefix": {
Type: schema.TypeString,
Optional: true,
DiffSuppressFunc: func(k, old, new string, d *schema.ResourceData) bool {
return !d.Get("connection_logs.0.enabled").(bool)
},
},
},
},
},
"customer_owned_ipv4_pool": {
Type: schema.TypeString,
Optional: true,
Expand Down Expand Up @@ -398,6 +427,17 @@ func resourceLoadBalancerCreate(ctx context.Context, d *schema.ResourceData, met
}
}

if lbType == elbv2.LoadBalancerTypeEnumApplication {
if v, ok := d.GetOk("connection_logs"); ok && len(v.([]interface{})) > 0 && v.([]interface{})[0] != nil {
attributes = append(attributes, expandLoadBalancerConnectionLogsAttributes(v.([]interface{})[0].(map[string]interface{}), false)...)
} else {
attributes = append(attributes, &elbv2.LoadBalancerAttribute{
Key: aws.String(loadBalancerAttributeConnectionLogsS3Enabled),
Value: flex.BoolValueToString(false),
})
}
}

attributes = append(attributes, loadBalancerAttributes.expand(d, false)...)

wait := false
Expand Down Expand Up @@ -483,6 +523,10 @@ func resourceLoadBalancerRead(ctx context.Context, d *schema.ResourceData, meta
return sdkdiag.AppendErrorf(diags, "setting access_logs: %s", err)
}

if err := d.Set("connection_logs", []interface{}{flattenLoadBalancerConnectionLogsAttributes(attributes)}); err != nil {
return sdkdiag.AppendErrorf(diags, "setting connection_logs: %s", err)
}

loadBalancerAttributes.flatten(d, attributes)

return diags
Expand All @@ -505,6 +549,17 @@ func resourceLoadBalancerUpdate(ctx context.Context, d *schema.ResourceData, met
}
}

if d.HasChange("connection_logs") {
if v, ok := d.GetOk("connection_logs"); ok && len(v.([]interface{})) > 0 && v.([]interface{})[0] != nil {
attributes = append(attributes, expandLoadBalancerConnectionLogsAttributes(v.([]interface{})[0].(map[string]interface{}), true)...)
} else {
attributes = append(attributes, &elbv2.LoadBalancerAttribute{
Key: aws.String(loadBalancerAttributeConnectionLogsS3Enabled),
Value: flex.BoolValueToString(false),
})
}
}

attributes = append(attributes, loadBalancerAttributes.expand(d, true)...)

if len(attributes) > 0 {
Expand Down Expand Up @@ -1072,6 +1127,39 @@ func expandLoadBalancerAccessLogsAttributes(tfMap map[string]interface{}, update
return apiObjects
}

func expandLoadBalancerConnectionLogsAttributes(tfMap map[string]interface{}, update bool) []*elbv2.LoadBalancerAttribute {
if tfMap == nil {
return nil
}

var apiObjects []*elbv2.LoadBalancerAttribute

if v, ok := tfMap["enabled"].(bool); ok {
apiObjects = append(apiObjects, &elbv2.LoadBalancerAttribute{
Key: aws.String(loadBalancerAttributeConnectionLogsS3Enabled),
Value: flex.BoolValueToString(v),
})

if v {
if v, ok := tfMap["bucket"].(string); ok && (update || v != "") {
apiObjects = append(apiObjects, &elbv2.LoadBalancerAttribute{
Key: aws.String(loadBalancerAttributeConnectionLogsS3Bucket),
Value: aws.String(v),
})
}

if v, ok := tfMap["prefix"].(string); ok && (update || v != "") {
apiObjects = append(apiObjects, &elbv2.LoadBalancerAttribute{
Key: aws.String(loadBalancerAttributeConnectionLogsS3Prefix),
Value: aws.String(v),
})
}
}
}

return apiObjects
}

func flattenLoadBalancerAccessLogsAttributes(apiObjects []*elbv2.LoadBalancerAttribute) map[string]interface{} {
if len(apiObjects) == 0 {
return nil
Expand All @@ -1093,6 +1181,27 @@ func flattenLoadBalancerAccessLogsAttributes(apiObjects []*elbv2.LoadBalancerAtt
return tfMap
}

func flattenLoadBalancerConnectionLogsAttributes(apiObjects []*elbv2.LoadBalancerAttribute) map[string]interface{} {
if len(apiObjects) == 0 {
return nil
}

tfMap := map[string]interface{}{}

for _, apiObject := range apiObjects {
switch k, v := aws.StringValue(apiObject.Key), apiObject.Value; k {
case loadBalancerAttributeConnectionLogsS3Enabled:
tfMap["enabled"] = flex.StringToBoolValue(v)
case loadBalancerAttributeConnectionLogsS3Bucket:
tfMap["bucket"] = aws.StringValue(v)
case loadBalancerAttributeConnectionLogsS3Prefix:
tfMap["prefix"] = aws.StringValue(v)
}
}

return tfMap
}

func expandSubnetMapping(tfMap map[string]interface{}) *elbv2.SubnetMapping {
if tfMap == nil {
return nil
Expand Down
24 changes: 24 additions & 0 deletions internal/service/elbv2/load_balancer_data_source.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,26 @@ func DataSourceLoadBalancer() *schema.Resource {
Type: schema.TypeString,
Computed: true,
},
"connection_logs": {
Type: schema.TypeList,
Computed: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"bucket": {
Type: schema.TypeString,
Computed: true,
},
"enabled": {
Type: schema.TypeBool,
Computed: true,
},
"prefix": {
Type: schema.TypeString,
Computed: true,
},
},
},
},
"customer_owned_ipv4_pool": {
Type: schema.TypeString,
Computed: true,
Expand Down Expand Up @@ -270,6 +290,10 @@ func dataSourceLoadBalancerRead(ctx context.Context, d *schema.ResourceData, met
return sdkdiag.AppendErrorf(diags, "setting access_logs: %s", err)
}

if err := d.Set("connection_logs", []interface{}{flattenLoadBalancerConnectionLogsAttributes(attributes)}); err != nil {
return sdkdiag.AppendErrorf(diags, "setting connection_logs: %s", err)
}

loadBalancerAttributes.flatten(d, attributes)

tags, err := listTags(ctx, conn, d.Id())
Expand Down
3 changes: 3 additions & 0 deletions internal/service/elbv2/load_balancer_data_source_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,7 @@ func TestAccELBV2LoadBalancerDataSource_backwardsCompatibility(t *testing.T) {
resource.TestCheckResourceAttrPair(dataSourceName1, "enable_http2", resourceName, "enable_http2"),
resource.TestCheckResourceAttrPair(dataSourceName1, "enable_waf_fail_open", resourceName, "enable_waf_fail_open"),
resource.TestCheckResourceAttrPair(dataSourceName1, "access_logs.#", resourceName, "access_logs.#"),
resource.TestCheckResourceAttrPair(dataSourceName1, "connection_logs.#", resourceName, "connection_logs.#"),
resource.TestCheckResourceAttrPair(dataSourceName2, "name", resourceName, "name"),
resource.TestCheckResourceAttrPair(dataSourceName2, "internal", resourceName, "internal"),
resource.TestCheckResourceAttrPair(dataSourceName2, "subnets.#", resourceName, "subnets.#"),
Expand All @@ -181,6 +182,7 @@ func TestAccELBV2LoadBalancerDataSource_backwardsCompatibility(t *testing.T) {
resource.TestCheckResourceAttrPair(dataSourceName2, "enable_http2", resourceName, "enable_http2"),
resource.TestCheckResourceAttrPair(dataSourceName2, "enable_waf_fail_open", resourceName, "enable_waf_fail_open"),
resource.TestCheckResourceAttrPair(dataSourceName2, "access_logs.#", resourceName, "access_logs.#"),
resource.TestCheckResourceAttrPair(dataSourceName2, "connection_logs.#", resourceName, "connection_logs.#"),
resource.TestCheckResourceAttrPair(dataSourceName3, "name", resourceName, "name"),
resource.TestCheckResourceAttrPair(dataSourceName3, "internal", resourceName, "internal"),
resource.TestCheckResourceAttrPair(dataSourceName3, "subnets.#", resourceName, "subnets.#"),
Expand All @@ -201,6 +203,7 @@ func TestAccELBV2LoadBalancerDataSource_backwardsCompatibility(t *testing.T) {
resource.TestCheckResourceAttrPair(dataSourceName3, "enable_http2", resourceName, "enable_http2"),
resource.TestCheckResourceAttrPair(dataSourceName3, "enable_waf_fail_open", resourceName, "enable_waf_fail_open"),
resource.TestCheckResourceAttrPair(dataSourceName3, "access_logs.#", resourceName, "access_logs.#"),
resource.TestCheckResourceAttrPair(dataSourceName3, "connection_logs.#", resourceName, "connection_logs.#"),
),
},
},
Expand Down
161 changes: 161 additions & 0 deletions internal/service/elbv2/load_balancer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,8 @@ func TestAccELBV2LoadBalancer_ALB_basic(t *testing.T) {
resource.TestCheckResourceAttr(resourceName, "access_logs.#", "1"),
resource.TestCheckResourceAttr(resourceName, "access_logs.0.enabled", "false"),
acctest.MatchResourceAttrRegionalARN(resourceName, "arn", "elasticloadbalancing", regexache.MustCompile(fmt.Sprintf("loadbalancer/app/%s/.+", rName))),
resource.TestCheckResourceAttr(resourceName, "connection_logs.#", "1"),
resource.TestCheckResourceAttr(resourceName, "connection_logs.0.enabled", "false"),
resource.TestCheckResourceAttr(resourceName, "desync_mitigation_mode", "defensive"),
resource.TestCheckResourceAttrSet(resourceName, "dns_name"),
resource.TestCheckResourceAttr(resourceName, "enable_deletion_protection", "false"),
Expand Down Expand Up @@ -1120,6 +1122,139 @@ func TestAccELBV2LoadBalancer_ApplicationLoadBalancer_accessLogsPrefix(t *testin
})
}

func TestAccELBV2LoadBalancer_ApplicationLoadBalancer_connectionLogs(t *testing.T) {
ctx := acctest.Context(t)
var conf elbv2.LoadBalancer
rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix)
resourceName := "aws_lb.test"

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { acctest.PreCheck(ctx, t) },
ErrorCheck: acctest.ErrorCheck(t, elbv2.EndpointsID),
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories,
CheckDestroy: testAccCheckLoadBalancerDestroy(ctx),
Steps: []resource.TestStep{
{
Config: testAccLoadBalancerConfig_albConnectionLogs(true, rName, ""),
Check: resource.ComposeAggregateTestCheckFunc(
testAccCheckLoadBalancerExists(ctx, resourceName, &conf),
testAccCheckLoadBalancerAttribute(ctx, resourceName, "connection_logs.s3.bucket", rName),
testAccCheckLoadBalancerAttribute(ctx, resourceName, "connection_logs.s3.enabled", "true"),
testAccCheckLoadBalancerAttribute(ctx, resourceName, "connection_logs.s3.prefix", ""),
resource.TestCheckResourceAttr(resourceName, "connection_logs.#", "1"),
resource.TestCheckResourceAttr(resourceName, "connection_logs.0.bucket", rName),
resource.TestCheckResourceAttr(resourceName, "connection_logs.0.enabled", "true"),
resource.TestCheckResourceAttr(resourceName, "connection_logs.0.prefix", ""),
),
},
{
ResourceName: resourceName,
ImportState: true,
ImportStateVerify: true,
},
{
Config: testAccLoadBalancerConfig_albConnectionLogs(false, rName, ""),
Check: resource.ComposeAggregateTestCheckFunc(
testAccCheckLoadBalancerExists(ctx, resourceName, &conf),
testAccCheckLoadBalancerAttribute(ctx, resourceName, "connection_logs.s3.bucket", rName),
testAccCheckLoadBalancerAttribute(ctx, resourceName, "connection_logs.s3.enabled", "false"),
testAccCheckLoadBalancerAttribute(ctx, resourceName, "connection_logs.s3.prefix", ""),
resource.TestCheckResourceAttr(resourceName, "connection_logs.#", "1"),
resource.TestCheckResourceAttr(resourceName, "connection_logs.0.bucket", rName),
resource.TestCheckResourceAttr(resourceName, "connection_logs.0.enabled", "false"),
resource.TestCheckResourceAttr(resourceName, "connection_logs.0.prefix", ""),
),
},
{
Config: testAccLoadBalancerConfig_albConnectionLogs(true, rName, ""),
Check: resource.ComposeAggregateTestCheckFunc(
testAccCheckLoadBalancerExists(ctx, resourceName, &conf),
testAccCheckLoadBalancerAttribute(ctx, resourceName, "connection_logs.s3.bucket", rName),
testAccCheckLoadBalancerAttribute(ctx, resourceName, "connection_logs.s3.enabled", "true"),
testAccCheckLoadBalancerAttribute(ctx, resourceName, "connection_logs.s3.prefix", ""),
resource.TestCheckResourceAttr(resourceName, "connection_logs.#", "1"),
resource.TestCheckResourceAttr(resourceName, "connection_logs.0.bucket", rName),
resource.TestCheckResourceAttr(resourceName, "connection_logs.0.enabled", "true"),
resource.TestCheckResourceAttr(resourceName, "connection_logs.0.prefix", ""),
),
},
{
Config: testAccLoadBalancerConfig_albConnectionLogsNoBlocks(rName),
Check: resource.ComposeAggregateTestCheckFunc(
testAccCheckLoadBalancerExists(ctx, resourceName, &conf),
testAccCheckLoadBalancerAttribute(ctx, resourceName, "connection_logs.s3.bucket", rName),
testAccCheckLoadBalancerAttribute(ctx, resourceName, "connection_logs.s3.enabled", "false"),
testAccCheckLoadBalancerAttribute(ctx, resourceName, "connection_logs.s3.prefix", ""),
resource.TestCheckResourceAttr(resourceName, "connection_logs.#", "1"),
resource.TestCheckResourceAttr(resourceName, "connection_logs.0.bucket", rName),
resource.TestCheckResourceAttr(resourceName, "connection_logs.0.enabled", "false"),
resource.TestCheckResourceAttr(resourceName, "connection_logs.0.prefix", ""),
),
},
},
})
}

func TestAccELBV2LoadBalancer_ApplicationLoadBalancer_connectionLogsPrefix(t *testing.T) {
ctx := acctest.Context(t)
var conf elbv2.LoadBalancer
rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix)
resourceName := "aws_lb.test"

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { acctest.PreCheck(ctx, t) },
ErrorCheck: acctest.ErrorCheck(t, elbv2.EndpointsID),
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories,
CheckDestroy: testAccCheckLoadBalancerDestroy(ctx),
Steps: []resource.TestStep{
{
Config: testAccLoadBalancerConfig_albConnectionLogs(true, rName, "prefix1"),
Check: resource.ComposeAggregateTestCheckFunc(
testAccCheckLoadBalancerExists(ctx, resourceName, &conf),
testAccCheckLoadBalancerAttribute(ctx, resourceName, "connection_logs.s3.bucket", rName),
testAccCheckLoadBalancerAttribute(ctx, resourceName, "connection_logs.s3.enabled", "true"),
testAccCheckLoadBalancerAttribute(ctx, resourceName, "connection_logs.s3.prefix", "prefix1"),
resource.TestCheckResourceAttr(resourceName, "connection_logs.#", "1"),
resource.TestCheckResourceAttr(resourceName, "connection_logs.0.bucket", rName),
resource.TestCheckResourceAttr(resourceName, "connection_logs.0.enabled", "true"),
resource.TestCheckResourceAttr(resourceName, "connection_logs.0.prefix", "prefix1"),
),
},
{
ResourceName: resourceName,
ImportState: true,
ImportStateVerify: true,
},
{
Config: testAccLoadBalancerConfig_albConnectionLogs(true, rName, ""),
Check: resource.ComposeAggregateTestCheckFunc(
testAccCheckLoadBalancerExists(ctx, resourceName, &conf),
testAccCheckLoadBalancerAttribute(ctx, resourceName, "connection_logs.s3.bucket", rName),
testAccCheckLoadBalancerAttribute(ctx, resourceName, "connection_logs.s3.enabled", "true"),
testAccCheckLoadBalancerAttribute(ctx, resourceName, "connection_logs.s3.prefix", ""),
resource.TestCheckResourceAttr(resourceName, "connection_logs.#", "1"),
resource.TestCheckResourceAttr(resourceName, "connection_logs.0.bucket", rName),
resource.TestCheckResourceAttr(resourceName, "connection_logs.0.enabled", "true"),
resource.TestCheckResourceAttr(resourceName, "connection_logs.0.prefix", ""),
),
},
{
Config: testAccLoadBalancerConfig_albConnectionLogs(true, rName, "prefix1"),
Check: resource.ComposeAggregateTestCheckFunc(
testAccCheckLoadBalancerExists(ctx, resourceName, &conf),
testAccCheckLoadBalancerAttribute(ctx, resourceName, "connection_logs.s3.bucket", rName),
testAccCheckLoadBalancerAttribute(ctx, resourceName, "connection_logs.s3.enabled", "true"),
testAccCheckLoadBalancerAttribute(ctx, resourceName, "connection_logs.s3.prefix", "prefix1"),
resource.TestCheckResourceAttr(resourceName, "connection_logs.#", "1"),
resource.TestCheckResourceAttr(resourceName, "connection_logs.0.bucket", rName),
resource.TestCheckResourceAttr(resourceName, "connection_logs.0.enabled", "true"),
resource.TestCheckResourceAttr(resourceName, "connection_logs.0.prefix", "prefix1"),
),
},
},
})
}

func TestAccELBV2LoadBalancer_NetworkLoadBalancer_accessLogs(t *testing.T) {
ctx := acctest.Context(t)
var conf elbv2.LoadBalancer
Expand Down Expand Up @@ -2528,6 +2663,32 @@ resource "aws_lb" "test" {
`, rName))
}

func testAccLoadBalancerConfig_albConnectionLogs(enabled bool, rName, bucketPrefix string) string {
return acctest.ConfigCompose(testAccLoadBalancerConfig_baseALBAccessLogs(rName), fmt.Sprintf(`
resource "aws_lb" "test" {
internal = true
name = %[1]q
subnets = aws_subnet.test[*].id
connection_logs {
bucket = aws_s3_bucket_policy.test.bucket
enabled = %[2]t
prefix = %[3]q
}
}
`, rName, enabled, bucketPrefix))
}

func testAccLoadBalancerConfig_albConnectionLogsNoBlocks(rName string) string {
return acctest.ConfigCompose(testAccLoadBalancerConfig_baseALBAccessLogs(rName), fmt.Sprintf(`
resource "aws_lb" "test" {
internal = true
name = %[1]q
subnets = aws_subnet.test[*].id
}
`, rName))
}

func testAccLoadBalancerConfig_baseNLBAccessLogs(rName string) string {
return acctest.ConfigCompose(acctest.ConfigVPCWithSubnets(rName, 2), fmt.Sprintf(`
resource "aws_s3_bucket" "test" {
Expand Down
Loading

0 comments on commit ac57c8e

Please sign in to comment.