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:
parent
c83a971efb
commit
babc52202c
|
@ -59,20 +59,40 @@ 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)
|
||||||
|
|
||||||
opts := &ec2.AttachVolumeInput{
|
// Find out if the volume is already attached to the instance, in which case
|
||||||
Device: aws.String(name),
|
// we have nothing to do
|
||||||
InstanceId: aws.String(iID),
|
request := &ec2.DescribeVolumesInput{
|
||||||
VolumeId: aws.String(vID),
|
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)},
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Printf("[DEBUG] Attaching Volume (%s) to Instance (%s)", vID, iID)
|
vols, err := conn.DescribeVolumes(request)
|
||||||
_, err := conn.AttachVolume(opts)
|
if (err != nil) || (len(vols.Volumes) == 0) {
|
||||||
if err != nil {
|
// not attached
|
||||||
if awsErr, ok := err.(awserr.Error); ok {
|
opts := &ec2.AttachVolumeInput{
|
||||||
return fmt.Errorf("[WARN] Error attaching volume (%s) to instance (%s), message: \"%s\", code: \"%s\"",
|
Device: aws.String(name),
|
||||||
vID, iID, awsErr.Message(), awsErr.Code())
|
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
|
||||||
}
|
}
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
stateConf := &resource.StateChangeConf{
|
stateConf := &resource.StateChangeConf{
|
||||||
|
|
Loading…
Reference in New Issue