github.com/erriapo/terraform@v0.6.12-0.20160203182612-0340ea72354f/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  }