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

feat: adding support aws_ecr_replication_configuration repository filter #21002

Merged
merged 12 commits into from
Dec 20, 2021
4 changes: 4 additions & 0 deletions .changelog/21231.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@

```release-note:enhancement
resource/aws_ecr_replication_configuration: Add `repository_filter` to `replication_configuration` block
```
69 changes: 65 additions & 4 deletions internal/service/ecr/replication_configuration.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"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"
"github.com/hashicorp/terraform-provider-aws/internal/verify"
)
Expand Down Expand Up @@ -44,8 +45,9 @@ func ResourceReplicationConfiguration() *schema.Resource {
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"region": {
Type: schema.TypeString,
Required: true,
Type: schema.TypeString,
Required: true,
ValidateFunc: verify.ValidRegionName,
},
"registry_id": {
Type: schema.TypeString,
Expand All @@ -55,6 +57,25 @@ func ResourceReplicationConfiguration() *schema.Resource {
},
},
},
"repository_filter": {
Type: schema.TypeList,
Optional: true,
MinItems: 1,
MaxItems: 100,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"filter": {
Type: schema.TypeString,
Required: true,
},
"filter_type": {
Type: schema.TypeString,
Required: true,
ValidateFunc: validation.StringInSlice(ecr.RepositoryFilterType_Values(), false),
},
},
},
},
},
},
},
Expand Down Expand Up @@ -153,7 +174,8 @@ func expandEcrReplicationConfigurationReplicationConfigurationRules(data []inter
for _, rule := range data {
ec := rule.(map[string]interface{})
config := &ecr.ReplicationRule{
Destinations: expandEcrReplicationConfigurationReplicationConfigurationRulesDestinations(ec["destination"].([]interface{})),
Destinations: expandEcrReplicationConfigurationReplicationConfigurationRulesDestinations(ec["destination"].([]interface{})),
RepositoryFilters: expandEcrReplicationConfigurationReplicationConfigurationRulesRepositoryFilters(ec["repository_filter"].([]interface{})),
}

rules = append(rules, config)
Expand All @@ -171,7 +193,8 @@ func flattenEcrReplicationConfigurationReplicationConfigurationRules(ec []*ecr.R

for _, apiObject := range ec {
tfMap := map[string]interface{}{
"destination": flattenEcrReplicationConfigurationReplicationConfigurationRulesDestinations(apiObject.Destinations),
"destination": flattenEcrReplicationConfigurationReplicationConfigurationRulesDestinations(apiObject.Destinations),
"repository_filter": flattenEcrReplicationConfigurationReplicationConfigurationRulesRepositoryFilters(apiObject.RepositoryFilters),
}

tfList = append(tfList, tfMap)
Expand Down Expand Up @@ -217,3 +240,41 @@ func flattenEcrReplicationConfigurationReplicationConfigurationRulesDestinations

return tfList
}

func expandEcrReplicationConfigurationReplicationConfigurationRulesRepositoryFilters(data []interface{}) []*ecr.RepositoryFilter {
if len(data) == 0 || data[0] == nil {
return nil
}

var filters []*ecr.RepositoryFilter

for _, filter := range data {
ec := filter.(map[string]interface{})
config := &ecr.RepositoryFilter{
Filter: aws.String(ec["filter"].(string)),
FilterType: aws.String(ec["filter_type"].(string)),
}

filters = append(filters, config)
}
return filters
}

func flattenEcrReplicationConfigurationReplicationConfigurationRulesRepositoryFilters(ec []*ecr.RepositoryFilter) []interface{} {
if len(ec) == 0 {
return nil
}

var tfList []interface{}

for _, apiObject := range ec {
tfMap := map[string]interface{}{
"filter": aws.StringValue(apiObject.Filter),
"filter_type": aws.StringValue(apiObject.FilterType),
}

tfList = append(tfList, tfMap)
}

return tfList
}
129 changes: 127 additions & 2 deletions internal/service/ecr/replication_configuration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,25 @@ import (
"github.com/hashicorp/terraform-provider-aws/internal/conns"
)

func TestAccECRReplicationConfiguration_basic(t *testing.T) {
func TestAccECRReplicationConfiguration_serial(t *testing.T) {
testFuncs := map[string]func(t *testing.T){
"basic": testAccReplicationConfiguration_basic,
"repositoryFilter": testAccReplicationConfiguration_repositoryFilter,
}

for name, testFunc := range testFuncs {
testFunc := testFunc

t.Run(name, func(t *testing.T) {
testFunc(t)
})
}
}

func testAccReplicationConfiguration_basic(t *testing.T) {
resourceName := "aws_ecr_replication_configuration.test"

resource.ParallelTest(t, resource.TestCase{
resource.Test(t, resource.TestCase{
PreCheck: func() { acctest.PreCheck(t) },
ErrorCheck: acctest.ErrorCheck(t, ecr.EndpointsID),
Providers: acctest.Providers,
Expand All @@ -30,6 +45,7 @@ func TestAccECRReplicationConfiguration_basic(t *testing.T) {
resource.TestCheckResourceAttr(resourceName, "replication_configuration.0.rule.0.destination.#", "1"),
resource.TestCheckResourceAttr(resourceName, "replication_configuration.0.rule.0.destination.0.region", acctest.AlternateRegion()),
acctest.CheckResourceAttrAccountID(resourceName, "replication_configuration.0.rule.0.destination.0.registry_id"),
resource.TestCheckResourceAttr(resourceName, "replication_configuration.0.rule.0.repository_filter.#", "0"),
),
},
{
Expand All @@ -49,6 +65,7 @@ func TestAccECRReplicationConfiguration_basic(t *testing.T) {
acctest.CheckResourceAttrAccountID(resourceName, "replication_configuration.0.rule.0.destination.0.registry_id"),
resource.TestCheckResourceAttr(resourceName, "replication_configuration.0.rule.0.destination.1.region", acctest.ThirdRegion()),
acctest.CheckResourceAttrAccountID(resourceName, "replication_configuration.0.rule.0.destination.1.registry_id"),
resource.TestCheckResourceAttr(resourceName, "replication_configuration.0.rule.0.repository_filter.#", "0"),
),
},
{
Expand All @@ -61,6 +78,65 @@ func TestAccECRReplicationConfiguration_basic(t *testing.T) {
resource.TestCheckResourceAttr(resourceName, "replication_configuration.0.rule.0.destination.#", "1"),
resource.TestCheckResourceAttr(resourceName, "replication_configuration.0.rule.0.destination.0.region", acctest.AlternateRegion()),
acctest.CheckResourceAttrAccountID(resourceName, "replication_configuration.0.rule.0.destination.0.registry_id"),
resource.TestCheckResourceAttr(resourceName, "replication_configuration.0.rule.0.repository_filter.#", "0"),
),
},
},
})
}

func testAccReplicationConfiguration_repositoryFilter(t *testing.T) {
resourceName := "aws_ecr_replication_configuration.test"

resource.Test(t, resource.TestCase{
PreCheck: func() { acctest.PreCheck(t) },
ErrorCheck: acctest.ErrorCheck(t, ecr.EndpointsID),
Providers: acctest.Providers,
CheckDestroy: testAccCheckReplicationConfigurationDestroy,
Steps: []resource.TestStep{
{
Config: testAccReplicationConfigurationRepositoryFilter(acctest.AlternateRegion()),
Check: resource.ComposeTestCheckFunc(
testAccCheckReplicationConfigurationExists(resourceName),
acctest.CheckResourceAttrAccountID(resourceName, "registry_id"),
resource.TestCheckResourceAttr(resourceName, "replication_configuration.#", "1"),
resource.TestCheckResourceAttr(resourceName, "replication_configuration.0.rule.#", "1"),
resource.TestCheckResourceAttr(resourceName, "replication_configuration.0.rule.0.destination.#", "1"),
resource.TestCheckResourceAttr(resourceName, "replication_configuration.0.rule.0.repository_filter.#", "1"),
resource.TestCheckResourceAttr(resourceName, "replication_configuration.0.rule.0.repository_filter.0.filter", "a-prefix"),
resource.TestCheckResourceAttr(resourceName, "replication_configuration.0.rule.0.repository_filter.0.filter_type", "PREFIX_MATCH"),
),
},
{
ResourceName: resourceName,
ImportState: true,
ImportStateVerify: true,
},
{
Config: testAccReplicationConfigurationRepositoryFilterMultiple(acctest.AlternateRegion()),
Check: resource.ComposeTestCheckFunc(
testAccCheckReplicationConfigurationExists(resourceName),
acctest.CheckResourceAttrAccountID(resourceName, "registry_id"),
resource.TestCheckResourceAttr(resourceName, "replication_configuration.#", "1"),
resource.TestCheckResourceAttr(resourceName, "replication_configuration.0.rule.#", "1"),
resource.TestCheckResourceAttr(resourceName, "replication_configuration.0.rule.0.repository_filter.#", "2"),
resource.TestCheckResourceAttr(resourceName, "replication_configuration.0.rule.0.repository_filter.0.filter", "a-prefix"),
resource.TestCheckResourceAttr(resourceName, "replication_configuration.0.rule.0.repository_filter.0.filter_type", "PREFIX_MATCH"),
resource.TestCheckResourceAttr(resourceName, "replication_configuration.0.rule.0.repository_filter.1.filter", "a-second-prefix"),
resource.TestCheckResourceAttr(resourceName, "replication_configuration.0.rule.0.repository_filter.1.filter_type", "PREFIX_MATCH"),
),
},
{
Config: testAccReplicationConfigurationRepositoryFilter(acctest.AlternateRegion()),
Check: resource.ComposeTestCheckFunc(
testAccCheckReplicationConfigurationExists(resourceName),
acctest.CheckResourceAttrAccountID(resourceName, "registry_id"),
resource.TestCheckResourceAttr(resourceName, "replication_configuration.#", "1"),
resource.TestCheckResourceAttr(resourceName, "replication_configuration.0.rule.#", "1"),
resource.TestCheckResourceAttr(resourceName, "replication_configuration.0.rule.0.destination.#", "1"),
resource.TestCheckResourceAttr(resourceName, "replication_configuration.0.rule.0.repository_filter.#", "1"),
resource.TestCheckResourceAttr(resourceName, "replication_configuration.0.rule.0.repository_filter.0.filter", "a-prefix"),
resource.TestCheckResourceAttr(resourceName, "replication_configuration.0.rule.0.repository_filter.0.filter_type", "PREFIX_MATCH"),
),
},
},
Expand Down Expand Up @@ -148,3 +224,52 @@ resource "aws_ecr_replication_configuration" "test" {
}
`, region1, region2)
}

func testAccReplicationConfigurationRepositoryFilter(region string) string {
return fmt.Sprintf(`
data "aws_caller_identity" "current" {}

resource "aws_ecr_replication_configuration" "test" {
replication_configuration {
rule {
destination {
region = %[1]q
registry_id = data.aws_caller_identity.current.account_id
}

repository_filter {
filter = "a-prefix"
filter_type = "PREFIX_MATCH"
}
}
}
}
`, region)
}

func testAccReplicationConfigurationRepositoryFilterMultiple(region string) string {
return fmt.Sprintf(`
data "aws_caller_identity" "current" {}

resource "aws_ecr_replication_configuration" "test" {
replication_configuration {
rule {
destination {
region = %[1]q
registry_id = data.aws_caller_identity.current.account_id
}

repository_filter {
filter = "a-prefix"
filter_type = "PREFIX_MATCH"
}

repository_filter {
filter = "a-second-prefix"
filter_type = "PREFIX_MATCH"
}
}
}
}
`, region)
}
32 changes: 31 additions & 1 deletion website/docs/r/ecr_replication_configuration.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,30 @@ resource "aws_ecr_replication_configuration" "example" {
}
```

## Repository Filter Usage

```terraform
data "aws_caller_identity" "current" {}

data "aws_regions" "example" {}

resource "aws_ecr_replication_configuration" "example" {
replication_configuration {
rule {
destination {
region = data.aws_regions.example.names[0]
registry_id = data.aws_caller_identity.current.account_id
}

repository_filter {
filter = "prod-microservice"
filter_type = "PREFIX_MATCH"
}
}
}
}
```

## Argument Reference

The following arguments are supported:
Expand All @@ -66,12 +90,18 @@ The following arguments are supported:
### Rule

* `destination` - (Required) the details of a replication destination. See [Destination](#destination).
* `repository_filter` - (Optional) filters for a replication rule. See [Repository Filter](#repository-filter).

### Destination

* `region` - (Required) A Region to replicate to.
* `registry_id` - (Required) The account ID of the destination registry to replicate to.

### Repository Filter

* `filter` - (Required) The repository filter details.
* `filter_type` - (Required) The repository filter type. The only supported value is `PREFIX_MATCH`, which is a repository name prefix specified with the filter parameter.

## Attributes Reference

In addition to all arguments above, the following attributes are exported:
Expand All @@ -84,4 +114,4 @@ ECR Replication Configuration can be imported using the `registry_id`, e.g.,

```
$ terraform import aws_ecr_replication_configuration.service 012345678912
```
```