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

r/aws_apigatewayv2_domain_name: Always send domain name configuration on update of mutual TLS configuration #18351

Merged
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
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