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  }