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.
This commit is contained in:
Shawn Silva 2016-08-22 19:32:32 -04:00
parent 38289ddbd5
commit 6977fff406
3 changed files with 61 additions and 8 deletions

View File

@ -4,6 +4,7 @@ import (
"bytes" "bytes"
"fmt" "fmt"
"log" "log"
"regexp"
"sort" "sort"
"time" "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{ "most_recent": &schema.Schema{
Type: schema.TypeBool, Type: schema.TypeBool,
Optional: true, Optional: true,
@ -206,10 +212,11 @@ func dataSourceAwsAmiRead(d *schema.ResourceData, meta interface{}) error {
executableUsers, executableUsersOk := d.GetOk("executable_users") executableUsers, executableUsersOk := d.GetOk("executable_users")
filters, filtersOk := d.GetOk("filter") filters, filtersOk := d.GetOk("filter")
localNameFilter, localNameFilterOk := d.GetOk("local_name_filter")
owners, ownersOk := d.GetOk("owners") owners, ownersOk := d.GetOk("owners")
if executableUsersOk == false && filtersOk == false && ownersOk == false { if executableUsersOk == false && filtersOk == false && localNameFilterOk == false && ownersOk == false {
return fmt.Errorf("One of executable_users, filters, or owners must be assigned") return fmt.Errorf("One of executable_users, filters, local_name_filter, or owners must be assigned")
} }
params := &ec2.DescribeImagesInput{} params := &ec2.DescribeImagesInput{}
@ -227,20 +234,33 @@ func dataSourceAwsAmiRead(d *schema.ResourceData, meta interface{}) error {
if err != nil { if err != nil {
return err 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 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.") 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 { if (d.Get("most_recent").(bool)) == true {
log.Printf("[DEBUG] aws_ami - multiple results found and most_recent is set") log.Printf("[DEBUG] aws_ami - multiple results found and most_recent is set")
image = mostRecentAmi(resp.Images) image = mostRecentAmi(filteredImages)
} else { } else {
log.Printf("[DEBUG] aws_ami - multiple results found and most_recent not set") 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.") return fmt.Errorf("Your query returned more than one result. Please try a more specific search, or set most_recent to true.")
} }
} else { } else {
log.Printf("[DEBUG] aws_ami - Single AMI found: %s", *resp.Images[0].ImageId) log.Printf("[DEBUG] aws_ami - Single AMI found: %s", *filteredImages[0].ImageId)
image = resp.Images[0] image = filteredImages[0]
} }
return amiDescriptionAttributes(d, image) return amiDescriptionAttributes(d, image)
} }

View File

@ -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 { func testAccCheckAwsAmiDataSourceDestroy(s *terraform.State) error {
return nil return nil
} }
@ -245,3 +261,16 @@ data "aws_ami" "amazon_ami" {
owners = ["amazon"] 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"
}
`

View File

@ -8,7 +8,7 @@ description: |-
# aws\_ami # 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. resources.
## Example Usage ## Example Usage
@ -25,6 +25,7 @@ data "aws_ami" "nat_ami" {
name = "name" name = "name"
values = ["amzn-ami-vpc-nat*"] values = ["amzn-ami-vpc-nat*"]
} }
local_name_filter = "^myami-\\d{3}"
owners = ["self"] owners = ["self"]
} }
``` ```
@ -41,6 +42,9 @@ recent AMI.
several valid keys, for a full reference, check out several valid keys, for a full reference, check out
[describe-images in the AWS CLI reference][1]. [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 * `owners` - (Optional) Limit search to specific AMI owners. Valid items are the numeric
account ID, `amazon`, or `self`. account ID, `amazon`, or `self`.