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