github.com/IBM-Cloud/terraform@v0.6.4-0.20170726051544-8872b87621df/builtin/providers/google/resource_compute_backend_service.go (about)

     1  package google
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"log"
     7  	"regexp"
     8  
     9  	"github.com/hashicorp/terraform/helper/hashcode"
    10  	"github.com/hashicorp/terraform/helper/schema"
    11  	"google.golang.org/api/compute/v1"
    12  )
    13  
    14  func resourceComputeBackendService() *schema.Resource {
    15  	return &schema.Resource{
    16  		Create: resourceComputeBackendServiceCreate,
    17  		Read:   resourceComputeBackendServiceRead,
    18  		Update: resourceComputeBackendServiceUpdate,
    19  		Delete: resourceComputeBackendServiceDelete,
    20  
    21  		Schema: map[string]*schema.Schema{
    22  			"name": &schema.Schema{
    23  				Type:     schema.TypeString,
    24  				Required: true,
    25  				ForceNew: true,
    26  				ValidateFunc: func(v interface{}, k string) (ws []string, errors []error) {
    27  					value := v.(string)
    28  					re := `^(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?)$`
    29  					if !regexp.MustCompile(re).MatchString(value) {
    30  						errors = append(errors, fmt.Errorf(
    31  							"%q (%q) doesn't match regexp %q", k, value, re))
    32  					}
    33  					return
    34  				},
    35  			},
    36  
    37  			"health_checks": &schema.Schema{
    38  				Type:     schema.TypeSet,
    39  				Elem:     &schema.Schema{Type: schema.TypeString},
    40  				Required: true,
    41  				Set:      schema.HashString,
    42  			},
    43  
    44  			"backend": &schema.Schema{
    45  				Type: schema.TypeSet,
    46  				Elem: &schema.Resource{
    47  					Schema: map[string]*schema.Schema{
    48  						"group": &schema.Schema{
    49  							Type:     schema.TypeString,
    50  							Optional: true,
    51  						},
    52  						"balancing_mode": &schema.Schema{
    53  							Type:     schema.TypeString,
    54  							Optional: true,
    55  							Default:  "UTILIZATION",
    56  						},
    57  						"capacity_scaler": &schema.Schema{
    58  							Type:     schema.TypeFloat,
    59  							Optional: true,
    60  							Default:  1,
    61  						},
    62  						"description": &schema.Schema{
    63  							Type:     schema.TypeString,
    64  							Optional: true,
    65  						},
    66  						"max_rate": &schema.Schema{
    67  							Type:     schema.TypeInt,
    68  							Optional: true,
    69  						},
    70  						"max_rate_per_instance": &schema.Schema{
    71  							Type:     schema.TypeFloat,
    72  							Optional: true,
    73  						},
    74  						"max_utilization": &schema.Schema{
    75  							Type:     schema.TypeFloat,
    76  							Optional: true,
    77  							Default:  0.8,
    78  						},
    79  					},
    80  				},
    81  				Optional: true,
    82  				Set:      resourceGoogleComputeBackendServiceBackendHash,
    83  			},
    84  
    85  			"description": &schema.Schema{
    86  				Type:     schema.TypeString,
    87  				Optional: true,
    88  			},
    89  
    90  			"enable_cdn": &schema.Schema{
    91  				Type:     schema.TypeBool,
    92  				Optional: true,
    93  				Default:  false,
    94  			},
    95  
    96  			"fingerprint": &schema.Schema{
    97  				Type:     schema.TypeString,
    98  				Computed: true,
    99  			},
   100  
   101  			"port_name": &schema.Schema{
   102  				Type:     schema.TypeString,
   103  				Optional: true,
   104  				Computed: true,
   105  			},
   106  
   107  			"project": &schema.Schema{
   108  				Type:     schema.TypeString,
   109  				Optional: true,
   110  				ForceNew: true,
   111  			},
   112  
   113  			"protocol": &schema.Schema{
   114  				Type:     schema.TypeString,
   115  				Optional: true,
   116  				Computed: true,
   117  			},
   118  
   119  			"region": &schema.Schema{
   120  				Type:     schema.TypeString,
   121  				Optional: true,
   122  				ForceNew: true,
   123  				Removed:  "region has been removed as it was never used. For internal load balancing, use google_compute_region_backend_service",
   124  			},
   125  
   126  			"self_link": &schema.Schema{
   127  				Type:     schema.TypeString,
   128  				Computed: true,
   129  			},
   130  
   131  			"session_affinity": &schema.Schema{
   132  				Type:     schema.TypeString,
   133  				Optional: true,
   134  				Computed: true,
   135  			},
   136  
   137  			"timeout_sec": &schema.Schema{
   138  				Type:     schema.TypeInt,
   139  				Optional: true,
   140  				Computed: true,
   141  			},
   142  		},
   143  	}
   144  }
   145  
   146  func resourceComputeBackendServiceCreate(d *schema.ResourceData, meta interface{}) error {
   147  	config := meta.(*Config)
   148  
   149  	hc := d.Get("health_checks").(*schema.Set).List()
   150  	healthChecks := make([]string, 0, len(hc))
   151  	for _, v := range hc {
   152  		healthChecks = append(healthChecks, v.(string))
   153  	}
   154  
   155  	service := compute.BackendService{
   156  		Name:         d.Get("name").(string),
   157  		HealthChecks: healthChecks,
   158  	}
   159  
   160  	if v, ok := d.GetOk("backend"); ok {
   161  		service.Backends = expandBackends(v.(*schema.Set).List())
   162  	}
   163  
   164  	if v, ok := d.GetOk("description"); ok {
   165  		service.Description = v.(string)
   166  	}
   167  
   168  	if v, ok := d.GetOk("port_name"); ok {
   169  		service.PortName = v.(string)
   170  	}
   171  
   172  	if v, ok := d.GetOk("protocol"); ok {
   173  		service.Protocol = v.(string)
   174  	}
   175  
   176  	if v, ok := d.GetOk("session_affinity"); ok {
   177  		service.SessionAffinity = v.(string)
   178  	}
   179  
   180  	if v, ok := d.GetOk("timeout_sec"); ok {
   181  		service.TimeoutSec = int64(v.(int))
   182  	}
   183  
   184  	if v, ok := d.GetOk("enable_cdn"); ok {
   185  		service.EnableCDN = v.(bool)
   186  	}
   187  
   188  	project, err := getProject(d, config)
   189  	if err != nil {
   190  		return err
   191  	}
   192  
   193  	log.Printf("[DEBUG] Creating new Backend Service: %#v", service)
   194  	op, err := config.clientCompute.BackendServices.Insert(
   195  		project, &service).Do()
   196  	if err != nil {
   197  		return fmt.Errorf("Error creating backend service: %s", err)
   198  	}
   199  
   200  	log.Printf("[DEBUG] Waiting for new backend service, operation: %#v", op)
   201  
   202  	// Store the ID now
   203  	d.SetId(service.Name)
   204  
   205  	// Wait for the operation to complete
   206  	waitErr := computeOperationWaitGlobal(config, op, project, "Creating Backend Service")
   207  	if waitErr != nil {
   208  		// The resource didn't actually create
   209  		d.SetId("")
   210  		return waitErr
   211  	}
   212  
   213  	return resourceComputeBackendServiceRead(d, meta)
   214  }
   215  
   216  func resourceComputeBackendServiceRead(d *schema.ResourceData, meta interface{}) error {
   217  	config := meta.(*Config)
   218  
   219  	project, err := getProject(d, config)
   220  	if err != nil {
   221  		return err
   222  	}
   223  
   224  	service, err := config.clientCompute.BackendServices.Get(
   225  		project, d.Id()).Do()
   226  	if err != nil {
   227  		return handleNotFoundError(err, d, fmt.Sprintf("Backend Service %q", d.Get("name").(string)))
   228  	}
   229  
   230  	d.Set("description", service.Description)
   231  	d.Set("enable_cdn", service.EnableCDN)
   232  	d.Set("port_name", service.PortName)
   233  	d.Set("protocol", service.Protocol)
   234  	d.Set("session_affinity", service.SessionAffinity)
   235  	d.Set("timeout_sec", service.TimeoutSec)
   236  	d.Set("fingerprint", service.Fingerprint)
   237  	d.Set("self_link", service.SelfLink)
   238  
   239  	d.Set("backend", flattenBackends(service.Backends))
   240  	d.Set("health_checks", service.HealthChecks)
   241  
   242  	return nil
   243  }
   244  
   245  func resourceComputeBackendServiceUpdate(d *schema.ResourceData, meta interface{}) error {
   246  	config := meta.(*Config)
   247  
   248  	project, err := getProject(d, config)
   249  	if err != nil {
   250  		return err
   251  	}
   252  
   253  	hc := d.Get("health_checks").(*schema.Set).List()
   254  	healthChecks := make([]string, 0, len(hc))
   255  	for _, v := range hc {
   256  		healthChecks = append(healthChecks, v.(string))
   257  	}
   258  
   259  	service := compute.BackendService{
   260  		Name:         d.Get("name").(string),
   261  		Fingerprint:  d.Get("fingerprint").(string),
   262  		HealthChecks: healthChecks,
   263  	}
   264  
   265  	// Optional things
   266  	if v, ok := d.GetOk("backend"); ok {
   267  		service.Backends = expandBackends(v.(*schema.Set).List())
   268  	}
   269  	if v, ok := d.GetOk("description"); ok {
   270  		service.Description = v.(string)
   271  	}
   272  	if v, ok := d.GetOk("port_name"); ok {
   273  		service.PortName = v.(string)
   274  	}
   275  	if v, ok := d.GetOk("protocol"); ok {
   276  		service.Protocol = v.(string)
   277  	}
   278  	if v, ok := d.GetOk("timeout_sec"); ok {
   279  		service.TimeoutSec = int64(v.(int))
   280  	}
   281  
   282  	if d.HasChange("session_affinity") {
   283  		service.SessionAffinity = d.Get("session_affinity").(string)
   284  	}
   285  
   286  	if d.HasChange("enable_cdn") {
   287  		service.EnableCDN = d.Get("enable_cdn").(bool)
   288  	}
   289  
   290  	log.Printf("[DEBUG] Updating existing Backend Service %q: %#v", d.Id(), service)
   291  	op, err := config.clientCompute.BackendServices.Update(
   292  		project, d.Id(), &service).Do()
   293  	if err != nil {
   294  		return fmt.Errorf("Error updating backend service: %s", err)
   295  	}
   296  
   297  	d.SetId(service.Name)
   298  
   299  	err = computeOperationWaitGlobal(config, op, project, "Updating Backend Service")
   300  	if err != nil {
   301  		return err
   302  	}
   303  
   304  	return resourceComputeBackendServiceRead(d, meta)
   305  }
   306  
   307  func resourceComputeBackendServiceDelete(d *schema.ResourceData, meta interface{}) error {
   308  	config := meta.(*Config)
   309  
   310  	project, err := getProject(d, config)
   311  	if err != nil {
   312  		return err
   313  	}
   314  
   315  	log.Printf("[DEBUG] Deleting backend service %s", d.Id())
   316  	op, err := config.clientCompute.BackendServices.Delete(
   317  		project, d.Id()).Do()
   318  	if err != nil {
   319  		return fmt.Errorf("Error deleting backend service: %s", err)
   320  	}
   321  
   322  	err = computeOperationWaitGlobal(config, op, project, "Deleting Backend Service")
   323  	if err != nil {
   324  		return err
   325  	}
   326  
   327  	d.SetId("")
   328  	return nil
   329  }
   330  
   331  func expandBackends(configured []interface{}) []*compute.Backend {
   332  	backends := make([]*compute.Backend, 0, len(configured))
   333  
   334  	for _, raw := range configured {
   335  		data := raw.(map[string]interface{})
   336  
   337  		b := compute.Backend{
   338  			Group: data["group"].(string),
   339  		}
   340  
   341  		if v, ok := data["balancing_mode"]; ok {
   342  			b.BalancingMode = v.(string)
   343  		}
   344  		if v, ok := data["capacity_scaler"]; ok {
   345  			b.CapacityScaler = v.(float64)
   346  		}
   347  		if v, ok := data["description"]; ok {
   348  			b.Description = v.(string)
   349  		}
   350  		if v, ok := data["max_rate"]; ok {
   351  			b.MaxRate = int64(v.(int))
   352  		}
   353  		if v, ok := data["max_rate_per_instance"]; ok {
   354  			b.MaxRatePerInstance = v.(float64)
   355  		}
   356  		if v, ok := data["max_utilization"]; ok {
   357  			b.MaxUtilization = v.(float64)
   358  		}
   359  
   360  		backends = append(backends, &b)
   361  	}
   362  
   363  	return backends
   364  }
   365  
   366  func flattenBackends(backends []*compute.Backend) []map[string]interface{} {
   367  	result := make([]map[string]interface{}, 0, len(backends))
   368  
   369  	for _, b := range backends {
   370  		data := make(map[string]interface{})
   371  
   372  		data["balancing_mode"] = b.BalancingMode
   373  		data["capacity_scaler"] = b.CapacityScaler
   374  		data["description"] = b.Description
   375  		data["group"] = b.Group
   376  		data["max_rate"] = b.MaxRate
   377  		data["max_rate_per_instance"] = b.MaxRatePerInstance
   378  		data["max_utilization"] = b.MaxUtilization
   379  
   380  		result = append(result, data)
   381  	}
   382  
   383  	return result
   384  }
   385  
   386  func resourceGoogleComputeBackendServiceBackendHash(v interface{}) int {
   387  	if v == nil {
   388  		return 0
   389  	}
   390  
   391  	var buf bytes.Buffer
   392  	m := v.(map[string]interface{})
   393  
   394  	buf.WriteString(fmt.Sprintf("%s-", m["group"].(string)))
   395  
   396  	if v, ok := m["balancing_mode"]; ok {
   397  		buf.WriteString(fmt.Sprintf("%s-", v.(string)))
   398  	}
   399  	if v, ok := m["capacity_scaler"]; ok {
   400  		buf.WriteString(fmt.Sprintf("%f-", v.(float64)))
   401  	}
   402  	if v, ok := m["description"]; ok {
   403  		buf.WriteString(fmt.Sprintf("%s-", v.(string)))
   404  	}
   405  	if v, ok := m["max_rate"]; ok {
   406  		buf.WriteString(fmt.Sprintf("%d-", int64(v.(int))))
   407  	}
   408  	if v, ok := m["max_rate_per_instance"]; ok {
   409  		buf.WriteString(fmt.Sprintf("%f-", v.(float64)))
   410  	}
   411  	if v, ok := m["max_rate_per_instance"]; ok {
   412  		buf.WriteString(fmt.Sprintf("%f-", v.(float64)))
   413  	}
   414  
   415  	return hashcode.String(buf.String())
   416  }