Add `aws_ami_ids` and `aws_ebs_snapshot_ids` resources (#13844)

Fixes #12081. Adds new `aws_ami_ids` and `aws_ebs_snapshot_ids` resources.
This commit is contained in:
Joshua Spence 2017-04-21 23:37:26 +10:00 committed by Paul Stack
parent c2a1e688cb
commit 2aac8fb8fc
9 changed files with 411 additions and 2 deletions

View File

@ -0,0 +1,112 @@
package aws
import (
"fmt"
"log"
"regexp"
"github.com/aws/aws-sdk-go/service/ec2"
"github.com/hashicorp/terraform/helper/hashcode"
"github.com/hashicorp/terraform/helper/schema"
)
func dataSourceAwsAmiIds() *schema.Resource {
return &schema.Resource{
Read: dataSourceAwsAmiIdsRead,
Schema: map[string]*schema.Schema{
"filter": dataSourceFiltersSchema(),
"executable_users": {
Type: schema.TypeList,
Optional: true,
ForceNew: true,
Elem: &schema.Schema{Type: schema.TypeString},
},
"name_regex": {
Type: schema.TypeString,
Optional: true,
ForceNew: true,
ValidateFunc: validateNameRegex,
},
"owners": {
Type: schema.TypeList,
Optional: true,
ForceNew: true,
Elem: &schema.Schema{Type: schema.TypeString},
},
"tags": dataSourceTagsSchema(),
"ids": &schema.Schema{
Type: schema.TypeSet,
Computed: true,
Elem: &schema.Schema{Type: schema.TypeString},
Set: schema.HashString,
},
},
}
}
func dataSourceAwsAmiIdsRead(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*AWSClient).ec2conn
executableUsers, executableUsersOk := d.GetOk("executable_users")
filters, filtersOk := d.GetOk("filter")
nameRegex, nameRegexOk := d.GetOk("name_regex")
owners, ownersOk := d.GetOk("owners")
if executableUsersOk == false && filtersOk == false && nameRegexOk == false && ownersOk == false {
return fmt.Errorf("One of executable_users, filters, name_regex, or owners must be assigned")
}
params := &ec2.DescribeImagesInput{}
if executableUsersOk {
params.ExecutableUsers = expandStringList(executableUsers.([]interface{}))
}
if filtersOk {
params.Filters = buildAwsDataSourceFilters(filters.(*schema.Set))
}
if ownersOk {
o := expandStringList(owners.([]interface{}))
if len(o) > 0 {
params.Owners = o
}
}
resp, err := conn.DescribeImages(params)
if err != nil {
return err
}
var filteredImages []*ec2.Image
imageIds := make([]string, 0)
if nameRegexOk {
r := regexp.MustCompile(nameRegex.(string))
for _, image := range resp.Images {
// Check for a very rare case where the response would include no
// image name. No name means nothing to attempt a match against,
// therefore we are skipping such image.
if image.Name == nil || *image.Name == "" {
log.Printf("[WARN] Unable to find AMI name to match against "+
"for image ID %q owned by %q, nothing to do.",
*image.ImageId, *image.OwnerId)
continue
}
if r.MatchString(*image.Name) {
filteredImages = append(filteredImages, image)
}
}
} else {
filteredImages = resp.Images[:]
}
for _, image := range filteredImages {
imageIds = append(imageIds, *image.ImageId)
}
d.SetId(fmt.Sprintf("%d", hashcode.String(params.String())))
d.Set("ids", imageIds)
return nil
}

View File

@ -0,0 +1,58 @@
package aws
import (
"testing"
"github.com/hashicorp/terraform/helper/resource"
)
func TestAccDataSourceAwsAmiIds_basic(t *testing.T) {
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
Steps: []resource.TestStep{
{
Config: testAccDataSourceAwsAmiIdsConfig_basic,
Check: resource.ComposeTestCheckFunc(
testAccCheckAwsAmiDataSourceID("data.aws_ami_ids.ubuntu"),
),
},
},
})
}
func TestAccDataSourceAwsAmiIds_empty(t *testing.T) {
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
Steps: []resource.TestStep{
{
Config: testAccDataSourceAwsAmiIdsConfig_empty,
Check: resource.ComposeTestCheckFunc(
testAccCheckAwsAmiDataSourceID("data.aws_ami_ids.empty"),
resource.TestCheckResourceAttr("data.aws_ami_ids.empty", "ids.#", "0"),
),
},
},
})
}
const testAccDataSourceAwsAmiIdsConfig_basic = `
data "aws_ami_ids" "ubuntu" {
owners = ["099720109477"]
filter {
name = "name"
values = ["ubuntu/images/ubuntu-*-*-amd64-server-*"]
}
}
`
const testAccDataSourceAwsAmiIdsConfig_empty = `
data "aws_ami_ids" "empty" {
filter {
name = "name"
values = []
}
}
`

View File

@ -0,0 +1,78 @@
package aws
import (
"fmt"
"github.com/aws/aws-sdk-go/service/ec2"
"github.com/hashicorp/terraform/helper/hashcode"
"github.com/hashicorp/terraform/helper/schema"
)
func dataSourceAwsEbsSnapshotIds() *schema.Resource {
return &schema.Resource{
Read: dataSourceAwsEbsSnapshotIdsRead,
Schema: map[string]*schema.Schema{
"filter": dataSourceFiltersSchema(),
"owners": {
Type: schema.TypeList,
Optional: true,
ForceNew: true,
Elem: &schema.Schema{Type: schema.TypeString},
},
"restorable_by_user_ids": {
Type: schema.TypeList,
Optional: true,
ForceNew: true,
Elem: &schema.Schema{Type: schema.TypeString},
},
"tags": dataSourceTagsSchema(),
"ids": &schema.Schema{
Type: schema.TypeSet,
Computed: true,
Elem: &schema.Schema{Type: schema.TypeString},
Set: schema.HashString,
},
},
}
}
func dataSourceAwsEbsSnapshotIdsRead(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*AWSClient).ec2conn
restorableUsers, restorableUsersOk := d.GetOk("restorable_by_user_ids")
filters, filtersOk := d.GetOk("filter")
owners, ownersOk := d.GetOk("owners")
if restorableUsers == false && filtersOk == false && ownersOk == false {
return fmt.Errorf("One of filters, restorable_by_user_ids, or owners must be assigned")
}
params := &ec2.DescribeSnapshotsInput{}
if restorableUsersOk {
params.RestorableByUserIds = expandStringList(restorableUsers.([]interface{}))
}
if filtersOk {
params.Filters = buildAwsDataSourceFilters(filters.(*schema.Set))
}
if ownersOk {
params.OwnerIds = expandStringList(owners.([]interface{}))
}
resp, err := conn.DescribeSnapshots(params)
if err != nil {
return err
}
snapshotIds := make([]string, 0)
for _, snapshot := range resp.Snapshots {
snapshotIds = append(snapshotIds, *snapshot.SnapshotId)
}
d.SetId(fmt.Sprintf("%d", hashcode.String(params.String())))
d.Set("ids", snapshotIds)
return nil
}

View File

@ -0,0 +1,59 @@
package aws
import (
"testing"
"github.com/hashicorp/terraform/helper/resource"
)
func TestAccDataSourceAwsEbsSnapshotIds_basic(t *testing.T) {
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
Steps: []resource.TestStep{
{
Config: testAccDataSourceAwsEbsSnapshotIdsConfig_basic,
Check: resource.ComposeTestCheckFunc(
testAccCheckAwsEbsSnapshotDataSourceID("data.aws_ebs_snapshot_ids.test"),
),
},
},
})
}
func TestAccDataSourceAwsEbsSnapshotIds_empty(t *testing.T) {
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
Steps: []resource.TestStep{
{
Config: testAccDataSourceAwsEbsSnapshotIdsConfig_empty,
Check: resource.ComposeTestCheckFunc(
testAccCheckAwsEbsSnapshotDataSourceID("data.aws_ebs_snapshot_ids.empty"),
resource.TestCheckResourceAttr("data.aws_ebs_snapshot_ids.empty", "ids.#", "0"),
),
},
},
})
}
const testAccDataSourceAwsEbsSnapshotIdsConfig_basic = `
resource "aws_ebs_volume" "test" {
availability_zone = "us-west-2a"
size = 40
}
resource "aws_ebs_snapshot" "test" {
volume_id = "${aws_ebs_volume.test.id}"
}
data "aws_ebs_snapshot_ids" "test" {
owners = ["self"]
}
`
const testAccDataSourceAwsEbsSnapshotIdsConfig_empty = `
data "aws_ebs_snapshot_ids" "empty" {
owners = ["000000000000"]
}
`

View File

@ -44,7 +44,7 @@ func testAccCheckAwsEbsSnapshotDataSourceID(n string) resource.TestCheckFunc {
return func(s *terraform.State) error { return func(s *terraform.State) error {
rs, ok := s.RootModule().Resources[n] rs, ok := s.RootModule().Resources[n]
if !ok { if !ok {
return fmt.Errorf("Can't find Volume data source: %s", n) return fmt.Errorf("Can't find snapshot data source: %s", n)
} }
if rs.Primary.ID == "" { if rs.Primary.ID == "" {

View File

@ -163,6 +163,7 @@ func Provider() terraform.ResourceProvider {
"aws_alb": dataSourceAwsAlb(), "aws_alb": dataSourceAwsAlb(),
"aws_alb_listener": dataSourceAwsAlbListener(), "aws_alb_listener": dataSourceAwsAlbListener(),
"aws_ami": dataSourceAwsAmi(), "aws_ami": dataSourceAwsAmi(),
"aws_ami_ids": dataSourceAwsAmiIds(),
"aws_autoscaling_groups": dataSourceAwsAutoscalingGroups(), "aws_autoscaling_groups": dataSourceAwsAutoscalingGroups(),
"aws_availability_zone": dataSourceAwsAvailabilityZone(), "aws_availability_zone": dataSourceAwsAvailabilityZone(),
"aws_availability_zones": dataSourceAwsAvailabilityZones(), "aws_availability_zones": dataSourceAwsAvailabilityZones(),
@ -172,6 +173,7 @@ func Provider() terraform.ResourceProvider {
"aws_cloudformation_stack": dataSourceAwsCloudFormationStack(), "aws_cloudformation_stack": dataSourceAwsCloudFormationStack(),
"aws_db_instance": dataSourceAwsDbInstance(), "aws_db_instance": dataSourceAwsDbInstance(),
"aws_ebs_snapshot": dataSourceAwsEbsSnapshot(), "aws_ebs_snapshot": dataSourceAwsEbsSnapshot(),
"aws_ebs_snapshot_ids": dataSourceAwsEbsSnapshotIds(),
"aws_ebs_volume": dataSourceAwsEbsVolume(), "aws_ebs_volume": dataSourceAwsEbsVolume(),
"aws_ecs_cluster": dataSourceAwsEcsCluster(), "aws_ecs_cluster": dataSourceAwsEcsCluster(),
"aws_ecs_container_definition": dataSourceAwsEcsContainerDefinition(), "aws_ecs_container_definition": dataSourceAwsEcsContainerDefinition(),

View File

@ -59,7 +59,8 @@ options to narrow down the list AWS returns.
~> **NOTE:** If more or less than a single match is returned by the search, ~> **NOTE:** If more or less than a single match is returned by the search,
Terraform will fail. Ensure that your search is specific enough to return Terraform will fail. Ensure that your search is specific enough to return
a single AMI ID only, or use `most_recent` to choose the most recent one. a single AMI ID only, or use `most_recent` to choose the most recent one. If
you want to match multiple AMIs, use the `aws_ami_ids` data source instead.
## Attributes Reference ## Attributes Reference

View File

@ -0,0 +1,51 @@
---
layout: "aws"
page_title: "AWS: aws_ami_ids"
sidebar_current: "docs-aws-datasource-ami-ids"
description: |-
Provides a list of AMI IDs.
---
# aws\_ami_ids
Use this data source to get a list of AMI IDs matching the specified criteria.
## Example Usage
```hcl
data "aws_ami_ids" "ubuntu" {
owners = ["099720109477"]
filter {
name = "name"
values = ["ubuntu/images/ubuntu-*-*-amd64-server-*"]
}
}
```
## Argument Reference
* `executable_users` - (Optional) Limit search to users with *explicit* launch
permission on the image. Valid items are the numeric account ID or `self`.
* `filter` - (Optional) One or more name/value pairs to filter off of. There
are several valid keys, for a full reference, check out
[describe-images in the AWS CLI reference][1].
* `owners` - (Optional) Limit search to specific AMI owners. Valid items are
the numeric account ID, `amazon`, or `self`.
* `name_regex` - (Optional) A regex string to apply to the AMI list returned
by AWS. This allows more advanced filtering not supported from the AWS API.
This filtering is done locally on what AWS returns, and could have a performance
impact if the result is large. It is recommended to combine this with other
options to narrow down the list AWS returns.
~> **NOTE:** At least one of `executable_users`, `filter`, `owners` or
`name_regex` must be specified.
## Attributes Reference
`ids` is set to the list of AMI IDs.
[1]: http://docs.aws.amazon.com/cli/latest/reference/ec2/describe-images.html

View File

@ -0,0 +1,48 @@
---
layout: "aws"
page_title: "AWS: aws_ebs_snapshot_ids"
sidebar_current: "docs-aws-datasource-ebs-snapshot-ids"
description: |-
Provides a list of EBS snapshot IDs.
---
# aws\_ebs\_snapshot\_ids
Use this data source to get a list of EBS Snapshot IDs matching the specified
criteria.
## Example Usage
```hcl
data "aws_ebs_snapshot_ids" "ebs_volumes" {
owners = ["self"]
filter {
name = "volume-size"
values = ["40"]
}
filter {
name = "tag:Name"
values = ["Example"]
}
}
```
## Argument Reference
The following arguments are supported:
* `owners` - (Optional) Returns the snapshots owned by the specified owner id. Multiple owners can be specified.
* `restorable_by_user_ids` - (Optional) One or more AWS accounts IDs that can create volumes from the snapshot.
* `filter` - (Optional) One or more name/value pairs to filter off of. There are
several valid keys, for a full reference, check out
[describe-volumes in the AWS CLI reference][1].
## Attributes Reference
`ids` is set to the list of EBS snapshot IDs.
[1]: http://docs.aws.amazon.com/cli/latest/reference/ec2/describe-snapshots.html