diff --git a/Makefile b/Makefile index 71e271a477..b7f9b84c10 100644 --- a/Makefile +++ b/Makefile @@ -12,7 +12,7 @@ PROJECT_REPO := github.com/upbound/$(PROJECT_NAME) export TERRAFORM_VERSION := 1.5.5 export TERRAFORM_PROVIDER_VERSION := 5.68.0 -export TERRAFORM_PROVIDER_RELEASE := v$(TERRAFORM_PROVIDER_VERSION)-upjet.1 +export TERRAFORM_PROVIDER_RELEASE := v$(TERRAFORM_PROVIDER_VERSION)-upjet.2 export TERRAFORM_PROVIDER_SOURCE := hashicorp/aws export TERRAFORM_PROVIDER_REPO ?= https://github.com/hashicorp/terraform-provider-aws export TERRAFORM_DOCS_PATH ?= website/docs/r diff --git a/config/elbv2/config.go b/config/elbv2/config.go index 4bbcde047f..2358196390 100644 --- a/config/elbv2/config.go +++ b/config/elbv2/config.go @@ -4,10 +4,17 @@ package elbv2 -import "github.com/crossplane/upjet/pkg/config" +import ( + "regexp" + "strings" + + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" + + "github.com/crossplane/upjet/pkg/config" +) // Configure adds configurations for the elbv2 group. -func Configure(p *config.Provider) { +func Configure(p *config.Provider) { //nolint:gocyclo p.AddResourceConfigurator("aws_lb", func(r *config.Resource) { r.ExternalName.OmittedFields = append(r.ExternalName.OmittedFields, "name_prefix") r.References = config.References{ @@ -44,6 +51,64 @@ func Configure(p *config.Provider) { TerraformName: "aws_lb_target_group", }, } + + // lb_listener schema allows to configure "default_action" with type + // "forward", in 2 different ways. + // 1. you can specify, default_action.0.forward, which allows configuring + // multiple target groups. + // 2. you can specify default_action.0.target_group_arn if you want + // to configure only one target group. + // Former is a more general way, and latter is more of a shortcut for + // a specific case, which can already be expressed with #1. + // TF implementation instructs to specify either #1 or #2, not both. + // However, they both end up in the state redundantly and cause + // unnecessary diff. + r.TerraformCustomDiff = func(diff *terraform.InstanceDiff, _ *terraform.InstanceState, _ *terraform.ResourceConfig) (*terraform.InstanceDiff, error) { //nolint:gocyclo + // skip no diff or destroy diffs + if diff == nil || diff.Empty() || diff.Destroy || diff.Attributes == nil { + return diff, nil + } + duplicatedAction := "" + for k, attrDiff := range diff.Attributes { + // user specified the "default_action.0.target_group_arn" and + // "default_action.0.forward" is not specified in config. + // In that case, default_action.0.forward is populated + // by the AWS API, which can cause an unnecessary diff, + // trying to remove that "auto-populated" element. + if regexp.MustCompile(`^default_action\.\d+\.forward\.#$`).MatchString(k) && + attrDiff.New == "0" && attrDiff.Old == "1" { + delete(diff.Attributes, k) + // save this attribute path to remove remaining diffs + // of its nested fields if any in a second pass + duplicatedAction = strings.TrimSuffix(k, ".#") + } + // this is the same case as above + if regexp.MustCompile(`^default_action\.\d+\.forward\.\d+\.target_group\.#$`).MatchString(k) && + attrDiff.New == "0" && attrDiff.Old == "1" { + delete(diff.Attributes, k) + } + // this is the same case but vice versa. user specified + // forward target via default_action.0.forward, and + // default_action.0.target_group_arn is omitted. + // In that case, default_action.0.target_group_arn is populated + // by the AWS API and ends up in the state, causing + // an unnecessary diff, which we omit here. + if regexp.MustCompile(`^default_action\.\d+\.target_group_arn$`).MatchString(k) && + attrDiff.New == "" && attrDiff.Old != "" && attrDiff.NewRemoved { + delete(diff.Attributes, k) + } + } + // if we have caught an unnecessary diff for default_action.0.forward, remove + // any sub-element diffs of it. + if duplicatedAction != "" { + for k := range diff.Attributes { + if strings.HasPrefix(k, duplicatedAction) { + delete(diff.Attributes, k) + } + } + } + return diff, nil + } }) p.AddResourceConfigurator("aws_lb_target_group", func(r *config.Resource) { @@ -54,6 +119,19 @@ func Configure(p *config.Provider) { s.Computed = false } r.LateInitializer.IgnoredFields = []string{"target_failover"} + r.TerraformCustomDiff = func(diff *terraform.InstanceDiff, _ *terraform.InstanceState, _ *terraform.ResourceConfig) (*terraform.InstanceDiff, error) { + // skip no diff or destroy diffs + if diff == nil || diff.Empty() || diff.Destroy || diff.Attributes == nil { + return diff, nil + } + + // ignore diff due to defaulting in the TF schema + udiDiff, ok := diff.Attributes["target_health_state.0.unhealthy_draining_interval"] + if ok && udiDiff.Old == "" && udiDiff.New == "0" { + delete(diff.Attributes, "target_health_state.0.unhealthy_draining_interval") + } + return diff, nil + } }) p.AddResourceConfigurator("aws_lb_target_group_attachment", func(r *config.Resource) { diff --git a/examples/elbv2/v1beta2/lblistener-forward-multiple-targetgroups.yaml b/examples/elbv2/v1beta2/lblistener-forward-multiple-targetgroups.yaml new file mode 100644 index 0000000000..c2ff297f3f --- /dev/null +++ b/examples/elbv2/v1beta2/lblistener-forward-multiple-targetgroups.yaml @@ -0,0 +1,195 @@ +# SPDX-FileCopyrightText: 2024 The Crossplane Authors +# +# SPDX-License-Identifier: Apache-2.0 + +apiVersion: elbv2.aws.upbound.io/v1beta2 +kind: LBListener +metadata: + annotations: + meta.upbound.io/example-id: elbv2/v1beta2/lblistener + labels: + testing.upbound.io/example-name: lblistener-forward-multiple + name: front-end +spec: + forProvider: + defaultAction: + - type: forward + forward: + targetGroup: + - arnSelector: + matchLabels: + testing.upbound.io/example-name: lblistener-forward-multiple + - arnSelector: + matchLabels: + testing.upbound.io/example-name: lblistener-forward-multiple-2 + stickiness: + enabled: true + duration: 3600 + loadBalancerArnSelector: + matchLabels: + testing.upbound.io/example-name: lblistener-forward-multiple + port: 80 + protocol: HTTP + region: us-west-1 +--- + +apiVersion: elbv2.aws.upbound.io/v1beta2 +kind: LBTargetGroup +metadata: + annotations: + meta.upbound.io/example-id: elbv2/v1beta2/lblistener + labels: + testing.upbound.io/example-name: lblistener-forward-multiple-2 + name: test-2 +spec: + forProvider: + name: example-lb-tg-2 + port: 8080 + protocol: HTTP + region: us-west-1 + targetType: ip + vpcIdSelector: + matchLabels: + testing.upbound.io/example-name: lblistener-forward-multiple + +--- + +apiVersion: elbv2.aws.upbound.io/v1beta2 +kind: LBTargetGroup +metadata: + annotations: + meta.upbound.io/example-id: elbv2/v1beta2/lblistener + labels: + testing.upbound.io/example-name: lblistener-forward-multiple + name: test +spec: + forProvider: + name: example-lb-tg + port: 80 + protocol: HTTP + region: us-west-1 + targetType: ip + vpcIdSelector: + matchLabels: + testing.upbound.io/example-name: lblistener-forward-multiple + +--- + +apiVersion: elbv2.aws.upbound.io/v1beta2 +kind: LB +metadata: + annotations: + meta.upbound.io/example-id: elbv2/v1beta2/lblistener + labels: + testing.upbound.io/example-name: lblistener-forward-multiple + name: test +spec: + forProvider: + enableDeletionProtection: false + internal: false + loadBalancerType: application + name: test-lb-tf + region: us-west-1 + securityGroupSelector: + matchLabels: + testing.upbound.io/example-name: lblistener-forward-multiple + subnetSelector: + matchLabels: + testing.upbound.io/example-name: lblistener-forward-multiple + tags: + Environment: production + +--- + +apiVersion: ec2.aws.upbound.io/v1beta1 +kind: VPC +metadata: + annotations: + meta.upbound.io/example-id: elbv2/v1beta2/lblistener + labels: + testing.upbound.io/example-name: lblistener-forward-multiple + name: elbv2-vpc +spec: + forProvider: + cidrBlock: 172.16.0.0/16 + region: us-west-1 + tags: + Name: DemoVpc + +--- + +apiVersion: ec2.aws.upbound.io/v1beta1 +kind: InternetGateway +metadata: + annotations: + meta.upbound.io/example-id: elbv2/v1beta2/lblistener + labels: + testing.upbound.io/example-name: lblistener-forward-multiple + name: elbv2-internet-gateway +spec: + forProvider: + region: us-west-1 + tags: + Name: testing + vpcIdSelector: + matchLabels: + testing.upbound.io/example-name: lblistener-forward-multiple + +--- + +apiVersion: ec2.aws.upbound.io/v1beta1 +kind: Subnet +metadata: + annotations: + meta.upbound.io/example-id: elbv2/v1beta2/lblistener + labels: + testing.upbound.io/example-name: lblistener-forward-multiple + name: elbv2-subnet +spec: + forProvider: + availabilityZone: us-west-1a + cidrBlock: 172.16.10.0/24 + region: us-west-1 + vpcIdSelector: + matchLabels: + testing.upbound.io/example-name: lblistener-forward-multiple + +--- + +apiVersion: ec2.aws.upbound.io/v1beta1 +kind: Subnet +metadata: + annotations: + meta.upbound.io/example-id: elbv2/v1beta2/lblistener + labels: + testing.upbound.io/example-name: lblistener-forward-multiple + name: elbv2-subnet-2 +spec: + forProvider: + availabilityZone: us-west-1b + cidrBlock: 172.16.20.0/24 + region: us-west-1 + vpcIdSelector: + matchLabels: + testing.upbound.io/example-name: lblistener-forward-multiple + +--- + +apiVersion: ec2.aws.upbound.io/v1beta1 +kind: SecurityGroup +metadata: + annotations: + meta.upbound.io/example-id: elbv2/v1beta2/lblistener + labels: + testing.upbound.io/example-name: lblistener-forward-multiple + name: elbv2-securitygroup +spec: + forProvider: + description: Allow TLS inbound traffic + name: allow_tls + region: us-west-1 + tags: + Name: allow_tls + vpcIdSelector: + matchLabels: + testing.upbound.io/example-name: lblistener-forward-multiple diff --git a/examples/elbv2/v1beta2/lblistener-forward-single-targetgroup.yaml b/examples/elbv2/v1beta2/lblistener-forward-single-targetgroup.yaml new file mode 100644 index 0000000000..79d46b1eec --- /dev/null +++ b/examples/elbv2/v1beta2/lblistener-forward-single-targetgroup.yaml @@ -0,0 +1,170 @@ +# SPDX-FileCopyrightText: 2024 The Crossplane Authors +# +# SPDX-License-Identifier: Apache-2.0 + +apiVersion: elbv2.aws.upbound.io/v1beta2 +kind: LBListener +metadata: + annotations: + meta.upbound.io/example-id: elbv2/v1beta2/lblistener + labels: + testing.upbound.io/example-name: lblistener-forward-single + name: front-end +spec: + forProvider: + defaultAction: + - type: forward + forward: + targetGroup: + - arnSelector: + matchLabels: + testing.upbound.io/example-name: lblistener-forward-single + + loadBalancerArnSelector: + matchLabels: + testing.upbound.io/example-name: lblistener-forward-single + port: 80 + protocol: HTTP + region: us-west-1 + +--- + +apiVersion: elbv2.aws.upbound.io/v1beta2 +kind: LBTargetGroup +metadata: + annotations: + meta.upbound.io/example-id: elbv2/v1beta2/lblistener + labels: + testing.upbound.io/example-name: lblistener-forward-single + name: test +spec: + forProvider: + name: example-lb-tg + port: 80 + protocol: HTTP + region: us-west-1 + targetType: ip + vpcIdSelector: + matchLabels: + testing.upbound.io/example-name: lblistener-forward-single + +--- + +apiVersion: elbv2.aws.upbound.io/v1beta2 +kind: LB +metadata: + annotations: + meta.upbound.io/example-id: elbv2/v1beta2/lblistener + labels: + testing.upbound.io/example-name: lblistener-forward-single + name: test +spec: + forProvider: + enableDeletionProtection: false + internal: false + loadBalancerType: application + name: test-lb-tf + region: us-west-1 + securityGroupSelector: + matchLabels: + testing.upbound.io/example-name: lblistener-forward-single + subnetSelector: + matchLabels: + testing.upbound.io/example-name: lblistener-forward-single + tags: + Environment: production + +--- + +apiVersion: ec2.aws.upbound.io/v1beta1 +kind: VPC +metadata: + annotations: + meta.upbound.io/example-id: elbv2/v1beta2/lblistener + labels: + testing.upbound.io/example-name: lblistener-forward-single + name: elbv2-vpc +spec: + forProvider: + cidrBlock: 172.16.0.0/16 + region: us-west-1 + tags: + Name: DemoVpc + +--- + +apiVersion: ec2.aws.upbound.io/v1beta1 +kind: InternetGateway +metadata: + annotations: + meta.upbound.io/example-id: elbv2/v1beta2/lblistener + labels: + testing.upbound.io/example-name: lblistener-forward-single + name: elbv2-internet-gateway +spec: + forProvider: + region: us-west-1 + tags: + Name: testing + vpcIdSelector: + matchLabels: + testing.upbound.io/example-name: lblistener-forward-single + +--- + +apiVersion: ec2.aws.upbound.io/v1beta1 +kind: Subnet +metadata: + annotations: + meta.upbound.io/example-id: elbv2/v1beta2/lblistener + labels: + testing.upbound.io/example-name: lblistener-forward-single + name: elbv2-subnet +spec: + forProvider: + availabilityZone: us-west-1a + cidrBlock: 172.16.10.0/24 + region: us-west-1 + vpcIdSelector: + matchLabels: + testing.upbound.io/example-name: lblistener-forward-single + +--- + +apiVersion: ec2.aws.upbound.io/v1beta1 +kind: Subnet +metadata: + annotations: + meta.upbound.io/example-id: elbv2/v1beta2/lblistener + labels: + testing.upbound.io/example-name: lblistener-forward-single + name: elbv2-subnet-2 +spec: + forProvider: + availabilityZone: us-west-1b + cidrBlock: 172.16.20.0/24 + region: us-west-1 + vpcIdSelector: + matchLabels: + testing.upbound.io/example-name: lblistener-forward-single + +--- + +apiVersion: ec2.aws.upbound.io/v1beta1 +kind: SecurityGroup +metadata: + annotations: + meta.upbound.io/example-id: elbv2/v1beta2/lblistener + labels: + testing.upbound.io/example-name: lblistener-forward-single + name: elbv2-securitygroup +spec: + forProvider: + description: Allow TLS inbound traffic + name: allow_tls + region: us-west-1 + tags: + Name: allow_tls + vpcIdSelector: + matchLabels: + testing.upbound.io/example-name: lblistener-forward-single diff --git a/go.mod b/go.mod index 862b656ced..2107e1a204 100644 --- a/go.mod +++ b/go.mod @@ -435,4 +435,4 @@ require ( // copied from the Terraform provider replace github.com/hashicorp/terraform-plugin-log => github.com/gdavison/terraform-plugin-log v0.0.0-20230928191232-6c653d8ef8fb -replace github.com/hashicorp/terraform-provider-aws => github.com/upbound/terraform-provider-aws v0.0.0-20241008123507-c58f3dd551f5 +replace github.com/hashicorp/terraform-provider-aws => github.com/upbound/terraform-provider-aws v0.0.0-20241019052313-8fed8454b0e3 diff --git a/go.sum b/go.sum index 8bba945fe7..09f347d74f 100644 --- a/go.sum +++ b/go.sum @@ -857,8 +857,8 @@ github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsT github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/tmccombs/hcl2json v0.3.3 h1:+DLNYqpWE0CsOQiEZu+OZm5ZBImake3wtITYxQ8uLFQ= github.com/tmccombs/hcl2json v0.3.3/go.mod h1:Y2chtz2x9bAeRTvSibVRVgbLJhLJXKlUeIvjeVdnm4w= -github.com/upbound/terraform-provider-aws v0.0.0-20241008123507-c58f3dd551f5 h1:2Ccu89BL+ZGzdUzpfFBDJ5MYnxdXSmyaDaHwQnZ5Dhc= -github.com/upbound/terraform-provider-aws v0.0.0-20241008123507-c58f3dd551f5/go.mod h1:gMeW31HPSyiaHsXeaesXhZXtFIDWP8x1Lr1YVeC8qQ4= +github.com/upbound/terraform-provider-aws v0.0.0-20241019052313-8fed8454b0e3 h1:f4VOuQgP3QN1+B41l9t3wz4eNWc4Nx2zm/1TVf6aX14= +github.com/upbound/terraform-provider-aws v0.0.0-20241019052313-8fed8454b0e3/go.mod h1:gMeW31HPSyiaHsXeaesXhZXtFIDWP8x1Lr1YVeC8qQ4= github.com/vmihailenco/msgpack v3.3.3+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6AcGMlsjHatGryHQYUTf1ShIgkk= github.com/vmihailenco/msgpack v4.0.4+incompatible h1:dSLoQfGFAo3F6OoNhwUmLwVgaUXK79GlxNBwueZn0xI= github.com/vmihailenco/msgpack v4.0.4+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6AcGMlsjHatGryHQYUTf1ShIgkk=