Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

resource/aws_lb: Enable ALB connection logs #34864

Merged
merged 5 commits into from
Dec 12, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
7 changes: 7 additions & 0 deletions .changelog/34864.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
```release-note:enhancement
resource/aws_lb: Add `connection_logs` configuration block
```

```release-note:enhancement
data-source/aws_lb: Add `connection_logs` attribute
```
114 changes: 113 additions & 1 deletion internal/service/elbv2/load_balancer.go
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,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 @@ -397,6 +426,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 @@ -459,7 +499,8 @@ func resourceLoadBalancerRead(ctx context.Context, d *schema.ResourceData, meta
d.Set("enforce_security_group_inbound_rules_on_private_link_traffic", lb.EnforceSecurityGroupInboundRulesOnPrivateLinkTraffic)
d.Set("internal", aws.StringValue(lb.Scheme) == elbv2.LoadBalancerSchemeEnumInternal)
d.Set("ip_address_type", lb.IpAddressType)
d.Set("load_balancer_type", lb.Type)
lbType := aws.StringValue(lb.Type)
d.Set("load_balancer_type", lbType)
d.Set("name", lb.LoadBalancerName)
d.Set("name_prefix", create.NamePrefixFromName(aws.StringValue(lb.LoadBalancerName)))
d.Set("security_groups", aws.StringValueSlice(lb.SecurityGroups))
Expand All @@ -482,6 +523,12 @@ func resourceLoadBalancerRead(ctx context.Context, d *schema.ResourceData, meta
return sdkdiag.AppendErrorf(diags, "setting access_logs: %s", err)
}

if lbType == elbv2.LoadBalancerTypeEnumApplication {
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 @@ -504,6 +551,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 @@ -1195,6 +1253,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 @@ -1216,6 +1307,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