From 0ad205f20b8c5d46ebbdf5e72d02d6eb4af0d4e7 Mon Sep 17 00:00:00 2001 From: Ben de Haan <53901866+bendehaan@users.noreply.github.com> Date: Fri, 10 Dec 2021 23:40:36 +0100 Subject: [PATCH 1/8] Create scaffold for ECR registry scanning configuration --- internal/provider/provider.go | 13 +- .../ecr/registry_scanning_configuration.go | 199 ++++++++++++++++++ .../registry_scanning_configuration_test.go | 148 +++++++++++++ ...istry_scanning_configuration.html.markdown | 61 ++++++ 4 files changed, 415 insertions(+), 6 deletions(-) create mode 100644 internal/service/ecr/registry_scanning_configuration.go create mode 100644 internal/service/ecr/registry_scanning_configuration_test.go create mode 100644 website/docs/r/ecr_registry_scanning_configuration.html.markdown diff --git a/internal/provider/provider.go b/internal/provider/provider.go index 67a914c0cd6..646c1cc115e 100644 --- a/internal/provider/provider.go +++ b/internal/provider/provider.go @@ -1125,12 +1125,13 @@ func Provider() *schema.Provider { "aws_vpn_gateway_attachment": ec2.ResourceVPNGatewayAttachment(), "aws_vpn_gateway_route_propagation": ec2.ResourceVPNGatewayRoutePropagation(), - "aws_ecr_lifecycle_policy": ecr.ResourceLifecyclePolicy(), - "aws_ecr_pull_through_cache_rule": ecr.ResourcePullThroughCacheRule(), - "aws_ecr_registry_policy": ecr.ResourceRegistryPolicy(), - "aws_ecr_replication_configuration": ecr.ResourceReplicationConfiguration(), - "aws_ecr_repository": ecr.ResourceRepository(), - "aws_ecr_repository_policy": ecr.ResourceRepositoryPolicy(), + "aws_ecr_lifecycle_policy": ecr.ResourceLifecyclePolicy(), + "aws_ecr_pull_through_cache_rule": ecr.ResourcePullThroughCacheRule(), + "aws_ecr_registry_policy": ecr.ResourceRegistryPolicy(), + "aws_ecr_registry_scanning_configuration": ecr.ResourceRegistryScanningConfiguration(), + "aws_ecr_replication_configuration": ecr.ResourceReplicationConfiguration(), + "aws_ecr_repository": ecr.ResourceRepository(), + "aws_ecr_repository_policy": ecr.ResourceRepositoryPolicy(), "aws_ecrpublic_repository": ecrpublic.ResourceRepository(), diff --git a/internal/service/ecr/registry_scanning_configuration.go b/internal/service/ecr/registry_scanning_configuration.go new file mode 100644 index 00000000000..8d586285cbc --- /dev/null +++ b/internal/service/ecr/registry_scanning_configuration.go @@ -0,0 +1,199 @@ +package ecr + +import ( + "fmt" + "log" + "regexp" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/ecr" + "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" +) + +func ResourceRegistryScanningConfiguration() *schema.Resource { + return &schema.Resource{ + Create: resourceRegistryScanningConfigurationPut, + Read: resourceRegistryScanningConfigurationRead, + Update: resourceRegistryScanningConfigurationPut, + Delete: resourceRegistryScanningConfigurationDelete, + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, + + Schema: map[string]*schema.Schema{ + "scan_type": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice(ecr.ScanType_Values(), false), + }, + "rule": { + Type: schema.TypeSet, + Optional: true, + MinItems: 0, + MaxItems: 100, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "repository_filter": { + Type: schema.TypeSet, + MinItems: 1, + Required: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "filter": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.All( + validation.StringLenBetween(1, 256), + validation.StringMatch(regexp.MustCompile(`^[a-z0-9*](?:[._\-/a-z0-9*]?[a-z0-9*]+)*$`), "must contain only lowercase alphanumeric, dot, underscore, hyphen, wildcard, and colon characters"), + ), + }, + "filter_type": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice(ecr.ScanningRepositoryFilterType_Values(), false), + }, + }, + }, + }, + "scan_frequency": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice(ecr.ScanFrequency_Values(), false), + }, + }, + }, + }, + }, + } +} + +func resourceRegistryScanningConfigurationPut(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*conns.AWSClient).ECRConn + + input := ecr.PutRegistryScanningConfigurationInput{ + ScanType: aws.String(d.Get("scan_type").(string)), + Rules: expandEcrScanningRegistryRules(d.Get("rule").(*schema.Set).List()), + } + + _, err := conn.PutRegistryScanningConfiguration(&input) + if err != nil { + return fmt.Errorf("Error creating ECR Scanning Configuration: %w", err) + } + + d.SetId(meta.(*conns.AWSClient).AccountID) + + return resourceRegistryScanningConfigurationRead(d, meta) +} + +func resourceRegistryScanningConfigurationRead(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*conns.AWSClient).ECRConn + + log.Printf("[DEBUG] Reading registry scanning configuration %s", d.Id()) + out, err := conn.GetRegistryScanningConfiguration(&ecr.GetRegistryScanningConfigurationInput{}) + + if err != nil { + return fmt.Errorf("Error reading registry scanning configuration: %s", err) + } + + d.Set("scan_type", out.ScanningConfiguration.ScanType) + d.Set("rule", flattenEcrScanningConfigurationRules(out.ScanningConfiguration.Rules)) + + return nil +} + +func resourceRegistryScanningConfigurationDelete(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*conns.AWSClient).ECRConn + + _, err := conn.PutRegistryScanningConfiguration(&ecr.PutRegistryScanningConfigurationInput{ + Rules: nil, + ScanType: aws.String(ecr.ScanTypeBasic), + }) + + if err != nil { + return fmt.Errorf("Error deleting registry scanning configuration: %s", err) + } + + return nil +} + +// Helper functions + +func expandEcrScanningRegistryRules(l []interface{}) []*ecr.RegistryScanningRule { + if len(l) == 0 || l[0] == nil { + return nil + } + + rules := make([]*ecr.RegistryScanningRule, 0) + + for _, rule := range l { + if rule == nil { + continue + } + rules = append(rules, expandEcrScanningRegistryRule(rule.(map[string]interface{}))) + } + + return rules +} + +func expandEcrScanningRegistryRule(m map[string]interface{}) *ecr.RegistryScanningRule { + if m == nil { + return nil + } + + rule := &ecr.RegistryScanningRule{ + RepositoryFilters: expandEcrScanningRegistryRuleRepositoryFilters(m["repository_filter"].(*schema.Set).List()), + ScanFrequency: aws.String(m["scan_frequency"].(string)), + } + + return rule +} + +func expandEcrScanningRegistryRuleRepositoryFilters(l []interface{}) []*ecr.ScanningRepositoryFilter { + if len(l) == 0 || l[0] == nil { + return nil + } + + filters := make([]*ecr.ScanningRepositoryFilter, 0) + + for _, f := range l { + if f == nil { + continue + } + m := f.(map[string]interface{}) + filters = append(filters, &ecr.ScanningRepositoryFilter{ + Filter: aws.String(m["filter"].(string)), + FilterType: aws.String(m["filter_type"].(string)), + }) + } + + return filters +} + +func flattenEcrScanningConfigurationRules(r []*ecr.RegistryScanningRule) interface{} { + out := make([]map[string]interface{}, len(r)) + for i, rule := range r { + m := make(map[string]interface{}) + m["scan_frequency"] = aws.StringValue(rule.ScanFrequency) + m["repository_filter"] = flattenEcrScanningConfigurationFilters(rule.RepositoryFilters) + out[i] = m + } + return out +} + +func flattenEcrScanningConfigurationFilters(l []*ecr.ScanningRepositoryFilter) []interface{} { + if len(l) == 0 { + return nil + } + + out := make([]interface{}, len(l)) + for i, filter := range l { + out[i] = map[string]interface{}{ + "filter": aws.StringValue(filter.Filter), + "filter_type": aws.StringValue(filter.FilterType), + } + } + + return out +} diff --git a/internal/service/ecr/registry_scanning_configuration_test.go b/internal/service/ecr/registry_scanning_configuration_test.go new file mode 100644 index 00000000000..4d881bf534e --- /dev/null +++ b/internal/service/ecr/registry_scanning_configuration_test.go @@ -0,0 +1,148 @@ +package ecr_test + +import ( + "fmt" + "testing" + + "github.com/aws/aws-sdk-go/service/ecr" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" + "github.com/hashicorp/terraform-provider-aws/internal/acctest" + "github.com/hashicorp/terraform-provider-aws/internal/conns" +) + +func TestAccECRScanningConfiguration_serial(t *testing.T) { + testFuncs := map[string]func(t *testing.T){ + "basic": testAccRegistryScanningConfiguration_basic, + // "disappears": testAccRegistryPolicy_disappears, + } + + for name, testFunc := range testFuncs { + testFunc := testFunc + + t.Run(name, func(t *testing.T) { + testFunc(t) + }) + } +} + +func testAccRegistryScanningConfiguration_basic(t *testing.T) { + var v ecr.GetRegistryScanningConfigurationOutput + resourceName := "aws_ecr_registry_scanning_configuration.test" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(t) }, + ErrorCheck: acctest.ErrorCheck(t, ecr.EndpointsID), + Providers: acctest.Providers, + CheckDestroy: testAccRegistryScanningConfigurationDestroy, + Steps: []resource.TestStep{ + { + Config: testAccRegistryScanningConfiguration(), + Check: resource.ComposeTestCheckFunc( + testAccRegistryScanningConfigurationExists(resourceName, &v), + resource.TestCheckResourceAttr(resourceName, "scan_type", "ENHANCED"), + resource.TestCheckResourceAttr(resourceName, "rule.#", "1"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccRegistryPolicyUpdated(), + Check: resource.ComposeTestCheckFunc( + testAccRegistryScanningConfigurationExists(resourceName, &v), + resource.TestCheckResourceAttr(resourceName, "scan_type", "BASIC"), + resource.TestCheckResourceAttr(resourceName, "rule.#", "0"), + ), + }, + }, + }) +} + +// func testAccRegistryScanningConfiguration_disappears(t *testing.T) { +// var v ecr.GetRegistryPolicyOutput +// resourceName := "aws_ecr_registry_policy.test" + +// resource.Test(t, resource.TestCase{ +// PreCheck: func() { acctest.PreCheck(t) }, +// ErrorCheck: acctest.ErrorCheck(t, ecr.EndpointsID), +// Providers: acctest.Providers, +// CheckDestroy: testAccCheckRegistryPolicyDestroy, +// Steps: []resource.TestStep{ +// { +// Config: testAccRegistryPolicy(), +// Check: resource.ComposeTestCheckFunc( +// testAccCheckRegistryPolicyExists(resourceName, &v), +// acctest.CheckResourceDisappears(acctest.Provider, tfecr.ResourceRegistryPolicy(), resourceName), +// ), +// ExpectNonEmptyPlan: true, +// }, +// }, +// }) +// } + +func testAccRegistryScanningConfigurationDestroy(s *terraform.State) error { + conn := acctest.Provider.Meta().(*conns.AWSClient).ECRConn + + for _, rs := range s.RootModule().Resources { + if rs.Type != "aws_ecr_registry_policy" { + continue + } + + _, err := conn.GetRegistryScanningConfiguration(&ecr.GetRegistryScanningConfigurationInput{}) + if err != nil { + return err + } + } + + return nil +} + +func testAccRegistryScanningConfigurationExists(name string, res *ecr.GetRegistryScanningConfigurationOutput) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[name] + if !ok { + return fmt.Errorf("Not found: %s", name) + } + + if rs.Primary.ID == "" { + return fmt.Errorf("No ECR registry policy ID is set") + } + + conn := acctest.Provider.Meta().(*conns.AWSClient).ECRConn + + output, err := conn.GetRegistryScanningConfiguration(&ecr.GetRegistryScanningConfigurationInput{}) + if err != nil { + return err + } + + *res = *output + + return nil + } +} + +func testAccRegistryScanningConfiguration() string { + return ` +resource "aws_ecr_registry_scanning_configuration" "test" { + scan_type = "ENHANCED" + rule { + scan_frequency = "CONTINUOUS_SCAN" + repository_filter { + filter = "example" + filter_type = "WILDCARD" + } + } +} +` +} + +func testAccRegistryScanningConfigurationUpdated() string { + return ` +resource "aws_ecr_registry_scanning_configuration" "test" { + scan_type = "BASIC" +} +` +} diff --git a/website/docs/r/ecr_registry_scanning_configuration.html.markdown b/website/docs/r/ecr_registry_scanning_configuration.html.markdown new file mode 100644 index 00000000000..c6a1b75479b --- /dev/null +++ b/website/docs/r/ecr_registry_scanning_configuration.html.markdown @@ -0,0 +1,61 @@ +--- +subcategory: "ECR" +layout: "aws" +page_title: "AWS: aws_ecr_registry_scanning_configuration" +description: |- + Provides an Elastic Container Registry Repository. +--- + +# Resource: aws_ecr_registry_scanning_configuration + +Provides an Elastic Container Registry Scanning Configuration. Can't be deleted. + +## Example Usage + +```terraform +resource "aws_ecr_registry_scanning_configuration" "configuration" { + scan_type = "ENHANCED" + + rule { + scan_frequency = "CONTINUOUS_SCAN" + repository_filter { + filter = "example" + filter_type = "WILDCARD" + } + } +} +``` + +## Argument Reference + +The following arguments are supported: + +- `scan_type` - (Required) the scanning type to set for the registry. Can be either `ENHANCED` or `BASIC`. +- `rule` - (Optional) One or multiple blocks specifying scanning rules to determine which repository filters are used and at what frequency scanning will occur. See [below for schema](#rule). + +### rule + +- `repository_filter` - (Required) One or more repository filter blocks, containing a `filter` (required string filtering repositories, see pattern regex [here](https://docs.aws.amazon.com/AmazonECR/latest/APIReference/API_ScanningRepositoryFilter.html)) and a `filter_type` (required string, currently only `WILDCARD` is supported). +- `scan_frequency` - (Required) The frequency that scans are performed at for a private registry. Can be `SCAN_ON_PUSH`, `CONTINUOUS_SCAN`, or `MANUAL`. + +## Attributes Reference + +In addition to all arguments above, the following attributes are exported: + +- `registry_id` - The registry ID where the repository was created. +- `scanning_configuration` - The scanning configuration for the registry. + +## Timeouts + +`aws_ecr_registry_scanning_configuration` provides the following [Timeouts](https://www.terraform.io/docs/configuration/blocks/resources/syntax.html#operation-timeouts) +configuration options: + +- `delete` - (Default `20 minutes`) How long to wait for a scanning configuration to be deleted. + +## Import + +ECR Scanning Configurations can be imported using the `registry_id`, e.g., + +``` +$ terraform import aws_ecr_registry_scanning_configuration 012345678901 +``` From 5a5d6a21137fdce2484339531875b07f65b0984c Mon Sep 17 00:00:00 2001 From: Ben de Haan <53901866+bendehaan@users.noreply.github.com> Date: Sat, 11 Dec 2021 00:09:58 +0100 Subject: [PATCH 2/8] Change update reference --- .../registry_scanning_configuration_test.go | 24 +------------------ 1 file changed, 1 insertion(+), 23 deletions(-) diff --git a/internal/service/ecr/registry_scanning_configuration_test.go b/internal/service/ecr/registry_scanning_configuration_test.go index 4d881bf534e..e128d938c83 100644 --- a/internal/service/ecr/registry_scanning_configuration_test.go +++ b/internal/service/ecr/registry_scanning_configuration_test.go @@ -50,7 +50,7 @@ func testAccRegistryScanningConfiguration_basic(t *testing.T) { ImportStateVerify: true, }, { - Config: testAccRegistryPolicyUpdated(), + Config: testAccRegistryScanningConfigurationUpdated(), Check: resource.ComposeTestCheckFunc( testAccRegistryScanningConfigurationExists(resourceName, &v), resource.TestCheckResourceAttr(resourceName, "scan_type", "BASIC"), @@ -61,28 +61,6 @@ func testAccRegistryScanningConfiguration_basic(t *testing.T) { }) } -// func testAccRegistryScanningConfiguration_disappears(t *testing.T) { -// var v ecr.GetRegistryPolicyOutput -// resourceName := "aws_ecr_registry_policy.test" - -// resource.Test(t, resource.TestCase{ -// PreCheck: func() { acctest.PreCheck(t) }, -// ErrorCheck: acctest.ErrorCheck(t, ecr.EndpointsID), -// Providers: acctest.Providers, -// CheckDestroy: testAccCheckRegistryPolicyDestroy, -// Steps: []resource.TestStep{ -// { -// Config: testAccRegistryPolicy(), -// Check: resource.ComposeTestCheckFunc( -// testAccCheckRegistryPolicyExists(resourceName, &v), -// acctest.CheckResourceDisappears(acctest.Provider, tfecr.ResourceRegistryPolicy(), resourceName), -// ), -// ExpectNonEmptyPlan: true, -// }, -// }, -// }) -// } - func testAccRegistryScanningConfigurationDestroy(s *terraform.State) error { conn := acctest.Provider.Meta().(*conns.AWSClient).ECRConn From 4087aeac3493d02550b171ede4150ea269719a65 Mon Sep 17 00:00:00 2001 From: Ben de Haan <53901866+bendehaan@users.noreply.github.com> Date: Sat, 11 Dec 2021 00:15:40 +0100 Subject: [PATCH 3/8] Change test to something that can be updated rapidly --- .../registry_scanning_configuration_test.go | 20 ++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/internal/service/ecr/registry_scanning_configuration_test.go b/internal/service/ecr/registry_scanning_configuration_test.go index e128d938c83..620a7014cce 100644 --- a/internal/service/ecr/registry_scanning_configuration_test.go +++ b/internal/service/ecr/registry_scanning_configuration_test.go @@ -53,8 +53,8 @@ func testAccRegistryScanningConfiguration_basic(t *testing.T) { Config: testAccRegistryScanningConfigurationUpdated(), Check: resource.ComposeTestCheckFunc( testAccRegistryScanningConfigurationExists(resourceName, &v), - resource.TestCheckResourceAttr(resourceName, "scan_type", "BASIC"), - resource.TestCheckResourceAttr(resourceName, "rule.#", "0"), + resource.TestCheckResourceAttr(resourceName, "scan_type", "ENHANCED"), + resource.TestCheckResourceAttr(resourceName, "rule.#", "2"), ), }, }, @@ -120,7 +120,21 @@ resource "aws_ecr_registry_scanning_configuration" "test" { func testAccRegistryScanningConfigurationUpdated() string { return ` resource "aws_ecr_registry_scanning_configuration" "test" { - scan_type = "BASIC" + scan_type = "ENHANCED" + rule { + scan_frequency = "CONTINUOUS_SCAN" + repository_filter { + filter = "*" + filter_type = "WILDCARD" + } + } + rule { + scan_frequency = "SCAN_ON_PUSH" + repository_filter { + filter = "example" + filter_type = "WILDCARD" + } + } } ` } From 7e39284e7a71b5345504b33b81bea57fbe281c91 Mon Sep 17 00:00:00 2001 From: Ben de Haan <53901866+bendehaan@users.noreply.github.com> Date: Sat, 11 Dec 2021 15:20:48 +0100 Subject: [PATCH 4/8] Expand README examples --- ...istry_scanning_configuration.html.markdown | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/website/docs/r/ecr_registry_scanning_configuration.html.markdown b/website/docs/r/ecr_registry_scanning_configuration.html.markdown index c6a1b75479b..d610aa00239 100644 --- a/website/docs/r/ecr_registry_scanning_configuration.html.markdown +++ b/website/docs/r/ecr_registry_scanning_configuration.html.markdown @@ -12,6 +12,8 @@ Provides an Elastic Container Registry Scanning Configuration. Can't be deleted. ## Example Usage +### Basic example + ```terraform resource "aws_ecr_registry_scanning_configuration" "configuration" { scan_type = "ENHANCED" @@ -26,6 +28,30 @@ resource "aws_ecr_registry_scanning_configuration" "configuration" { } ``` +### Multiple rules + +```terraform +resource "aws_ecr_registry_scanning_configuration" "test" { + scan_type = "ENHANCED" + + rule { + scan_frequency = "SCAN_ON_PUSH" + repository_filter { + filter = "*" + filter_type = "WILDCARD" + } + } + + rule { + scan_frequency = "CONTINUOUS_SCAN" + repository_filter { + filter = "example" + filter_type = "WILDCARD" + } + } +} +``` + ## Argument Reference The following arguments are supported: From 478ea6bf5bcdaa12421352d80280603eca0da792 Mon Sep 17 00:00:00 2001 From: Ben de Haan <53901866+bendehaan@users.noreply.github.com> Date: Sat, 11 Dec 2021 15:41:55 +0100 Subject: [PATCH 5/8] Remove rules on destroy, improve readme --- internal/service/ecr/registry_scanning_configuration.go | 2 +- .../service/ecr/registry_scanning_configuration_test.go | 4 ++-- .../r/ecr_registry_scanning_configuration.html.markdown | 7 +++---- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/internal/service/ecr/registry_scanning_configuration.go b/internal/service/ecr/registry_scanning_configuration.go index 8d586285cbc..1e04b958c87 100644 --- a/internal/service/ecr/registry_scanning_configuration.go +++ b/internal/service/ecr/registry_scanning_configuration.go @@ -107,7 +107,7 @@ func resourceRegistryScanningConfigurationDelete(d *schema.ResourceData, meta in conn := meta.(*conns.AWSClient).ECRConn _, err := conn.PutRegistryScanningConfiguration(&ecr.PutRegistryScanningConfigurationInput{ - Rules: nil, + Rules: []*ecr.RegistryScanningRule{}, ScanType: aws.String(ecr.ScanTypeBasic), }) diff --git a/internal/service/ecr/registry_scanning_configuration_test.go b/internal/service/ecr/registry_scanning_configuration_test.go index 620a7014cce..e9840dbe04f 100644 --- a/internal/service/ecr/registry_scanning_configuration_test.go +++ b/internal/service/ecr/registry_scanning_configuration_test.go @@ -124,14 +124,14 @@ resource "aws_ecr_registry_scanning_configuration" "test" { rule { scan_frequency = "CONTINUOUS_SCAN" repository_filter { - filter = "*" + filter = "example" filter_type = "WILDCARD" } } rule { scan_frequency = "SCAN_ON_PUSH" repository_filter { - filter = "example" + filter = "*" filter_type = "WILDCARD" } } diff --git a/website/docs/r/ecr_registry_scanning_configuration.html.markdown b/website/docs/r/ecr_registry_scanning_configuration.html.markdown index d610aa00239..20c6839461c 100644 --- a/website/docs/r/ecr_registry_scanning_configuration.html.markdown +++ b/website/docs/r/ecr_registry_scanning_configuration.html.markdown @@ -3,12 +3,12 @@ subcategory: "ECR" layout: "aws" page_title: "AWS: aws_ecr_registry_scanning_configuration" description: |- - Provides an Elastic Container Registry Repository. + Provides an Elastic Container Registry Scanning Configuration. --- # Resource: aws_ecr_registry_scanning_configuration -Provides an Elastic Container Registry Scanning Configuration. Can't be deleted. +Provides an Elastic Container Registry Scanning Configuration. Can't be completely deleted, instead reverts to the default `BASIC` scanning configuration without rules. ## Example Usage @@ -68,8 +68,7 @@ The following arguments are supported: In addition to all arguments above, the following attributes are exported: -- `registry_id` - The registry ID where the repository was created. -- `scanning_configuration` - The scanning configuration for the registry. +- `id` - The registry ID the scanning configuration applies to. ## Timeouts From 309f8512938346dd29f8514676e2c4535b6130c7 Mon Sep 17 00:00:00 2001 From: Ben de Haan <53901866+bendehaan@users.noreply.github.com> Date: Sat, 11 Dec 2021 15:47:10 +0100 Subject: [PATCH 6/8] Add changelog entry --- .changelog/22179.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .changelog/22179.txt diff --git a/.changelog/22179.txt b/.changelog/22179.txt new file mode 100644 index 00000000000..ed83733a805 --- /dev/null +++ b/.changelog/22179.txt @@ -0,0 +1,3 @@ +```release-note:new-resource +aws_ecr_registry_scanning_configuration +``` From 40d8ca55427658f5e9660a777c54c929073c278e Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Mon, 13 Dec 2021 09:48:07 -0500 Subject: [PATCH 7/8] r/aws_ecr_registry_scanning_configuration: Add 'registry_id' attribute. --- .../ecr/registry_scanning_configuration.go | 22 +++--- .../registry_scanning_configuration_test.go | 67 +++++++++++++++---- ...istry_scanning_configuration.html.markdown | 9 +-- 3 files changed, 68 insertions(+), 30 deletions(-) diff --git a/internal/service/ecr/registry_scanning_configuration.go b/internal/service/ecr/registry_scanning_configuration.go index 1e04b958c87..0d379b4ce38 100644 --- a/internal/service/ecr/registry_scanning_configuration.go +++ b/internal/service/ecr/registry_scanning_configuration.go @@ -23,10 +23,9 @@ func ResourceRegistryScanningConfiguration() *schema.Resource { }, Schema: map[string]*schema.Schema{ - "scan_type": { - Type: schema.TypeString, - Required: true, - ValidateFunc: validation.StringInSlice(ecr.ScanType_Values(), false), + "registry_id": { + Type: schema.TypeString, + Computed: true, }, "rule": { Type: schema.TypeSet, @@ -65,6 +64,11 @@ func ResourceRegistryScanningConfiguration() *schema.Resource { }, }, }, + "scan_type": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice(ecr.ScanType_Values(), false), + }, }, } } @@ -78,8 +82,9 @@ func resourceRegistryScanningConfigurationPut(d *schema.ResourceData, meta inter } _, err := conn.PutRegistryScanningConfiguration(&input) + if err != nil { - return fmt.Errorf("Error creating ECR Scanning Configuration: %w", err) + return fmt.Errorf("error creating ECR Registry Scanning Configuration: %w", err) } d.SetId(meta.(*conns.AWSClient).AccountID) @@ -90,13 +95,13 @@ func resourceRegistryScanningConfigurationPut(d *schema.ResourceData, meta inter func resourceRegistryScanningConfigurationRead(d *schema.ResourceData, meta interface{}) error { conn := meta.(*conns.AWSClient).ECRConn - log.Printf("[DEBUG] Reading registry scanning configuration %s", d.Id()) out, err := conn.GetRegistryScanningConfiguration(&ecr.GetRegistryScanningConfigurationInput{}) if err != nil { - return fmt.Errorf("Error reading registry scanning configuration: %s", err) + return fmt.Errorf("error reading ECR Registry Scanning Configuration (%s): %w", d.Id(), err) } + d.Set("registry_id", out.RegistryId) d.Set("scan_type", out.ScanningConfiguration.ScanType) d.Set("rule", flattenEcrScanningConfigurationRules(out.ScanningConfiguration.Rules)) @@ -106,13 +111,14 @@ func resourceRegistryScanningConfigurationRead(d *schema.ResourceData, meta inte func resourceRegistryScanningConfigurationDelete(d *schema.ResourceData, meta interface{}) error { conn := meta.(*conns.AWSClient).ECRConn + log.Printf("[DEBUG] Deleting ECR Registry Scanning Configuration: (%s)", d.Id()) _, err := conn.PutRegistryScanningConfiguration(&ecr.PutRegistryScanningConfigurationInput{ Rules: []*ecr.RegistryScanningRule{}, ScanType: aws.String(ecr.ScanTypeBasic), }) if err != nil { - return fmt.Errorf("Error deleting registry scanning configuration: %s", err) + return fmt.Errorf("error deleting ECR Registry Scanning Configuration (%s): %w", d.Id(), err) } return nil diff --git a/internal/service/ecr/registry_scanning_configuration_test.go b/internal/service/ecr/registry_scanning_configuration_test.go index e9840dbe04f..5c2e56f7f72 100644 --- a/internal/service/ecr/registry_scanning_configuration_test.go +++ b/internal/service/ecr/registry_scanning_configuration_test.go @@ -13,8 +13,8 @@ import ( func TestAccECRScanningConfiguration_serial(t *testing.T) { testFuncs := map[string]func(t *testing.T){ - "basic": testAccRegistryScanningConfiguration_basic, - // "disappears": testAccRegistryPolicy_disappears, + "basic": testAccRegistryScanningConfiguration_basic, + "update": testAccRegistryScanningConfiguration_update, } for name, testFunc := range testFuncs { @@ -37,11 +37,40 @@ func testAccRegistryScanningConfiguration_basic(t *testing.T) { CheckDestroy: testAccRegistryScanningConfigurationDestroy, Steps: []resource.TestStep{ { - Config: testAccRegistryScanningConfiguration(), + Config: testAccRegistryScanningConfigurationConfig(), Check: resource.ComposeTestCheckFunc( testAccRegistryScanningConfigurationExists(resourceName, &v), - resource.TestCheckResourceAttr(resourceName, "scan_type", "ENHANCED"), + acctest.CheckResourceAttrAccountID(resourceName, "registry_id"), + resource.TestCheckResourceAttr(resourceName, "rule.#", "0"), + resource.TestCheckResourceAttr(resourceName, "scan_type", "BASIC"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func testAccRegistryScanningConfiguration_update(t *testing.T) { + var v ecr.GetRegistryScanningConfigurationOutput + resourceName := "aws_ecr_registry_scanning_configuration.test" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(t) }, + ErrorCheck: acctest.ErrorCheck(t, ecr.EndpointsID), + Providers: acctest.Providers, + CheckDestroy: testAccRegistryScanningConfigurationDestroy, + Steps: []resource.TestStep{ + { + Config: testAccRegistryScanningConfigurationConfigOneRule(), + Check: resource.ComposeTestCheckFunc( + testAccRegistryScanningConfigurationExists(resourceName, &v), + acctest.CheckResourceAttrAccountID(resourceName, "registry_id"), resource.TestCheckResourceAttr(resourceName, "rule.#", "1"), + resource.TestCheckResourceAttr(resourceName, "scan_type", "BASIC"), ), }, { @@ -50,11 +79,11 @@ func testAccRegistryScanningConfiguration_basic(t *testing.T) { ImportStateVerify: true, }, { - Config: testAccRegistryScanningConfigurationUpdated(), + Config: testAccRegistryScanningConfigurationConfigTwoRules(), Check: resource.ComposeTestCheckFunc( testAccRegistryScanningConfigurationExists(resourceName, &v), - resource.TestCheckResourceAttr(resourceName, "scan_type", "ENHANCED"), resource.TestCheckResourceAttr(resourceName, "rule.#", "2"), + resource.TestCheckResourceAttr(resourceName, "scan_type", "ENHANCED"), ), }, }, @@ -65,11 +94,12 @@ func testAccRegistryScanningConfigurationDestroy(s *terraform.State) error { conn := acctest.Provider.Meta().(*conns.AWSClient).ECRConn for _, rs := range s.RootModule().Resources { - if rs.Type != "aws_ecr_registry_policy" { + if rs.Type != "aws_ecr_registry_scanning_configuration" { continue } _, err := conn.GetRegistryScanningConfiguration(&ecr.GetRegistryScanningConfigurationInput{}) + if err != nil { return err } @@ -78,7 +108,7 @@ func testAccRegistryScanningConfigurationDestroy(s *terraform.State) error { return nil } -func testAccRegistryScanningConfigurationExists(name string, res *ecr.GetRegistryScanningConfigurationOutput) resource.TestCheckFunc { +func testAccRegistryScanningConfigurationExists(name string, v *ecr.GetRegistryScanningConfigurationOutput) resource.TestCheckFunc { return func(s *terraform.State) error { rs, ok := s.RootModule().Resources[name] if !ok { @@ -86,28 +116,37 @@ func testAccRegistryScanningConfigurationExists(name string, res *ecr.GetRegistr } if rs.Primary.ID == "" { - return fmt.Errorf("No ECR registry policy ID is set") + return fmt.Errorf("No ECR Registry Scanning Configuration ID is set") } conn := acctest.Provider.Meta().(*conns.AWSClient).ECRConn output, err := conn.GetRegistryScanningConfiguration(&ecr.GetRegistryScanningConfigurationInput{}) + if err != nil { return err } - *res = *output + *v = *output return nil } } -func testAccRegistryScanningConfiguration() string { +func testAccRegistryScanningConfigurationConfig() string { return ` resource "aws_ecr_registry_scanning_configuration" "test" { - scan_type = "ENHANCED" + scan_type = "BASIC" +} +` +} + +func testAccRegistryScanningConfigurationConfigOneRule() string { + return ` +resource "aws_ecr_registry_scanning_configuration" "test" { + scan_type = "BASIC" rule { - scan_frequency = "CONTINUOUS_SCAN" + scan_frequency = "SCAN_ON_PUSH" repository_filter { filter = "example" filter_type = "WILDCARD" @@ -117,7 +156,7 @@ resource "aws_ecr_registry_scanning_configuration" "test" { ` } -func testAccRegistryScanningConfigurationUpdated() string { +func testAccRegistryScanningConfigurationConfigTwoRules() string { return ` resource "aws_ecr_registry_scanning_configuration" "test" { scan_type = "ENHANCED" diff --git a/website/docs/r/ecr_registry_scanning_configuration.html.markdown b/website/docs/r/ecr_registry_scanning_configuration.html.markdown index 20c6839461c..31fc304be6b 100644 --- a/website/docs/r/ecr_registry_scanning_configuration.html.markdown +++ b/website/docs/r/ecr_registry_scanning_configuration.html.markdown @@ -68,14 +68,7 @@ The following arguments are supported: In addition to all arguments above, the following attributes are exported: -- `id` - The registry ID the scanning configuration applies to. - -## Timeouts - -`aws_ecr_registry_scanning_configuration` provides the following [Timeouts](https://www.terraform.io/docs/configuration/blocks/resources/syntax.html#operation-timeouts) -configuration options: - -- `delete` - (Default `20 minutes`) How long to wait for a scanning configuration to be deleted. +* `registry_id` - The registry ID the scanning configuration applies to. ## Import From 20465bd6de0644cc0087d7c54aa96fae897ab05a Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Mon, 13 Dec 2021 10:01:17 -0500 Subject: [PATCH 8/8] Use 'resource.TestCheckTypeSetElemNestedAttrs' to check set values. --- .../registry_scanning_configuration_test.go | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/internal/service/ecr/registry_scanning_configuration_test.go b/internal/service/ecr/registry_scanning_configuration_test.go index 5c2e56f7f72..a95e47cfc07 100644 --- a/internal/service/ecr/registry_scanning_configuration_test.go +++ b/internal/service/ecr/registry_scanning_configuration_test.go @@ -70,6 +70,13 @@ func testAccRegistryScanningConfiguration_update(t *testing.T) { testAccRegistryScanningConfigurationExists(resourceName, &v), acctest.CheckResourceAttrAccountID(resourceName, "registry_id"), resource.TestCheckResourceAttr(resourceName, "rule.#", "1"), + resource.TestCheckTypeSetElemNestedAttrs(resourceName, "rule.*", map[string]string{ + "scan_frequency": "SCAN_ON_PUSH", + }), + resource.TestCheckTypeSetElemNestedAttrs(resourceName, "rule.*.repository_filter.*", map[string]string{ + "filter": "example", + "filter_type": "WILDCARD", + }), resource.TestCheckResourceAttr(resourceName, "scan_type", "BASIC"), ), }, @@ -83,6 +90,20 @@ func testAccRegistryScanningConfiguration_update(t *testing.T) { Check: resource.ComposeTestCheckFunc( testAccRegistryScanningConfigurationExists(resourceName, &v), resource.TestCheckResourceAttr(resourceName, "rule.#", "2"), + resource.TestCheckTypeSetElemNestedAttrs(resourceName, "rule.*", map[string]string{ + "scan_frequency": "CONTINUOUS_SCAN", + }), + resource.TestCheckTypeSetElemNestedAttrs(resourceName, "rule.*.repository_filter.*", map[string]string{ + "filter": "example", + "filter_type": "WILDCARD", + }), + resource.TestCheckTypeSetElemNestedAttrs(resourceName, "rule.*", map[string]string{ + "scan_frequency": "SCAN_ON_PUSH", + }), + resource.TestCheckTypeSetElemNestedAttrs(resourceName, "rule.*.repository_filter.*", map[string]string{ + "filter": "*", + "filter_type": "WILDCARD", + }), resource.TestCheckResourceAttr(resourceName, "scan_type", "ENHANCED"), ), },