github.com/articulate/terraform@v0.6.13-0.20160303003731-8d31c93862de/builtin/providers/aws/resource_aws_s3_bucket_object.go (about) 1 package aws 2 3 import ( 4 "bytes" 5 "fmt" 6 "io" 7 "log" 8 "os" 9 "strings" 10 11 "github.com/hashicorp/terraform/helper/schema" 12 "github.com/mitchellh/go-homedir" 13 14 "github.com/aws/aws-sdk-go/aws" 15 "github.com/aws/aws-sdk-go/aws/awserr" 16 "github.com/aws/aws-sdk-go/service/s3" 17 ) 18 19 func resourceAwsS3BucketObject() *schema.Resource { 20 return &schema.Resource{ 21 Create: resourceAwsS3BucketObjectPut, 22 Read: resourceAwsS3BucketObjectRead, 23 Update: resourceAwsS3BucketObjectPut, 24 Delete: resourceAwsS3BucketObjectDelete, 25 26 Schema: map[string]*schema.Schema{ 27 "bucket": &schema.Schema{ 28 Type: schema.TypeString, 29 Required: true, 30 ForceNew: true, 31 }, 32 33 "cache_control": &schema.Schema{ 34 Type: schema.TypeString, 35 Optional: true, 36 }, 37 38 "content_disposition": &schema.Schema{ 39 Type: schema.TypeString, 40 Optional: true, 41 }, 42 43 "content_encoding": &schema.Schema{ 44 Type: schema.TypeString, 45 Optional: true, 46 }, 47 48 "content_language": &schema.Schema{ 49 Type: schema.TypeString, 50 Optional: true, 51 }, 52 53 "content_type": &schema.Schema{ 54 Type: schema.TypeString, 55 Optional: true, 56 Computed: true, 57 }, 58 59 "key": &schema.Schema{ 60 Type: schema.TypeString, 61 Required: true, 62 ForceNew: true, 63 }, 64 65 "source": &schema.Schema{ 66 Type: schema.TypeString, 67 Optional: true, 68 ConflictsWith: []string{"content"}, 69 }, 70 71 "content": &schema.Schema{ 72 Type: schema.TypeString, 73 Optional: true, 74 ConflictsWith: []string{"source"}, 75 }, 76 77 "etag": &schema.Schema{ 78 Type: schema.TypeString, 79 // This will conflict with SSE-C and SSE-KMS encryption and multi-part upload 80 // if/when it's actually implemented. The Etag then won't match raw-file MD5. 81 // See http://docs.aws.amazon.com/AmazonS3/latest/API/RESTCommonResponseHeaders.html 82 Optional: true, 83 Computed: true, 84 }, 85 86 "version_id": &schema.Schema{ 87 Type: schema.TypeString, 88 Computed: true, 89 }, 90 }, 91 } 92 } 93 94 func resourceAwsS3BucketObjectPut(d *schema.ResourceData, meta interface{}) error { 95 s3conn := meta.(*AWSClient).s3conn 96 97 bucket := d.Get("bucket").(string) 98 key := d.Get("key").(string) 99 var body io.ReadSeeker 100 101 if v, ok := d.GetOk("source"); ok { 102 source := v.(string) 103 path, err := homedir.Expand(source) 104 if err != nil { 105 return fmt.Errorf("Error expanding homedir in source (%s): %s", source, err) 106 } 107 file, err := os.Open(path) 108 if err != nil { 109 return fmt.Errorf("Error opening S3 bucket object source (%s): %s", source, err) 110 } 111 112 body = file 113 } else if v, ok := d.GetOk("content"); ok { 114 content := v.(string) 115 body = bytes.NewReader([]byte(content)) 116 } else { 117 return fmt.Errorf("Must specify \"source\" or \"content\" field") 118 } 119 120 putInput := &s3.PutObjectInput{ 121 Bucket: aws.String(bucket), 122 Key: aws.String(key), 123 Body: body, 124 } 125 126 if v, ok := d.GetOk("cache_control"); ok { 127 putInput.CacheControl = aws.String(v.(string)) 128 } 129 130 if v, ok := d.GetOk("content_type"); ok { 131 putInput.ContentType = aws.String(v.(string)) 132 } 133 134 if v, ok := d.GetOk("content_encoding"); ok { 135 putInput.ContentEncoding = aws.String(v.(string)) 136 } 137 138 if v, ok := d.GetOk("content_language"); ok { 139 putInput.ContentLanguage = aws.String(v.(string)) 140 } 141 142 if v, ok := d.GetOk("content_disposition"); ok { 143 putInput.ContentDisposition = aws.String(v.(string)) 144 } 145 146 resp, err := s3conn.PutObject(putInput) 147 if err != nil { 148 return fmt.Errorf("Error putting object in S3 bucket (%s): %s", bucket, err) 149 } 150 151 // See https://forums.aws.amazon.com/thread.jspa?threadID=44003 152 d.Set("etag", strings.Trim(*resp.ETag, `"`)) 153 154 d.Set("version_id", resp.VersionId) 155 d.SetId(key) 156 return resourceAwsS3BucketObjectRead(d, meta) 157 } 158 159 func resourceAwsS3BucketObjectRead(d *schema.ResourceData, meta interface{}) error { 160 s3conn := meta.(*AWSClient).s3conn 161 162 bucket := d.Get("bucket").(string) 163 key := d.Get("key").(string) 164 etag := d.Get("etag").(string) 165 166 resp, err := s3conn.HeadObject( 167 &s3.HeadObjectInput{ 168 Bucket: aws.String(bucket), 169 Key: aws.String(key), 170 IfMatch: aws.String(etag), 171 }) 172 173 if err != nil { 174 // If S3 returns a 404 Request Failure, mark the object as destroyed 175 if awsErr, ok := err.(awserr.RequestFailure); ok && awsErr.StatusCode() == 404 { 176 d.SetId("") 177 log.Printf("[WARN] Error Reading Object (%s), object not found (HTTP status 404)", key) 178 return nil 179 } 180 return err 181 } 182 183 d.Set("cache_control", resp.CacheControl) 184 d.Set("content_disposition", resp.ContentDisposition) 185 d.Set("content_encoding", resp.ContentEncoding) 186 d.Set("content_language", resp.ContentLanguage) 187 d.Set("content_type", resp.ContentType) 188 d.Set("version_id", resp.VersionId) 189 190 log.Printf("[DEBUG] Reading S3 Bucket Object meta: %s", resp) 191 return nil 192 } 193 194 func resourceAwsS3BucketObjectDelete(d *schema.ResourceData, meta interface{}) error { 195 s3conn := meta.(*AWSClient).s3conn 196 197 bucket := d.Get("bucket").(string) 198 key := d.Get("key").(string) 199 200 if _, ok := d.GetOk("version_id"); ok { 201 // Bucket is versioned, we need to delete all versions 202 vInput := s3.ListObjectVersionsInput{ 203 Bucket: aws.String(bucket), 204 Prefix: aws.String(key), 205 } 206 out, err := s3conn.ListObjectVersions(&vInput) 207 if err != nil { 208 return fmt.Errorf("Failed listing S3 object versions: %s", err) 209 } 210 211 for _, v := range out.Versions { 212 input := s3.DeleteObjectInput{ 213 Bucket: aws.String(bucket), 214 Key: aws.String(key), 215 VersionId: v.VersionId, 216 } 217 _, err := s3conn.DeleteObject(&input) 218 if err != nil { 219 return fmt.Errorf("Error deleting S3 object version of %s:\n %s:\n %s", 220 key, v, err) 221 } 222 } 223 } else { 224 // Just delete the object 225 input := s3.DeleteObjectInput{ 226 Bucket: aws.String(bucket), 227 Key: aws.String(key), 228 } 229 _, err := s3conn.DeleteObject(&input) 230 if err != nil { 231 return fmt.Errorf("Error deleting S3 bucket object: %s", err) 232 } 233 } 234 235 return nil 236 }