github.com/danp/terraform@v0.9.5-0.20170426144147-39d740081351/builtin/providers/google/resource_storage_bucket.go (about)

     1  package google
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"log"
     7  	"time"
     8  
     9  	"github.com/hashicorp/terraform/helper/resource"
    10  	"github.com/hashicorp/terraform/helper/schema"
    11  
    12  	"google.golang.org/api/googleapi"
    13  	"google.golang.org/api/storage/v1"
    14  )
    15  
    16  func resourceStorageBucket() *schema.Resource {
    17  	return &schema.Resource{
    18  		Create: resourceStorageBucketCreate,
    19  		Read:   resourceStorageBucketRead,
    20  		Update: resourceStorageBucketUpdate,
    21  		Delete: resourceStorageBucketDelete,
    22  
    23  		Schema: map[string]*schema.Schema{
    24  			"name": &schema.Schema{
    25  				Type:     schema.TypeString,
    26  				Required: true,
    27  				ForceNew: true,
    28  			},
    29  
    30  			"force_destroy": &schema.Schema{
    31  				Type:     schema.TypeBool,
    32  				Optional: true,
    33  				Default:  false,
    34  			},
    35  
    36  			"location": &schema.Schema{
    37  				Type:     schema.TypeString,
    38  				Default:  "US",
    39  				Optional: true,
    40  				ForceNew: true,
    41  			},
    42  
    43  			"predefined_acl": &schema.Schema{
    44  				Type:       schema.TypeString,
    45  				Deprecated: "Please use resource \"storage_bucket_acl.predefined_acl\" instead.",
    46  				Optional:   true,
    47  				ForceNew:   true,
    48  			},
    49  
    50  			"project": &schema.Schema{
    51  				Type:     schema.TypeString,
    52  				Optional: true,
    53  				ForceNew: true,
    54  			},
    55  
    56  			"self_link": &schema.Schema{
    57  				Type:     schema.TypeString,
    58  				Computed: true,
    59  			},
    60  
    61  			"storage_class": &schema.Schema{
    62  				Type:     schema.TypeString,
    63  				Optional: true,
    64  				Default:  "STANDARD",
    65  				ForceNew: true,
    66  			},
    67  
    68  			"website": &schema.Schema{
    69  				Type:     schema.TypeList,
    70  				Optional: true,
    71  				Elem: &schema.Resource{
    72  					Schema: map[string]*schema.Schema{
    73  						"main_page_suffix": &schema.Schema{
    74  							Type:     schema.TypeString,
    75  							Optional: true,
    76  						},
    77  						"not_found_page": &schema.Schema{
    78  							Type:     schema.TypeString,
    79  							Optional: true,
    80  						},
    81  					},
    82  				},
    83  			},
    84  		},
    85  	}
    86  }
    87  
    88  func resourceStorageBucketCreate(d *schema.ResourceData, meta interface{}) error {
    89  	config := meta.(*Config)
    90  
    91  	project, err := getProject(d, config)
    92  	if err != nil {
    93  		return err
    94  	}
    95  
    96  	// Get the bucket and acl
    97  	bucket := d.Get("name").(string)
    98  	location := d.Get("location").(string)
    99  
   100  	// Create a bucket, setting the acl, location and name.
   101  	sb := &storage.Bucket{Name: bucket, Location: location}
   102  
   103  	if v, ok := d.GetOk("storage_class"); ok {
   104  		sb.StorageClass = v.(string)
   105  	}
   106  
   107  	if v, ok := d.GetOk("website"); ok {
   108  		websites := v.([]interface{})
   109  
   110  		if len(websites) > 1 {
   111  			return fmt.Errorf("At most one website block is allowed")
   112  		}
   113  
   114  		sb.Website = &storage.BucketWebsite{}
   115  
   116  		website := websites[0].(map[string]interface{})
   117  
   118  		if v, ok := website["not_found_page"]; ok {
   119  			sb.Website.NotFoundPage = v.(string)
   120  		}
   121  
   122  		if v, ok := website["main_page_suffix"]; ok {
   123  			sb.Website.MainPageSuffix = v.(string)
   124  		}
   125  	}
   126  
   127  	var res *storage.Bucket
   128  
   129  	err = resource.Retry(1*time.Minute, func() *resource.RetryError {
   130  		call := config.clientStorage.Buckets.Insert(project, sb)
   131  		if v, ok := d.GetOk("predefined_acl"); ok {
   132  			call = call.PredefinedAcl(v.(string))
   133  		}
   134  
   135  		res, err = call.Do()
   136  		if err == nil {
   137  			return nil
   138  		}
   139  		if gerr, ok := err.(*googleapi.Error); ok && gerr.Code == 429 {
   140  			return resource.RetryableError(gerr)
   141  		}
   142  		return resource.NonRetryableError(err)
   143  	})
   144  
   145  	if err != nil {
   146  		fmt.Printf("Error creating bucket %s: %v", bucket, err)
   147  		return err
   148  	}
   149  
   150  	log.Printf("[DEBUG] Created bucket %v at location %v\n\n", res.Name, res.SelfLink)
   151  
   152  	// Assign the bucket ID as the resource ID
   153  	d.Set("self_link", res.SelfLink)
   154  	d.SetId(res.Id)
   155  
   156  	return nil
   157  }
   158  
   159  func resourceStorageBucketUpdate(d *schema.ResourceData, meta interface{}) error {
   160  	config := meta.(*Config)
   161  
   162  	sb := &storage.Bucket{}
   163  
   164  	if d.HasChange("website") {
   165  		if v, ok := d.GetOk("website"); ok {
   166  			websites := v.([]interface{})
   167  
   168  			if len(websites) > 1 {
   169  				return fmt.Errorf("At most one website block is allowed")
   170  			}
   171  
   172  			// Setting fields to "" to be explicit that the PATCH call will
   173  			// delete this field.
   174  			if len(websites) == 0 {
   175  				sb.Website.NotFoundPage = ""
   176  				sb.Website.MainPageSuffix = ""
   177  			} else {
   178  				website := websites[0].(map[string]interface{})
   179  				sb.Website = &storage.BucketWebsite{}
   180  				if v, ok := website["not_found_page"]; ok {
   181  					sb.Website.NotFoundPage = v.(string)
   182  				} else {
   183  					sb.Website.NotFoundPage = ""
   184  				}
   185  
   186  				if v, ok := website["main_page_suffix"]; ok {
   187  					sb.Website.MainPageSuffix = v.(string)
   188  				} else {
   189  					sb.Website.MainPageSuffix = ""
   190  				}
   191  			}
   192  		}
   193  	}
   194  
   195  	res, err := config.clientStorage.Buckets.Patch(d.Get("name").(string), sb).Do()
   196  
   197  	if err != nil {
   198  		return err
   199  	}
   200  
   201  	log.Printf("[DEBUG] Patched bucket %v at location %v\n\n", res.Name, res.SelfLink)
   202  
   203  	// Assign the bucket ID as the resource ID
   204  	d.Set("self_link", res.SelfLink)
   205  	d.SetId(res.Id)
   206  
   207  	return nil
   208  }
   209  
   210  func resourceStorageBucketRead(d *schema.ResourceData, meta interface{}) error {
   211  	config := meta.(*Config)
   212  
   213  	// Get the bucket and acl
   214  	bucket := d.Get("name").(string)
   215  	res, err := config.clientStorage.Buckets.Get(bucket).Do()
   216  
   217  	if err != nil {
   218  		if gerr, ok := err.(*googleapi.Error); ok && gerr.Code == 404 {
   219  			log.Printf("[WARN] Removing Bucket %q because it's gone", d.Get("name").(string))
   220  			// The resource doesn't exist anymore
   221  			d.SetId("")
   222  
   223  			return nil
   224  		}
   225  
   226  		return fmt.Errorf("Error reading bucket %s: %v", bucket, err)
   227  	}
   228  
   229  	log.Printf("[DEBUG] Read bucket %v at location %v\n\n", res.Name, res.SelfLink)
   230  
   231  	// Update the bucket ID according to the resource ID
   232  	d.Set("self_link", res.SelfLink)
   233  	d.SetId(res.Id)
   234  
   235  	return nil
   236  }
   237  
   238  func resourceStorageBucketDelete(d *schema.ResourceData, meta interface{}) error {
   239  	config := meta.(*Config)
   240  
   241  	// Get the bucket
   242  	bucket := d.Get("name").(string)
   243  
   244  	for {
   245  		res, err := config.clientStorage.Objects.List(bucket).Do()
   246  		if err != nil {
   247  			fmt.Printf("Error Objects.List failed: %v", err)
   248  			return err
   249  		}
   250  
   251  		if len(res.Items) != 0 {
   252  			if d.Get("force_destroy").(bool) {
   253  				// purge the bucket...
   254  				log.Printf("[DEBUG] GCS Bucket attempting to forceDestroy\n\n")
   255  
   256  				for _, object := range res.Items {
   257  					log.Printf("[DEBUG] Found %s", object.Name)
   258  					if err := config.clientStorage.Objects.Delete(bucket, object.Name).Do(); err != nil {
   259  						log.Fatalf("Error trying to delete object: %s %s\n\n", object.Name, err)
   260  					} else {
   261  						log.Printf("Object deleted: %s \n\n", object.Name)
   262  					}
   263  				}
   264  
   265  			} else {
   266  				delete_err := errors.New("Error trying to delete a bucket containing objects without `force_destroy` set to true")
   267  				log.Printf("Error! %s : %s\n\n", bucket, delete_err)
   268  				return delete_err
   269  			}
   270  		} else {
   271  			break // 0 items, bucket empty
   272  		}
   273  	}
   274  
   275  	// remove empty bucket
   276  	err := resource.Retry(1*time.Minute, func() *resource.RetryError {
   277  		err := config.clientStorage.Buckets.Delete(bucket).Do()
   278  		if err == nil {
   279  			return nil
   280  		}
   281  		if gerr, ok := err.(*googleapi.Error); ok && gerr.Code == 429 {
   282  			return resource.RetryableError(gerr)
   283  		}
   284  		return resource.NonRetryableError(err)
   285  	})
   286  	if err != nil {
   287  		fmt.Printf("Error deleting bucket %s: %v\n\n", bucket, err)
   288  		return err
   289  	}
   290  	log.Printf("[DEBUG] Deleted bucket %v\n\n", bucket)
   291  
   292  	return nil
   293  }