github.com/IBM-Cloud/terraform@v0.6.4-0.20170726051544-8872b87621df/builtin/providers/google/resource_storage_bucket.go (about) 1 package google 2 3 import ( 4 "errors" 5 "fmt" 6 "log" 7 "time" 8 9 "github.com/hashicorp/terraform/helper/resource" 10 "github.com/hashicorp/terraform/helper/schema" 11 12 "google.golang.org/api/googleapi" 13 "google.golang.org/api/storage/v1" 14 ) 15 16 func resourceStorageBucket() *schema.Resource { 17 return &schema.Resource{ 18 Create: resourceStorageBucketCreate, 19 Read: resourceStorageBucketRead, 20 Update: resourceStorageBucketUpdate, 21 Delete: resourceStorageBucketDelete, 22 23 Schema: map[string]*schema.Schema{ 24 "name": &schema.Schema{ 25 Type: schema.TypeString, 26 Required: true, 27 ForceNew: true, 28 }, 29 30 "force_destroy": &schema.Schema{ 31 Type: schema.TypeBool, 32 Optional: true, 33 Default: false, 34 }, 35 36 "location": &schema.Schema{ 37 Type: schema.TypeString, 38 Default: "US", 39 Optional: true, 40 ForceNew: true, 41 }, 42 43 "predefined_acl": &schema.Schema{ 44 Type: schema.TypeString, 45 Deprecated: "Please use resource \"storage_bucket_acl.predefined_acl\" instead.", 46 Optional: true, 47 ForceNew: true, 48 }, 49 50 "project": &schema.Schema{ 51 Type: schema.TypeString, 52 Optional: true, 53 ForceNew: true, 54 }, 55 56 "self_link": &schema.Schema{ 57 Type: schema.TypeString, 58 Computed: true, 59 }, 60 61 "url": &schema.Schema{ 62 Type: schema.TypeString, 63 Computed: true, 64 }, 65 66 "storage_class": &schema.Schema{ 67 Type: schema.TypeString, 68 Optional: true, 69 Default: "STANDARD", 70 ForceNew: true, 71 }, 72 73 "website": &schema.Schema{ 74 Type: schema.TypeList, 75 Optional: true, 76 Elem: &schema.Resource{ 77 Schema: map[string]*schema.Schema{ 78 "main_page_suffix": &schema.Schema{ 79 Type: schema.TypeString, 80 Optional: true, 81 }, 82 "not_found_page": &schema.Schema{ 83 Type: schema.TypeString, 84 Optional: true, 85 }, 86 }, 87 }, 88 }, 89 }, 90 } 91 } 92 93 func resourceStorageBucketCreate(d *schema.ResourceData, meta interface{}) error { 94 config := meta.(*Config) 95 96 project, err := getProject(d, config) 97 if err != nil { 98 return err 99 } 100 101 // Get the bucket and acl 102 bucket := d.Get("name").(string) 103 location := d.Get("location").(string) 104 105 // Create a bucket, setting the acl, location and name. 106 sb := &storage.Bucket{Name: bucket, Location: location} 107 108 if v, ok := d.GetOk("storage_class"); ok { 109 sb.StorageClass = v.(string) 110 } 111 112 if v, ok := d.GetOk("website"); ok { 113 websites := v.([]interface{}) 114 115 if len(websites) > 1 { 116 return fmt.Errorf("At most one website block is allowed") 117 } 118 119 sb.Website = &storage.BucketWebsite{} 120 121 website := websites[0].(map[string]interface{}) 122 123 if v, ok := website["not_found_page"]; ok { 124 sb.Website.NotFoundPage = v.(string) 125 } 126 127 if v, ok := website["main_page_suffix"]; ok { 128 sb.Website.MainPageSuffix = v.(string) 129 } 130 } 131 132 var res *storage.Bucket 133 134 err = resource.Retry(1*time.Minute, func() *resource.RetryError { 135 call := config.clientStorage.Buckets.Insert(project, sb) 136 if v, ok := d.GetOk("predefined_acl"); ok { 137 call = call.PredefinedAcl(v.(string)) 138 } 139 140 res, err = call.Do() 141 if err == nil { 142 return nil 143 } 144 if gerr, ok := err.(*googleapi.Error); ok && gerr.Code == 429 { 145 return resource.RetryableError(gerr) 146 } 147 return resource.NonRetryableError(err) 148 }) 149 150 if err != nil { 151 fmt.Printf("Error creating bucket %s: %v", bucket, err) 152 return err 153 } 154 155 log.Printf("[DEBUG] Created bucket %v at location %v\n\n", res.Name, res.SelfLink) 156 157 // Assign the bucket ID as the resource ID 158 d.Set("self_link", res.SelfLink) 159 d.Set("url", fmt.Sprintf("gs://%s", bucket)) 160 d.SetId(res.Id) 161 162 return nil 163 } 164 165 func resourceStorageBucketUpdate(d *schema.ResourceData, meta interface{}) error { 166 config := meta.(*Config) 167 168 sb := &storage.Bucket{} 169 170 if d.HasChange("website") { 171 if v, ok := d.GetOk("website"); ok { 172 websites := v.([]interface{}) 173 174 if len(websites) > 1 { 175 return fmt.Errorf("At most one website block is allowed") 176 } 177 178 // Setting fields to "" to be explicit that the PATCH call will 179 // delete this field. 180 if len(websites) == 0 { 181 sb.Website.NotFoundPage = "" 182 sb.Website.MainPageSuffix = "" 183 } else { 184 website := websites[0].(map[string]interface{}) 185 sb.Website = &storage.BucketWebsite{} 186 if v, ok := website["not_found_page"]; ok { 187 sb.Website.NotFoundPage = v.(string) 188 } else { 189 sb.Website.NotFoundPage = "" 190 } 191 192 if v, ok := website["main_page_suffix"]; ok { 193 sb.Website.MainPageSuffix = v.(string) 194 } else { 195 sb.Website.MainPageSuffix = "" 196 } 197 } 198 } 199 } 200 201 res, err := config.clientStorage.Buckets.Patch(d.Get("name").(string), sb).Do() 202 203 if err != nil { 204 return err 205 } 206 207 log.Printf("[DEBUG] Patched bucket %v at location %v\n\n", res.Name, res.SelfLink) 208 209 // Assign the bucket ID as the resource ID 210 d.Set("self_link", res.SelfLink) 211 d.SetId(res.Id) 212 213 return nil 214 } 215 216 func resourceStorageBucketRead(d *schema.ResourceData, meta interface{}) error { 217 config := meta.(*Config) 218 219 // Get the bucket and acl 220 bucket := d.Get("name").(string) 221 res, err := config.clientStorage.Buckets.Get(bucket).Do() 222 223 if err != nil { 224 return handleNotFoundError(err, d, fmt.Sprintf("Storage Bucket %q", d.Get("name").(string))) 225 } 226 227 log.Printf("[DEBUG] Read bucket %v at location %v\n\n", res.Name, res.SelfLink) 228 229 // Update the bucket ID according to the resource ID 230 d.Set("self_link", res.SelfLink) 231 d.SetId(res.Id) 232 233 return nil 234 } 235 236 func resourceStorageBucketDelete(d *schema.ResourceData, meta interface{}) error { 237 config := meta.(*Config) 238 239 // Get the bucket 240 bucket := d.Get("name").(string) 241 242 for { 243 res, err := config.clientStorage.Objects.List(bucket).Do() 244 if err != nil { 245 fmt.Printf("Error Objects.List failed: %v", err) 246 return err 247 } 248 249 if len(res.Items) != 0 { 250 if d.Get("force_destroy").(bool) { 251 // purge the bucket... 252 log.Printf("[DEBUG] GCS Bucket attempting to forceDestroy\n\n") 253 254 for _, object := range res.Items { 255 log.Printf("[DEBUG] Found %s", object.Name) 256 if err := config.clientStorage.Objects.Delete(bucket, object.Name).Do(); err != nil { 257 log.Fatalf("Error trying to delete object: %s %s\n\n", object.Name, err) 258 } else { 259 log.Printf("Object deleted: %s \n\n", object.Name) 260 } 261 } 262 263 } else { 264 delete_err := errors.New("Error trying to delete a bucket containing objects without `force_destroy` set to true") 265 log.Printf("Error! %s : %s\n\n", bucket, delete_err) 266 return delete_err 267 } 268 } else { 269 break // 0 items, bucket empty 270 } 271 } 272 273 // remove empty bucket 274 err := resource.Retry(1*time.Minute, func() *resource.RetryError { 275 err := config.clientStorage.Buckets.Delete(bucket).Do() 276 if err == nil { 277 return nil 278 } 279 if gerr, ok := err.(*googleapi.Error); ok && gerr.Code == 429 { 280 return resource.RetryableError(gerr) 281 } 282 return resource.NonRetryableError(err) 283 }) 284 if err != nil { 285 fmt.Printf("Error deleting bucket %s: %v\n\n", bucket, err) 286 return err 287 } 288 log.Printf("[DEBUG] Deleted bucket %v\n\n", bucket) 289 290 return nil 291 }