Succeed creating aws_volume_attachment if identical attachment exists (#11060)

If an `aws_volume_attachment` is identical to one that already exists in
the API, don't attempt to re-create it (which fails), simply act as
though the creation command had already been run and continue.

This allows Terraform to cleanly recover from a situation where a volume
attachment action hangs indefinitely, possibly due to a bad instance
state, requiring manual intervention such as an instance reboot. In such
a situation, Terraform believes the attachment has failed, when in fact
it succeeded after the timeout had expired. On the subsequent retry run,
attempting to re-create the attachment will fail outright, due to the
AttachVolume API call being non-idempotent. This patch implements the
idempotency client-side by matching the (name, vID, iID) tuple.

Note that volume attachments are not assigned an ID by the API.
This commit is contained in:
Doug Neal 2017-02-01 15:41:53 +00:00 committed by Paul Stack
parent c83a971efb
commit babc52202c
1 changed files with 31 additions and 11 deletions

View File

@ -59,6 +59,25 @@ func resourceAwsVolumeAttachmentCreate(d *schema.ResourceData, meta interface{})
iID := d.Get("instance_id").(string) iID := d.Get("instance_id").(string)
vID := d.Get("volume_id").(string) vID := d.Get("volume_id").(string)
// Find out if the volume is already attached to the instance, in which case
// we have nothing to do
request := &ec2.DescribeVolumesInput{
VolumeIds: []*string{aws.String(vID)},
Filters: []*ec2.Filter{
&ec2.Filter{
Name: aws.String("attachment.instance-id"),
Values: []*string{aws.String(iID)},
},
&ec2.Filter{
Name: aws.String("attachment.device"),
Values: []*string{aws.String(name)},
},
},
}
vols, err := conn.DescribeVolumes(request)
if (err != nil) || (len(vols.Volumes) == 0) {
// not attached
opts := &ec2.AttachVolumeInput{ opts := &ec2.AttachVolumeInput{
Device: aws.String(name), Device: aws.String(name),
InstanceId: aws.String(iID), InstanceId: aws.String(iID),
@ -74,6 +93,7 @@ func resourceAwsVolumeAttachmentCreate(d *schema.ResourceData, meta interface{})
} }
return err return err
} }
}
stateConf := &resource.StateChangeConf{ stateConf := &resource.StateChangeConf{
Pending: []string{"attaching"}, Pending: []string{"attaching"},