github.com/leeprovoost/terraform@v0.6.10-0.20160119085442-96f3f76118e7/builtin/providers/google/resource_storage_bucket_acl.go (about) 1 package google 2 3 import ( 4 "fmt" 5 "log" 6 "strings" 7 8 "github.com/hashicorp/terraform/helper/schema" 9 10 "google.golang.org/api/googleapi" 11 "google.golang.org/api/storage/v1" 12 ) 13 14 func resourceStorageBucketAcl() *schema.Resource { 15 return &schema.Resource{ 16 Create: resourceStorageBucketAclCreate, 17 Read: resourceStorageBucketAclRead, 18 Update: resourceStorageBucketAclUpdate, 19 Delete: resourceStorageBucketAclDelete, 20 21 Schema: map[string]*schema.Schema{ 22 "bucket": &schema.Schema{ 23 Type: schema.TypeString, 24 Required: true, 25 ForceNew: true, 26 }, 27 "predefined_acl": &schema.Schema{ 28 Type: schema.TypeString, 29 Optional: true, 30 ForceNew: true, 31 }, 32 "role_entity": &schema.Schema{ 33 Type: schema.TypeList, 34 Optional: true, 35 Elem: &schema.Schema{Type: schema.TypeString}, 36 }, 37 "default_acl": &schema.Schema{ 38 Type: schema.TypeString, 39 Optional: true, 40 }, 41 }, 42 } 43 } 44 45 type RoleEntity struct { 46 Role string 47 Entity string 48 } 49 50 func getBucketAclId(bucket string) string { 51 return bucket + "-acl" 52 } 53 54 func getRoleEntityPair(role_entity string) (*RoleEntity, error) { 55 split := strings.Split(role_entity, ":") 56 if len(split) != 2 { 57 return nil, fmt.Errorf("Error, each role entity pair must be " + 58 "formatted as ROLE:entity") 59 } 60 61 return &RoleEntity{Role: split[0], Entity: split[1]}, nil 62 } 63 64 func resourceStorageBucketAclCreate(d *schema.ResourceData, meta interface{}) error { 65 config := meta.(*Config) 66 67 bucket := d.Get("bucket").(string) 68 predefined_acl := "" 69 default_acl := "" 70 role_entity := make([]interface{}, 0) 71 72 if v, ok := d.GetOk("predefined_acl"); ok { 73 predefined_acl = v.(string) 74 } 75 76 if v, ok := d.GetOk("role_entity"); ok { 77 role_entity = v.([]interface{}) 78 } 79 80 if v, ok := d.GetOk("default_acl"); ok { 81 default_acl = v.(string) 82 } 83 84 if len(predefined_acl) > 0 { 85 if len(role_entity) > 0 { 86 return fmt.Errorf("Error, you cannot specify both " + 87 "\"predefined_acl\" and \"role_entity\"") 88 } 89 90 res, err := config.clientStorage.Buckets.Get(bucket).Do() 91 92 if err != nil { 93 return fmt.Errorf("Error reading bucket %s: %v", bucket, err) 94 } 95 96 res, err = config.clientStorage.Buckets.Update(bucket, 97 res).PredefinedAcl(predefined_acl).Do() 98 99 if err != nil { 100 return fmt.Errorf("Error updating bucket %s: %v", bucket, err) 101 } 102 103 return resourceStorageBucketAclRead(d, meta) 104 } else if len(role_entity) > 0 { 105 for _, v := range role_entity { 106 pair, err := getRoleEntityPair(v.(string)) 107 108 bucketAccessControl := &storage.BucketAccessControl{ 109 Role: pair.Role, 110 Entity: pair.Entity, 111 } 112 113 log.Printf("[DEBUG]: storing re %s-%s", pair.Role, pair.Entity) 114 115 _, err = config.clientStorage.BucketAccessControls.Insert(bucket, bucketAccessControl).Do() 116 117 if err != nil { 118 return fmt.Errorf("Error updating ACL for bucket %s: %v", bucket, err) 119 } 120 } 121 122 return resourceStorageBucketAclRead(d, meta) 123 } 124 125 if len(default_acl) > 0 { 126 res, err := config.clientStorage.Buckets.Get(bucket).Do() 127 128 if err != nil { 129 return fmt.Errorf("Error reading bucket %s: %v", bucket, err) 130 } 131 132 res, err = config.clientStorage.Buckets.Update(bucket, 133 res).PredefinedDefaultObjectAcl(default_acl).Do() 134 135 if err != nil { 136 return fmt.Errorf("Error updating bucket %s: %v", bucket, err) 137 } 138 139 return resourceStorageBucketAclRead(d, meta) 140 } 141 142 return nil 143 } 144 145 func resourceStorageBucketAclRead(d *schema.ResourceData, meta interface{}) error { 146 config := meta.(*Config) 147 148 bucket := d.Get("bucket").(string) 149 150 // Predefined ACLs cannot easily be parsed once they have been processed 151 // by the GCP server 152 if _, ok := d.GetOk("predefined_acl"); !ok { 153 role_entity := make([]interface{}, 0) 154 re_local := d.Get("role_entity").([]interface{}) 155 re_local_map := make(map[string]string) 156 for _, v := range re_local { 157 res, err := getRoleEntityPair(v.(string)) 158 159 if err != nil { 160 return fmt.Errorf( 161 "Old state has malformed Role/Entity pair: %v", err) 162 } 163 164 re_local_map[res.Entity] = res.Role 165 } 166 167 res, err := config.clientStorage.BucketAccessControls.List(bucket).Do() 168 169 if err != nil { 170 if gerr, ok := err.(*googleapi.Error); ok && gerr.Code == 404 { 171 log.Printf("[WARN] Removing Bucket ACL for bucket %q because it's gone", d.Get("bucket").(string)) 172 // The resource doesn't exist anymore 173 d.SetId("") 174 175 return nil 176 } 177 178 return err 179 } 180 181 for _, v := range res.Items { 182 log.Printf("[DEBUG]: examining re %s-%s", v.Role, v.Entity) 183 // We only store updates to the locally defined access controls 184 if _, in := re_local_map[v.Entity]; in { 185 role_entity = append(role_entity, fmt.Sprintf("%s:%s", v.Role, v.Entity)) 186 log.Printf("[DEBUG]: saving re %s-%s", v.Role, v.Entity) 187 } 188 } 189 190 d.Set("role_entity", role_entity) 191 } 192 193 d.SetId(getBucketAclId(bucket)) 194 return nil 195 } 196 197 func resourceStorageBucketAclUpdate(d *schema.ResourceData, meta interface{}) error { 198 config := meta.(*Config) 199 200 bucket := d.Get("bucket").(string) 201 202 if d.HasChange("role_entity") { 203 o, n := d.GetChange("role_entity") 204 old_re, new_re := o.([]interface{}), n.([]interface{}) 205 206 old_re_map := make(map[string]string) 207 for _, v := range old_re { 208 res, err := getRoleEntityPair(v.(string)) 209 210 if err != nil { 211 return fmt.Errorf( 212 "Old state has malformed Role/Entity pair: %v", err) 213 } 214 215 old_re_map[res.Entity] = res.Role 216 } 217 218 for _, v := range new_re { 219 pair, err := getRoleEntityPair(v.(string)) 220 221 bucketAccessControl := &storage.BucketAccessControl{ 222 Role: pair.Role, 223 Entity: pair.Entity, 224 } 225 226 // If the old state is missing this entity, it needs to 227 // be created. Otherwise it is updated 228 if _, ok := old_re_map[pair.Entity]; ok { 229 _, err = config.clientStorage.BucketAccessControls.Update( 230 bucket, pair.Entity, bucketAccessControl).Do() 231 } else { 232 _, err = config.clientStorage.BucketAccessControls.Insert( 233 bucket, bucketAccessControl).Do() 234 } 235 236 // Now we only store the keys that have to be removed 237 delete(old_re_map, pair.Entity) 238 239 if err != nil { 240 return fmt.Errorf("Error updating ACL for bucket %s: %v", bucket, err) 241 } 242 } 243 244 for entity, _ := range old_re_map { 245 log.Printf("[DEBUG]: removing entity %s", entity) 246 err := config.clientStorage.BucketAccessControls.Delete(bucket, entity).Do() 247 248 if err != nil { 249 return fmt.Errorf("Error updating ACL for bucket %s: %v", bucket, err) 250 } 251 } 252 253 return resourceStorageBucketAclRead(d, meta) 254 } 255 256 if d.HasChange("default_acl") { 257 default_acl := d.Get("default_acl").(string) 258 259 res, err := config.clientStorage.Buckets.Get(bucket).Do() 260 261 if err != nil { 262 return fmt.Errorf("Error reading bucket %s: %v", bucket, err) 263 } 264 265 res, err = config.clientStorage.Buckets.Update(bucket, 266 res).PredefinedDefaultObjectAcl(default_acl).Do() 267 268 if err != nil { 269 return fmt.Errorf("Error updating bucket %s: %v", bucket, err) 270 } 271 272 return resourceStorageBucketAclRead(d, meta) 273 } 274 275 return nil 276 } 277 278 func resourceStorageBucketAclDelete(d *schema.ResourceData, meta interface{}) error { 279 config := meta.(*Config) 280 281 bucket := d.Get("bucket").(string) 282 283 re_local := d.Get("role_entity").([]interface{}) 284 for _, v := range re_local { 285 res, err := getRoleEntityPair(v.(string)) 286 if err != nil { 287 return err 288 } 289 290 log.Printf("[DEBUG]: removing entity %s", res.Entity) 291 292 err = config.clientStorage.BucketAccessControls.Delete(bucket, res.Entity).Do() 293 294 if err != nil { 295 return fmt.Errorf("Error deleting entity %s ACL: %s", res.Entity, err) 296 } 297 } 298 299 return nil 300 }