From 28cabd9db1550567897a001dae5dd10e0292a090 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Thu, 27 Aug 2020 18:19:55 -0400 Subject: [PATCH 1/4] r/aws_route53_resolver_query_log_config: New resource. --- .../service/route53resolver/finder/finder.go | 25 ++ .../service/route53resolver/waiter/status.go | 35 +++ .../service/route53resolver/waiter/waiter.go | 52 ++++ aws/provider.go | 1 + ...e_aws_route53_resolver_query_log_config.go | 166 +++++++++++ ..._route53_resolver_query_log_config_test.go | 269 ++++++++++++++++++ ...53_resolver_query_log_config.html.markdown | 52 ++++ 7 files changed, 600 insertions(+) create mode 100644 aws/internal/service/route53resolver/finder/finder.go create mode 100644 aws/internal/service/route53resolver/waiter/status.go create mode 100644 aws/internal/service/route53resolver/waiter/waiter.go create mode 100644 aws/resource_aws_route53_resolver_query_log_config.go create mode 100644 aws/resource_aws_route53_resolver_query_log_config_test.go create mode 100644 website/docs/r/route53_resolver_query_log_config.html.markdown diff --git a/aws/internal/service/route53resolver/finder/finder.go b/aws/internal/service/route53resolver/finder/finder.go new file mode 100644 index 000000000000..483bb0e7f07d --- /dev/null +++ b/aws/internal/service/route53resolver/finder/finder.go @@ -0,0 +1,25 @@ +package finder + +import ( + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/route53resolver" +) + +// ResolverQueryLogConfigByID returns the query logging configuration corresponding to the specified ID. +// Returns nil if no configuration is found. +func ResolverQueryLogConfigByID(conn *route53resolver.Route53Resolver, queryLogConfigID string) (*route53resolver.ResolverQueryLogConfig, error) { + input := &route53resolver.GetResolverQueryLogConfigInput{ + ResolverQueryLogConfigId: aws.String(queryLogConfigID), + } + + output, err := conn.GetResolverQueryLogConfig(input) + if err != nil { + return nil, err + } + + if output == nil { + return nil, nil + } + + return output.ResolverQueryLogConfig, nil +} diff --git a/aws/internal/service/route53resolver/waiter/status.go b/aws/internal/service/route53resolver/waiter/status.go new file mode 100644 index 000000000000..a1aee569b44b --- /dev/null +++ b/aws/internal/service/route53resolver/waiter/status.go @@ -0,0 +1,35 @@ +package waiter + +import ( + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/route53resolver" + "github.com/hashicorp/aws-sdk-go-base/tfawserr" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/route53resolver/finder" +) + +const ( + resolverQueryLogConfigStatusNotFound = "NotFound" + resolverQueryLogConfigStatusUnknown = "Unknown" +) + +// QueryLogConfigStatus fetches the QueryLogConfig and its Status +func QueryLogConfigStatus(conn *route53resolver.Route53Resolver, queryLogConfigID string) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + queryLogConfig, err := finder.ResolverQueryLogConfigByID(conn, queryLogConfigID) + + if tfawserr.ErrCodeEquals(err, route53resolver.ErrCodeResourceNotFoundException) { + return nil, resolverQueryLogConfigStatusNotFound, nil + } + + if err != nil { + return nil, resolverQueryLogConfigStatusUnknown, err + } + + if queryLogConfig == nil { + return nil, resolverQueryLogConfigStatusNotFound, nil + } + + return queryLogConfig, aws.StringValue(queryLogConfig.Status), nil + } +} diff --git a/aws/internal/service/route53resolver/waiter/waiter.go b/aws/internal/service/route53resolver/waiter/waiter.go new file mode 100644 index 000000000000..6faf5a941f54 --- /dev/null +++ b/aws/internal/service/route53resolver/waiter/waiter.go @@ -0,0 +1,52 @@ +package waiter + +import ( + "time" + + "github.com/aws/aws-sdk-go/service/route53resolver" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +const ( + // Maximum amount of time to wait for a QueryLogConfig to return CREATED + QueryLogConfigCreatedTimeout = 5 * time.Minute + + // Maximum amount of time to wait for a QueryLogConfig to be deleted + QueryLogConfigDeletedTimeout = 5 * time.Minute +) + +// QueryLogConfigCreated waits for a QueryLogConfig to return CREATED +func QueryLogConfigCreated(conn *route53resolver.Route53Resolver, queryLogConfigID string) (*route53resolver.ResolverQueryLogConfig, error) { + stateConf := &resource.StateChangeConf{ + Pending: []string{route53resolver.ResolverQueryLogConfigStatusCreating}, + Target: []string{route53resolver.ResolverQueryLogConfigStatusCreated}, + Refresh: QueryLogConfigStatus(conn, queryLogConfigID), + Timeout: QueryLogConfigCreatedTimeout, + } + + outputRaw, err := stateConf.WaitForState() + + if v, ok := outputRaw.(*route53resolver.ResolverQueryLogConfig); ok { + return v, err + } + + return nil, err +} + +// QueryLogConfigCreated waits for a QueryLogConfig to be deleted +func QueryLogConfigDeleted(conn *route53resolver.Route53Resolver, queryLogConfigID string) (*route53resolver.ResolverQueryLogConfig, error) { + stateConf := &resource.StateChangeConf{ + Pending: []string{route53resolver.ResolverQueryLogConfigStatusDeleting}, + Target: []string{}, + Refresh: QueryLogConfigStatus(conn, queryLogConfigID), + Timeout: QueryLogConfigDeletedTimeout, + } + + outputRaw, err := stateConf.WaitForState() + + if v, ok := outputRaw.(*route53resolver.ResolverQueryLogConfig); ok { + return v, err + } + + return nil, err +} diff --git a/aws/provider.go b/aws/provider.go index e8e439536f55..0213be3ebb46 100644 --- a/aws/provider.go +++ b/aws/provider.go @@ -777,6 +777,7 @@ func Provider() *schema.Provider { "aws_route53_zone": resourceAwsRoute53Zone(), "aws_route53_health_check": resourceAwsRoute53HealthCheck(), "aws_route53_resolver_endpoint": resourceAwsRoute53ResolverEndpoint(), + "aws_route53_resolver_query_log_config": resourceAwsRoute53ResolverQueryLogConfig(), "aws_route53_resolver_rule_association": resourceAwsRoute53ResolverRuleAssociation(), "aws_route53_resolver_rule": resourceAwsRoute53ResolverRule(), "aws_route": resourceAwsRoute(), diff --git a/aws/resource_aws_route53_resolver_query_log_config.go b/aws/resource_aws_route53_resolver_query_log_config.go new file mode 100644 index 000000000000..ac6bb338402c --- /dev/null +++ b/aws/resource_aws_route53_resolver_query_log_config.go @@ -0,0 +1,166 @@ +package aws + +import ( + "fmt" + "log" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/route53resolver" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/keyvaluetags" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/route53resolver/finder" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/route53resolver/waiter" +) + +func resourceAwsRoute53ResolverQueryLogConfig() *schema.Resource { + return &schema.Resource{ + Create: resourceAwsRoute53ResolverQueryLogConfigCreate, + Read: resourceAwsRoute53ResolverQueryLogConfigRead, + Update: resourceAwsRoute53ResolverQueryLogConfigUpdate, + Delete: resourceAwsRoute53ResolverQueryLogConfigDelete, + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, + + Schema: map[string]*schema.Schema{ + "arn": { + Type: schema.TypeString, + Computed: true, + }, + + "destination_arn": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validateArn, + }, + + "name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validateRoute53ResolverName, + }, + + "owner_id": { + Type: schema.TypeString, + Computed: true, + }, + + "share_status": { + Type: schema.TypeString, + Computed: true, + }, + + "tags": tagsSchema(), + }, + } +} + +func resourceAwsRoute53ResolverQueryLogConfigCreate(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).route53resolverconn + + input := &route53resolver.CreateResolverQueryLogConfigInput{ + CreatorRequestId: aws.String(resource.PrefixedUniqueId("tf-r53-resolver-query-log-config-")), + DestinationArn: aws.String(d.Get("destination_arn").(string)), + Name: aws.String(d.Get("name").(string)), + } + if v, ok := d.GetOk("tags"); ok && len(v.(map[string]interface{})) > 0 { + input.Tags = keyvaluetags.New(d.Get("tags").(map[string]interface{})).IgnoreAws().Route53resolverTags() + } + + log.Printf("[DEBUG] Creating Route53 Resolver Query Log Config: %s", input) + output, err := conn.CreateResolverQueryLogConfig(input) + + if err != nil { + return fmt.Errorf("error creating Route53 Resolver Query Log Config: %w", err) + } + + d.SetId(aws.StringValue(output.ResolverQueryLogConfig.Id)) + + _, err = waiter.QueryLogConfigCreated(conn, d.Id()) + + if err != nil { + return fmt.Errorf("error waiting for Route53 Resolver Query Log Config (%s) to become available: %w", d.Id(), err) + } + + return resourceAwsRoute53ResolverQueryLogConfigRead(d, meta) +} + +func resourceAwsRoute53ResolverQueryLogConfigRead(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).route53resolverconn + ignoreTagsConfig := meta.(*AWSClient).IgnoreTagsConfig + + queryLogConfig, err := finder.ResolverQueryLogConfigByID(conn, d.Id()) + + if isAWSErr(err, route53resolver.ErrCodeResourceNotFoundException, "") { + log.Printf("[WARN] Route53 Resolver Query Log Config (%s), removing from state", d.Id()) + d.SetId("") + return nil + } + + if err != nil { + return fmt.Errorf("error reading Route53 Resolver Query Log Config (%s): %w", d.Id(), err) + } + + if queryLogConfig == nil { + log.Printf("[WARN] Route53 Resolver Query Log Config (%s), removing from state", d.Id()) + d.SetId("") + return nil + } + + arn := aws.StringValue(queryLogConfig.Arn) + d.Set("arn", arn) + d.Set("destination_arn", queryLogConfig.DestinationArn) + d.Set("name", queryLogConfig.Name) + d.Set("owner_id", queryLogConfig.OwnerId) + d.Set("share_status", queryLogConfig.ShareStatus) + + tags, err := keyvaluetags.Route53resolverListTags(conn, arn) + if err != nil { + return fmt.Errorf("error listing tags for Route53 Resolver Query Log Config (%s): %w", arn, err) + } + + if err := d.Set("tags", tags.IgnoreAws().IgnoreConfig(ignoreTagsConfig).Map()); err != nil { + return fmt.Errorf("error setting tags: %w", err) + } + + return nil +} + +func resourceAwsRoute53ResolverQueryLogConfigUpdate(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).route53resolverconn + + if d.HasChange("tags") { + o, n := d.GetChange("tags") + if err := keyvaluetags.Route53resolverUpdateTags(conn, d.Get("arn").(string), o, n); err != nil { + return fmt.Errorf("error updating Route53 Resolver Query Log Config (%s) tags: %s", d.Get("arn").(string), err) + } + } + + return resourceAwsRoute53ResolverQueryLogConfigRead(d, meta) +} + +func resourceAwsRoute53ResolverQueryLogConfigDelete(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).route53resolverconn + + log.Printf("[DEBUG] Deleting Route53 Resolver Query Log Config (%s)", d.Id()) + _, err := conn.DeleteResolverQueryLogConfig(&route53resolver.DeleteResolverQueryLogConfigInput{ + ResolverQueryLogConfigId: aws.String(d.Id()), + }) + if isAWSErr(err, route53resolver.ErrCodeResourceNotFoundException, "") { + return nil + } + if err != nil { + return fmt.Errorf("error deleting Route53 Resolver Query Log Config (%s): %w", d.Id(), err) + } + + _, err = waiter.QueryLogConfigDeleted(conn, d.Id()) + + if err != nil { + return fmt.Errorf("error waiting for Route53 Resolver Query Log Config (%s) to be deleted: %w", d.Id(), err) + } + + return nil +} diff --git a/aws/resource_aws_route53_resolver_query_log_config_test.go b/aws/resource_aws_route53_resolver_query_log_config_test.go new file mode 100644 index 000000000000..9baced45f0cf --- /dev/null +++ b/aws/resource_aws_route53_resolver_query_log_config_test.go @@ -0,0 +1,269 @@ +package aws + +import ( + "fmt" + "log" + "testing" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/route53resolver" + "github.com/hashicorp/go-multierror" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/route53resolver/finder" +) + +func init() { + resource.AddTestSweepers("aws_route53_resolver_query_log_config", &resource.Sweeper{ + Name: "aws_route53_resolver_query_log_config", + F: testSweepRoute53ResolverQueryLogConfigs, + }) +} + +func testSweepRoute53ResolverQueryLogConfigs(region string) error { + client, err := sharedClientForRegion(region) + if err != nil { + return fmt.Errorf("error getting client: %s", err) + } + conn := client.(*AWSClient).route53resolverconn + var sweeperErrs *multierror.Error + + err = conn.ListResolverQueryLogConfigsPages(&route53resolver.ListResolverQueryLogConfigsInput{}, func(page *route53resolver.ListResolverQueryLogConfigsOutput, isLast bool) bool { + if page == nil { + return !isLast + } + + for _, queryLogConfig := range page.ResolverQueryLogConfigs { + id := aws.StringValue(queryLogConfig.Id) + + log.Printf("[INFO] Deleting Route53 Resolver Query Log Config: %s", id) + r := resourceAwsRoute53ResolverQueryLogConfig() + d := r.Data(nil) + d.SetId(id) + err := r.Delete(d, client) + + if err != nil { + log.Printf("[ERROR] %s", err) + sweeperErrs = multierror.Append(sweeperErrs, err) + continue + } + } + + return !isLast + }) + if testSweepSkipSweepError(err) { + log.Printf("[WARN] Skipping Route53 Resolver Query Log Configs sweep for %s: %s", region, err) + return sweeperErrs.ErrorOrNil() // In case we have completed some pages, but had errors + } + if err != nil { + sweeperErrs = multierror.Append(sweeperErrs, fmt.Errorf("error retrieving Route53 Resolver Query Log Configs: %w", err)) + } + + return sweeperErrs.ErrorOrNil() +} + +func TestAccAWSRoute53ResolverQueryLogConfig_basic(t *testing.T) { + var v route53resolver.ResolverQueryLogConfig + rName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_route53_resolver_query_log_config.test" + s3BucketResourceName := "aws_s3_bucket.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSRoute53Resolver(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckRoute53ResolverQueryLogConfigDestroy, + Steps: []resource.TestStep{ + { + Config: testAccRoute53ResolverQueryLogConfig(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckRoute53ResolverQueryLogConfigExists(resourceName, &v), + resource.TestCheckResourceAttrPair(resourceName, "destination_arn", s3BucketResourceName, "arn"), + resource.TestCheckResourceAttr(resourceName, "name", rName), + testAccCheckResourceAttrAccountID(resourceName, "owner_id"), + resource.TestCheckResourceAttr(resourceName, "share_status", "NOT_SHARED"), + resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccAWSRoute53ResolverQueryLogConfig_disappears(t *testing.T) { + var v route53resolver.ResolverQueryLogConfig + rName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_route53_resolver_query_log_config.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSRoute53Resolver(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckRoute53ResolverQueryLogConfigDestroy, + Steps: []resource.TestStep{ + { + Config: testAccRoute53ResolverQueryLogConfig(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckRoute53ResolverQueryLogConfigExists(resourceName, &v), + testAccCheckResourceDisappears(testAccProvider, resourceAwsRoute53ResolverQueryLogConfig(), resourceName), + ), + ExpectNonEmptyPlan: true, + }, + }, + }) +} + +func TestAccAWSRoute53ResolverQueryLogConfig_tags(t *testing.T) { + var v route53resolver.ResolverQueryLogConfig + rName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_route53_resolver_query_log_config.test" + cwLogGroupResourceName := "aws_cloudwatch_log_group.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSRoute53Resolver(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckRoute53ResolverQueryLogConfigDestroy, + Steps: []resource.TestStep{ + { + Config: testAccRoute53ResolverQueryLogConfigTags1(rName, "key1", "value1"), + Check: resource.ComposeTestCheckFunc( + testAccCheckRoute53ResolverQueryLogConfigExists(resourceName, &v), + resource.TestCheckResourceAttrPair(resourceName, "destination_arn", cwLogGroupResourceName, "arn"), + resource.TestCheckResourceAttr(resourceName, "name", rName), + testAccCheckResourceAttrAccountID(resourceName, "owner_id"), + resource.TestCheckResourceAttr(resourceName, "share_status", "NOT_SHARED"), + resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), + resource.TestCheckResourceAttr(resourceName, "tags.key1", "value1"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccRoute53ResolverQueryLogConfigTags2(rName, "key1", "value1updated", "key2", "value2"), + Check: resource.ComposeTestCheckFunc( + testAccCheckRoute53ResolverQueryLogConfigExists(resourceName, &v), + resource.TestCheckResourceAttrPair(resourceName, "destination_arn", cwLogGroupResourceName, "arn"), + resource.TestCheckResourceAttr(resourceName, "name", rName), + testAccCheckResourceAttrAccountID(resourceName, "owner_id"), + resource.TestCheckResourceAttr(resourceName, "share_status", "NOT_SHARED"), + resource.TestCheckResourceAttr(resourceName, "tags.%", "2"), + resource.TestCheckResourceAttr(resourceName, "tags.key1", "value1updated"), + resource.TestCheckResourceAttr(resourceName, "tags.key2", "value2"), + ), + }, + { + Config: testAccRoute53ResolverQueryLogConfigTags1(rName, "key2", "value2"), + Check: resource.ComposeTestCheckFunc( + testAccCheckRoute53ResolverQueryLogConfigExists(resourceName, &v), + resource.TestCheckResourceAttrPair(resourceName, "destination_arn", cwLogGroupResourceName, "arn"), + resource.TestCheckResourceAttr(resourceName, "name", rName), + testAccCheckResourceAttrAccountID(resourceName, "owner_id"), + resource.TestCheckResourceAttr(resourceName, "share_status", "NOT_SHARED"), + resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), + resource.TestCheckResourceAttr(resourceName, "tags.key2", "value2"), + ), + }, + }, + }) +} + +func testAccCheckRoute53ResolverQueryLogConfigDestroy(s *terraform.State) error { + conn := testAccProvider.Meta().(*AWSClient).route53resolverconn + + for _, rs := range s.RootModule().Resources { + if rs.Type != "aws_route53_resolver_query_log_config" { + continue + } + + // Try to find the resource + _, err := finder.ResolverQueryLogConfigByID(conn, rs.Primary.ID) + // Verify the error is what we want + if isAWSErr(err, route53resolver.ErrCodeResourceNotFoundException, "") { + continue + } + if err != nil { + return err + } + return fmt.Errorf("Route 53 Resolver Query Log Config still exists: %s", rs.Primary.ID) + } + + return nil +} + +func testAccCheckRoute53ResolverQueryLogConfigExists(n string, v *route53resolver.ResolverQueryLogConfig) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + if !ok { + return fmt.Errorf("Not found: %s", n) + } + + if rs.Primary.ID == "" { + return fmt.Errorf("No Route 53 Resolver Query Log Config ID is set") + } + + conn := testAccProvider.Meta().(*AWSClient).route53resolverconn + out, err := finder.ResolverQueryLogConfigByID(conn, rs.Primary.ID) + if err != nil { + return err + } + + *v = *out + + return nil + } +} + +func testAccRoute53ResolverQueryLogConfig(rName string) string { + return fmt.Sprintf(` +resource "aws_s3_bucket" "test" { + bucket = %[1]q + force_destroy = true +} + +resource "aws_route53_resolver_query_log_config" "test" { + name = %[1]q + destination_arn = aws_s3_bucket.test.arn +} +`, rName) +} + +func testAccRoute53ResolverQueryLogConfigTags1(rName, tagKey1, tagValue1 string) string { + return fmt.Sprintf(` +resource "aws_cloudwatch_log_group" "test" { + name = %[1]q +} + +resource "aws_route53_resolver_query_log_config" "test" { + name = %[1]q + destination_arn = aws_cloudwatch_log_group.test.arn + + tags = { + %[2]q = %[3]q + } +} +`, rName, tagKey1, tagValue1) +} + +func testAccRoute53ResolverQueryLogConfigTags2(rName, tagKey1, tagValue1, tagKey2, tagValue2 string) string { + return fmt.Sprintf(` +resource "aws_cloudwatch_log_group" "test" { + name = %[1]q +} + +resource "aws_route53_resolver_query_log_config" "test" { + name = %[1]q + destination_arn = aws_cloudwatch_log_group.test.arn + + tags = { + %[2]q = %[3]q + %[4]q = %[5]q + } +} +`, rName, tagKey1, tagValue1, tagKey2, tagValue2) +} diff --git a/website/docs/r/route53_resolver_query_log_config.html.markdown b/website/docs/r/route53_resolver_query_log_config.html.markdown new file mode 100644 index 000000000000..db1f4ba05998 --- /dev/null +++ b/website/docs/r/route53_resolver_query_log_config.html.markdown @@ -0,0 +1,52 @@ +--- +subcategory: "Route53 Resolver" +layout: "aws" +page_title: "AWS: aws_route53_resolver_query_log_config" +description: |- + Provides a Route 53 Resolver query logging configuration resource. +--- + +# Resource: aws_route53_resolver_query_log_config + +Provides a Route 53 Resolver query logging configuration resource. + +## Example Usage + +```hcl +resource "aws_route53_resolver_query_log_config" "example" { + name = "example" + destination_arn = aws_s3_bucket.example.arn + + tags = { + Environment = "Prod" + } +} +``` + +## Argument Reference + +The following arguments are supported: + +* `destination_arn` - (Required) The ARN of the resource that you want Route 53 Resolver to send query logs. +You can send query logs to an [S3 bucket](s3_bucket.html), a [CloudWatch Logs log group](cloudwatch_log_group.html), or a [Kinesis Data Firehose delivery stream](kinesis_firehose_delivery_stream.html). +* `name` - (Required) The name of the Route 53 Resolver query logging configuration. +* `tags` - (Optional) A map of tags to assign to the resource. + +## Attributes Reference + +In addition to all arguments above, the following attributes are exported: + +* `id` - The ID of the Route 53 Resolver query logging configuration. +* `arn` - The ARN (Amazon Resource Name) of the Route 53 Resolver query logging configuration. +* `owner_id` - The AWS account ID of the account that created the query logging configuration. +* `share_status` - An indication of whether the query logging configuration is shared with other AWS accounts, or was shared with the current account by another AWS account. +Sharing is configured through AWS Resource Access Manager (AWS RAM). +Values are `NOT_SHARED`, `SHARED_BY_ME` or `SHARED_WITH_ME` + +## Import + + Route 53 Resolver endpoints can be imported using the Route 53 Resolver query logging configuration ID, e.g. + +``` +$ terraform import aws_route53_resolver_query_log_config.example rqlc-92edc3b1838248bf +``` From 8262498e0781883ccc9c8aa3f9546fc2a34dc2d1 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Fri, 28 Aug 2020 16:20:58 -0400 Subject: [PATCH 2/4] r/aws_route53_resolver_query_log_config_association: New resource. --- .../service/route53resolver/finder/finder.go | 19 +++ .../service/route53resolver/waiter/status.go | 24 ++++ .../service/route53resolver/waiter/waiter.go | 42 ++++++ aws/provider.go | 1 + ...3_resolver_query_log_config_association.go | 114 +++++++++++++++ ...olver_query_log_config_association_test.go | 135 ++++++++++++++++++ ...query_log_config_association.html.markdown | 41 ++++++ 7 files changed, 376 insertions(+) create mode 100644 aws/resource_aws_route53_resolver_query_log_config_association.go create mode 100644 aws/resource_aws_route53_resolver_query_log_config_association_test.go create mode 100644 website/docs/r/route53_resolver_query_log_config_association.html.markdown diff --git a/aws/internal/service/route53resolver/finder/finder.go b/aws/internal/service/route53resolver/finder/finder.go index 483bb0e7f07d..ab246be9be36 100644 --- a/aws/internal/service/route53resolver/finder/finder.go +++ b/aws/internal/service/route53resolver/finder/finder.go @@ -5,6 +5,25 @@ import ( "github.com/aws/aws-sdk-go/service/route53resolver" ) +// ResolverQueryLogConfigAssociationByID returns the query logging configuration association corresponding to the specified ID. +// Returns nil if no configuration is found. +func ResolverQueryLogConfigAssociationByID(conn *route53resolver.Route53Resolver, queryLogConfigAssociationID string) (*route53resolver.ResolverQueryLogConfigAssociation, error) { + input := &route53resolver.GetResolverQueryLogConfigAssociationInput{ + ResolverQueryLogConfigAssociationId: aws.String(queryLogConfigAssociationID), + } + + output, err := conn.GetResolverQueryLogConfigAssociation(input) + if err != nil { + return nil, err + } + + if output == nil { + return nil, nil + } + + return output.ResolverQueryLogConfigAssociation, nil +} + // ResolverQueryLogConfigByID returns the query logging configuration corresponding to the specified ID. // Returns nil if no configuration is found. func ResolverQueryLogConfigByID(conn *route53resolver.Route53Resolver, queryLogConfigID string) (*route53resolver.ResolverQueryLogConfig, error) { diff --git a/aws/internal/service/route53resolver/waiter/status.go b/aws/internal/service/route53resolver/waiter/status.go index a1aee569b44b..7c8c91dd5e17 100644 --- a/aws/internal/service/route53resolver/waiter/status.go +++ b/aws/internal/service/route53resolver/waiter/status.go @@ -9,10 +9,34 @@ import ( ) const ( + resolverQueryLogConfigAssociationStatusNotFound = "NotFound" + resolverQueryLogConfigAssociationStatusUnknown = "Unknown" + resolverQueryLogConfigStatusNotFound = "NotFound" resolverQueryLogConfigStatusUnknown = "Unknown" ) +// QueryLogConfigAssociationStatus fetches the QueryLogConfigAssociation and its Status +func QueryLogConfigAssociationStatus(conn *route53resolver.Route53Resolver, queryLogConfigAssociationID string) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + queryLogConfigAssociation, err := finder.ResolverQueryLogConfigAssociationByID(conn, queryLogConfigAssociationID) + + if tfawserr.ErrCodeEquals(err, route53resolver.ErrCodeResourceNotFoundException) { + return nil, resolverQueryLogConfigAssociationStatusNotFound, nil + } + + if err != nil { + return nil, resolverQueryLogConfigAssociationStatusUnknown, err + } + + if queryLogConfigAssociation == nil { + return nil, resolverQueryLogConfigAssociationStatusNotFound, nil + } + + return queryLogConfigAssociation, aws.StringValue(queryLogConfigAssociation.Status), nil + } +} + // QueryLogConfigStatus fetches the QueryLogConfig and its Status func QueryLogConfigStatus(conn *route53resolver.Route53Resolver, queryLogConfigID string) resource.StateRefreshFunc { return func() (interface{}, string, error) { diff --git a/aws/internal/service/route53resolver/waiter/waiter.go b/aws/internal/service/route53resolver/waiter/waiter.go index 6faf5a941f54..744ad94bac1a 100644 --- a/aws/internal/service/route53resolver/waiter/waiter.go +++ b/aws/internal/service/route53resolver/waiter/waiter.go @@ -8,6 +8,12 @@ import ( ) const ( + // Maximum amount of time to wait for a QueryLogConfigAssociation to return ACTIVE + QueryLogConfigAssociationCreatedTimeout = 5 * time.Minute + + // Maximum amount of time to wait for a QueryLogConfigAssociation to be deleted + QueryLogConfigAssociationDeletedTimeout = 5 * time.Minute + // Maximum amount of time to wait for a QueryLogConfig to return CREATED QueryLogConfigCreatedTimeout = 5 * time.Minute @@ -15,6 +21,42 @@ const ( QueryLogConfigDeletedTimeout = 5 * time.Minute ) +// QueryLogConfigAssociationCreated waits for a QueryLogConfig to return ACTIVE +func QueryLogConfigAssociationCreated(conn *route53resolver.Route53Resolver, queryLogConfigAssociationID string) (*route53resolver.ResolverQueryLogConfigAssociation, error) { + stateConf := &resource.StateChangeConf{ + Pending: []string{route53resolver.ResolverQueryLogConfigAssociationStatusCreating}, + Target: []string{route53resolver.ResolverQueryLogConfigAssociationStatusActive}, + Refresh: QueryLogConfigAssociationStatus(conn, queryLogConfigAssociationID), + Timeout: QueryLogConfigAssociationCreatedTimeout, + } + + outputRaw, err := stateConf.WaitForState() + + if v, ok := outputRaw.(*route53resolver.ResolverQueryLogConfigAssociation); ok { + return v, err + } + + return nil, err +} + +// QueryLogConfigAssociationCreated waits for a QueryLogConfig to be deleted +func QueryLogConfigAssociationDeleted(conn *route53resolver.Route53Resolver, queryLogConfigAssociationID string) (*route53resolver.ResolverQueryLogConfigAssociation, error) { + stateConf := &resource.StateChangeConf{ + Pending: []string{route53resolver.ResolverQueryLogConfigAssociationStatusDeleting}, + Target: []string{}, + Refresh: QueryLogConfigAssociationStatus(conn, queryLogConfigAssociationID), + Timeout: QueryLogConfigAssociationDeletedTimeout, + } + + outputRaw, err := stateConf.WaitForState() + + if v, ok := outputRaw.(*route53resolver.ResolverQueryLogConfigAssociation); ok { + return v, err + } + + return nil, err +} + // QueryLogConfigCreated waits for a QueryLogConfig to return CREATED func QueryLogConfigCreated(conn *route53resolver.Route53Resolver, queryLogConfigID string) (*route53resolver.ResolverQueryLogConfig, error) { stateConf := &resource.StateChangeConf{ diff --git a/aws/provider.go b/aws/provider.go index 0213be3ebb46..865b9d2c0e38 100644 --- a/aws/provider.go +++ b/aws/provider.go @@ -778,6 +778,7 @@ func Provider() *schema.Provider { "aws_route53_health_check": resourceAwsRoute53HealthCheck(), "aws_route53_resolver_endpoint": resourceAwsRoute53ResolverEndpoint(), "aws_route53_resolver_query_log_config": resourceAwsRoute53ResolverQueryLogConfig(), + "aws_route53_resolver_query_log_config_association": resourceAwsRoute53ResolverQueryLogConfigAssociation(), "aws_route53_resolver_rule_association": resourceAwsRoute53ResolverRuleAssociation(), "aws_route53_resolver_rule": resourceAwsRoute53ResolverRule(), "aws_route": resourceAwsRoute(), diff --git a/aws/resource_aws_route53_resolver_query_log_config_association.go b/aws/resource_aws_route53_resolver_query_log_config_association.go new file mode 100644 index 000000000000..c07e4603e760 --- /dev/null +++ b/aws/resource_aws_route53_resolver_query_log_config_association.go @@ -0,0 +1,114 @@ +package aws + +import ( + "fmt" + "log" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/route53resolver" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/route53resolver/finder" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/route53resolver/waiter" +) + +func resourceAwsRoute53ResolverQueryLogConfigAssociation() *schema.Resource { + return &schema.Resource{ + Create: resourceAwsRoute53ResolverQueryLogConfigAssociationCreate, + Read: resourceAwsRoute53ResolverQueryLogConfigAssociationRead, + Delete: resourceAwsRoute53ResolverQueryLogConfigAssociationDelete, + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, + + Schema: map[string]*schema.Schema{ + "resolver_query_log_config_id": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + + "resource_id": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + }, + } +} + +func resourceAwsRoute53ResolverQueryLogConfigAssociationCreate(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).route53resolverconn + + input := &route53resolver.AssociateResolverQueryLogConfigInput{ + ResolverQueryLogConfigId: aws.String(d.Get("resolver_query_log_config_id").(string)), + ResourceId: aws.String(d.Get("resource_id").(string)), + } + + log.Printf("[DEBUG] Creating Route53 Resolver Query Log Config Association: %s", input) + output, err := conn.AssociateResolverQueryLogConfig(input) + + if err != nil { + return fmt.Errorf("error creating Route53 Resolver Query Log Config Association: %w", err) + } + + d.SetId(aws.StringValue(output.ResolverQueryLogConfigAssociation.Id)) + + _, err = waiter.QueryLogConfigAssociationCreated(conn, d.Id()) + + if err != nil { + return fmt.Errorf("error waiting for Route53 Resolver Query Log Config Association (%s) to become available: %w", d.Id(), err) + } + + return resourceAwsRoute53ResolverQueryLogConfigAssociationRead(d, meta) +} + +func resourceAwsRoute53ResolverQueryLogConfigAssociationRead(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).route53resolverconn + + queryLogConfigAssociation, err := finder.ResolverQueryLogConfigAssociationByID(conn, d.Id()) + + if isAWSErr(err, route53resolver.ErrCodeResourceNotFoundException, "") { + log.Printf("[WARN] Route53 Resolver Query Log Config Association (%s), removing from state", d.Id()) + d.SetId("") + return nil + } + + if err != nil { + return fmt.Errorf("error reading Route53 Resolver Query Log Config Association (%s): %w", d.Id(), err) + } + + if queryLogConfigAssociation == nil { + log.Printf("[WARN] Route53 Resolver Query Log Config Association (%s), removing from state", d.Id()) + d.SetId("") + return nil + } + + d.Set("resolver_query_log_config_id", queryLogConfigAssociation.ResolverQueryLogConfigId) + d.Set("resource_id", queryLogConfigAssociation.ResourceId) + + return nil +} + +func resourceAwsRoute53ResolverQueryLogConfigAssociationDelete(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).route53resolverconn + + log.Printf("[DEBUG] Deleting Route53 Resolver Query Log Config Association (%s)", d.Id()) + _, err := conn.DisassociateResolverQueryLogConfig(&route53resolver.DisassociateResolverQueryLogConfigInput{ + ResolverQueryLogConfigId: aws.String(d.Get("resolver_query_log_config_id").(string)), + ResourceId: aws.String(d.Get("resource_id").(string)), + }) + if isAWSErr(err, route53resolver.ErrCodeResourceNotFoundException, "") { + return nil + } + if err != nil { + return fmt.Errorf("error deleting Route53 Resolver Query Log Config Association (%s): %w", d.Id(), err) + } + + _, err = waiter.QueryLogConfigAssociationDeleted(conn, d.Id()) + + if err != nil { + return fmt.Errorf("error waiting for Route53 Resolver Query Log Config Association (%s) to be deleted: %w", d.Id(), err) + } + + return nil +} diff --git a/aws/resource_aws_route53_resolver_query_log_config_association_test.go b/aws/resource_aws_route53_resolver_query_log_config_association_test.go new file mode 100644 index 000000000000..39f211dc1ca2 --- /dev/null +++ b/aws/resource_aws_route53_resolver_query_log_config_association_test.go @@ -0,0 +1,135 @@ +package aws + +import ( + "fmt" + "testing" + + "github.com/aws/aws-sdk-go/service/route53resolver" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/route53resolver/finder" +) + +func TestAccAWSRoute53ResolverQueryLogConfigAssociation_basic(t *testing.T) { + var v route53resolver.ResolverQueryLogConfigAssociation + rName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_route53_resolver_query_log_config_association.test" + queryLogConfigResourceName := "aws_route53_resolver_query_log_config.test" + vpcResourceName := "aws_vpc.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSRoute53Resolver(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckRoute53ResolverQueryLogConfigAssociationDestroy, + Steps: []resource.TestStep{ + { + Config: testAccRoute53ResolverQueryLogConfigAssociationConfig(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckRoute53ResolverQueryLogConfigAssociationExists(resourceName, &v), + resource.TestCheckResourceAttrPair(resourceName, "resolver_query_log_config_id", queryLogConfigResourceName, "id"), + resource.TestCheckResourceAttrPair(resourceName, "resource_id", vpcResourceName, "id"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccAWSRoute53ResolverQueryLogConfigAssociation_disappears(t *testing.T) { + var v route53resolver.ResolverQueryLogConfigAssociation + rName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_route53_resolver_query_log_config_association.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSRoute53Resolver(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckRoute53ResolverQueryLogConfigAssociationDestroy, + Steps: []resource.TestStep{ + { + Config: testAccRoute53ResolverQueryLogConfigAssociationConfig(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckRoute53ResolverQueryLogConfigAssociationExists(resourceName, &v), + testAccCheckResourceDisappears(testAccProvider, resourceAwsRoute53ResolverQueryLogConfigAssociation(), resourceName), + ), + ExpectNonEmptyPlan: true, + }, + }, + }) +} + +func testAccCheckRoute53ResolverQueryLogConfigAssociationDestroy(s *terraform.State) error { + conn := testAccProvider.Meta().(*AWSClient).route53resolverconn + + for _, rs := range s.RootModule().Resources { + if rs.Type != "aws_route53_resolver_query_log_config_association" { + continue + } + + // Try to find the resource + _, err := finder.ResolverQueryLogConfigAssociationByID(conn, rs.Primary.ID) + // Verify the error is what we want + if isAWSErr(err, route53resolver.ErrCodeResourceNotFoundException, "") { + continue + } + if err != nil { + return err + } + return fmt.Errorf("Route 53 Resolver Query Log Config Association still exists: %s", rs.Primary.ID) + } + + return nil +} + +func testAccCheckRoute53ResolverQueryLogConfigAssociationExists(n string, v *route53resolver.ResolverQueryLogConfigAssociation) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + if !ok { + return fmt.Errorf("Not found: %s", n) + } + + if rs.Primary.ID == "" { + return fmt.Errorf("No Route 53 Resolver Query Log Config Association ID is set") + } + + conn := testAccProvider.Meta().(*AWSClient).route53resolverconn + out, err := finder.ResolverQueryLogConfigAssociationByID(conn, rs.Primary.ID) + if err != nil { + return err + } + + *v = *out + + return nil + } +} + +func testAccRoute53ResolverQueryLogConfigAssociationConfig(rName string) string { + return fmt.Sprintf(` +resource "aws_cloudwatch_log_group" "test" { + name = %[1]q +} + +resource "aws_vpc" "test" { + cidr_block = "10.1.0.0/16" + + tags = { + Name = %[1]q + } +} + +resource "aws_route53_resolver_query_log_config" "test" { + name = %[1]q + destination_arn = aws_cloudwatch_log_group.test.arn +} + +resource "aws_route53_resolver_query_log_config_association" "test" { + resolver_query_log_config_id = aws_route53_resolver_query_log_config.test.id + resource_id = aws_vpc.test.id +} +`, rName) +} diff --git a/website/docs/r/route53_resolver_query_log_config_association.html.markdown b/website/docs/r/route53_resolver_query_log_config_association.html.markdown new file mode 100644 index 000000000000..de8b338bc5e2 --- /dev/null +++ b/website/docs/r/route53_resolver_query_log_config_association.html.markdown @@ -0,0 +1,41 @@ +--- +subcategory: "Route53 Resolver" +layout: "aws" +page_title: "AWS: aws_route53_resolver_query_log_config_association" +description: |- + Provides a Route 53 Resolver query logging configuration association resource. +--- + +# Resource: aws_route53_resolver_query_log_config_association + +Provides a Route 53 Resolver query logging configuration association resource. + +## Example Usage + +```hcl +resource "aws_route53_resolver_query_log_config_association" "example" { + resolver_query_log_config_id = aws_route53_resolver_query_log_config.example.id + resource_id = aws_vpc.example.id +} +``` + +## Argument Reference + +The following arguments are supported: + +* `resolver_query_log_config_id` - (Required) The ID of the [Route 53 Resolver query logging configuration](route53_resolver_query_log_config.html) that you want to associate a VPC with. +* `resource_id` - (Required) The ID of a VPC that you want this query logging configuration to log queries for. + +## Attributes Reference + +In addition to all arguments above, the following attributes are exported: + +* `id` -The ID of the Route 53 Resolver query logging configuration association. + +## Import + + Route 53 Resolver query logging configuration associations can be imported using the Route 53 Resolver query logging configuration association ID, e.g. + +``` +$ terraform import aws_route53_resolver_query_log_config_association.example rqlca-b320624fef3c4d70 +``` From 858240136d62e4a156e13ebb2dcb5e6328790957 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Sat, 29 Aug 2020 18:38:14 -0400 Subject: [PATCH 3/4] r/aws_route53_resolver_query_log_config_association: Add acceptance test sweeper. --- ...olver_query_log_config_association_test.go | 52 +++++++++++++++++++ ..._route53_resolver_query_log_config_test.go | 3 ++ 2 files changed, 55 insertions(+) diff --git a/aws/resource_aws_route53_resolver_query_log_config_association_test.go b/aws/resource_aws_route53_resolver_query_log_config_association_test.go index 39f211dc1ca2..d864428b689d 100644 --- a/aws/resource_aws_route53_resolver_query_log_config_association_test.go +++ b/aws/resource_aws_route53_resolver_query_log_config_association_test.go @@ -2,15 +2,67 @@ package aws import ( "fmt" + "log" "testing" + "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/route53resolver" + "github.com/hashicorp/go-multierror" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/route53resolver/finder" ) +func init() { + resource.AddTestSweepers("aws_route53_resolver_query_log_config_association", &resource.Sweeper{ + Name: "aws_route53_resolver_query_log_config_association", + F: testSweepRoute53ResolverQueryLogConfigAssociations, + }) +} + +func testSweepRoute53ResolverQueryLogConfigAssociations(region string) error { + client, err := sharedClientForRegion(region) + if err != nil { + return fmt.Errorf("error getting client: %s", err) + } + conn := client.(*AWSClient).route53resolverconn + var sweeperErrs *multierror.Error + + err = conn.ListResolverQueryLogConfigAssociationsPages(&route53resolver.ListResolverQueryLogConfigAssociationsInput{}, func(page *route53resolver.ListResolverQueryLogConfigAssociationsOutput, isLast bool) bool { + if page == nil { + return !isLast + } + + for _, queryLogConfigAssociation := range page.ResolverQueryLogConfigAssociations { + id := aws.StringValue(queryLogConfigAssociation.Id) + + log.Printf("[INFO] Deleting Route53 Resolver Query Log Config Association: %s", id) + r := resourceAwsRoute53ResolverQueryLogConfigAssociation() + d := r.Data(nil) + d.SetId(id) + err := r.Delete(d, client) + + if err != nil { + log.Printf("[ERROR] %s", err) + sweeperErrs = multierror.Append(sweeperErrs, err) + continue + } + } + + return !isLast + }) + if testSweepSkipSweepError(err) { + log.Printf("[WARN] Skipping Route53 Resolver Query Log Config Associations sweep for %s: %s", region, err) + return sweeperErrs.ErrorOrNil() // In case we have completed some pages, but had errors + } + if err != nil { + sweeperErrs = multierror.Append(sweeperErrs, fmt.Errorf("error retrieving Route53 Resolver Query Log Config Associations: %w", err)) + } + + return sweeperErrs.ErrorOrNil() +} + func TestAccAWSRoute53ResolverQueryLogConfigAssociation_basic(t *testing.T) { var v route53resolver.ResolverQueryLogConfigAssociation rName := acctest.RandomWithPrefix("tf-acc-test") diff --git a/aws/resource_aws_route53_resolver_query_log_config_test.go b/aws/resource_aws_route53_resolver_query_log_config_test.go index 9baced45f0cf..cf44d3de93d7 100644 --- a/aws/resource_aws_route53_resolver_query_log_config_test.go +++ b/aws/resource_aws_route53_resolver_query_log_config_test.go @@ -18,6 +18,9 @@ func init() { resource.AddTestSweepers("aws_route53_resolver_query_log_config", &resource.Sweeper{ Name: "aws_route53_resolver_query_log_config", F: testSweepRoute53ResolverQueryLogConfigs, + Dependencies: []string{ + "aws_route53_resolver_query_log_config_association", + }, }) } From 29bb5d0006d1318af45ebef567d2aac12f9f13a0 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 2 Sep 2020 14:12:07 -0400 Subject: [PATCH 4/4] Tweak log message when resource not found. --- ...rce_aws_route53_resolver_query_log_config_association.go | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/aws/resource_aws_route53_resolver_query_log_config_association.go b/aws/resource_aws_route53_resolver_query_log_config_association.go index c07e4603e760..8d16c8252144 100644 --- a/aws/resource_aws_route53_resolver_query_log_config_association.go +++ b/aws/resource_aws_route53_resolver_query_log_config_association.go @@ -68,7 +68,7 @@ func resourceAwsRoute53ResolverQueryLogConfigAssociationRead(d *schema.ResourceD queryLogConfigAssociation, err := finder.ResolverQueryLogConfigAssociationByID(conn, d.Id()) if isAWSErr(err, route53resolver.ErrCodeResourceNotFoundException, "") { - log.Printf("[WARN] Route53 Resolver Query Log Config Association (%s), removing from state", d.Id()) + log.Printf("[WARN] Route53 Resolver Query Log Config Association (%s) not found, removing from state", d.Id()) d.SetId("") return nil } @@ -78,7 +78,7 @@ func resourceAwsRoute53ResolverQueryLogConfigAssociationRead(d *schema.ResourceD } if queryLogConfigAssociation == nil { - log.Printf("[WARN] Route53 Resolver Query Log Config Association (%s), removing from state", d.Id()) + log.Printf("[WARN] Route53 Resolver Query Log Config Association (%s) not found, removing from state", d.Id()) d.SetId("") return nil } @@ -97,9 +97,11 @@ func resourceAwsRoute53ResolverQueryLogConfigAssociationDelete(d *schema.Resourc ResolverQueryLogConfigId: aws.String(d.Get("resolver_query_log_config_id").(string)), ResourceId: aws.String(d.Get("resource_id").(string)), }) + if isAWSErr(err, route53resolver.ErrCodeResourceNotFoundException, "") { return nil } + if err != nil { return fmt.Errorf("error deleting Route53 Resolver Query Log Config Association (%s): %w", d.Id(), err) }