Skip to content

Commit

Permalink
Merge pull request #18351 from ewbankkit/b-aws_apigatewayv2_domain_na…
Browse files Browse the repository at this point in the history
…me-update

r/aws_apigatewayv2_domain_name: Always send domain name configuration on update of mutual TLS configuration
  • Loading branch information
gdavison authored Mar 25, 2021
2 parents 3b18f11 + 6bd9874 commit 043fa9d
Show file tree
Hide file tree
Showing 9 changed files with 209 additions and 126 deletions.
3 changes: 3 additions & 0 deletions .changelog/18351.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:bug
resource/aws_apigatewayv2_domain_name: Allow update of mutual TLS S3 object version
```
33 changes: 33 additions & 0 deletions aws/internal/service/apigatewayv2/finder/finder.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,3 +72,36 @@ func Apis(conn *apigatewayv2.ApiGatewayV2, input *apigatewayv2.GetApisInput) ([]

return apis, nil
}

func DomainNameByName(conn *apigatewayv2.ApiGatewayV2, name string) (*apigatewayv2.GetDomainNameOutput, error) {
input := &apigatewayv2.GetDomainNameInput{
DomainName: aws.String(name),
}

return DomainName(conn, input)
}

func DomainName(conn *apigatewayv2.ApiGatewayV2, input *apigatewayv2.GetDomainNameInput) (*apigatewayv2.GetDomainNameOutput, error) {
output, err := conn.GetDomainName(input)

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

if err != nil {
return nil, err
}

// Handle any empty result.
if output == nil || len(output.DomainNameConfigurations) == 0 {
return nil, &resource.NotFoundError{
Message: "Empty result",
LastRequest: input,
}
}

return output, nil
}
2 changes: 1 addition & 1 deletion aws/internal/service/apigatewayv2/lister/list.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
//go:generate go run ../../../generators/listpages/main.go -function=GetApis github.com/aws/aws-sdk-go/service/apigatewayv2
//go:generate go run ../../../generators/listpages/main.go -function=GetApis,GetDomainNames github.com/aws/aws-sdk-go/service/apigatewayv2

package lister
23 changes: 22 additions & 1 deletion aws/internal/service/apigatewayv2/lister/list_pages_gen.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

23 changes: 23 additions & 0 deletions aws/internal/service/apigatewayv2/waiter/status.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,13 @@ package waiter

import (
"fmt"
"log"

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

// DeploymentStatus fetches the Deployment and its Status
Expand All @@ -32,6 +35,26 @@ func DeploymentStatus(conn *apigatewayv2.ApiGatewayV2, apiId, deploymentId strin
}
}

func DomainNameStatus(conn *apigatewayv2.ApiGatewayV2, name string) resource.StateRefreshFunc {
return func() (interface{}, string, error) {
domainName, err := finder.DomainNameByName(conn, name)

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

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

if statusMessage := aws.StringValue(domainName.DomainNameConfigurations[0].DomainNameStatusMessage); statusMessage != "" {
log.Printf("[INFO] API Gateway v2 domain name (%s) status message: %s", name, statusMessage)
}

return domainName, aws.StringValue(domainName.DomainNameConfigurations[0].DomainNameStatus), nil
}
}

// VpcLinkStatus fetches the VPC Link and its Status
func VpcLinkStatus(conn *apigatewayv2.ApiGatewayV2, vpcLinkId string) resource.StateRefreshFunc {
return func() (interface{}, string, error) {
Expand Down
17 changes: 17 additions & 0 deletions aws/internal/service/apigatewayv2/waiter/waiter.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,23 @@ func DeploymentDeployed(conn *apigatewayv2.ApiGatewayV2, apiId, deploymentId str
return nil, err
}

func DomainNameAvailable(conn *apigatewayv2.ApiGatewayV2, name string, timeout time.Duration) (*apigatewayv2.GetDomainNameOutput, error) {
stateConf := &resource.StateChangeConf{
Pending: []string{apigatewayv2.DomainNameStatusUpdating},
Target: []string{apigatewayv2.DomainNameStatusAvailable},
Refresh: DomainNameStatus(conn, name),
Timeout: timeout,
}

outputRaw, err := stateConf.WaitForState()

if v, ok := outputRaw.(*apigatewayv2.GetDomainNameOutput); ok {
return v, err
}

return nil, err
}

// VpcLinkAvailable waits for a VPC Link to return Available
func VpcLinkAvailable(conn *apigatewayv2.ApiGatewayV2, vpcLinkId string) (*apigatewayv2.GetVpcLinkOutput, error) {
stateConf := &resource.StateChangeConf{
Expand Down
127 changes: 47 additions & 80 deletions aws/resource_aws_apigatewayv2_domain_name.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,13 @@ import (
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/arn"
"github.com/aws/aws-sdk-go/service/apigatewayv2"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
"github.com/hashicorp/aws-sdk-go-base/tfawserr"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
"github.com/terraform-providers/terraform-provider-aws/aws/internal/keyvaluetags"
)

const (
apiGatewayV2DomainNameStatusDeleted = "DELETED"
"github.com/terraform-providers/terraform-provider-aws/aws/internal/service/apigatewayv2/finder"
"github.com/terraform-providers/terraform-provider-aws/aws/internal/service/apigatewayv2/waiter"
"github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource"
)

func resourceAwsApiGatewayV2DomainName() *schema.Resource {
Expand All @@ -29,6 +28,7 @@ func resourceAwsApiGatewayV2DomainName() *schema.Resource {
},

Timeouts: &schema.ResourceTimeout{
Create: schema.DefaultTimeout(10 * time.Minute),
Update: schema.DefaultTimeout(60 * time.Minute),
},

Expand Down Expand Up @@ -109,21 +109,27 @@ func resourceAwsApiGatewayV2DomainName() *schema.Resource {

func resourceAwsApiGatewayV2DomainNameCreate(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*AWSClient).apigatewayv2conn
domainName := d.Get("domain_name").(string)

req := &apigatewayv2.CreateDomainNameInput{
DomainName: aws.String(d.Get("domain_name").(string)),
input := &apigatewayv2.CreateDomainNameInput{
DomainName: aws.String(domainName),
DomainNameConfigurations: expandApiGatewayV2DomainNameConfiguration(d.Get("domain_name_configuration").([]interface{})),
MutualTlsAuthentication: expandApiGatewayV2MutualTlsAuthentication(d.Get("mutual_tls_authentication").([]interface{})),
Tags: keyvaluetags.New(d.Get("tags").(map[string]interface{})).IgnoreAws().Apigatewayv2Tags(),
}

log.Printf("[DEBUG] Creating API Gateway v2 domain name: %s", req)
resp, err := conn.CreateDomainName(req)
log.Printf("[DEBUG] Creating API Gateway v2 domain name: %s", input)
output, err := conn.CreateDomainName(input)

if err != nil {
return fmt.Errorf("error creating API Gateway v2 domain name: %s", err)
return fmt.Errorf("error creating API Gateway v2 domain name (%s): %w", domainName, err)
}

d.SetId(aws.StringValue(resp.DomainName))
d.SetId(aws.StringValue(output.DomainName))

if _, err := waiter.DomainNameAvailable(conn, d.Id(), d.Timeout(schema.TimeoutCreate)); err != nil {
return fmt.Errorf("error waiting for API Gateway v2 domain name (%s) to become available: %w", d.Id(), err)
}

return resourceAwsApiGatewayV2DomainNameRead(d, meta)
}
Expand All @@ -132,37 +138,37 @@ func resourceAwsApiGatewayV2DomainNameRead(d *schema.ResourceData, meta interfac
conn := meta.(*AWSClient).apigatewayv2conn
ignoreTagsConfig := meta.(*AWSClient).IgnoreTagsConfig

respRaw, state, err := apiGatewayV2DomainNameRefresh(conn, d.Id())()
if err != nil {
return fmt.Errorf("error reading API Gateway v2 domain name (%s): %s", d.Id(), err)
}
output, err := finder.DomainNameByName(conn, d.Id())

if state == apiGatewayV2DomainNameStatusDeleted {
if !d.IsNewResource() && tfresource.NotFound(err) {
log.Printf("[WARN] API Gateway v2 domain name (%s) not found, removing from state", d.Id())
d.SetId("")
return nil
}

resp := respRaw.(*apigatewayv2.GetDomainNameOutput)
d.Set("api_mapping_selection_expression", resp.ApiMappingSelectionExpression)
if err != nil {
return fmt.Errorf("error reading API Gateway v2 domain name (%s): %w", d.Id(), err)
}

d.Set("api_mapping_selection_expression", output.ApiMappingSelectionExpression)
arn := arn.ARN{
Partition: meta.(*AWSClient).partition,
Service: "apigateway",
Region: meta.(*AWSClient).region,
Resource: fmt.Sprintf("/domainnames/%s", d.Id()),
}.String()
d.Set("arn", arn)
d.Set("domain_name", resp.DomainName)
err = d.Set("domain_name_configuration", flattenApiGatewayV2DomainNameConfiguration(resp.DomainNameConfigurations[0]))
d.Set("domain_name", output.DomainName)
err = d.Set("domain_name_configuration", flattenApiGatewayV2DomainNameConfiguration(output.DomainNameConfigurations[0]))
if err != nil {
return fmt.Errorf("error setting domain_name_configuration: %s", err)
return fmt.Errorf("error setting domain_name_configuration: %w", err)
}
err = d.Set("mutual_tls_authentication", flattenApiGatewayV2MutualTlsAuthentication(resp.MutualTlsAuthentication))
err = d.Set("mutual_tls_authentication", flattenApiGatewayV2MutualTlsAuthentication(output.MutualTlsAuthentication))
if err != nil {
return fmt.Errorf("error setting mutual_tls_authentication: %s", err)
return fmt.Errorf("error setting mutual_tls_authentication: %w", err)
}
if err := d.Set("tags", keyvaluetags.Apigatewayv2KeyValueTags(resp.Tags).IgnoreAws().IgnoreConfig(ignoreTagsConfig).Map()); err != nil {
return fmt.Errorf("error setting tags: %s", err)
if err := d.Set("tags", keyvaluetags.Apigatewayv2KeyValueTags(output.Tags).IgnoreAws().IgnoreConfig(ignoreTagsConfig).Map()); err != nil {
return fmt.Errorf("error setting tags: %w", err)
}

return nil
Expand All @@ -172,43 +178,42 @@ func resourceAwsApiGatewayV2DomainNameUpdate(d *schema.ResourceData, meta interf
conn := meta.(*AWSClient).apigatewayv2conn

if d.HasChanges("domain_name_configuration", "mutual_tls_authentication") {
req := &apigatewayv2.UpdateDomainNameInput{
DomainName: aws.String(d.Id()),
input := &apigatewayv2.UpdateDomainNameInput{
DomainName: aws.String(d.Id()),
DomainNameConfigurations: expandApiGatewayV2DomainNameConfiguration(d.Get("domain_name_configuration").([]interface{})),
}

if d.HasChange("domain_name_configuration") {
req.DomainNameConfigurations = expandApiGatewayV2DomainNameConfiguration(d.Get("domain_name_configuration").([]interface{}))
}
if d.HasChange("mutual_tls_authentication") {
vMutualTlsAuthentication := d.Get("mutual_tls_authentication").([]interface{})

if len(vMutualTlsAuthentication) == 0 || vMutualTlsAuthentication[0] == nil {
// To disable mutual TLS for a custom domain name, remove the truststore from your custom domain name.
req.MutualTlsAuthentication = &apigatewayv2.MutualTlsAuthenticationInput{
input.MutualTlsAuthentication = &apigatewayv2.MutualTlsAuthenticationInput{
TruststoreUri: aws.String(""),
}
} else {
req.MutualTlsAuthentication = &apigatewayv2.MutualTlsAuthenticationInput{
input.MutualTlsAuthentication = &apigatewayv2.MutualTlsAuthenticationInput{
TruststoreVersion: aws.String(vMutualTlsAuthentication[0].(map[string]interface{})["truststore_version"].(string)),
}
}
}

log.Printf("[DEBUG] Updating API Gateway v2 domain name: %s", req)
_, err := conn.UpdateDomainName(req)
log.Printf("[DEBUG] Updating API Gateway v2 domain name: %s", input)
_, err := conn.UpdateDomainName(input)

if err != nil {
return fmt.Errorf("error updating API Gateway v2 domain name (%s): %s", d.Id(), err)
return fmt.Errorf("error updating API Gateway v2 domain name (%s): %w", d.Id(), err)
}

if err := waitForApiGatewayV2DomainNameAvailabilityOnUpdate(conn, d.Id(), d.Timeout(schema.TimeoutUpdate)); err != nil {
return fmt.Errorf("error waiting for API Gateway v2 domain name (%s) to become available: %s", d.Id(), err)
if _, err := waiter.DomainNameAvailable(conn, d.Id(), d.Timeout(schema.TimeoutUpdate)); err != nil {
return fmt.Errorf("error waiting for API Gateway v2 domain name (%s) to become available: %w", d.Id(), err)
}
}

if d.HasChange("tags") {
o, n := d.GetChange("tags")
if err := keyvaluetags.Apigatewayv2UpdateTags(conn, d.Get("arn").(string), o, n); err != nil {
return fmt.Errorf("error updating API Gateway v2 domain name (%s) tags: %s", d.Id(), err)
return fmt.Errorf("error updating API Gateway v2 domain name (%s) tags: %w", d.Id(), err)
}
}

Expand All @@ -222,56 +227,18 @@ func resourceAwsApiGatewayV2DomainNameDelete(d *schema.ResourceData, meta interf
_, err := conn.DeleteDomainName(&apigatewayv2.DeleteDomainNameInput{
DomainName: aws.String(d.Id()),
})
if isAWSErr(err, apigatewayv2.ErrCodeNotFoundException, "") {

if tfawserr.ErrCodeEquals(err, apigatewayv2.ErrCodeNotFoundException) {
return nil
}

if err != nil {
return fmt.Errorf("error deleting API Gateway v2 domain name (%s): %s", d.Id(), err)
return fmt.Errorf("error deleting API Gateway v2 domain name (%s): %w", d.Id(), err)
}

return nil
}

func apiGatewayV2DomainNameRefresh(conn *apigatewayv2.ApiGatewayV2, domainName string) resource.StateRefreshFunc {
return func() (interface{}, string, error) {
resp, err := conn.GetDomainName(&apigatewayv2.GetDomainNameInput{
DomainName: aws.String(domainName),
})
if isAWSErr(err, apigatewayv2.ErrCodeNotFoundException, "") {
return "", apiGatewayV2DomainNameStatusDeleted, nil
}
if err != nil {
return nil, "", err
}

if n := len(resp.DomainNameConfigurations); n != 1 {
return nil, "", fmt.Errorf("Found %d domain name configurations for %s, expected 1", n, domainName)
}

domainNameConfiguration := resp.DomainNameConfigurations[0]
if statusMessage := aws.StringValue(domainNameConfiguration.DomainNameStatusMessage); statusMessage != "" {
log.Printf("[INFO] Domain name (%s) status message: %s", domainName, statusMessage)
}

return resp, aws.StringValue(domainNameConfiguration.DomainNameStatus), nil
}
}

func waitForApiGatewayV2DomainNameAvailabilityOnUpdate(conn *apigatewayv2.ApiGatewayV2, domainName string, timeout time.Duration) error {
stateConf := &resource.StateChangeConf{
Pending: []string{apigatewayv2.DomainNameStatusUpdating},
Target: []string{apigatewayv2.DomainNameStatusAvailable},
Refresh: apiGatewayV2DomainNameRefresh(conn, domainName),
Timeout: timeout,
Delay: 10 * time.Second,
MinTimeout: 5 * time.Second,
}

_, err := stateConf.WaitForState()

return err
}

func expandApiGatewayV2DomainNameConfiguration(vDomainNameConfiguration []interface{}) []*apigatewayv2.DomainNameConfiguration {
if len(vDomainNameConfiguration) == 0 || vDomainNameConfiguration[0] == nil {
return nil
Expand Down
Loading

0 comments on commit 043fa9d

Please sign in to comment.