Skip to content

Commit 148d66e

Browse files
[New Data Source]: aws_ecrpublic_images : Add new data source to fetch the list of images in a specified public repository (#44795)
* add datasource for ecrpublic `DescribeImages` * add test * add website documentation
1 parent 09dc57c commit 148d66e

File tree

5 files changed

+313
-1
lines changed

5 files changed

+313
-1
lines changed

.changelog/44795.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
```release-note:new-data-source
2+
aws_ecrpublic_images
3+
```
Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
// Copyright (c) HashiCorp, Inc.
2+
// SPDX-License-Identifier: MPL-2.0
3+
4+
package ecrpublic
5+
6+
import (
7+
"context"
8+
9+
"github.com/YakDriver/regexache"
10+
"github.com/aws/aws-sdk-go-v2/service/ecrpublic"
11+
awstypes "github.com/aws/aws-sdk-go-v2/service/ecrpublic/types"
12+
"github.com/hashicorp/terraform-plugin-framework-timetypes/timetypes"
13+
"github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator"
14+
"github.com/hashicorp/terraform-plugin-framework/datasource"
15+
"github.com/hashicorp/terraform-plugin-framework/datasource/schema"
16+
"github.com/hashicorp/terraform-plugin-framework/schema/validator"
17+
"github.com/hashicorp/terraform-plugin-framework/types"
18+
"github.com/hashicorp/terraform-provider-aws/internal/framework"
19+
fwflex "github.com/hashicorp/terraform-provider-aws/internal/framework/flex"
20+
fwtypes "github.com/hashicorp/terraform-provider-aws/internal/framework/types"
21+
"github.com/hashicorp/terraform-provider-aws/internal/smerr"
22+
"github.com/hashicorp/terraform-provider-aws/names"
23+
)
24+
25+
// @FrameworkDataSource("aws_ecrpublic_images", name="Images")
26+
func newDataSourceImages(_ context.Context) (datasource.DataSourceWithConfigure, error) {
27+
return &dataSourceImages{}, nil
28+
}
29+
30+
type dataSourceImages struct {
31+
framework.DataSourceWithModel[dataSourceImagesModel]
32+
}
33+
34+
func (d *dataSourceImages) Schema(ctx context.Context, _ datasource.SchemaRequest, resp *datasource.SchemaResponse) {
35+
resp.Schema = schema.Schema{
36+
Description: "Provides details about AWS ECR Public Images in a public repository.",
37+
Attributes: map[string]schema.Attribute{
38+
names.AttrRepositoryName: schema.StringAttribute{
39+
Description: "Name of the public repository.",
40+
Required: true,
41+
Validators: []validator.String{
42+
stringvalidator.LengthBetween(2, 205),
43+
},
44+
},
45+
"registry_id": schema.StringAttribute{
46+
Description: "AWS account ID associated with the public registry that contains the repository. If not specified, the default public registry is assumed.",
47+
Optional: true,
48+
Validators: []validator.String{
49+
stringvalidator.RegexMatches(regexache.MustCompile(`^[0-9]{12}$`), "must be a 12-digit AWS account ID"),
50+
},
51+
},
52+
"images": framework.DataSourceComputedListOfObjectAttribute[imageItemModel](ctx),
53+
},
54+
Blocks: map[string]schema.Block{
55+
"image_ids": schema.ListNestedBlock{
56+
Description: "List of image IDs to filter. Each image ID can use either a tag or digest.",
57+
CustomType: fwtypes.NewListNestedObjectTypeOf[imagesIDsModel](ctx),
58+
NestedObject: schema.NestedBlockObject{
59+
Attributes: map[string]schema.Attribute{
60+
"image_tag": schema.StringAttribute{
61+
Description: "Image tag.",
62+
Optional: true,
63+
},
64+
"image_digest": schema.StringAttribute{
65+
Description: "Image digest.",
66+
Optional: true,
67+
},
68+
},
69+
},
70+
},
71+
},
72+
}
73+
}
74+
75+
func (d *dataSourceImages) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) {
76+
var data dataSourceImagesModel
77+
resp.Diagnostics.Append(req.Config.Get(ctx, &data)...)
78+
if resp.Diagnostics.HasError() {
79+
return
80+
}
81+
82+
conn := d.Meta().ECRPublicClient(ctx)
83+
84+
var input ecrpublic.DescribeImagesInput
85+
resp.Diagnostics.Append(fwflex.Expand(ctx, &data, &input)...)
86+
if resp.Diagnostics.HasError() {
87+
return
88+
}
89+
90+
var images []awstypes.ImageDetail
91+
92+
paginator := ecrpublic.NewDescribeImagesPaginator(conn, &input)
93+
for paginator.HasMorePages() {
94+
output, err := paginator.NextPage(ctx)
95+
96+
if err != nil {
97+
smerr.AddError(ctx, &resp.Diagnostics, err, smerr.ID, data.RepositoryName.String())
98+
return
99+
}
100+
101+
images = append(images, output.ImageDetails...)
102+
}
103+
104+
resp.Diagnostics.Append(fwflex.Flatten(ctx, images, &data.Images)...)
105+
if resp.Diagnostics.HasError() {
106+
return
107+
}
108+
109+
resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
110+
}
111+
112+
type dataSourceImagesModel struct {
113+
framework.WithRegionModel
114+
RepositoryName types.String `tfsdk:"repository_name"`
115+
RegistryId types.String `tfsdk:"registry_id"`
116+
ImageIds fwtypes.ListNestedObjectValueOf[imagesIDsModel] `tfsdk:"image_ids"`
117+
Images fwtypes.ListNestedObjectValueOf[imageItemModel] `tfsdk:"images"`
118+
}
119+
120+
type imagesIDsModel struct {
121+
ImageTag types.String `tfsdk:"image_tag"`
122+
ImageDigest types.String `tfsdk:"image_digest"`
123+
}
124+
125+
type imageItemModel struct {
126+
ArtifactMediaType types.String `tfsdk:"artifact_media_type"`
127+
ImageDigest types.String `tfsdk:"image_digest"`
128+
ImageManifestMediaType types.String `tfsdk:"image_manifest_media_type"`
129+
ImagePushedAt timetypes.RFC3339 `tfsdk:"image_pushed_at"`
130+
ImageSizeInBytes types.Int64 `tfsdk:"image_size_in_bytes"`
131+
ImageTags fwtypes.ListValueOf[types.String] `tfsdk:"image_tags"`
132+
RegistryId types.String `tfsdk:"registry_id"`
133+
RepositoryName types.String `tfsdk:"repository_name"`
134+
}
Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
// Copyright (c) HashiCorp, Inc.
2+
// SPDX-License-Identifier: MPL-2.0
3+
4+
package ecrpublic_test
5+
6+
import (
7+
"fmt"
8+
"testing"
9+
10+
"github.com/YakDriver/regexache"
11+
"github.com/hashicorp/aws-sdk-go-base/v2/endpoints"
12+
sdkacctest "github.com/hashicorp/terraform-plugin-testing/helper/acctest"
13+
"github.com/hashicorp/terraform-plugin-testing/helper/resource"
14+
"github.com/hashicorp/terraform-provider-aws/internal/acctest"
15+
"github.com/hashicorp/terraform-provider-aws/names"
16+
)
17+
18+
func TestAccECRPublicImagesDataSource_basic(t *testing.T) {
19+
ctx := acctest.Context(t)
20+
rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix)
21+
dataSourceName := "data.aws_ecrpublic_images.test"
22+
23+
resource.ParallelTest(t, resource.TestCase{
24+
PreCheck: func() { acctest.PreCheck(ctx, t); acctest.PreCheckRegion(t, endpoints.UsEast1RegionID) },
25+
ErrorCheck: acctest.ErrorCheck(t, names.ECRPublicServiceID),
26+
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories,
27+
Steps: []resource.TestStep{
28+
{
29+
Config: testAccImagesDataSourceConfig_basic(rName),
30+
Check: resource.ComposeTestCheckFunc(
31+
resource.TestCheckResourceAttr(dataSourceName, names.AttrRepositoryName, rName),
32+
resource.TestCheckResourceAttr(dataSourceName, "images.#", "0"),
33+
),
34+
},
35+
},
36+
})
37+
}
38+
39+
func TestAccECRPublicImagesDataSource_registryID(t *testing.T) {
40+
ctx := acctest.Context(t)
41+
rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix)
42+
dataSourceName := "data.aws_ecrpublic_images.test"
43+
44+
resource.ParallelTest(t, resource.TestCase{
45+
PreCheck: func() { acctest.PreCheck(ctx, t); acctest.PreCheckRegion(t, endpoints.UsEast1RegionID) },
46+
ErrorCheck: acctest.ErrorCheck(t, names.ECRPublicServiceID),
47+
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories,
48+
Steps: []resource.TestStep{
49+
{
50+
Config: testAccImagesDataSourceConfig_registryID(rName),
51+
Check: resource.ComposeTestCheckFunc(
52+
resource.TestCheckResourceAttr(dataSourceName, names.AttrRepositoryName, rName),
53+
resource.TestCheckResourceAttrSet(dataSourceName, "registry_id"),
54+
resource.TestCheckResourceAttr(dataSourceName, "images.#", "0"),
55+
),
56+
},
57+
},
58+
})
59+
}
60+
61+
func TestAccECRPublicImagesDataSource_registryIDValidation(t *testing.T) {
62+
ctx := acctest.Context(t)
63+
rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix)
64+
65+
resource.ParallelTest(t, resource.TestCase{
66+
PreCheck: func() { acctest.PreCheck(ctx, t); acctest.PreCheckRegion(t, endpoints.UsEast1RegionID) },
67+
ErrorCheck: acctest.ErrorCheck(t, names.ECRPublicServiceID),
68+
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories,
69+
Steps: []resource.TestStep{
70+
{
71+
Config: testAccImagesDataSourceConfig_registryIDInvalid(rName),
72+
ExpectError: regexache.MustCompile(`must be a 12-digit AWS account ID`),
73+
},
74+
},
75+
})
76+
}
77+
78+
func testAccImagesDataSourceConfig_basic(rName string) string {
79+
return fmt.Sprintf(`
80+
resource "aws_ecrpublic_repository" "test" {
81+
repository_name = %[1]q
82+
}
83+
84+
data "aws_ecrpublic_images" "test" {
85+
repository_name = aws_ecrpublic_repository.test.repository_name
86+
}
87+
`, rName)
88+
}
89+
90+
func testAccImagesDataSourceConfig_registryID(rName string) string {
91+
return fmt.Sprintf(`
92+
data "aws_caller_identity" "current" {}
93+
94+
resource "aws_ecrpublic_repository" "test" {
95+
repository_name = %[1]q
96+
}
97+
98+
data "aws_ecrpublic_images" "test" {
99+
repository_name = aws_ecrpublic_repository.test.repository_name
100+
registry_id = data.aws_caller_identity.current.account_id
101+
}
102+
`, rName)
103+
}
104+
105+
func testAccImagesDataSourceConfig_registryIDInvalid(rName string) string {
106+
return fmt.Sprintf(`
107+
resource "aws_ecrpublic_repository" "test" {
108+
repository_name = %[1]q
109+
}
110+
111+
data "aws_ecrpublic_images" "test" {
112+
repository_name = aws_ecrpublic_repository.test.repository_name
113+
registry_id = "invalid"
114+
}
115+
`, rName)
116+
}

internal/service/ecrpublic/service_package_gen.go

Lines changed: 8 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
---
2+
subcategory: "ECR Public"
3+
layout: "aws"
4+
page_title: "AWS: aws_ecrpublic_images"
5+
description: |-
6+
Provides a list of images for a specified AWS ECR Public Repository.
7+
---
8+
9+
# Data Source: aws_ecrpublic_images
10+
11+
The ECR Public Images data source allows the list of images in a specified public repository to be retrieved.
12+
13+
## Example Usage
14+
15+
```terraform
16+
data "aws_ecrpublic_images" "example" {
17+
repository_name = "my-public-repository"
18+
}
19+
20+
output "image_digests" {
21+
value = [for img in data.aws_ecrpublic_images.example.images : img.digest if img.digest != null]
22+
}
23+
24+
output "image_tags" {
25+
value = distinct(flatten([for img in data.aws_ecrpublic_images.example.images : img.tags]))
26+
}
27+
```
28+
29+
## Argument Reference
30+
31+
This data source supports the following arguments:
32+
33+
* `region` - (Optional) Region where this resource will be [managed](https://docs.aws.amazon.com/general/latest/gr/rande.html#regional-endpoints). Defaults to the Region set in the [provider configuration](https://registry.terraform.io/providers/hashicorp/aws/latest/docs#aws-configuration-reference).
34+
* `repository_name` - (Required) Name of the public repository.
35+
* `registry_id` - (Optional) AWS account ID associated with the public registry that contains the repository. If not specified, the default public registry is assumed.
36+
* `image_ids` - (Optional) One or more image ID filters. Each image ID can use either a tag or digest (or both). Each object has the following attributes:
37+
* `image_tag` - (Optional) Tag used for the image.
38+
* `image_digest` - (Optional) Digest of the image manifest.
39+
40+
## Attribute Reference
41+
42+
This data source exports the following attributes in addition to the arguments above:
43+
44+
* `images` - List of images returned. Each image contains:
45+
* `digest` - Image digest.
46+
* `tags` - List of image tags.
47+
* `size_in_bytes` - Image size in bytes.
48+
* `pushed_at` - Timestamp when image was pushed.
49+
* `artifact_media_type` - Media type of the artifact.
50+
* `image_manifest_media_type` - Media type of the image manifest.
51+
* `registry_id` - AWS account ID associated with the public registry.
52+
* `repository_name` - Name of the repository.

0 commit comments

Comments
 (0)