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