Skip to content

Commit

Permalink
Merge pull request #17739 from ewbankkit/b-aws_globalaccelerator_acce…
Browse files Browse the repository at this point in the history
…lerator-update-flow-logs

r/aws_globalaccelerator_accelerator: Correctly update flow log attributes when enabled
  • Loading branch information
breathingdust authored Mar 4, 2021
2 parents 512c8bb + 87de131 commit 366aa1d
Show file tree
Hide file tree
Showing 12 changed files with 888 additions and 452 deletions.
7 changes: 7 additions & 0 deletions .changelog/17739.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
```release-note:bug
resource/aws_globalaccelerator_accelerator: Allow update of flow log attribute for active flow logs
```

```release-note:enhancement
resource/aws_globalaccelerator_accelerator: Add plan time validation to `name`, `flow_logs_s3_bucket` and `flow_logs_s3_prefix` attributes
```
73 changes: 73 additions & 0 deletions aws/internal/service/globalaccelerator/arn.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package globalaccelerator

import (
"fmt"
"strings"

"github.com/aws/aws-sdk-go/aws/arn"
)

const (
ARNSeparator = "/"
ARNService = "globalaccelerator"
)

// EndpointGroupARNToListenerARN converts an endpoint group ARN to a listener ARN.
// See https://docs.aws.amazon.com/service-authorization/latest/reference/list_awsglobalaccelerator.html#awsglobalaccelerator-resources-for-iam-policies.
func EndpointGroupARNToListenerARN(inputARN string) (string, error) {
parsedARN, err := arn.Parse(inputARN)

if err != nil {
return "", fmt.Errorf("error parsing ARN (%s): %w", inputARN, err)
}

if actual, expected := parsedARN.Service, ARNService; actual != expected {
return "", fmt.Errorf("expected service %s in ARN (%s), got: %s", expected, inputARN, actual)
}

resourceParts := strings.Split(parsedARN.Resource, ARNSeparator)

if actual, expected := len(resourceParts), 6; actual < expected {
return "", fmt.Errorf("expected at least %d resource parts in ARN (%s), got: %d", expected, inputARN, actual)
}

outputARN := arn.ARN{
Partition: parsedARN.Partition,
Service: parsedARN.Service,
Region: parsedARN.Region,
AccountID: parsedARN.AccountID,
Resource: strings.Join(resourceParts[0:4], ARNSeparator),
}.String()

return outputARN, nil
}

// ListenerOrEndpointGroupARNToAcceleratorARN converts a listener or endpoint group ARN to an accelerator ARN.
// See https://docs.aws.amazon.com/service-authorization/latest/reference/list_awsglobalaccelerator.html#awsglobalaccelerator-resources-for-iam-policies.
func ListenerOrEndpointGroupARNToAcceleratorARN(inputARN string) (string, error) {
parsedARN, err := arn.Parse(inputARN)

if err != nil {
return "", fmt.Errorf("error parsing ARN (%s): %w", inputARN, err)
}

if actual, expected := parsedARN.Service, ARNService; actual != expected {
return "", fmt.Errorf("expected service %s in ARN (%s), got: %s", expected, inputARN, actual)
}

resourceParts := strings.Split(parsedARN.Resource, ARNSeparator)

if actual, expected := len(resourceParts), 4; actual < expected {
return "", fmt.Errorf("expected at least %d resource parts in ARN (%s), got: %d", expected, inputARN, actual)
}

outputARN := arn.ARN{
Partition: parsedARN.Partition,
Service: parsedARN.Service,
Region: parsedARN.Region,
AccountID: parsedARN.AccountID,
Resource: strings.Join(resourceParts[0:2], ARNSeparator),
}.String()

return outputARN, nil
}
127 changes: 127 additions & 0 deletions aws/internal/service/globalaccelerator/arn_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
package globalaccelerator_test

import (
"regexp"
"testing"

tfglobalaccelerator "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/globalaccelerator"
)

func TestEndpointGroupARNToListenerARN(t *testing.T) {
testCases := []struct {
TestName string
InputARN string
ExpectedError *regexp.Regexp
ExpectedARN string
}{
{
TestName: "empty ARN",
InputARN: "",
ExpectedError: regexp.MustCompile(`error parsing ARN`),
},
{
TestName: "unparsable ARN",
InputARN: "test",
ExpectedError: regexp.MustCompile(`error parsing ARN`),
},
{
TestName: "invalid ARN service",
InputARN: "arn:aws:ec2::123456789012:accelerator/a-123/listener/l-456/endpoint-group/eg-789",
ExpectedError: regexp.MustCompile(`expected service globalaccelerator`),
},
{
TestName: "invalid ARN resource parts",
InputARN: "arn:aws:globalaccelerator::123456789012:accelerator/a-123/listener/l-456",
ExpectedError: regexp.MustCompile(`expected at least 6 resource parts`),
},
{
TestName: "valid ARN",
InputARN: "arn:aws:globalaccelerator::123456789012:accelerator/a-123/listener/l-456/endpoint-group/eg-789",
ExpectedARN: "arn:aws:globalaccelerator::123456789012:accelerator/a-123/listener/l-456",
},
}

for _, testCase := range testCases {
t.Run(testCase.TestName, func(t *testing.T) {
got, err := tfglobalaccelerator.EndpointGroupARNToListenerARN(testCase.InputARN)

if err == nil && testCase.ExpectedError != nil {
t.Fatalf("expected error %s, got no error", testCase.ExpectedError.String())
}

if err != nil && testCase.ExpectedError == nil {
t.Fatalf("got unexpected error: %s", err)
}

if err != nil && !testCase.ExpectedError.MatchString(err.Error()) {
t.Fatalf("expected error %s, got: %s", testCase.ExpectedError.String(), err)
}

if got != testCase.ExpectedARN {
t.Errorf("got %s, expected %s", got, testCase.ExpectedARN)
}
})
}
}

func TestListenerOrEndpointGroupARNToAcceleratorARN(t *testing.T) {
testCases := []struct {
TestName string
InputARN string
ExpectedError *regexp.Regexp
ExpectedARN string
}{
{
TestName: "empty ARN",
InputARN: "",
ExpectedError: regexp.MustCompile(`error parsing ARN`),
},
{
TestName: "unparsable ARN",
InputARN: "test",
ExpectedError: regexp.MustCompile(`error parsing ARN`),
},
{
TestName: "invalid ARN service",
InputARN: "arn:aws:ec2::123456789012:accelerator/a-123/listener/l-456",
ExpectedError: regexp.MustCompile(`expected service globalaccelerator`),
},
{
TestName: "invalid ARN resource parts",
InputARN: "arn:aws:globalaccelerator::123456789012:accelerator/a-123",
ExpectedError: regexp.MustCompile(`expected at least 4 resource parts`),
},
{
TestName: "valid listener ARN",
InputARN: "arn:aws:globalaccelerator::123456789012:accelerator/a-123/listener/l-456",
ExpectedARN: "arn:aws:globalaccelerator::123456789012:accelerator/a-123",
},
{
TestName: "valid endpoint group ARN",
InputARN: "arn:aws:globalaccelerator::123456789012:accelerator/a-123/listener/l-456/endpoint-group/eg-789",
ExpectedARN: "arn:aws:globalaccelerator::123456789012:accelerator/a-123",
},
}

for _, testCase := range testCases {
t.Run(testCase.TestName, func(t *testing.T) {
got, err := tfglobalaccelerator.ListenerOrEndpointGroupARNToAcceleratorARN(testCase.InputARN)

if err == nil && testCase.ExpectedError != nil {
t.Fatalf("expected error %s, got no error", testCase.ExpectedError.String())
}

if err != nil && testCase.ExpectedError == nil {
t.Fatalf("got unexpected error: %s", err)
}

if err != nil && !testCase.ExpectedError.MatchString(err.Error()) {
t.Fatalf("expected error %s, got: %s", testCase.ExpectedError.String(), err)
}

if got != testCase.ExpectedARN {
t.Errorf("got %s, expected %s", got, testCase.ExpectedARN)
}
})
}
}
132 changes: 132 additions & 0 deletions aws/internal/service/globalaccelerator/finder/finder.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,150 @@ package finder
import (
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/globalaccelerator"
"github.com/hashicorp/aws-sdk-go-base/tfawserr"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
)

// AcceleratorByARN returns the accelerator corresponding to the specified ARN.
// Returns NotFoundError if no accelerator is found.
func AcceleratorByARN(conn *globalaccelerator.GlobalAccelerator, arn string) (*globalaccelerator.Accelerator, error) {
input := &globalaccelerator.DescribeAcceleratorInput{
AcceleratorArn: aws.String(arn),
}

return Accelerator(conn, input)
}

// Accelerator returns the accelerator corresponding to the specified input.
// Returns NotFoundError if no accelerator is found.
func Accelerator(conn *globalaccelerator.GlobalAccelerator, input *globalaccelerator.DescribeAcceleratorInput) (*globalaccelerator.Accelerator, error) {
output, err := conn.DescribeAccelerator(input)

if tfawserr.ErrCodeEquals(err, globalaccelerator.ErrCodeAcceleratorNotFoundException) {
return nil, &resource.NotFoundError{
LastError: err,
LastRequest: input,
}
}

if err != nil {
return nil, err
}

if output == nil || output.Accelerator == nil {
return nil, &resource.NotFoundError{
Message: "Empty result",
LastRequest: input,
}
}

return output.Accelerator, nil
}

// AcceleratorAttributesByARN returns the accelerator attributes corresponding to the specified ARN.
// Returns NotFoundError if no accelerator is found.
func AcceleratorAttributesByARN(conn *globalaccelerator.GlobalAccelerator, arn string) (*globalaccelerator.AcceleratorAttributes, error) {
input := &globalaccelerator.DescribeAcceleratorAttributesInput{
AcceleratorArn: aws.String(arn),
}

return AcceleratorAttributes(conn, input)
}

// AcceleratorAttributes returns the accelerator attributes corresponding to the specified input.
// Returns NotFoundError if no accelerator is found.
func AcceleratorAttributes(conn *globalaccelerator.GlobalAccelerator, input *globalaccelerator.DescribeAcceleratorAttributesInput) (*globalaccelerator.AcceleratorAttributes, error) {
output, err := conn.DescribeAcceleratorAttributes(input)

if tfawserr.ErrCodeEquals(err, globalaccelerator.ErrCodeAcceleratorNotFoundException) {
return nil, &resource.NotFoundError{
LastError: err,
LastRequest: input,
}
}

if err != nil {
return nil, err
}

if output == nil || output.AcceleratorAttributes == nil {
return nil, &resource.NotFoundError{
Message: "Empty result",
LastRequest: input,
}
}

return output.AcceleratorAttributes, nil
}

// EndpointGroupByARN returns the endpoint group corresponding to the specified ARN.
// Returns NotFoundError if no endpoint group is found.
func EndpointGroupByARN(conn *globalaccelerator.GlobalAccelerator, arn string) (*globalaccelerator.EndpointGroup, error) {
input := &globalaccelerator.DescribeEndpointGroupInput{
EndpointGroupArn: aws.String(arn),
}

return EndpointGroup(conn, input)
}

// EndpointGroup returns the endpoint group corresponding to the specified input.
// Returns NotFoundError if no endpoint group is found.
func EndpointGroup(conn *globalaccelerator.GlobalAccelerator, input *globalaccelerator.DescribeEndpointGroupInput) (*globalaccelerator.EndpointGroup, error) {
output, err := conn.DescribeEndpointGroup(input)

if tfawserr.ErrCodeEquals(err, globalaccelerator.ErrCodeEndpointGroupNotFoundException) {
return nil, &resource.NotFoundError{
LastError: err,
LastRequest: input,
}
}

if err != nil {
return nil, err
}

if output == nil || output.EndpointGroup == nil {
return nil, &resource.NotFoundError{
Message: "Empty result",
LastRequest: input,
}
}

return output.EndpointGroup, nil
}

// ListenerByARN returns the listener corresponding to the specified ARN.
// Returns NotFoundError if no listener is found.
func ListenerByARN(conn *globalaccelerator.GlobalAccelerator, arn string) (*globalaccelerator.Listener, error) {
input := &globalaccelerator.DescribeListenerInput{
ListenerArn: aws.String(arn),
}

return Listener(conn, input)
}

// Listener returns the listener corresponding to the specified input.
// Returns NotFoundError if no listener is found.
func Listener(conn *globalaccelerator.GlobalAccelerator, input *globalaccelerator.DescribeListenerInput) (*globalaccelerator.Listener, error) {
output, err := conn.DescribeListener(input)

if tfawserr.ErrCodeEquals(err, globalaccelerator.ErrCodeListenerNotFoundException) {
return nil, &resource.NotFoundError{
LastError: err,
LastRequest: input,
}
}

if err != nil {
return nil, err
}

if output == nil || output.Listener == nil {
return nil, &resource.NotFoundError{
Message: "Empty result",
LastRequest: input,
}
}

return output.Listener, nil
}
26 changes: 26 additions & 0 deletions aws/internal/service/globalaccelerator/waiter/status.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package waiter

import (
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/globalaccelerator"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
"github.com/terraform-providers/terraform-provider-aws/aws/internal/service/globalaccelerator/finder"
"github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource"
)

// AcceleratorStatus fetches the Accelerator and its Status
func AcceleratorStatus(conn *globalaccelerator.GlobalAccelerator, arn string) resource.StateRefreshFunc {
return func() (interface{}, string, error) {
accelerator, err := finder.AcceleratorByARN(conn, arn)

if tfresource.NotFound(err) {
return nil, "", nil
}

if err != nil {
return nil, "", err
}

return accelerator, aws.StringValue(accelerator.Status), nil
}
}
Loading

0 comments on commit 366aa1d

Please sign in to comment.