Merge pull request #440 from buth/awsblockdevices
AWS Instance `block_device` Attribute
This commit is contained in:
commit
4303232533
|
@ -1,6 +1,7 @@
|
||||||
package aws
|
package aws
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"crypto/sha1"
|
"crypto/sha1"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
@ -125,6 +126,52 @@ func resourceAwsInstance() *schema.Resource {
|
||||||
Optional: true,
|
Optional: true,
|
||||||
},
|
},
|
||||||
"tags": tagsSchema(),
|
"tags": tagsSchema(),
|
||||||
|
|
||||||
|
"block_device": &schema.Schema{
|
||||||
|
Type: schema.TypeSet,
|
||||||
|
Optional: true,
|
||||||
|
Elem: &schema.Resource{
|
||||||
|
Schema: map[string]*schema.Schema{
|
||||||
|
"device_name": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Required: true,
|
||||||
|
ForceNew: true,
|
||||||
|
},
|
||||||
|
|
||||||
|
"snapshot_id": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Optional: true,
|
||||||
|
ForceNew: true,
|
||||||
|
},
|
||||||
|
|
||||||
|
"volume_type": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Optional: true,
|
||||||
|
ForceNew: true,
|
||||||
|
},
|
||||||
|
|
||||||
|
"volume_size": &schema.Schema{
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Optional: true,
|
||||||
|
ForceNew: true,
|
||||||
|
},
|
||||||
|
|
||||||
|
"delete_on_termination": &schema.Schema{
|
||||||
|
Type: schema.TypeBool,
|
||||||
|
Optional: true,
|
||||||
|
Default: true,
|
||||||
|
ForceNew: true,
|
||||||
|
},
|
||||||
|
|
||||||
|
"encrypted": &schema.Schema{
|
||||||
|
Type: schema.TypeBool,
|
||||||
|
Optional: true,
|
||||||
|
ForceNew: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Set: resourceAwsInstanceBlockDevicesHash,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -173,6 +220,22 @@ func resourceAwsInstanceCreate(d *schema.ResourceData, meta interface{}) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if v := d.Get("block_device"); v != nil {
|
||||||
|
vs := v.(*schema.Set).List()
|
||||||
|
if len(vs) > 0 {
|
||||||
|
runOpts.BlockDevices = make([]ec2.BlockDeviceMapping, len(vs))
|
||||||
|
for i, v := range vs {
|
||||||
|
bd := v.(map[string]interface{})
|
||||||
|
runOpts.BlockDevices[i].DeviceName = bd["device_name"].(string)
|
||||||
|
runOpts.BlockDevices[i].SnapshotId = bd["snapshot_id"].(string)
|
||||||
|
runOpts.BlockDevices[i].VolumeType = bd["volume_type"].(string)
|
||||||
|
runOpts.BlockDevices[i].VolumeSize = int64(bd["volume_size"].(int))
|
||||||
|
runOpts.BlockDevices[i].DeleteOnTermination = bd["delete_on_termination"].(bool)
|
||||||
|
runOpts.BlockDevices[i].Encrypted = bd["encrypted"].(bool)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Create the instance
|
// Create the instance
|
||||||
log.Printf("[DEBUG] Run configuration: %#v", runOpts)
|
log.Printf("[DEBUG] Run configuration: %#v", runOpts)
|
||||||
runResp, err := ec2conn.RunInstances(runOpts)
|
runResp, err := ec2conn.RunInstances(runOpts)
|
||||||
|
@ -360,6 +423,30 @@ func resourceAwsInstanceRead(d *schema.ResourceData, meta interface{}) error {
|
||||||
}
|
}
|
||||||
d.Set("security_groups", sgs)
|
d.Set("security_groups", sgs)
|
||||||
|
|
||||||
|
volIDs := make([]string, len(instance.BlockDevices))
|
||||||
|
bdByVolID := make(map[string]ec2.BlockDevice)
|
||||||
|
for i, bd := range instance.BlockDevices {
|
||||||
|
volIDs[i] = bd.VolumeId
|
||||||
|
bdByVolID[bd.VolumeId] = bd
|
||||||
|
}
|
||||||
|
|
||||||
|
volResp, err := ec2conn.Volumes(volIDs, ec2.NewFilter())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
bds := make([]map[string]interface{}, len(instance.BlockDevices))
|
||||||
|
for i, vol := range volResp.Volumes {
|
||||||
|
bds[i] = make(map[string]interface{})
|
||||||
|
bds[i]["device_name"] = bdByVolID[vol.VolumeId].DeviceName
|
||||||
|
bds[i]["snapshot_id"] = vol.SnapshotId
|
||||||
|
bds[i]["volume_type"] = vol.VolumeType
|
||||||
|
bds[i]["volume_size"] = vol.Size
|
||||||
|
bds[i]["delete_on_termination"] = bdByVolID[vol.VolumeId].DeleteOnTermination
|
||||||
|
bds[i]["encrypted"] = vol.Encrypted
|
||||||
|
}
|
||||||
|
d.Set("block_device", bds)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -388,3 +475,15 @@ func InstanceStateRefreshFunc(conn *ec2.EC2, instanceID string) resource.StateRe
|
||||||
return i, i.State.Name, nil
|
return i, i.State.Name, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func resourceAwsInstanceBlockDevicesHash(v interface{}) int {
|
||||||
|
var buf bytes.Buffer
|
||||||
|
m := v.(map[string]interface{})
|
||||||
|
buf.WriteString(fmt.Sprintf("%s-", m["device_name"].(string)))
|
||||||
|
buf.WriteString(fmt.Sprintf("%s-", m["snapshot_id"].(string)))
|
||||||
|
buf.WriteString(fmt.Sprintf("%s-", m["volume_type"].(string)))
|
||||||
|
buf.WriteString(fmt.Sprintf("%d-", m["volume_size"].(int)))
|
||||||
|
buf.WriteString(fmt.Sprintf("%t-", m["delete_on_termination"].(bool)))
|
||||||
|
buf.WriteString(fmt.Sprintf("%t-", m["encrypted"].(bool)))
|
||||||
|
return hashcode.String(buf.String())
|
||||||
|
}
|
||||||
|
|
|
@ -64,6 +64,44 @@ func TestAccAWSInstance_normal(t *testing.T) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestAccAWSInstance_blockDevicesCheck(t *testing.T) {
|
||||||
|
var v ec2.Instance
|
||||||
|
|
||||||
|
testCheck := func() resource.TestCheckFunc {
|
||||||
|
return func(*terraform.State) error {
|
||||||
|
|
||||||
|
// Map out the block devices by name, which should be unique.
|
||||||
|
blockDevices := make(map[string]ec2.BlockDevice)
|
||||||
|
for _, blockDevice := range v.BlockDevices {
|
||||||
|
blockDevices[blockDevice.DeviceName] = blockDevice
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if the secondary block device exists.
|
||||||
|
if _, ok := blockDevices["/dev/sdb"]; !ok {
|
||||||
|
fmt.Errorf("block device doesn't exist: /dev/sdb")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resource.Test(t, resource.TestCase{
|
||||||
|
PreCheck: func() { testAccPreCheck(t) },
|
||||||
|
Providers: testAccProviders,
|
||||||
|
CheckDestroy: testAccCheckInstanceDestroy,
|
||||||
|
Steps: []resource.TestStep{
|
||||||
|
resource.TestStep{
|
||||||
|
Config: testAccInstanceConfigBlockDevices,
|
||||||
|
Check: resource.ComposeTestCheckFunc(
|
||||||
|
testAccCheckInstanceExists(
|
||||||
|
"aws_instance.foo", &v),
|
||||||
|
testCheck(),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
func TestAccAWSInstance_sourceDestCheck(t *testing.T) {
|
func TestAccAWSInstance_sourceDestCheck(t *testing.T) {
|
||||||
var v ec2.Instance
|
var v ec2.Instance
|
||||||
|
|
||||||
|
@ -233,6 +271,19 @@ resource "aws_instance" "foo" {
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
|
const testAccInstanceConfigBlockDevices = `
|
||||||
|
resource "aws_instance" "foo" {
|
||||||
|
# us-west-2
|
||||||
|
ami = "ami-55a7ea65"
|
||||||
|
instance_type = "m1.small"
|
||||||
|
block_device {
|
||||||
|
device_name = "/dev/sdb"
|
||||||
|
volume_type = "gp2"
|
||||||
|
volume_size = 10
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
const testAccInstanceConfigSourceDest = `
|
const testAccInstanceConfigSourceDest = `
|
||||||
resource "aws_vpc" "foo" {
|
resource "aws_vpc" "foo" {
|
||||||
cidr_block = "10.1.0.0/16"
|
cidr_block = "10.1.0.0/16"
|
||||||
|
|
Loading…
Reference in New Issue