-
Notifications
You must be signed in to change notification settings - Fork 9.3k
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
Add 'aws_ecr_image' datasource #8403
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
@@ -0,0 +1,124 @@ | ||||||
package aws | ||||||
|
||||||
import ( | ||||||
"fmt" | ||||||
"log" | ||||||
"time" | ||||||
|
||||||
"github.com/aws/aws-sdk-go/aws" | ||||||
"github.com/aws/aws-sdk-go/service/ecr" | ||||||
"github.com/hashicorp/terraform/helper/schema" | ||||||
"github.com/hashicorp/terraform/helper/validation" | ||||||
) | ||||||
|
||||||
func dataSourceAwsEcrImage() *schema.Resource { | ||||||
return &schema.Resource{ | ||||||
Read: dataSourceAwsEcrImageRead, | ||||||
Schema: map[string]*schema.Schema{ | ||||||
"registry_id": { | ||||||
Type: schema.TypeString, | ||||||
Optional: true, | ||||||
Computed: true, | ||||||
ValidateFunc: validation.NoZeroValues, | ||||||
}, | ||||||
"repository_name": { | ||||||
Type: schema.TypeString, | ||||||
Required: true, | ||||||
}, | ||||||
"image_digest": { | ||||||
Type: schema.TypeString, | ||||||
Computed: true, | ||||||
Optional: true, | ||||||
}, | ||||||
"image_tag": { | ||||||
Type: schema.TypeString, | ||||||
Optional: true, | ||||||
}, | ||||||
"image_pushed_at": { | ||||||
Type: schema.TypeInt, | ||||||
Computed: true, | ||||||
}, | ||||||
"image_size_in_bytes": { | ||||||
Type: schema.TypeInt, | ||||||
Computed: true, | ||||||
}, | ||||||
"image_tags": { | ||||||
Type: schema.TypeList, | ||||||
Computed: true, | ||||||
Elem: &schema.Schema{Type: schema.TypeString}, | ||||||
}, | ||||||
}, | ||||||
} | ||||||
} | ||||||
|
||||||
func dataSourceAwsEcrImageRead(d *schema.ResourceData, meta interface{}) error { | ||||||
conn := meta.(*AWSClient).ecrconn | ||||||
|
||||||
params := &ecr.DescribeImagesInput{ | ||||||
RepositoryName: aws.String(d.Get("repository_name").(string)), | ||||||
} | ||||||
|
||||||
regId, ok := d.GetOk("registry_id") | ||||||
if ok { | ||||||
params.RegistryId = aws.String(regId.(string)) | ||||||
} | ||||||
|
||||||
imgId := ecr.ImageIdentifier{} | ||||||
digest, ok := d.GetOk("image_digest") | ||||||
if ok { | ||||||
imgId.ImageDigest = aws.String(digest.(string)) | ||||||
} | ||||||
tag, ok := d.GetOk("image_tag") | ||||||
if ok { | ||||||
imgId.ImageTag = aws.String(tag.(string)) | ||||||
} | ||||||
|
||||||
if imgId.ImageDigest == nil && imgId.ImageTag == nil { | ||||||
return fmt.Errorf("At least one of either image_digest or image_tag must be defined") | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In a future update of this data souce: instead of returning an error in this situation, we should likely just perform a |
||||||
} | ||||||
|
||||||
params.ImageIds = []*ecr.ImageIdentifier{&imgId} | ||||||
|
||||||
var imageDetails []*ecr.ImageDetail | ||||||
log.Printf("[DEBUG] Reading ECR Images: %s", params) | ||||||
err := conn.DescribeImagesPages(params, func(page *ecr.DescribeImagesOutput, lastPage bool) bool { | ||||||
imageDetails = append(imageDetails, page.ImageDetails...) | ||||||
return true | ||||||
}) | ||||||
if err != nil { | ||||||
return fmt.Errorf("Error describing ECR images: %q", err) | ||||||
} | ||||||
|
||||||
if len(imageDetails) == 0 { | ||||||
return fmt.Errorf("No matching image found") | ||||||
} | ||||||
if len(imageDetails) > 1 { | ||||||
return fmt.Errorf("More than one image found for tag/digest combination") | ||||||
} | ||||||
|
||||||
image := imageDetails[0] | ||||||
|
||||||
d.SetId(time.Now().UTC().String()) | ||||||
if err = d.Set("registry_id", *image.RegistryId); err != nil { | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. To prevent potential panics, we should prefer to skip direct
Suggested change
|
||||||
return fmt.Errorf("failed to set registry_id: %s", err) | ||||||
} | ||||||
if err = d.Set("image_digest", *image.ImageDigest); err != nil { | ||||||
return fmt.Errorf("failed to set image_digest: %s", err) | ||||||
} | ||||||
if err = d.Set("image_pushed_at", image.ImagePushedAt.Unix()); err != nil { | ||||||
return fmt.Errorf("failed to set image_pushed_at: %s", err) | ||||||
} | ||||||
if err = d.Set("image_size_in_bytes", *image.ImageSizeInBytes); err != nil { | ||||||
return fmt.Errorf("failed to set image_size_in_bytes: %s", err) | ||||||
} | ||||||
|
||||||
tags := []string{} | ||||||
for _, t := range image.ImageTags { | ||||||
tags = append(tags, *t) | ||||||
} | ||||||
if err := d.Set("image_tags", tags); err != nil { | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This can be simplified with the AWS Go SDK provided conversion function,
Suggested change
|
||||||
return fmt.Errorf("failed to set image_tags: %s", err) | ||||||
} | ||||||
|
||||||
return nil | ||||||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
package aws | ||
|
||
import ( | ||
"fmt" | ||
"strconv" | ||
"testing" | ||
|
||
"github.com/hashicorp/terraform/helper/resource" | ||
"github.com/hashicorp/terraform/terraform" | ||
) | ||
|
||
func TestAccAWSEcrDataSource_ecrImage(t *testing.T) { | ||
registry, repo, tag := "137112412989", "amazonlinux", "latest" | ||
resourceByTag := "data.aws_ecr_image.by_tag" | ||
resourceByDigest := "data.aws_ecr_image.by_digest" | ||
|
||
resource.ParallelTest(t, resource.TestCase{ | ||
PreCheck: func() { testAccPreCheck(t) }, | ||
Providers: testAccProviders, | ||
Steps: []resource.TestStep{ | ||
{ | ||
Config: testAccCheckAwsEcrImageDataSourceConfig(registry, repo, tag), | ||
Check: resource.ComposeTestCheckFunc( | ||
resource.TestCheckResourceAttrSet(resourceByTag, "image_digest"), | ||
resource.TestCheckResourceAttrSet(resourceByTag, "image_pushed_at"), | ||
resource.TestCheckResourceAttrSet(resourceByTag, "image_size_in_bytes"), | ||
testCheckTagInImageTags(resourceByTag, tag), | ||
resource.TestCheckResourceAttrSet(resourceByDigest, "image_pushed_at"), | ||
resource.TestCheckResourceAttrSet(resourceByDigest, "image_size_in_bytes"), | ||
testCheckTagInImageTags(resourceByDigest, tag), | ||
), | ||
}, | ||
}, | ||
}) | ||
} | ||
|
||
func testAccCheckAwsEcrImageDataSourceConfig(reg, repo, tag string) string { | ||
return fmt.Sprintf(` | ||
data "aws_ecr_image" "by_tag" { | ||
registry_id = "%s" | ||
repository_name = "%s" | ||
image_tag = "%s" | ||
} | ||
|
||
data "aws_ecr_image" "by_digest" { | ||
registry_id = "${data.aws_ecr_image.by_tag.registry_id}" | ||
repository_name = "${data.aws_ecr_image.by_tag.repository_name}" | ||
image_digest = "${data.aws_ecr_image.by_tag.image_digest}" | ||
} | ||
`, reg, repo, tag) | ||
} | ||
|
||
func testCheckTagInImageTags(name, expectedTag string) resource.TestCheckFunc { | ||
return func(s *terraform.State) error { | ||
// Ensure we have enough information in state to look up in API | ||
rs, ok := s.RootModule().Resources[name] | ||
if !ok { | ||
return fmt.Errorf("Resource not found: %s", name) | ||
} | ||
|
||
tagsLenStr, ok := rs.Primary.Attributes["image_tags.#"] | ||
if !ok { | ||
return fmt.Errorf("No attribute 'image_tags' in resource: %s", name) | ||
} | ||
tagsLen, _ := strconv.Atoi(tagsLenStr) | ||
|
||
for i := 0; i < tagsLen; i++ { | ||
tag := rs.Primary.Attributes[fmt.Sprintf("image_tags.%d", i)] | ||
if tag == expectedTag { | ||
return nil | ||
} | ||
} | ||
return fmt.Errorf("No tag '%s' in images_tags of resource %s", expectedTag, name) | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
--- | ||
layout: "aws" | ||
page_title: "AWS: aws_ecr_image" | ||
sidebar_current: "docs-aws-datasource-ecr-image" | ||
description: |- | ||
Provides details about an ECR Image | ||
--- | ||
|
||
# Data Source: aws_ecr_image | ||
|
||
The ECR Image data source allows the details of an image with a particular tag or digest to be retrieved. | ||
|
||
## Example Usage | ||
|
||
```hcl | ||
data "aws_ecr_image" "service_image" { | ||
repository_name = "my/service" | ||
image_tag = "latest" | ||
} | ||
``` | ||
|
||
## Argument Reference | ||
|
||
The following arguments are supported: | ||
|
||
* `registry_id` - (Optional) The ID of the Registry where the repository resides. | ||
* `repository_name` - (Required) The name of the ECR Repository. | ||
* `image_digest` - (Optional) The sha256 digest of the image manifest. At least one of `image_digest` or `image_tag` must be specified. | ||
* `image_tag` - (Optional) The tag associated with this image. At least one of `image_digest` or `image_tag` must be specified. | ||
|
||
## Attributes Reference | ||
|
||
In addition to all arguments above, the following attributes are exported: | ||
|
||
* `image_pushed_at` - The date and time, expressed as a unix timestamp, at which the current image was pushed to the repository. | ||
* `image_size_in_bytes` - The size, in bytes, of the image in the repository. | ||
* `image_tags` - The list of tags associated with this image. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In a future update of this data source: we should likely remove this validation since in Terraform 0.11 it may be helpful to define this data source as part of a Terraform module that uses an optional variable to override image lookup and the below
d.GetOk()
usage will skip""
automatically.