provider/aws: New Resource aws_ebs_snapshot (#10017)
* provider/aws: Add ability to create aws_ebs_snapshot ``` % make testacc TEST=./builtin/providers/aws TESTARGS='-run=TestAccAWSEBSSnapshot_' ==> Checking that code complies with gofmt requirements... go generate $(go list ./... | grep -v /terraform/vendor/) 2016/11/10 14:18:36 Generated command/internal_plugin_list.go TF_ACC=1 go test ./builtin/providers/aws -v -run=TestAccAWSEBSSnapshot_ -timeout 120m === RUN TestAccAWSEBSSnapshot_basic --- PASS: TestAccAWSEBSSnapshot_basic (31.56s) === RUN TestAccAWSEBSSnapshot_withDescription --- PASS: TestAccAWSEBSSnapshot_withDescription (189.35s) PASS ok github.com/hashicorp/terraform/builtin/providers/aws220.928s ``` * docs/aws: Addition of the docs for aws_ebs_snapshot resource * provider/aws: Creation of shared schema funcs for common AWS data source patterns * provider/aws: Create aws_ebs_snapshot datasource Fixes #8828 This data source will use a number of filters, owner_ids, snapshot_ids and restorable_by_user_ids in order to find the correct snapshot. The data source has no real use case for most_recent and will error on no snapshots found or greater than 1 snapshot found ``` % make testacc TEST=./builtin/providers/aws TESTARGS='-run=TestAccAWSEbsSnapshotDataSource_' ==> Checking that code complies with gofmt requirements... go generate $(go list ./... | grep -v /terraform/vendor/) 2016/11/10 14:34:33 Generated command/internal_plugin_list.go TF_ACC=1 go test ./builtin/providers/aws -v -run=TestAccAWSEbsSnapshotDataSource_ -timeout 120m === RUN TestAccAWSEbsSnapshotDataSource_basic --- PASS: TestAccAWSEbsSnapshotDataSource_basic (192.66s) === RUN TestAccAWSEbsSnapshotDataSource_multipleFilters --- PASS: TestAccAWSEbsSnapshotDataSource_multipleFilters (33.84s) PASS ok github.com/hashicorp/terraform/builtin/providers/aws226.522s ``` * docs/aws: Addition of docs for the aws_ebs_snapshot data source Adds the new resource `aws_ebs_snapshot`
This commit is contained in:
parent
a79092b86c
commit
7fde952d02
|
@ -8,7 +8,6 @@ import (
|
|||
"sort"
|
||||
"time"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/service/ec2"
|
||||
"github.com/hashicorp/terraform/helper/hashcode"
|
||||
"github.com/hashicorp/terraform/helper/schema"
|
||||
|
@ -19,31 +18,13 @@ func dataSourceAwsAmi() *schema.Resource {
|
|||
Read: dataSourceAwsAmiRead,
|
||||
|
||||
Schema: map[string]*schema.Schema{
|
||||
"filter": dataSourceFiltersSchema(),
|
||||
"executable_users": {
|
||||
Type: schema.TypeList,
|
||||
Optional: true,
|
||||
ForceNew: true,
|
||||
Elem: &schema.Schema{Type: schema.TypeString},
|
||||
},
|
||||
"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},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
"name_regex": {
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
|
@ -186,23 +167,7 @@ func dataSourceAwsAmi() *schema.Resource {
|
|||
Type: schema.TypeMap,
|
||||
Computed: true,
|
||||
},
|
||||
"tags": {
|
||||
Type: schema.TypeSet,
|
||||
Computed: true,
|
||||
Set: amiTagsHash,
|
||||
Elem: &schema.Resource{
|
||||
Schema: map[string]*schema.Schema{
|
||||
"key": {
|
||||
Type: schema.TypeString,
|
||||
Computed: true,
|
||||
},
|
||||
"value": {
|
||||
Type: schema.TypeString,
|
||||
Computed: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
"tags": dataSourceTagsSchema(),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
@ -225,7 +190,7 @@ func dataSourceAwsAmiRead(d *schema.ResourceData, meta interface{}) error {
|
|||
params.ExecutableUsers = expandStringList(executableUsers.([]interface{}))
|
||||
}
|
||||
if filtersOk {
|
||||
params.Filters = buildAmiFilters(filters.(*schema.Set))
|
||||
params.Filters = buildAwsDataSourceFilters(filters.(*schema.Set))
|
||||
}
|
||||
if ownersOk {
|
||||
params.Owners = expandStringList(owners.([]interface{}))
|
||||
|
@ -280,23 +245,6 @@ func dataSourceAwsAmiRead(d *schema.ResourceData, meta interface{}) error {
|
|||
return amiDescriptionAttributes(d, image)
|
||||
}
|
||||
|
||||
// Build a slice of AMI filter options from the filters provided.
|
||||
func buildAmiFilters(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 imageSort []*ec2.Image
|
||||
|
||||
func (a imageSort) Len() int { return len(a) }
|
||||
|
@ -361,7 +309,7 @@ func amiDescriptionAttributes(d *schema.ResourceData, image *ec2.Image) error {
|
|||
if err := d.Set("state_reason", amiStateReason(image.StateReason)); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := d.Set("tags", amiTags(image.Tags)); err != nil {
|
||||
if err := d.Set("tags", dataSourceTags(image.Tags)); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
|
@ -433,21 +381,6 @@ func amiStateReason(m *ec2.StateReason) map[string]interface{} {
|
|||
return s
|
||||
}
|
||||
|
||||
// Returns a set of tags.
|
||||
func amiTags(m []*ec2.Tag) *schema.Set {
|
||||
s := &schema.Set{
|
||||
F: amiTagsHash,
|
||||
}
|
||||
for _, v := range m {
|
||||
tag := map[string]interface{}{
|
||||
"key": *v.Key,
|
||||
"value": *v.Value,
|
||||
}
|
||||
s.Add(tag)
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// Generates a hash for the set hash function used by the block_device_mappings
|
||||
// attribute.
|
||||
func amiBlockDeviceMappingHash(v interface{}) int {
|
||||
|
@ -488,17 +421,6 @@ func amiProductCodesHash(v interface{}) int {
|
|||
return hashcode.String(buf.String())
|
||||
}
|
||||
|
||||
// Generates a hash for the set hash function used by the tags
|
||||
// attribute.
|
||||
func amiTagsHash(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())
|
||||
}
|
||||
|
||||
func validateNameRegex(v interface{}, k string) (ws []string, errors []error) {
|
||||
value := v.(string)
|
||||
|
||||
|
|
|
@ -0,0 +1,91 @@
|
|||
package aws
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/service/ec2"
|
||||
"github.com/hashicorp/terraform/helper/hashcode"
|
||||
"github.com/hashicorp/terraform/helper/schema"
|
||||
)
|
||||
|
||||
func dataSourceTagsHash(v interface{}) int {
|
||||
var buf bytes.Buffer
|
||||
m := v.(map[string]interface{})
|
||||
buf.WriteString(fmt.Sprintf("%s-", m["key"].(string)))
|
||||
buf.WriteString(fmt.Sprintf("%s-", m["value"].(string)))
|
||||
return hashcode.String(buf.String())
|
||||
}
|
||||
|
||||
func dataSourceTags(m []*ec2.Tag) *schema.Set {
|
||||
s := &schema.Set{
|
||||
F: dataSourceTagsHash,
|
||||
}
|
||||
for _, v := range m {
|
||||
tag := map[string]interface{}{
|
||||
"key": *v.Key,
|
||||
"value": *v.Value,
|
||||
}
|
||||
s.Add(tag)
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
func buildAwsDataSourceFilters(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
|
||||
}
|
||||
|
||||
func dataSourceFiltersSchema() *schema.Schema {
|
||||
return &schema.Schema{
|
||||
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},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func dataSourceTagsSchema() *schema.Schema {
|
||||
return &schema.Schema{
|
||||
Type: schema.TypeSet,
|
||||
Computed: true,
|
||||
Set: dataSourceTagsHash,
|
||||
Elem: &schema.Resource{
|
||||
Schema: map[string]*schema.Schema{
|
||||
"key": {
|
||||
Type: schema.TypeString,
|
||||
Computed: true,
|
||||
},
|
||||
"value": {
|
||||
Type: schema.TypeString,
|
||||
Computed: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
|
@ -0,0 +1,143 @@
|
|||
package aws
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/aws/aws-sdk-go/service/ec2"
|
||||
"github.com/hashicorp/terraform/helper/schema"
|
||||
)
|
||||
|
||||
func dataSourceAwsEbsSnapshot() *schema.Resource {
|
||||
return &schema.Resource{
|
||||
Read: dataSourceAwsEbsSnapshotRead,
|
||||
|
||||
Schema: map[string]*schema.Schema{
|
||||
//selection criteria
|
||||
"filter": dataSourceFiltersSchema(),
|
||||
|
||||
"owners": {
|
||||
Type: schema.TypeList,
|
||||
Optional: true,
|
||||
ForceNew: true,
|
||||
Elem: &schema.Schema{Type: schema.TypeString},
|
||||
},
|
||||
"snapshot_ids": {
|
||||
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},
|
||||
},
|
||||
//Computed values returned
|
||||
"snapshot_id": {
|
||||
Type: schema.TypeString,
|
||||
Computed: true,
|
||||
},
|
||||
"volume_id": {
|
||||
Type: schema.TypeString,
|
||||
Computed: true,
|
||||
},
|
||||
"state": {
|
||||
Type: schema.TypeString,
|
||||
Computed: true,
|
||||
},
|
||||
"owner_id": {
|
||||
Type: schema.TypeString,
|
||||
Computed: true,
|
||||
},
|
||||
"owner_alias": {
|
||||
Type: schema.TypeString,
|
||||
Computed: true,
|
||||
},
|
||||
"encrypted": {
|
||||
Type: schema.TypeBool,
|
||||
Computed: true,
|
||||
},
|
||||
"description": {
|
||||
Type: schema.TypeString,
|
||||
Computed: true,
|
||||
},
|
||||
"volume_size": {
|
||||
Type: schema.TypeInt,
|
||||
Computed: true,
|
||||
},
|
||||
"kms_key_id": {
|
||||
Type: schema.TypeString,
|
||||
Computed: true,
|
||||
},
|
||||
"data_encryption_key_id": {
|
||||
Type: schema.TypeString,
|
||||
Computed: true,
|
||||
},
|
||||
"tags": dataSourceTagsSchema(),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func dataSourceAwsEbsSnapshotRead(d *schema.ResourceData, meta interface{}) error {
|
||||
conn := meta.(*AWSClient).ec2conn
|
||||
|
||||
restorableUsers, restorableUsersOk := d.GetOk("restorable_by_user_ids")
|
||||
filters, filtersOk := d.GetOk("filter")
|
||||
snapshotIds, snapshotIdsOk := d.GetOk("snapshot_ids")
|
||||
owners, ownersOk := d.GetOk("owners")
|
||||
|
||||
if restorableUsers == false && filtersOk == false && snapshotIds == false && ownersOk == false {
|
||||
return fmt.Errorf("One of snapshot_ids, 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{}))
|
||||
}
|
||||
if snapshotIdsOk {
|
||||
params.SnapshotIds = expandStringList(snapshotIds.([]interface{}))
|
||||
}
|
||||
|
||||
resp, err := conn.DescribeSnapshots(params)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(resp.Snapshots) < 1 {
|
||||
return fmt.Errorf("Your query returned no results. Please change your search criteria and try again.")
|
||||
}
|
||||
|
||||
if len(resp.Snapshots) > 1 {
|
||||
return fmt.Errorf("Your query returned more than one result. Please try a more specific search criteria.")
|
||||
}
|
||||
|
||||
//Single Snapshot found so set to state
|
||||
return snapshotDescriptionAttributes(d, resp.Snapshots[0])
|
||||
}
|
||||
|
||||
func snapshotDescriptionAttributes(d *schema.ResourceData, snapshot *ec2.Snapshot) error {
|
||||
d.SetId(*snapshot.SnapshotId)
|
||||
d.Set("snapshot_id", snapshot.SnapshotId)
|
||||
d.Set("volume_id", snapshot.VolumeId)
|
||||
d.Set("data_encryption_key_id", snapshot.DataEncryptionKeyId)
|
||||
d.Set("description", snapshot.Description)
|
||||
d.Set("encrypted", snapshot.Encrypted)
|
||||
d.Set("kms_key_id", snapshot.KmsKeyId)
|
||||
d.Set("volume_size", snapshot.VolumeSize)
|
||||
d.Set("state", snapshot.State)
|
||||
d.Set("owner_id", snapshot.OwnerId)
|
||||
d.Set("owner_alias", snapshot.OwnerAlias)
|
||||
|
||||
if err := d.Set("tags", dataSourceTags(snapshot.Tags)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
|
@ -0,0 +1,97 @@
|
|||
package aws
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/terraform/helper/resource"
|
||||
"github.com/hashicorp/terraform/terraform"
|
||||
)
|
||||
|
||||
func TestAccAWSEbsSnapshotDataSource_basic(t *testing.T) {
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Providers: testAccProviders,
|
||||
Steps: []resource.TestStep{
|
||||
{
|
||||
Config: testAccCheckAwsEbsSnapshotDataSourceConfig,
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckAwsEbsSnapshotDataSourceID("data.aws_ebs_snapshot.snapshot"),
|
||||
resource.TestCheckResourceAttr("data.aws_ebs_snapshot.snapshot", "volume_size", "40"),
|
||||
),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func TestAccAWSEbsSnapshotDataSource_multipleFilters(t *testing.T) {
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Providers: testAccProviders,
|
||||
Steps: []resource.TestStep{
|
||||
{
|
||||
Config: testAccCheckAwsEbsSnapshotDataSourceConfigWithMultipleFilters,
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckAwsEbsSnapshotDataSourceID("data.aws_ebs_snapshot.snapshot"),
|
||||
resource.TestCheckResourceAttr("data.aws_ebs_snapshot.snapshot", "volume_size", "10"),
|
||||
),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func testAccCheckAwsEbsSnapshotDataSourceID(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("Snapshot data source ID not set")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
const testAccCheckAwsEbsSnapshotDataSourceConfig = `
|
||||
resource "aws_ebs_volume" "example" {
|
||||
availability_zone = "us-west-2a"
|
||||
type = "gp2"
|
||||
size = 40
|
||||
tags {
|
||||
Name = "External Volume"
|
||||
}
|
||||
}
|
||||
|
||||
resource "aws_ebs_snapshot" "snapshot" {
|
||||
volume_id = "${aws_ebs_volume.example.id}"
|
||||
}
|
||||
|
||||
data "aws_ebs_snapshot" "snapshot" {
|
||||
snapshot_ids = ["${aws_ebs_snapshot.snapshot.id}"]
|
||||
}
|
||||
`
|
||||
|
||||
const testAccCheckAwsEbsSnapshotDataSourceConfigWithMultipleFilters = `
|
||||
resource "aws_ebs_volume" "external1" {
|
||||
availability_zone = "us-west-2a"
|
||||
type = "gp2"
|
||||
size = 10
|
||||
tags {
|
||||
Name = "External Volume 1"
|
||||
}
|
||||
}
|
||||
|
||||
resource "aws_ebs_snapshot" "snapshot" {
|
||||
volume_id = "${aws_ebs_volume.external1.id}"
|
||||
}
|
||||
|
||||
data "aws_ebs_snapshot" "snapshot" {
|
||||
snapshot_ids = ["${aws_ebs_snapshot.snapshot.id}"]
|
||||
filter {
|
||||
name = "volume-size"
|
||||
values = ["10"]
|
||||
}
|
||||
}
|
||||
`
|
|
@ -1,15 +1,12 @@
|
|||
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"
|
||||
)
|
||||
|
||||
|
@ -18,25 +15,7 @@ func dataSourceAwsEbsVolume() *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},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
"filter": dataSourceFiltersSchema(),
|
||||
"most_recent": {
|
||||
Type: schema.TypeBool,
|
||||
Optional: true,
|
||||
|
@ -75,23 +54,7 @@ func dataSourceAwsEbsVolume() *schema.Resource {
|
|||
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,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
"tags": dataSourceTagsSchema(),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
@ -103,7 +66,7 @@ func dataSourceAwsEbsVolumeRead(d *schema.ResourceData, meta interface{}) error
|
|||
|
||||
params := &ec2.DescribeVolumesInput{}
|
||||
if filtersOk {
|
||||
params.Filters = buildVolumeFilters(filters.(*schema.Set))
|
||||
params.Filters = buildAwsDataSourceFilters(filters.(*schema.Set))
|
||||
}
|
||||
|
||||
resp, err := conn.DescribeVolumes(params)
|
||||
|
@ -138,22 +101,6 @@ func dataSourceAwsEbsVolumeRead(d *schema.ResourceData, meta interface{}) error
|
|||
return volumeDescriptionAttributes(d, volume)
|
||||
}
|
||||
|
||||
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) }
|
||||
|
@ -181,31 +128,9 @@ func volumeDescriptionAttributes(d *schema.ResourceData, volume *ec2.Volume) err
|
|||
d.Set("snapshot_id", volume.SnapshotId)
|
||||
d.Set("volume_type", volume.VolumeType)
|
||||
|
||||
if err := d.Set("tags", volumeTags(volume.Tags)); err != nil {
|
||||
if err := d.Set("tags", dataSourceTags(volume.Tags)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
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{})
|
||||
buf.WriteString(fmt.Sprintf("%s-", m["key"].(string)))
|
||||
buf.WriteString(fmt.Sprintf("%s-", m["value"].(string)))
|
||||
return hashcode.String(buf.String())
|
||||
}
|
||||
|
|
|
@ -152,6 +152,7 @@ func Provider() terraform.ResourceProvider {
|
|||
"aws_billing_service_account": dataSourceAwsBillingServiceAccount(),
|
||||
"aws_caller_identity": dataSourceAwsCallerIdentity(),
|
||||
"aws_cloudformation_stack": dataSourceAwsCloudFormationStack(),
|
||||
"aws_ebs_snapshot": dataSourceAwsEbsSnapshot(),
|
||||
"aws_ebs_volume": dataSourceAwsEbsVolume(),
|
||||
"aws_ecs_container_definition": dataSourceAwsEcsContainerDefinition(),
|
||||
"aws_elb_service_account": dataSourceAwsElbServiceAccount(),
|
||||
|
@ -223,6 +224,7 @@ func Provider() terraform.ResourceProvider {
|
|||
"aws_db_subnet_group": resourceAwsDbSubnetGroup(),
|
||||
"aws_directory_service_directory": resourceAwsDirectoryServiceDirectory(),
|
||||
"aws_dynamodb_table": resourceAwsDynamoDbTable(),
|
||||
"aws_ebs_snapshot": resourceAwsEbsSnapshot(),
|
||||
"aws_ebs_volume": resourceAwsEbsVolume(),
|
||||
"aws_ecr_repository": resourceAwsEcrRepository(),
|
||||
"aws_ecr_repository_policy": resourceAwsEcrRepositoryPolicy(),
|
||||
|
|
|
@ -0,0 +1,145 @@
|
|||
package aws
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"time"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/awserr"
|
||||
"github.com/aws/aws-sdk-go/service/ec2"
|
||||
"github.com/hashicorp/terraform/helper/resource"
|
||||
"github.com/hashicorp/terraform/helper/schema"
|
||||
)
|
||||
|
||||
func resourceAwsEbsSnapshot() *schema.Resource {
|
||||
return &schema.Resource{
|
||||
Create: resourceAwsEbsSnapshotCreate,
|
||||
Read: resourceAwsEbsSnapshotRead,
|
||||
Delete: resourceAwsEbsSnapshotDelete,
|
||||
|
||||
Schema: map[string]*schema.Schema{
|
||||
"volume_id": {
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
ForceNew: true,
|
||||
},
|
||||
"description": {
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
ForceNew: true,
|
||||
},
|
||||
"owner_id": {
|
||||
Type: schema.TypeString,
|
||||
Computed: true,
|
||||
},
|
||||
"owner_alias": {
|
||||
Type: schema.TypeString,
|
||||
Computed: true,
|
||||
},
|
||||
"encrypted": {
|
||||
Type: schema.TypeBool,
|
||||
Computed: true,
|
||||
},
|
||||
"volume_size": {
|
||||
Type: schema.TypeInt,
|
||||
Computed: true,
|
||||
},
|
||||
"kms_key_id": {
|
||||
Type: schema.TypeString,
|
||||
Computed: true,
|
||||
},
|
||||
"data_encryption_key_id": {
|
||||
Type: schema.TypeString,
|
||||
Computed: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func resourceAwsEbsSnapshotCreate(d *schema.ResourceData, meta interface{}) error {
|
||||
conn := meta.(*AWSClient).ec2conn
|
||||
|
||||
request := &ec2.CreateSnapshotInput{
|
||||
VolumeId: aws.String(d.Get("volume_id").(string)),
|
||||
}
|
||||
if v, ok := d.GetOk("description"); ok {
|
||||
request.Description = aws.String(v.(string))
|
||||
}
|
||||
|
||||
res, err := conn.CreateSnapshot(request)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
d.SetId(*res.SnapshotId)
|
||||
|
||||
err = resourceAwsEbsSnapshotWaitForAvailable(d.Id(), conn)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return resourceAwsEbsSnapshotRead(d, meta)
|
||||
}
|
||||
|
||||
func resourceAwsEbsSnapshotRead(d *schema.ResourceData, meta interface{}) error {
|
||||
conn := meta.(*AWSClient).ec2conn
|
||||
|
||||
req := &ec2.DescribeSnapshotsInput{
|
||||
SnapshotIds: []*string{aws.String(d.Id())},
|
||||
}
|
||||
res, err := conn.DescribeSnapshots(req)
|
||||
if ec2err, ok := err.(awserr.Error); ok && ec2err.Code() == "InvalidSnapshotID.NotFound" {
|
||||
log.Printf("Snapshot %q Not found - removing from state", d.Id())
|
||||
d.SetId("")
|
||||
return nil
|
||||
}
|
||||
|
||||
snapshot := res.Snapshots[0]
|
||||
|
||||
d.Set("description", snapshot.Description)
|
||||
d.Set("owner_id", snapshot.OwnerId)
|
||||
d.Set("encrypted", snapshot.Encrypted)
|
||||
d.Set("owner_alias", snapshot.OwnerAlias)
|
||||
d.Set("volume_id", snapshot.VolumeId)
|
||||
d.Set("data_encryption_key_id", snapshot.DataEncryptionKeyId)
|
||||
d.Set("kms_keey_id", snapshot.KmsKeyId)
|
||||
d.Set("volume_size", snapshot.VolumeSize)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func resourceAwsEbsSnapshotDelete(d *schema.ResourceData, meta interface{}) error {
|
||||
conn := meta.(*AWSClient).ec2conn
|
||||
|
||||
return resource.Retry(5*time.Minute, func() *resource.RetryError {
|
||||
request := &ec2.DeleteSnapshotInput{
|
||||
SnapshotId: aws.String(d.Id()),
|
||||
}
|
||||
_, err := conn.DeleteSnapshot(request)
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
ebsErr, ok := err.(awserr.Error)
|
||||
if ebsErr.Code() == "SnapshotInUse" {
|
||||
return resource.RetryableError(fmt.Errorf("EBS SnapshotInUse - trying again while it detaches"))
|
||||
}
|
||||
|
||||
if !ok {
|
||||
return resource.NonRetryableError(err)
|
||||
}
|
||||
|
||||
return resource.NonRetryableError(err)
|
||||
})
|
||||
}
|
||||
|
||||
func resourceAwsEbsSnapshotWaitForAvailable(id string, conn *ec2.EC2) error {
|
||||
log.Printf("Waiting for Snapshot %s to become available...", id)
|
||||
|
||||
req := &ec2.DescribeSnapshotsInput{
|
||||
SnapshotIds: []*string{aws.String(id)},
|
||||
}
|
||||
err := conn.WaitUntilSnapshotCompleted(req)
|
||||
return err
|
||||
}
|
|
@ -0,0 +1,95 @@
|
|||
package aws
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/service/ec2"
|
||||
"github.com/hashicorp/terraform/helper/resource"
|
||||
"github.com/hashicorp/terraform/terraform"
|
||||
)
|
||||
|
||||
func TestAccAWSEBSSnapshot_basic(t *testing.T) {
|
||||
var v ec2.Snapshot
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Providers: testAccProviders,
|
||||
Steps: []resource.TestStep{
|
||||
{
|
||||
Config: testAccAwsEbsSnapshotConfig,
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckSnapshotExists("aws_ebs_snapshot.test", &v),
|
||||
),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func TestAccAWSEBSSnapshot_withDescription(t *testing.T) {
|
||||
var v ec2.Snapshot
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Providers: testAccProviders,
|
||||
Steps: []resource.TestStep{
|
||||
{
|
||||
Config: testAccAwsEbsSnapshotConfigWithDescription,
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckSnapshotExists("aws_ebs_snapshot.test", &v),
|
||||
resource.TestCheckResourceAttr("aws_ebs_snapshot.test", "description", "EBS Snapshot Acceptance Test"),
|
||||
),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func testAccCheckSnapshotExists(n string, v *ec2.Snapshot) resource.TestCheckFunc {
|
||||
return func(s *terraform.State) error {
|
||||
rs, ok := s.RootModule().Resources[n]
|
||||
if !ok {
|
||||
return fmt.Errorf("Not found: %s", n)
|
||||
}
|
||||
|
||||
if rs.Primary.ID == "" {
|
||||
return fmt.Errorf("No ID is set")
|
||||
}
|
||||
|
||||
conn := testAccProvider.Meta().(*AWSClient).ec2conn
|
||||
|
||||
request := &ec2.DescribeSnapshotsInput{
|
||||
SnapshotIds: []*string{aws.String(rs.Primary.ID)},
|
||||
}
|
||||
|
||||
response, err := conn.DescribeSnapshots(request)
|
||||
if err == nil {
|
||||
if response.Snapshots != nil && len(response.Snapshots) > 0 {
|
||||
*v = *response.Snapshots[0]
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return fmt.Errorf("Error finding EC2 Snapshot %s", rs.Primary.ID)
|
||||
}
|
||||
}
|
||||
|
||||
const testAccAwsEbsSnapshotConfig = `
|
||||
resource "aws_ebs_volume" "test" {
|
||||
availability_zone = "us-west-2a"
|
||||
size = 1
|
||||
}
|
||||
|
||||
resource "aws_ebs_snapshot" "test" {
|
||||
volume_id = "${aws_ebs_volume.test.id}"
|
||||
}
|
||||
`
|
||||
|
||||
const testAccAwsEbsSnapshotConfigWithDescription = `
|
||||
resource "aws_ebs_volume" "description_test" {
|
||||
availability_zone = "us-west-2a"
|
||||
size = 1
|
||||
}
|
||||
|
||||
resource "aws_ebs_snapshot" "test" {
|
||||
volume_id = "${aws_ebs_volume.description_test.id}"
|
||||
description = "EBS Snapshot Acceptance Test"
|
||||
}
|
||||
`
|
|
@ -0,0 +1,61 @@
|
|||
---
|
||||
layout: "aws"
|
||||
page_title: "AWS: aws_ebs_snapshot"
|
||||
sidebar_current: "docs-aws-datasource-ebs-snapshot"
|
||||
description: |-
|
||||
Get information on an EBS Snapshot.
|
||||
---
|
||||
|
||||
# aws\_ebs\_snapshot
|
||||
|
||||
Use this data source to get information about an EBS Snapshot for use when provisioning EBS Volumes
|
||||
|
||||
## Example Usage
|
||||
|
||||
```
|
||||
data "aws_ebs_snapshot" "ebs_volume" {
|
||||
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.
|
||||
|
||||
* `snapshot_ids` - (Optional) Returns information on a specific snapshot_id.
|
||||
|
||||
* `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
|
||||
|
||||
The following attributes are exported:
|
||||
|
||||
* `id` - The snapshot ID (e.g. snap-59fcb34e).
|
||||
* `snapshot_id` - The snapshot ID (e.g. snap-59fcb34e).
|
||||
* `description` - A description for the snapshot
|
||||
* `owner_id` - The AWS account ID of the EBS snapshot owner.
|
||||
* `owner_alias` - Value from an Amazon-maintained list (`amazon`, `aws-marketplace`, `microsoft`) of snapshot owners.
|
||||
* `volume_id` - The volume ID (e.g. vol-59fcb34e).
|
||||
* `encrypted` - Whether the snapshot is encrypted.
|
||||
* `volume_size` - The size of the drive in GiBs.
|
||||
* `kms_key_id` - The ARN for the KMS encryption key.
|
||||
* `data_encryption_key_id` - The data encryption key identifier for the snapshot.
|
||||
* `state` - The snapshot state.
|
||||
* `tags` - A mapping of tags for the resource.
|
||||
|
||||
[1]: http://docs.aws.amazon.com/cli/latest/reference/ec2/describe-snapshots.html
|
|
@ -0,0 +1,48 @@
|
|||
---
|
||||
layout: "aws"
|
||||
page_title: "AWS: aws_ebs_snapshot"
|
||||
sidebar_current: "docs-aws-resource-ebs-snapshot"
|
||||
description: |-
|
||||
Provides an elastic block storage snapshot resource.
|
||||
---
|
||||
|
||||
# aws\_ebs\_snapshot
|
||||
|
||||
Creates a Snapshot of an EBS Volume.
|
||||
|
||||
## Example Usage
|
||||
|
||||
```
|
||||
resource "aws_ebs_volume" "example" {
|
||||
availability_zone = "us-west-2a"
|
||||
size = 40
|
||||
tags {
|
||||
Name = "HelloWorld"
|
||||
}
|
||||
}
|
||||
|
||||
resource "aws_ebs_snapshot" "example_snapshot" {
|
||||
volume_id = "${aws_ebs_volume.example.id}"
|
||||
}
|
||||
```
|
||||
|
||||
## Argument Reference
|
||||
|
||||
The following arguments are supported:
|
||||
|
||||
* `volume_id` - (Required) The Volume ID of which to make a snapshot.
|
||||
* `description` - (Optional) A description of what the snapshot is.
|
||||
|
||||
|
||||
## Attributes Reference
|
||||
|
||||
The following attributes are exported:
|
||||
|
||||
* `id` - The snapshot ID (e.g. snap-59fcb34e).
|
||||
* `owner_id` - The AWS account ID of the EBS snapshot owner.
|
||||
* `owner_alias` - Value from an Amazon-maintained list (`amazon`, `aws-marketplace`, `microsoft`) of snapshot owners.
|
||||
* `encrypted` - Whether the snapshot is encrypted.
|
||||
* `volume_size` - The size of the drive in GiBs.
|
||||
* `kms_key_id` - The ARN for the KMS encryption key.
|
||||
* `data_encryption_key_id` - The data encryption key identifier for the snapshot.
|
||||
* `tags` - A mapping of tags for the resource.
|
|
@ -20,6 +20,7 @@
|
|||
<li<%= sidebar_current("docs-aws-datasource-alb") %>>
|
||||
<a href="/docs/providers/aws/d/alb.html">aws_alb</a>
|
||||
</li>
|
||||
|
||||
<li<%= sidebar_current("docs-aws-datasource-ami") %>>
|
||||
<a href="/docs/providers/aws/d/ami.html">aws_ami</a>
|
||||
</li>
|
||||
|
@ -38,6 +39,9 @@
|
|||
<li<%= sidebar_current("docs-aws-datasource-cloudformation-stack") %>>
|
||||
<a href="/docs/providers/aws/d/cloudformation_stack.html">aws_cloudformation_stack</a>
|
||||
</li>
|
||||
<li<%= sidebar_current("docs-aws-datasource-ebs-snapshot") %>>
|
||||
<a href="/docs/providers/aws/d/ebs_snapshot.html">aws_ebs_snapshot</a>
|
||||
</li>
|
||||
<li<%= sidebar_current("docs-aws-datasource-ebs-volume") %>>
|
||||
<a href="/docs/providers/aws/d/ebs_volume.html">aws_ebs_volume</a>
|
||||
</li>
|
||||
|
@ -304,10 +308,6 @@
|
|||
<a href="/docs/providers/aws/r/autoscaling_group.html">aws_autoscaling_group</a>
|
||||
</li>
|
||||
|
||||
<li<%= sidebar_current("docs-aws-resource-autoscaling-attachment") %>>
|
||||
<a href="/docs/providers/aws/r/autoscaling_attachment.html">aws_autoscaling_attachment</a>
|
||||
</li>
|
||||
|
||||
<li<%= sidebar_current("docs-aws-resource-autoscaling-lifecycle-hook") %>>
|
||||
<a href="/docs/providers/aws/r/autoscaling_lifecycle_hooks.html">aws_autoscaling_lifecycle_hook</a>
|
||||
</li>
|
||||
|
@ -324,6 +324,10 @@
|
|||
<a href="/docs/providers/aws/r/autoscaling_schedule.html">aws_autoscaling_schedule</a>
|
||||
</li>
|
||||
|
||||
<li<%= sidebar_current("docs-aws-resource-ebs-snapshot") %>>
|
||||
<a href="/docs/providers/aws/r/ebs_snapshot.html">aws_ebs_snapshot</a>
|
||||
</li>
|
||||
|
||||
<li<%= sidebar_current("docs-aws-resource-ebs-volume") %>>
|
||||
<a href="/docs/providers/aws/r/ebs_volume.html">aws_ebs_volume</a>
|
||||
</li>
|
||||
|
@ -819,11 +823,11 @@
|
|||
<li<%= sidebar_current("docs-aws-resource-waf-webacl") %>>
|
||||
<a href="/docs/providers/aws/r/waf_web_acl.html">aws_waf_web_acl</a>
|
||||
</li>
|
||||
|
||||
|
||||
<li<%= sidebar_current("docs-aws-resource-waf-bytematchset") %>>
|
||||
<a href="/docs/providers/aws/r/waf_byte_match_set.html">aws_waf_byte_match_set</a>
|
||||
</li>
|
||||
|
||||
|
||||
<li<%= sidebar_current("docs-aws-resource-waf-size-constraint-set") %>>
|
||||
<a href="/docs/providers/aws/r/waf_size_constraint_set.html">aws_waf_size_constraint_set</a>
|
||||
</li>
|
||||
|
@ -835,7 +839,7 @@
|
|||
<li<%= sidebar_current("docs-aws-resource-waf-ipset") %>>
|
||||
<a href="/docs/providers/aws/r/waf_ipset.html">aws_waf_ipset</a>
|
||||
</li>
|
||||
|
||||
|
||||
<li<%= sidebar_current("docs-aws-resource-waf-xss-match-set") %>>
|
||||
<a href="/docs/providers/aws/r/waf_xss_match_set.html">aws_waf_xss_match_set</a>
|
||||
</li>
|
||||
|
|
Loading…
Reference in New Issue