-
Notifications
You must be signed in to change notification settings - Fork 9.7k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
provider/aws: Adding a datasource for aws_ebs_volume
This will allows us to filter a specific ebs_volume for attachment to an aws_instance ``` make testacc TEST=./builtin/providers/aws TESTARGS='-run=TestAccAWSEbsVolumeDataSource_'✹ ==> Checking that code complies with gofmt requirements... go generate $(go list ./... | grep -v /terraform/vendor/) 2016/11/01 12:39:19 Generated command/internal_plugin_list.go TF_ACC=1 go test ./builtin/providers/aws -v -run=TestAccAWSEbsVolumeDataSource_ -timeout 120m === RUN TestAccAWSEbsVolumeDataSource_basic --- PASS: TestAccAWSEbsVolumeDataSource_basic (28.74s) === RUN TestAccAWSEbsVolumeDataSource_multipleFilters --- PASS: TestAccAWSEbsVolumeDataSource_multipleFilters (28.37s) PASS ok github.com/hashicorp/terraform/builtin/providers/aws57.145s ```
- Loading branch information
Showing
6 changed files
with
385 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,216 @@ | ||
package aws | ||
|
||
import ( | ||
"bytes" | ||
"fmt" | ||
"log" | ||
"sort" | ||
|
||
"github.com/aws/aws-sdk-go/aws" | ||
"github.com/aws/aws-sdk-go/service/ec2" | ||
"github.com/davecgh/go-spew/spew" | ||
"github.com/hashicorp/terraform/helper/hashcode" | ||
"github.com/hashicorp/terraform/helper/schema" | ||
) | ||
|
||
func dataSourceAwsEbsVolume() *schema.Resource { | ||
return &schema.Resource{ | ||
Read: dataSourceAwsEbsVolumeRead, | ||
|
||
Schema: map[string]*schema.Schema{ | ||
"filter": { | ||
Type: schema.TypeSet, | ||
Optional: true, | ||
ForceNew: true, | ||
Elem: &schema.Resource{ | ||
Schema: map[string]*schema.Schema{ | ||
"name": { | ||
Type: schema.TypeString, | ||
Required: true, | ||
}, | ||
|
||
"values": { | ||
Type: schema.TypeList, | ||
Required: true, | ||
Elem: &schema.Schema{Type: schema.TypeString}, | ||
}, | ||
}, | ||
}, | ||
}, | ||
"most_recent": { | ||
Type: schema.TypeBool, | ||
Optional: true, | ||
Default: false, | ||
ForceNew: true, | ||
}, | ||
"availability_zone": { | ||
Type: schema.TypeString, | ||
Computed: true, | ||
}, | ||
"encrypted": { | ||
Type: schema.TypeBool, | ||
Computed: true, | ||
}, | ||
"iops": { | ||
Type: schema.TypeInt, | ||
Computed: true, | ||
}, | ||
"volume_type": { | ||
Type: schema.TypeString, | ||
Computed: true, | ||
}, | ||
"size": { | ||
Type: schema.TypeInt, | ||
Computed: true, | ||
}, | ||
"snapshot_id": { | ||
Type: schema.TypeString, | ||
Computed: true, | ||
}, | ||
"kms_key_id": { | ||
Type: schema.TypeString, | ||
Computed: true, | ||
}, | ||
"volume_id": { | ||
Type: schema.TypeString, | ||
Computed: true, | ||
}, | ||
"tags": { | ||
Type: schema.TypeSet, | ||
Computed: true, | ||
Set: volumeTagsHash, | ||
Elem: &schema.Resource{ | ||
Schema: map[string]*schema.Schema{ | ||
"key": { | ||
Type: schema.TypeString, | ||
Computed: true, | ||
}, | ||
"value": { | ||
Type: schema.TypeString, | ||
Computed: true, | ||
}, | ||
}, | ||
}, | ||
}, | ||
}, | ||
} | ||
} | ||
|
||
func dataSourceAwsEbsVolumeRead(d *schema.ResourceData, meta interface{}) error { | ||
conn := meta.(*AWSClient).ec2conn | ||
|
||
filters, filtersOk := d.GetOk("filter") | ||
|
||
params := &ec2.DescribeVolumesInput{} | ||
if filtersOk { | ||
params.Filters = buildVolumeFilters(filters.(*schema.Set)) | ||
} | ||
|
||
resp, err := conn.DescribeVolumes(params) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
log.Printf("Found These Volumes %s", spew.Sdump(resp.Volumes)) | ||
|
||
filteredVolumes := resp.Volumes[:] | ||
|
||
var volume *ec2.Volume | ||
if len(filteredVolumes) < 1 { | ||
return fmt.Errorf("Your query returned no results. Please change your search criteria and try again.") | ||
} | ||
|
||
if len(filteredVolumes) > 1 { | ||
recent := d.Get("most_recent").(bool) | ||
log.Printf("[DEBUG] aws_ebs_volume - multiple results found and `most_recent` is set to: %t", recent) | ||
if recent { | ||
volume = mostRecentVolume(filteredVolumes) | ||
} else { | ||
return fmt.Errorf("Your query returned more than one result. Please try a more " + | ||
"specific search criteria, or set `most_recent` attribute to true.") | ||
} | ||
} else { | ||
// Query returned single result. | ||
volume = filteredVolumes[0] | ||
} | ||
|
||
log.Printf("[DEBUG] aws_volume - Single Volume found: %s", *volume.VolumeId) | ||
return volumeDescriptionAttributes(d, volume) | ||
} | ||
|
||
// Build a slice of AMI filter options from the filters provided. | ||
func buildVolumeFilters(set *schema.Set) []*ec2.Filter { | ||
var filters []*ec2.Filter | ||
for _, v := range set.List() { | ||
m := v.(map[string]interface{}) | ||
var filterValues []*string | ||
for _, e := range m["values"].([]interface{}) { | ||
filterValues = append(filterValues, aws.String(e.(string))) | ||
} | ||
filters = append(filters, &ec2.Filter{ | ||
Name: aws.String(m["name"].(string)), | ||
Values: filterValues, | ||
}) | ||
} | ||
return filters | ||
} | ||
|
||
type volumeSort []*ec2.Volume | ||
|
||
func (a volumeSort) Len() int { return len(a) } | ||
func (a volumeSort) Swap(i, j int) { a[i], a[j] = a[j], a[i] } | ||
func (a volumeSort) Less(i, j int) bool { | ||
itime := *a[i].CreateTime | ||
jtime := *a[j].CreateTime | ||
return itime.Unix() < jtime.Unix() | ||
} | ||
|
||
func mostRecentVolume(volumes []*ec2.Volume) *ec2.Volume { | ||
sortedVolumes := volumes | ||
sort.Sort(volumeSort(sortedVolumes)) | ||
return sortedVolumes[len(sortedVolumes)-1] | ||
} | ||
|
||
// populate the numerous fields that the image description returns. | ||
func volumeDescriptionAttributes(d *schema.ResourceData, volume *ec2.Volume) error { | ||
// Simple attributes first | ||
d.SetId(*volume.VolumeId) | ||
d.Set("volume_id", volume.VolumeId) | ||
d.Set("availability_zone", volume.AvailabilityZone) | ||
d.Set("encrypted", volume.Encrypted) | ||
d.Set("iops", volume.Iops) | ||
d.Set("kms_key_id", volume.KmsKeyId) | ||
d.Set("size", volume.Size) | ||
d.Set("snapshot_id", volume.SnapshotId) | ||
d.Set("volume_type", volume.VolumeType) | ||
|
||
if err := d.Set("tags", volumeTags(volume.Tags)); err != nil { | ||
return err | ||
} | ||
|
||
return nil | ||
} | ||
|
||
// Returns a set of tags. | ||
func volumeTags(m []*ec2.Tag) *schema.Set { | ||
s := &schema.Set{ | ||
F: volumeTagsHash, | ||
} | ||
for _, v := range m { | ||
tag := map[string]interface{}{ | ||
"key": *v.Key, | ||
"value": *v.Value, | ||
} | ||
s.Add(tag) | ||
} | ||
return s | ||
} | ||
|
||
func volumeTagsHash(v interface{}) int { | ||
var buf bytes.Buffer | ||
m := v.(map[string]interface{}) | ||
// All keys added in alphabetical order. | ||
buf.WriteString(fmt.Sprintf("%s-", m["key"].(string))) | ||
buf.WriteString(fmt.Sprintf("%s-", m["value"].(string))) | ||
return hashcode.String(buf.String()) | ||
} |
106 changes: 106 additions & 0 deletions
106
builtin/providers/aws/data_source_aws_ebs_volume_test.go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,106 @@ | ||
package aws | ||
|
||
import ( | ||
"fmt" | ||
"testing" | ||
|
||
"github.com/hashicorp/terraform/helper/resource" | ||
"github.com/hashicorp/terraform/terraform" | ||
) | ||
|
||
func TestAccAWSEbsVolumeDataSource_basic(t *testing.T) { | ||
resource.Test(t, resource.TestCase{ | ||
PreCheck: func() { testAccPreCheck(t) }, | ||
Providers: testAccProviders, | ||
Steps: []resource.TestStep{ | ||
{ | ||
Config: testAccCheckAwsEbsVolumeDataSourceConfig, | ||
Check: resource.ComposeTestCheckFunc( | ||
testAccCheckAwsEbsVolumeDataSourceID("data.aws_ebs_volume.ebs_volume"), | ||
resource.TestCheckResourceAttr("data.aws_ebs_volume.ebs_volume", "size", "40"), | ||
), | ||
}, | ||
}, | ||
}) | ||
} | ||
|
||
func TestAccAWSEbsVolumeDataSource_multipleFilters(t *testing.T) { | ||
resource.Test(t, resource.TestCase{ | ||
PreCheck: func() { testAccPreCheck(t) }, | ||
Providers: testAccProviders, | ||
Steps: []resource.TestStep{ | ||
{ | ||
Config: testAccCheckAwsEbsVolumeDataSourceConfigWithMultipleFilters, | ||
Check: resource.ComposeTestCheckFunc( | ||
testAccCheckAwsEbsVolumeDataSourceID("data.aws_ebs_volume.ebs_volume"), | ||
resource.TestCheckResourceAttr("data.aws_ebs_volume.ebs_volume", "size", "10"), | ||
resource.TestCheckResourceAttr("data.aws_ebs_volume.ebs_volume", "volume_type", "gp2"), | ||
), | ||
}, | ||
}, | ||
}) | ||
} | ||
|
||
func testAccCheckAwsEbsVolumeDataSourceID(n string) resource.TestCheckFunc { | ||
return func(s *terraform.State) error { | ||
rs, ok := s.RootModule().Resources[n] | ||
if !ok { | ||
return fmt.Errorf("Can't find Volume data source: %s", n) | ||
} | ||
|
||
if rs.Primary.ID == "" { | ||
return fmt.Errorf("Volume data source ID not set") | ||
} | ||
return nil | ||
} | ||
} | ||
|
||
const testAccCheckAwsEbsVolumeDataSourceConfig = ` | ||
resource "aws_ebs_volume" "example" { | ||
availability_zone = "us-west-2a" | ||
type = "gp2" | ||
size = 40 | ||
tags { | ||
Name = "External Volume" | ||
} | ||
} | ||
data "aws_ebs_volume" "ebs_volume" { | ||
most_recent = true | ||
filter { | ||
name = "tag:Name" | ||
values = ["External Volume"] | ||
} | ||
filter { | ||
name = "volume-type" | ||
values = ["${aws_ebs_volume.example.type}"] | ||
} | ||
} | ||
` | ||
|
||
const testAccCheckAwsEbsVolumeDataSourceConfigWithMultipleFilters = ` | ||
resource "aws_ebs_volume" "external1" { | ||
availability_zone = "us-west-2a" | ||
type = "gp2" | ||
size = 10 | ||
tags { | ||
Name = "External Volume 1" | ||
} | ||
} | ||
data "aws_ebs_volume" "ebs_volume" { | ||
most_recent = true | ||
filter { | ||
name = "tag:Name" | ||
values = ["External Volume 1"] | ||
} | ||
filter { | ||
name = "size" | ||
values = ["${aws_ebs_volume.external1.size}"] | ||
} | ||
filter { | ||
name = "volume-type" | ||
values = ["${aws_ebs_volume.external1.type}"] | ||
} | ||
} | ||
` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.