Merge pull request #2050 from hashicorp/f-aws-volume-attachment
provider/aws: Add resource_aws_volume_attachment
This commit is contained in:
commit
440537a6cf
|
@ -127,6 +127,7 @@ func Provider() terraform.ResourceProvider {
|
||||||
"aws_sns_topic": resourceAwsSnsTopic(),
|
"aws_sns_topic": resourceAwsSnsTopic(),
|
||||||
"aws_sns_topic_subscription": resourceAwsSnsTopicSubscription(),
|
"aws_sns_topic_subscription": resourceAwsSnsTopicSubscription(),
|
||||||
"aws_subnet": resourceAwsSubnet(),
|
"aws_subnet": resourceAwsSubnet(),
|
||||||
|
"aws_volume_attachment": resourceAwsVolumeAttachment(),
|
||||||
"aws_vpc_dhcp_options_association": resourceAwsVpcDhcpOptionsAssociation(),
|
"aws_vpc_dhcp_options_association": resourceAwsVpcDhcpOptionsAssociation(),
|
||||||
"aws_vpc_dhcp_options": resourceAwsVpcDhcpOptions(),
|
"aws_vpc_dhcp_options": resourceAwsVpcDhcpOptions(),
|
||||||
"aws_vpc_peering_connection": resourceAwsVpcPeeringConnection(),
|
"aws_vpc_peering_connection": resourceAwsVpcPeeringConnection(),
|
||||||
|
|
|
@ -2,11 +2,14 @@ package aws
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/awslabs/aws-sdk-go/aws"
|
"github.com/awslabs/aws-sdk-go/aws"
|
||||||
"github.com/awslabs/aws-sdk-go/aws/awserr"
|
"github.com/awslabs/aws-sdk-go/aws/awserr"
|
||||||
"github.com/awslabs/aws-sdk-go/service/ec2"
|
"github.com/awslabs/aws-sdk-go/service/ec2"
|
||||||
|
|
||||||
|
"github.com/hashicorp/terraform/helper/resource"
|
||||||
"github.com/hashicorp/terraform/helper/schema"
|
"github.com/hashicorp/terraform/helper/schema"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -91,9 +94,55 @@ func resourceAwsEbsVolumeCreate(d *schema.ResourceData, meta interface{}) error
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("Error creating EC2 volume: %s", err)
|
return fmt.Errorf("Error creating EC2 volume: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log.Printf(
|
||||||
|
"[DEBUG] Waiting for Volume (%s) to become available",
|
||||||
|
d.Id())
|
||||||
|
|
||||||
|
stateConf := &resource.StateChangeConf{
|
||||||
|
Pending: []string{"creating"},
|
||||||
|
Target: "available",
|
||||||
|
Refresh: volumeStateRefreshFunc(conn, *result.VolumeID),
|
||||||
|
Timeout: 5 * time.Minute,
|
||||||
|
Delay: 10 * time.Second,
|
||||||
|
MinTimeout: 3 * time.Second,
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = stateConf.WaitForState()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf(
|
||||||
|
"Error waiting for Volume (%s) to become available: %s",
|
||||||
|
*result.VolumeID, err)
|
||||||
|
}
|
||||||
|
|
||||||
return readVolume(d, result)
|
return readVolume(d, result)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// volumeStateRefreshFunc returns a resource.StateRefreshFunc that is used to watch
|
||||||
|
// a the state of a Volume. Returns successfully when volume is available
|
||||||
|
func volumeStateRefreshFunc(conn *ec2.EC2, volumeID string) resource.StateRefreshFunc {
|
||||||
|
return func() (interface{}, string, error) {
|
||||||
|
resp, err := conn.DescribeVolumes(&ec2.DescribeVolumesInput{
|
||||||
|
VolumeIDs: []*string{aws.String(volumeID)},
|
||||||
|
})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
if ec2err, ok := err.(awserr.Error); ok {
|
||||||
|
// Set this to nil as if we didn't find anything.
|
||||||
|
log.Printf("Error on Volume State Refresh: message: \"%s\", code:\"%s\"", ec2err.Message(), ec2err.Code())
|
||||||
|
resp = nil
|
||||||
|
return nil, "", err
|
||||||
|
} else {
|
||||||
|
log.Printf("Error on Volume State Refresh: %s", err)
|
||||||
|
return nil, "", err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
v := resp.Volumes[0]
|
||||||
|
return v, *v.State, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func resourceAwsEbsVolumeRead(d *schema.ResourceData, meta interface{}) error {
|
func resourceAwsEbsVolumeRead(d *schema.ResourceData, meta interface{}) error {
|
||||||
conn := meta.(*AWSClient).ec2conn
|
conn := meta.(*AWSClient).ec2conn
|
||||||
|
|
||||||
|
|
|
@ -1,23 +1,59 @@
|
||||||
package aws
|
package aws
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/awslabs/aws-sdk-go/aws"
|
||||||
|
"github.com/awslabs/aws-sdk-go/service/ec2"
|
||||||
"github.com/hashicorp/terraform/helper/resource"
|
"github.com/hashicorp/terraform/helper/resource"
|
||||||
|
"github.com/hashicorp/terraform/terraform"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestAccAWSEBSVolume(t *testing.T) {
|
func TestAccAWSEBSVolume(t *testing.T) {
|
||||||
|
var v ec2.Volume
|
||||||
resource.Test(t, resource.TestCase{
|
resource.Test(t, resource.TestCase{
|
||||||
PreCheck: func() { testAccPreCheck(t) },
|
PreCheck: func() { testAccPreCheck(t) },
|
||||||
Providers: testAccProviders,
|
Providers: testAccProviders,
|
||||||
Steps: []resource.TestStep{
|
Steps: []resource.TestStep{
|
||||||
resource.TestStep{
|
resource.TestStep{
|
||||||
Config: testAccAwsEbsVolumeConfig,
|
Config: testAccAwsEbsVolumeConfig,
|
||||||
|
Check: resource.ComposeTestCheckFunc(
|
||||||
|
testAccCheckVolumeExists("aws_ebs_volume.test", &v),
|
||||||
|
),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func testAccCheckVolumeExists(n string, v *ec2.Volume) 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.DescribeVolumesInput{
|
||||||
|
VolumeIDs: []*string{aws.String(rs.Primary.ID)},
|
||||||
|
}
|
||||||
|
|
||||||
|
response, err := conn.DescribeVolumes(request)
|
||||||
|
if err == nil {
|
||||||
|
if response.Volumes != nil && len(response.Volumes) > 0 {
|
||||||
|
*v = *response.Volumes[0]
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return fmt.Errorf("Error finding EC2 volume %s", rs.Primary.ID)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const testAccAwsEbsVolumeConfig = `
|
const testAccAwsEbsVolumeConfig = `
|
||||||
resource "aws_ebs_volume" "test" {
|
resource "aws_ebs_volume" "test" {
|
||||||
availability_zone = "us-west-2a"
|
availability_zone = "us-west-2a"
|
||||||
|
|
|
@ -0,0 +1,191 @@
|
||||||
|
package aws
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/awslabs/aws-sdk-go/aws"
|
||||||
|
"github.com/awslabs/aws-sdk-go/aws/awserr"
|
||||||
|
"github.com/awslabs/aws-sdk-go/service/ec2"
|
||||||
|
"github.com/hashicorp/terraform/helper/hashcode"
|
||||||
|
"github.com/hashicorp/terraform/helper/resource"
|
||||||
|
"github.com/hashicorp/terraform/helper/schema"
|
||||||
|
)
|
||||||
|
|
||||||
|
func resourceAwsVolumeAttachment() *schema.Resource {
|
||||||
|
return &schema.Resource{
|
||||||
|
Create: resourceAwsVolumeAttachmentCreate,
|
||||||
|
Read: resourceAwsVolumeAttachmentRead,
|
||||||
|
Delete: resourceAwsVolumeAttachmentDelete,
|
||||||
|
|
||||||
|
Schema: map[string]*schema.Schema{
|
||||||
|
"device_name": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Required: true,
|
||||||
|
ForceNew: true,
|
||||||
|
},
|
||||||
|
|
||||||
|
"instance_id": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Required: true,
|
||||||
|
ForceNew: true,
|
||||||
|
},
|
||||||
|
|
||||||
|
"volume_id": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Required: true,
|
||||||
|
ForceNew: true,
|
||||||
|
},
|
||||||
|
|
||||||
|
"force_detach": &schema.Schema{
|
||||||
|
Type: schema.TypeBool,
|
||||||
|
Optional: true,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceAwsVolumeAttachmentCreate(d *schema.ResourceData, meta interface{}) error {
|
||||||
|
conn := meta.(*AWSClient).ec2conn
|
||||||
|
name := d.Get("device_name").(string)
|
||||||
|
iID := d.Get("instance_id").(string)
|
||||||
|
vID := d.Get("volume_id").(string)
|
||||||
|
|
||||||
|
opts := &ec2.AttachVolumeInput{
|
||||||
|
Device: aws.String(name),
|
||||||
|
InstanceID: aws.String(iID),
|
||||||
|
VolumeID: aws.String(vID),
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Printf("[DEBUG] Attaching Volume (%s) to Instance (%s)", vID, iID)
|
||||||
|
_, err := conn.AttachVolume(opts)
|
||||||
|
if err != nil {
|
||||||
|
if awsErr, ok := err.(awserr.Error); ok {
|
||||||
|
return fmt.Errorf("[WARN] Error attaching volume (%s) to instance (%s), message: \"%s\", code: \"%s\"",
|
||||||
|
vID, iID, awsErr.Message(), awsErr.Code())
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
stateConf := &resource.StateChangeConf{
|
||||||
|
Pending: []string{"attaching"},
|
||||||
|
Target: "attached",
|
||||||
|
Refresh: volumeAttachmentStateRefreshFunc(conn, vID, iID),
|
||||||
|
Timeout: 5 * time.Minute,
|
||||||
|
Delay: 10 * time.Second,
|
||||||
|
MinTimeout: 3 * time.Second,
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = stateConf.WaitForState()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf(
|
||||||
|
"Error waiting for Volume (%s) to attach to Instance: %s, error:",
|
||||||
|
vID, iID, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
d.SetId(volumeAttachmentID(name, vID, iID))
|
||||||
|
return resourceAwsVolumeAttachmentRead(d, meta)
|
||||||
|
}
|
||||||
|
|
||||||
|
func volumeAttachmentStateRefreshFunc(conn *ec2.EC2, volumeID, instanceID string) resource.StateRefreshFunc {
|
||||||
|
return func() (interface{}, string, error) {
|
||||||
|
|
||||||
|
request := &ec2.DescribeVolumesInput{
|
||||||
|
VolumeIDs: []*string{aws.String(volumeID)},
|
||||||
|
Filters: []*ec2.Filter{
|
||||||
|
&ec2.Filter{
|
||||||
|
Name: aws.String("attachment.instance-id"),
|
||||||
|
Values: []*string{aws.String(instanceID)},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := conn.DescribeVolumes(request)
|
||||||
|
if err != nil {
|
||||||
|
if awsErr, ok := err.(awserr.Error); ok {
|
||||||
|
return nil, "failed", fmt.Errorf("code: %s, message: %s", awsErr.Code(), awsErr.Message())
|
||||||
|
}
|
||||||
|
return nil, "failed", err
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(resp.Volumes) > 0 {
|
||||||
|
v := resp.Volumes[0]
|
||||||
|
for _, a := range v.Attachments {
|
||||||
|
if a.InstanceID != nil && *a.InstanceID == instanceID {
|
||||||
|
return a, *a.State, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// assume detached if volume count is 0
|
||||||
|
return 42, "detached", nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
func resourceAwsVolumeAttachmentRead(d *schema.ResourceData, meta interface{}) error {
|
||||||
|
conn := meta.(*AWSClient).ec2conn
|
||||||
|
|
||||||
|
request := &ec2.DescribeVolumesInput{
|
||||||
|
VolumeIDs: []*string{aws.String(d.Get("volume_id").(string))},
|
||||||
|
Filters: []*ec2.Filter{
|
||||||
|
&ec2.Filter{
|
||||||
|
Name: aws.String("attachment.instance-id"),
|
||||||
|
Values: []*string{aws.String(d.Get("instance_id").(string))},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err := conn.DescribeVolumes(request)
|
||||||
|
if err != nil {
|
||||||
|
if ec2err, ok := err.(awserr.Error); ok && ec2err.Code() == "InvalidVolume.NotFound" {
|
||||||
|
d.SetId("")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return fmt.Errorf("Error reading EC2 volume %s for instance: %s: %#v", d.Get("volume_id").(string), d.Get("instance_id").(string), err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceAwsVolumeAttachmentDelete(d *schema.ResourceData, meta interface{}) error {
|
||||||
|
conn := meta.(*AWSClient).ec2conn
|
||||||
|
|
||||||
|
vID := d.Get("volume_id").(string)
|
||||||
|
iID := d.Get("instance_id").(string)
|
||||||
|
|
||||||
|
opts := &ec2.DetachVolumeInput{
|
||||||
|
Device: aws.String(d.Get("device_name").(string)),
|
||||||
|
InstanceID: aws.String(iID),
|
||||||
|
VolumeID: aws.String(vID),
|
||||||
|
Force: aws.Boolean(d.Get("force_detach").(bool)),
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err := conn.DetachVolume(opts)
|
||||||
|
stateConf := &resource.StateChangeConf{
|
||||||
|
Pending: []string{"detaching"},
|
||||||
|
Target: "detached",
|
||||||
|
Refresh: volumeAttachmentStateRefreshFunc(conn, vID, iID),
|
||||||
|
Timeout: 5 * time.Minute,
|
||||||
|
Delay: 10 * time.Second,
|
||||||
|
MinTimeout: 3 * time.Second,
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Printf("[DEBUG] Detaching Volume (%s) from Instance (%s)", vID, iID)
|
||||||
|
_, err = stateConf.WaitForState()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf(
|
||||||
|
"Error waiting for Volume (%s) to detach from Instance: %s",
|
||||||
|
vID, iID)
|
||||||
|
}
|
||||||
|
d.SetId("")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func volumeAttachmentID(name, volumeID, instanceID string) string {
|
||||||
|
var buf bytes.Buffer
|
||||||
|
buf.WriteString(fmt.Sprintf("%s-", name))
|
||||||
|
buf.WriteString(fmt.Sprintf("%s-", instanceID))
|
||||||
|
buf.WriteString(fmt.Sprintf("%s-", volumeID))
|
||||||
|
|
||||||
|
return fmt.Sprintf("vai-%d", hashcode.String(buf.String()))
|
||||||
|
}
|
|
@ -0,0 +1,93 @@
|
||||||
|
package aws
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/awslabs/aws-sdk-go/service/ec2"
|
||||||
|
"github.com/hashicorp/terraform/helper/resource"
|
||||||
|
"github.com/hashicorp/terraform/terraform"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestAccAWSVolumeAttachment_basic(t *testing.T) {
|
||||||
|
var i ec2.Instance
|
||||||
|
var v ec2.Volume
|
||||||
|
|
||||||
|
resource.Test(t, resource.TestCase{
|
||||||
|
PreCheck: func() { testAccPreCheck(t) },
|
||||||
|
Providers: testAccProviders,
|
||||||
|
CheckDestroy: testAccCheckVolumeAttachmentDestroy,
|
||||||
|
Steps: []resource.TestStep{
|
||||||
|
resource.TestStep{
|
||||||
|
Config: testAccVolumeAttachmentConfig,
|
||||||
|
Check: resource.ComposeTestCheckFunc(
|
||||||
|
resource.TestCheckResourceAttr(
|
||||||
|
"aws_volume_attachment.ebs_att", "device_name", "/dev/sdh"),
|
||||||
|
testAccCheckInstanceExists(
|
||||||
|
"aws_instance.web", &i),
|
||||||
|
testAccCheckVolumeExists(
|
||||||
|
"aws_ebs_volume.example", &v),
|
||||||
|
testAccCheckVolumeAttachmentExists(
|
||||||
|
"aws_volume_attachment.ebs_att", &i, &v),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func testAccCheckVolumeAttachmentExists(n string, i *ec2.Instance, v *ec2.Volume) 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")
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, b := range i.BlockDeviceMappings {
|
||||||
|
if rs.Primary.Attributes["device_name"] == *b.DeviceName {
|
||||||
|
if b.EBS.VolumeID != nil && rs.Primary.Attributes["volume_id"] == *b.EBS.VolumeID {
|
||||||
|
// pass
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return fmt.Errorf("Error finding instance/volume")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func testAccCheckVolumeAttachmentDestroy(s *terraform.State) error {
|
||||||
|
for _, rs := range s.RootModule().Resources {
|
||||||
|
log.Printf("\n\n----- This is never called")
|
||||||
|
if rs.Type != "aws_volume_attachment" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
const testAccVolumeAttachmentConfig = `
|
||||||
|
resource "aws_instance" "web" {
|
||||||
|
ami = "ami-21f78e11"
|
||||||
|
availability_zone = "us-west-2a"
|
||||||
|
instance_type = "t1.micro"
|
||||||
|
tags {
|
||||||
|
Name = "HelloWorld"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_ebs_volume" "example" {
|
||||||
|
availability_zone = "us-west-2a"
|
||||||
|
size = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_volume_attachment" "ebs_att" {
|
||||||
|
device_name = "/dev/sdh"
|
||||||
|
volume_id = "${aws_ebs_volume.example.id}"
|
||||||
|
instance_id = "${aws_instance.web.id}"
|
||||||
|
}
|
||||||
|
`
|
|
@ -0,0 +1,57 @@
|
||||||
|
---
|
||||||
|
layout: "aws"
|
||||||
|
page_title: "AWS: aws_volume_attachment"
|
||||||
|
sidebar_current: "docs-aws-resource-volume-attachment"
|
||||||
|
description: |-
|
||||||
|
Provides an AWS EBS Volume Attachment
|
||||||
|
---
|
||||||
|
|
||||||
|
# aws\_volume\_attachment
|
||||||
|
|
||||||
|
Provides an AWS EBS Volume Attachment as a top level resource, to attach and
|
||||||
|
detach volumes from AWS Instances.
|
||||||
|
|
||||||
|
## Example Usage
|
||||||
|
|
||||||
|
```
|
||||||
|
resource "aws_volume_attachment" "ebs_att" {
|
||||||
|
device_name = "/dev/sdh"
|
||||||
|
volume_id = "${aws_ebs_volume.example.id}"
|
||||||
|
instance_id = "${aws_instance.web.id}"
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_instance" "web" {
|
||||||
|
ami = "ami-21f78e11"
|
||||||
|
availability_zone = "us-west-2a"
|
||||||
|
instance_type = "t1.micro"
|
||||||
|
tags {
|
||||||
|
Name = "HelloWorld"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_ebs_volume" "example" {
|
||||||
|
availability_zone = "us-west-2a"
|
||||||
|
size = 1
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Argument Reference
|
||||||
|
|
||||||
|
The following arguments are supported:
|
||||||
|
|
||||||
|
* `device_name` - (Required) The device name to expose to the instance (for
|
||||||
|
example, `/dev/sdh` or `xvdh`)
|
||||||
|
* `instance_id` - (Required) ID of the Instance to attach to
|
||||||
|
* `volume_id` - (Required) ID of the Volume to be attached
|
||||||
|
* `force_detach` - (Optional, Boolean) Set to `true` if you want to force the
|
||||||
|
volume to detach. Useful if previous attempts failed, but use this option only
|
||||||
|
as a last resort, as this can result in **data loss**. See
|
||||||
|
[Detaching an Amazon EBS Volume from an Instance][1] for more information.
|
||||||
|
|
||||||
|
## Attributes Reference
|
||||||
|
|
||||||
|
* `device_name` - The device name exposed to the instance
|
||||||
|
* `instance_id` - ID of the Instance
|
||||||
|
* `volume_id` - ID of the Volume
|
||||||
|
|
||||||
|
[1]: http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ebs-detaching-volume.html
|
|
@ -180,6 +180,10 @@
|
||||||
<a href="/docs/providers/aws/r/subnet.html">aws_subnet</a>
|
<a href="/docs/providers/aws/r/subnet.html">aws_subnet</a>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
|
<li<%= sidebar_current("docs-aws-resource-volume-attachment") %>>
|
||||||
|
<a href="/docs/providers/aws/r/volume_attachment.html">aws_volume_attachment</a>
|
||||||
|
</li>
|
||||||
|
|
||||||
<li<%= sidebar_current("docs-aws-resource-vpc") %>>
|
<li<%= sidebar_current("docs-aws-resource-vpc") %>>
|
||||||
<a href="/docs/providers/aws/r/vpc.html">aws_vpc</a>
|
<a href="/docs/providers/aws/r/vpc.html">aws_vpc</a>
|
||||||
</li>
|
</li>
|
||||||
|
|
Loading…
Reference in New Issue