diff --git a/builtin/providers/aws/resource_aws_s3_bucket.go b/builtin/providers/aws/resource_aws_s3_bucket.go index 142b8006944a..1c1de96ed9dc 100644 --- a/builtin/providers/aws/resource_aws_s3_bucket.go +++ b/builtin/providers/aws/resource_aws_s3_bucket.go @@ -85,6 +85,12 @@ func resourceAwsS3Bucket() *schema.Resource { }, "tags": tagsSchema(), + + "force_destroy": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + Default: false, + }, }, } } @@ -259,7 +265,46 @@ func resourceAwsS3BucketDelete(d *schema.ResourceData, meta interface{}) error { Bucket: aws.String(d.Id()), }) if err != nil { - return err + ec2err, ok := err.(awserr.Error) + if ok && ec2err.Code() == "BucketNotEmpty" { + if d.Get("force_destroy").(bool) { + // bucket may have things delete them + log.Printf("[DEBUG] S3 Bucket attempting to forceDestroy %+v", err) + + bucket := d.Get("bucket").(string) + resp, err := s3conn.ListObjects( + &s3.ListObjectsInput{ + Bucket: aws.String(bucket), + }, + ) + + if err != nil { + return fmt.Errorf("Error S3 Bucket list Objects err: %s", err) + } + + objectsToDelete := make([]*s3.ObjectIdentifier, len(resp.Contents)) + for i, v := range resp.Contents { + objectsToDelete[i] = &s3.ObjectIdentifier{ + Key: v.Key, + } + } + _, err = s3conn.DeleteObjects( + &s3.DeleteObjectsInput{ + Bucket: aws.String(bucket), + Delete: &s3.Delete{ + Objects: objectsToDelete, + }, + }, + ) + if err != nil { + return fmt.Errorf("Error S3 Bucket force_destroy error deleting: %s", err) + } + + // this line recurses until all objects are deleted or an error is returned + return resourceAwsS3BucketDelete(d, meta) + } + } + return fmt.Errorf("Error deleting S3 Bucket: %s", err) } return nil } diff --git a/website/source/docs/providers/aws/r/s3_bucket.html.markdown b/website/source/docs/providers/aws/r/s3_bucket.html.markdown index 83c6b241b02c..c0ecd91c7bb8 100644 --- a/website/source/docs/providers/aws/r/s3_bucket.html.markdown +++ b/website/source/docs/providers/aws/r/s3_bucket.html.markdown @@ -49,6 +49,7 @@ The following arguments are supported: * `acl` - (Optional) The [canned ACL](http://docs.aws.amazon.com/AmazonS3/latest/dev/acl-overview.html#canned-acl) to apply. Defaults to "private". * `policy` - (Optional) A valid [bucket policy](http://docs.aws.amazon.com/AmazonS3/latest/dev/example-bucket-policies.html) JSON document. * `tags` - (Optional) A mapping of tags to assign to the bucket. +* `force_destroy` - (Optional, Default:false ) A boolean that indicates all objects should be deleted from the bucket so that the bucket can be destroyed without error. These objects are *not* recoverable. * `website` - (Optional) A website object (documented below). The website object supports the following: