From 6977fff406937bf62bb77ea87afd62d3366abcd5 Mon Sep 17 00:00:00 2001 From: Shawn Silva Date: Mon, 22 Aug 2016 19:32:32 -0400 Subject: [PATCH] provider/aws: add local name filter to aws_ami datasource In cases where the filters provided by AWS against the name of an AMI are not sufficient, allow adding a "local_name_filter" which is a regex that is used to filter the AMIs returned by amazon. --- builtin/providers/aws/data_source_aws_ami.go | 34 +++++++++++++++---- .../providers/aws/data_source_aws_ami_test.go | 29 ++++++++++++++++ .../docs/providers/aws/d/ami.html.markdown | 6 +++- 3 files changed, 61 insertions(+), 8 deletions(-) diff --git a/builtin/providers/aws/data_source_aws_ami.go b/builtin/providers/aws/data_source_aws_ami.go index ec3b62c8c..a5b7ba06c 100644 --- a/builtin/providers/aws/data_source_aws_ami.go +++ b/builtin/providers/aws/data_source_aws_ami.go @@ -4,6 +4,7 @@ import ( "bytes" "fmt" "log" + "regexp" "sort" "time" @@ -43,6 +44,11 @@ func dataSourceAwsAmi() *schema.Resource { }, }, }, + "local_name_filter": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ForceNew: true, + }, "most_recent": &schema.Schema{ Type: schema.TypeBool, Optional: true, @@ -206,10 +212,11 @@ func dataSourceAwsAmiRead(d *schema.ResourceData, meta interface{}) error { executableUsers, executableUsersOk := d.GetOk("executable_users") filters, filtersOk := d.GetOk("filter") + localNameFilter, localNameFilterOk := d.GetOk("local_name_filter") owners, ownersOk := d.GetOk("owners") - if executableUsersOk == false && filtersOk == false && ownersOk == false { - return fmt.Errorf("One of executable_users, filters, or owners must be assigned") + if executableUsersOk == false && filtersOk == false && localNameFilterOk == false && ownersOk == false { + return fmt.Errorf("One of executable_users, filters, local_name_filter, or owners must be assigned") } params := &ec2.DescribeImagesInput{} @@ -227,20 +234,33 @@ func dataSourceAwsAmiRead(d *schema.ResourceData, meta interface{}) error { if err != nil { return err } + + var filteredImages []*ec2.Image + if localNameFilterOk == true { + r := regexp.MustCompile(localNameFilter.(string)) + for _, image := range resp.Images { + if r.MatchString(*image.Name) == true { + filteredImages = append(filteredImages, image) + } + } + } else { + filteredImages = resp.Images[:] + } + var image *ec2.Image - if len(resp.Images) < 1 { + if len(filteredImages) < 1 { return fmt.Errorf("Your query returned no results. Please change your filters and try again.") - } else if len(resp.Images) > 1 { + } else if len(filteredImages) > 1 { if (d.Get("most_recent").(bool)) == true { log.Printf("[DEBUG] aws_ami - multiple results found and most_recent is set") - image = mostRecentAmi(resp.Images) + image = mostRecentAmi(filteredImages) } else { log.Printf("[DEBUG] aws_ami - multiple results found and most_recent not set") return fmt.Errorf("Your query returned more than one result. Please try a more specific search, or set most_recent to true.") } } else { - log.Printf("[DEBUG] aws_ami - Single AMI found: %s", *resp.Images[0].ImageId) - image = resp.Images[0] + log.Printf("[DEBUG] aws_ami - Single AMI found: %s", *filteredImages[0].ImageId) + image = filteredImages[0] } return amiDescriptionAttributes(d, image) } diff --git a/builtin/providers/aws/data_source_aws_ami_test.go b/builtin/providers/aws/data_source_aws_ami_test.go index 2f8eba3eb..3db2b56ce 100644 --- a/builtin/providers/aws/data_source_aws_ami_test.go +++ b/builtin/providers/aws/data_source_aws_ami_test.go @@ -139,6 +139,22 @@ func TestAccAWSAmiDataSource_owners(t *testing.T) { }) } +func TestAccAWSAmiDataSource_localNameFilter(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCheckAwsAmiDataSourceLocalNameFilterConfig, + Check: resource.ComposeTestCheckFunc( + testAccCheckAwsAmiDataSourceID("data.aws_ami.local_filtered_ami"), + resource.TestMatchResourceAttr("data.aws_ami.local_filtered_ami", "image_id", regexp.MustCompile("^ami-")), + ), + }, + }, + }) +} + func testAccCheckAwsAmiDataSourceDestroy(s *terraform.State) error { return nil } @@ -245,3 +261,16 @@ data "aws_ami" "amazon_ami" { owners = ["amazon"] } ` + +// Testing local_name_filter parameter +const testAccCheckAwsAmiDataSourceLocalNameFilterConfig = ` +data "aws_ami" "local_filtered_ami" { + most_recent = true + owners = ["amazon"] + filter { + name = "name" + values = ["amzn-ami-*"] + } + local_name_filter = "^amzn-ami-\\d{3}[5].*-ecs-optimized" +} +` diff --git a/website/source/docs/providers/aws/d/ami.html.markdown b/website/source/docs/providers/aws/d/ami.html.markdown index 8df0b12c1..1b5f8a888 100644 --- a/website/source/docs/providers/aws/d/ami.html.markdown +++ b/website/source/docs/providers/aws/d/ami.html.markdown @@ -8,7 +8,7 @@ description: |- # aws\_ami -Use this data source to get the ID of a registered AMI for use in other +Use this data source to get the ID of a registered AMI for use in other resources. ## Example Usage @@ -25,6 +25,7 @@ data "aws_ami" "nat_ami" { name = "name" values = ["amzn-ami-vpc-nat*"] } + local_name_filter = "^myami-\\d{3}" owners = ["self"] } ``` @@ -41,6 +42,9 @@ recent AMI. several valid keys, for a full reference, check out [describe-images in the AWS CLI reference][1]. +* `local_name_filter` - (Optional) A regex string to apply to the AMI list returned +by AWS. This allows more advanced filtering not supported from the AWS API. + * `owners` - (Optional) Limit search to specific AMI owners. Valid items are the numeric account ID, `amazon`, or `self`.