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