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

Allow to rename the dx gateway name #30375

Merged
merged 5 commits into from
Apr 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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .changelog/30375.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
```release-note:enhancement
resource/aws_dx_gateway: Add plan time validation to `name` argument
```

```release-note:enhancement
resource/aws_dx_gateway: Allow updates to `name` without forcing resource replacement
```
48 changes: 34 additions & 14 deletions internal/service/directconnect/gateway.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package directconnect
import (
"context"
"log"
"regexp"
"strconv"
"time"

Expand All @@ -11,16 +12,19 @@ import (
"github.com/hashicorp/aws-sdk-go-base/v2/awsv1shim/v2/tfawserr"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
"github.com/hashicorp/terraform-provider-aws/internal/conns"
"github.com/hashicorp/terraform-provider-aws/internal/errs/sdkdiag"
"github.com/hashicorp/terraform-provider-aws/internal/tfresource"
"github.com/hashicorp/terraform-provider-aws/internal/verify"
)

// @SDKResource("aws_dx_gateway")
func ResourceGateway() *schema.Resource {
return &schema.Resource{
CreateWithoutTimeout: resourceGatewayCreate,
ReadWithoutTimeout: resourceGatewayRead,
UpdateWithoutTimeout: resourceGatewayUpdate,
DeleteWithoutTimeout: resourceGatewayDelete,

Importer: &schema.ResourceImporter{
Expand All @@ -32,15 +36,13 @@ func ResourceGateway() *schema.Resource {
Type: schema.TypeString,
Required: true,
ForceNew: true,
ValidateFunc: validAmazonSideASN,
ValidateFunc: verify.ValidAmazonSideASN,
},

"name": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
Type: schema.TypeString,
Required: true,
ValidateFunc: validation.StringMatch(regexp.MustCompile(`^[a-z0-9-]{1,100}$`), "Name must contain no more than 100 characters. Valid characters are a-z, 0-9, and hyphens (–)."),
},

"owner_account_id": {
Type: schema.TypeString,
Computed: true,
Expand All @@ -64,22 +66,20 @@ func resourceGatewayCreate(ctx context.Context, d *schema.ResourceData, meta int
}

if v, ok := d.Get("amazon_side_asn").(string); ok && v != "" {
if v, err := strconv.ParseInt(v, 10, 64); err == nil {
input.AmazonSideAsn = aws.Int64(v)
}
v, _ := strconv.ParseInt(v, 10, 64)
input.AmazonSideAsn = aws.Int64(v)
}

log.Printf("[DEBUG] Creating Direct Connect Gateway: %s", input)
resp, err := conn.CreateDirectConnectGatewayWithContext(ctx, input)
output, err := conn.CreateDirectConnectGatewayWithContext(ctx, input)

if err != nil {
return sdkdiag.AppendErrorf(diags, "creating Direct Connect Gateway (%s): %s", name, err)
}

d.SetId(aws.StringValue(resp.DirectConnectGateway.DirectConnectGatewayId))
d.SetId(aws.StringValue(output.DirectConnectGateway.DirectConnectGatewayId))

if _, err := waitGatewayCreated(ctx, conn, d.Id(), d.Timeout(schema.TimeoutCreate)); err != nil {
return sdkdiag.AppendErrorf(diags, "waiting for Direct Connect Gateway (%s) to create: %s", d.Id(), err)
return sdkdiag.AppendErrorf(diags, "waiting for Direct Connect Gateway (%s) create: %s", d.Id(), err)
}

return append(diags, resourceGatewayRead(ctx, d, meta)...)
Expand Down Expand Up @@ -108,6 +108,26 @@ func resourceGatewayRead(ctx context.Context, d *schema.ResourceData, meta inter
return diags
}

func resourceGatewayUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
var diags diag.Diagnostics
conn := meta.(*conns.AWSClient).DirectConnectConn()

if d.HasChange("name") {
input := &directconnect.UpdateDirectConnectGatewayInput{
DirectConnectGatewayId: aws.String(d.Id()),
NewDirectConnectGatewayName: aws.String(d.Get("name").(string)),
}

_, err := conn.UpdateDirectConnectGatewayWithContext(ctx, input)

if err != nil {
return sdkdiag.AppendErrorf(diags, "updating Direct Connect Gateway (%s): %s", d.Id(), err)
}
}

return append(diags, resourceGatewayRead(ctx, d, meta)...)
}

func resourceGatewayDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
var diags diag.Diagnostics
conn := meta.(*conns.AWSClient).DirectConnectConn()
Expand All @@ -126,7 +146,7 @@ func resourceGatewayDelete(ctx context.Context, d *schema.ResourceData, meta int
}

if _, err := waitGatewayDeleted(ctx, conn, d.Id(), d.Timeout(schema.TimeoutDelete)); err != nil {
return sdkdiag.AppendErrorf(diags, "waiting for Direct Connect Gateway (%s) to delete: %s", d.Id(), err)
return sdkdiag.AppendErrorf(diags, "waiting for Direct Connect Gateway (%s) delete: %s", d.Id(), err)
}

return diags
Expand Down
32 changes: 32 additions & 0 deletions internal/service/directconnect/gateway_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,38 @@ func TestAccDirectConnectGateway_complex(t *testing.T) {
})
}

func TestAccDirectConnectGateway_update(t *testing.T) {
ctx := acctest.Context(t)
var v directconnect.Gateway
rName1 := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix)
rName2 := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix)
rBgpAsn := sdkacctest.RandIntRange(64512, 65534)
resourceName := "aws_dx_gateway.test"

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { acctest.PreCheck(ctx, t) },
ErrorCheck: acctest.ErrorCheck(t, directconnect.EndpointsID),
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories,
CheckDestroy: testAccCheckGatewayDestroy(ctx),
Steps: []resource.TestStep{
{
Config: testAccGatewayConfig_basic(rName1, rBgpAsn),
Check: resource.ComposeTestCheckFunc(
testAccCheckGatewayExists(ctx, resourceName, &v),
resource.TestCheckResourceAttr(resourceName, "name", rName1),
),
},
{
Config: testAccGatewayConfig_basic(rName2, rBgpAsn),
Check: resource.ComposeTestCheckFunc(
testAccCheckGatewayExists(ctx, resourceName, &v),
resource.TestCheckResourceAttr(resourceName, "name", rName2),
),
},
},
})
}

func testAccCheckGatewayDestroy(ctx context.Context) resource.TestCheckFunc {
return func(s *terraform.State) error {
conn := acctest.Provider.Meta().(*conns.AWSClient).DirectConnectConn()
Expand Down
24 changes: 0 additions & 24 deletions internal/service/directconnect/validate.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
package directconnect

import (
"fmt"
"strconv"

"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
)
Expand All @@ -22,24 +19,3 @@ func validConnectionBandWidth() schema.SchemaValidateFunc {
"400Mbps",
"500Mbps"}, false)
}

func validAmazonSideASN(v interface{}, k string) (ws []string, errors []error) {
value := v.(string)

// http://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_CreateVpnGateway.html
asn, err := strconv.ParseInt(value, 10, 64)
if err != nil {
errors = append(errors, fmt.Errorf("%q (%q) must be a 64-bit integer", k, v))
return
}

// https://github.com/hashicorp/terraform-provider-aws/issues/5263
isLegacyAsn := func(a int64) bool {
return a == 7224 || a == 9059 || a == 10124 || a == 17493
}

if !isLegacyAsn(asn) && ((asn < 64512) || (asn > 65534 && asn < 4200000000) || (asn > 4294967294)) {
errors = append(errors, fmt.Errorf("%q (%q) must be 7224, 9059, 10124 or 17493 or in the range 64512 to 65534 or 4200000000 to 4294967294", k, v))
}
return
}
46 changes: 0 additions & 46 deletions internal/service/directconnect/validate_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,49 +42,3 @@ func TestValidConnectionBandWidth(t *testing.T) {
}
}
}

func TestValidAmazonSideASN(t *testing.T) {
t.Parallel()

validAsns := []string{
"7224",
"9059",
"10124",
"17493",
"64512",
"64513",
"65533",
"65534",
"4200000000",
"4200000001",
"4294967293",
"4294967294",
}
for _, v := range validAsns {
_, errors := validAmazonSideASN(v, "amazon_side_asn")
if len(errors) != 0 {
t.Fatalf("%q should be a valid ASN: %q", v, errors)
}
}

invalidAsns := []string{
"1",
"ABCDEFG",
"",
"7225",
"9058",
"10125",
"17492",
"64511",
"65535",
"4199999999",
"4294967295",
"9999999999",
}
for _, v := range invalidAsns {
_, errors := validAmazonSideASN(v, "amazon_side_asn")
if len(errors) == 0 {
t.Fatalf("%q should be an invalid ASN", v)
}
}
}
22 changes: 0 additions & 22 deletions internal/service/ec2/validate.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package ec2
import (
"fmt"
"regexp"
"strconv"
"strings"
)

Expand Down Expand Up @@ -43,24 +42,3 @@ func validNestedExactlyOneOf(m map[string]interface{}, valid []string) error {
}
return nil
}

func validAmazonSideASN(v interface{}, k string) (ws []string, errors []error) {
value := v.(string)

// http://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_CreateVpnGateway.html
asn, err := strconv.ParseInt(value, 10, 64)
if err != nil {
errors = append(errors, fmt.Errorf("%q (%q) must be a 64-bit integer", k, v))
return
}

// https://github.com/hashicorp/terraform-provider-aws/issues/5263
isLegacyAsn := func(a int64) bool {
return a == 7224 || a == 9059 || a == 10124 || a == 17493
}

if !isLegacyAsn(asn) && ((asn < 64512) || (asn > 65534 && asn < 4200000000) || (asn > 4294967294)) {
errors = append(errors, fmt.Errorf("%q (%q) must be 7224, 9059, 10124 or 17493 or in the range 64512 to 65534 or 4200000000 to 4294967294", k, v))
}
return
}
46 changes: 0 additions & 46 deletions internal/service/ec2/validate_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,49 +32,3 @@ func TestValidSecurityGroupRuleDescription(t *testing.T) {
}
}
}

func TestValidAmazonSideASN(t *testing.T) {
t.Parallel()

validAsns := []string{
"7224",
"9059",
"10124",
"17493",
"64512",
"64513",
"65533",
"65534",
"4200000000",
"4200000001",
"4294967293",
"4294967294",
}
for _, v := range validAsns {
_, errors := validAmazonSideASN(v, "amazon_side_asn")
if len(errors) != 0 {
t.Fatalf("%q should be a valid ASN: %q", v, errors)
}
}

invalidAsns := []string{
"1",
"ABCDEFG",
"",
"7225",
"9058",
"10125",
"17492",
"64511",
"65535",
"4199999999",
"4294967295",
"9999999999",
}
for _, v := range invalidAsns {
_, errors := validAmazonSideASN(v, "amazon_side_asn")
if len(errors) == 0 {
t.Fatalf("%q should be an invalid ASN", v)
}
}
}
2 changes: 1 addition & 1 deletion internal/service/ec2/vpnsite_gateway.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ func ResourceVPNGateway() *schema.Resource {
Optional: true,
ForceNew: true,
Computed: true,
ValidateFunc: validAmazonSideASN,
ValidateFunc: verify.ValidAmazonSideASN,
},
"arn": {
Type: schema.TypeString,
Expand Down
21 changes: 21 additions & 0 deletions internal/verify/validate.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,27 @@ func Valid4ByteASN(v interface{}, k string) (ws []string, errors []error) {
return
}

func ValidAmazonSideASN(v interface{}, k string) (ws []string, errors []error) {
value := v.(string)

// http://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_CreateVpnGateway.html
asn, err := strconv.ParseInt(value, 10, 64)
if err != nil {
errors = append(errors, fmt.Errorf("%q (%q) must be a 64-bit integer", k, v))
return
}

// https://github.com/hashicorp/terraform-provider-aws/issues/5263
isLegacyAsn := func(a int64) bool {
return a == 7224 || a == 9059 || a == 10124 || a == 17493
}

if !isLegacyAsn(asn) && ((asn < 64512) || (asn > 65534 && asn < 4200000000) || (asn > 4294967294)) {
errors = append(errors, fmt.Errorf("%q (%q) must be 7224, 9059, 10124 or 17493 or in the range 64512 to 65534 or 4200000000 to 4294967294", k, v))
}
return
}

// ValidARN validates that a string value matches a generic ARN format
var ValidARN = ValidARNCheck()

Expand Down
Loading