github.com/andresvia/terraform@v0.6.15-0.20160412045437-d51c75946785/builtin/providers/google/resource_compute_target_pool.go (about)

     1  package google
     2  
     3  import (
     4  	"fmt"
     5  	"log"
     6  	"strings"
     7  
     8  	"github.com/hashicorp/terraform/helper/schema"
     9  	"google.golang.org/api/compute/v1"
    10  	"google.golang.org/api/googleapi"
    11  )
    12  
    13  func resourceComputeTargetPool() *schema.Resource {
    14  	return &schema.Resource{
    15  		Create: resourceComputeTargetPoolCreate,
    16  		Read:   resourceComputeTargetPoolRead,
    17  		Delete: resourceComputeTargetPoolDelete,
    18  		Update: resourceComputeTargetPoolUpdate,
    19  
    20  		Schema: map[string]*schema.Schema{
    21  			"name": &schema.Schema{
    22  				Type:     schema.TypeString,
    23  				Required: true,
    24  				ForceNew: true,
    25  			},
    26  
    27  			"backup_pool": &schema.Schema{
    28  				Type:     schema.TypeString,
    29  				Optional: true,
    30  				ForceNew: false,
    31  			},
    32  
    33  			"description": &schema.Schema{
    34  				Type:     schema.TypeString,
    35  				Optional: true,
    36  				ForceNew: true,
    37  			},
    38  
    39  			"failover_ratio": &schema.Schema{
    40  				Type:     schema.TypeFloat,
    41  				Optional: true,
    42  				ForceNew: true,
    43  			},
    44  
    45  			"health_checks": &schema.Schema{
    46  				Type:     schema.TypeList,
    47  				Optional: true,
    48  				ForceNew: false,
    49  				Elem:     &schema.Schema{Type: schema.TypeString},
    50  			},
    51  
    52  			"instances": &schema.Schema{
    53  				Type:     schema.TypeList,
    54  				Optional: true,
    55  				ForceNew: false,
    56  				Elem:     &schema.Schema{Type: schema.TypeString},
    57  			},
    58  
    59  			"project": &schema.Schema{
    60  				Type:     schema.TypeString,
    61  				Optional: true,
    62  				ForceNew: true,
    63  			},
    64  
    65  			"region": &schema.Schema{
    66  				Type:     schema.TypeString,
    67  				Optional: true,
    68  				ForceNew: true,
    69  			},
    70  
    71  			"self_link": &schema.Schema{
    72  				Type:     schema.TypeString,
    73  				Computed: true,
    74  			},
    75  
    76  			"session_affinity": &schema.Schema{
    77  				Type:     schema.TypeString,
    78  				Optional: true,
    79  				ForceNew: true,
    80  			},
    81  		},
    82  	}
    83  }
    84  
    85  func convertStringArr(ifaceArr []interface{}) []string {
    86  	arr := make([]string, len(ifaceArr))
    87  	for i, v := range ifaceArr {
    88  		arr[i] = v.(string)
    89  	}
    90  	return arr
    91  }
    92  
    93  // Healthchecks need to exist before being referred to from the target pool.
    94  func convertHealthChecks(config *Config, project string, names []string) ([]string, error) {
    95  	urls := make([]string, len(names))
    96  	for i, name := range names {
    97  		// Look up the healthcheck
    98  		res, err := config.clientCompute.HttpHealthChecks.Get(project, name).Do()
    99  		if err != nil {
   100  			return nil, fmt.Errorf("Error reading HealthCheck: %s", err)
   101  		}
   102  		urls[i] = res.SelfLink
   103  	}
   104  	return urls, nil
   105  }
   106  
   107  // Instances do not need to exist yet, so we simply generate URLs.
   108  // Instances can be full URLS or zone/name
   109  func convertInstances(config *Config, project string, names []string) ([]string, error) {
   110  	urls := make([]string, len(names))
   111  	for i, name := range names {
   112  		if strings.HasPrefix(name, "https://www.googleapis.com/compute/v1/") {
   113  			urls[i] = name
   114  		} else {
   115  			splitName := strings.Split(name, "/")
   116  			if len(splitName) != 2 {
   117  				return nil, fmt.Errorf("Invalid instance name, require URL or zone/name: %s", name)
   118  			} else {
   119  				urls[i] = fmt.Sprintf(
   120  					"https://www.googleapis.com/compute/v1/projects/%s/zones/%s/instances/%s",
   121  					project, splitName[0], splitName[1])
   122  			}
   123  		}
   124  	}
   125  	return urls, nil
   126  }
   127  
   128  func resourceComputeTargetPoolCreate(d *schema.ResourceData, meta interface{}) error {
   129  	config := meta.(*Config)
   130  
   131  	region, err := getRegion(d, config)
   132  	if err != nil {
   133  		return err
   134  	}
   135  
   136  	project, err := getProject(d, config)
   137  	if err != nil {
   138  		return err
   139  	}
   140  
   141  	hchkUrls, err := convertHealthChecks(
   142  		config, project, convertStringArr(d.Get("health_checks").([]interface{})))
   143  	if err != nil {
   144  		return err
   145  	}
   146  
   147  	instanceUrls, err := convertInstances(
   148  		config, project, convertStringArr(d.Get("instances").([]interface{})))
   149  	if err != nil {
   150  		return err
   151  	}
   152  
   153  	// Build the parameter
   154  	tpool := &compute.TargetPool{
   155  		BackupPool:      d.Get("backup_pool").(string),
   156  		Description:     d.Get("description").(string),
   157  		HealthChecks:    hchkUrls,
   158  		Instances:       instanceUrls,
   159  		Name:            d.Get("name").(string),
   160  		SessionAffinity: d.Get("session_affinity").(string),
   161  	}
   162  	if d.Get("failover_ratio") != nil {
   163  		tpool.FailoverRatio = d.Get("failover_ratio").(float64)
   164  	}
   165  	log.Printf("[DEBUG] TargetPool insert request: %#v", tpool)
   166  	op, err := config.clientCompute.TargetPools.Insert(
   167  		project, region, tpool).Do()
   168  	if err != nil {
   169  		return fmt.Errorf("Error creating TargetPool: %s", err)
   170  	}
   171  
   172  	// It probably maybe worked, so store the ID now
   173  	d.SetId(tpool.Name)
   174  
   175  	err = computeOperationWaitRegion(config, op, region, "Creating Target Pool")
   176  	if err != nil {
   177  		return err
   178  	}
   179  	return resourceComputeTargetPoolRead(d, meta)
   180  }
   181  
   182  func calcAddRemove(from []string, to []string) ([]string, []string) {
   183  	add := make([]string, 0)
   184  	remove := make([]string, 0)
   185  	for _, u := range to {
   186  		found := false
   187  		for _, v := range from {
   188  			if u == v {
   189  				found = true
   190  				break
   191  			}
   192  		}
   193  		if !found {
   194  			add = append(add, u)
   195  		}
   196  	}
   197  	for _, u := range from {
   198  		found := false
   199  		for _, v := range to {
   200  			if u == v {
   201  				found = true
   202  				break
   203  			}
   204  		}
   205  		if !found {
   206  			remove = append(remove, u)
   207  		}
   208  	}
   209  	return add, remove
   210  }
   211  
   212  func resourceComputeTargetPoolUpdate(d *schema.ResourceData, meta interface{}) error {
   213  	config := meta.(*Config)
   214  
   215  	region, err := getRegion(d, config)
   216  	if err != nil {
   217  		return err
   218  	}
   219  
   220  	project, err := getProject(d, config)
   221  	if err != nil {
   222  		return err
   223  	}
   224  
   225  	d.Partial(true)
   226  
   227  	if d.HasChange("health_checks") {
   228  
   229  		from_, to_ := d.GetChange("health_checks")
   230  		from := convertStringArr(from_.([]interface{}))
   231  		to := convertStringArr(to_.([]interface{}))
   232  		fromUrls, err := convertHealthChecks(config, project, from)
   233  		if err != nil {
   234  			return err
   235  		}
   236  		toUrls, err := convertHealthChecks(config, project, to)
   237  		if err != nil {
   238  			return err
   239  		}
   240  		add, remove := calcAddRemove(fromUrls, toUrls)
   241  
   242  		removeReq := &compute.TargetPoolsRemoveHealthCheckRequest{
   243  			HealthChecks: make([]*compute.HealthCheckReference, len(remove)),
   244  		}
   245  		for i, v := range remove {
   246  			removeReq.HealthChecks[i] = &compute.HealthCheckReference{HealthCheck: v}
   247  		}
   248  		op, err := config.clientCompute.TargetPools.RemoveHealthCheck(
   249  			project, region, d.Id(), removeReq).Do()
   250  		if err != nil {
   251  			return fmt.Errorf("Error updating health_check: %s", err)
   252  		}
   253  
   254  		err = computeOperationWaitRegion(config, op, region, "Updating Target Pool")
   255  		if err != nil {
   256  			return err
   257  		}
   258  		addReq := &compute.TargetPoolsAddHealthCheckRequest{
   259  			HealthChecks: make([]*compute.HealthCheckReference, len(add)),
   260  		}
   261  		for i, v := range add {
   262  			addReq.HealthChecks[i] = &compute.HealthCheckReference{HealthCheck: v}
   263  		}
   264  		op, err = config.clientCompute.TargetPools.AddHealthCheck(
   265  			project, region, d.Id(), addReq).Do()
   266  		if err != nil {
   267  			return fmt.Errorf("Error updating health_check: %s", err)
   268  		}
   269  
   270  		err = computeOperationWaitRegion(config, op, region, "Updating Target Pool")
   271  		if err != nil {
   272  			return err
   273  		}
   274  		d.SetPartial("health_checks")
   275  	}
   276  
   277  	if d.HasChange("instances") {
   278  
   279  		from_, to_ := d.GetChange("instances")
   280  		from := convertStringArr(from_.([]interface{}))
   281  		to := convertStringArr(to_.([]interface{}))
   282  		fromUrls, err := convertInstances(config, project, from)
   283  		if err != nil {
   284  			return err
   285  		}
   286  		toUrls, err := convertInstances(config, project, to)
   287  		if err != nil {
   288  			return err
   289  		}
   290  		add, remove := calcAddRemove(fromUrls, toUrls)
   291  
   292  		addReq := &compute.TargetPoolsAddInstanceRequest{
   293  			Instances: make([]*compute.InstanceReference, len(add)),
   294  		}
   295  		for i, v := range add {
   296  			addReq.Instances[i] = &compute.InstanceReference{Instance: v}
   297  		}
   298  		op, err := config.clientCompute.TargetPools.AddInstance(
   299  			project, region, d.Id(), addReq).Do()
   300  		if err != nil {
   301  			return fmt.Errorf("Error updating instances: %s", err)
   302  		}
   303  
   304  		err = computeOperationWaitRegion(config, op, region, "Updating Target Pool")
   305  		if err != nil {
   306  			return err
   307  		}
   308  		removeReq := &compute.TargetPoolsRemoveInstanceRequest{
   309  			Instances: make([]*compute.InstanceReference, len(remove)),
   310  		}
   311  		for i, v := range remove {
   312  			removeReq.Instances[i] = &compute.InstanceReference{Instance: v}
   313  		}
   314  		op, err = config.clientCompute.TargetPools.RemoveInstance(
   315  			project, region, d.Id(), removeReq).Do()
   316  		if err != nil {
   317  			return fmt.Errorf("Error updating instances: %s", err)
   318  		}
   319  		err = computeOperationWaitRegion(config, op, region, "Updating Target Pool")
   320  		if err != nil {
   321  			return err
   322  		}
   323  		d.SetPartial("instances")
   324  	}
   325  
   326  	if d.HasChange("backup_pool") {
   327  		bpool_name := d.Get("backup_pool").(string)
   328  		tref := &compute.TargetReference{
   329  			Target: bpool_name,
   330  		}
   331  		op, err := config.clientCompute.TargetPools.SetBackup(
   332  			project, region, d.Id(), tref).Do()
   333  		if err != nil {
   334  			return fmt.Errorf("Error updating backup_pool: %s", err)
   335  		}
   336  
   337  		err = computeOperationWaitRegion(config, op, region, "Updating Target Pool")
   338  		if err != nil {
   339  			return err
   340  		}
   341  		d.SetPartial("backup_pool")
   342  	}
   343  
   344  	d.Partial(false)
   345  
   346  	return resourceComputeTargetPoolRead(d, meta)
   347  }
   348  
   349  func resourceComputeTargetPoolRead(d *schema.ResourceData, meta interface{}) error {
   350  	config := meta.(*Config)
   351  
   352  	region, err := getRegion(d, config)
   353  	if err != nil {
   354  		return err
   355  	}
   356  
   357  	project, err := getProject(d, config)
   358  	if err != nil {
   359  		return err
   360  	}
   361  
   362  	tpool, err := config.clientCompute.TargetPools.Get(
   363  		project, region, d.Id()).Do()
   364  	if err != nil {
   365  		if gerr, ok := err.(*googleapi.Error); ok && gerr.Code == 404 {
   366  			log.Printf("[WARN] Removing Target Pool %q because it's gone", d.Get("name").(string))
   367  			// The resource doesn't exist anymore
   368  			d.SetId("")
   369  
   370  			return nil
   371  		}
   372  
   373  		return fmt.Errorf("Error reading TargetPool: %s", err)
   374  	}
   375  
   376  	d.Set("self_link", tpool.SelfLink)
   377  
   378  	return nil
   379  }
   380  
   381  func resourceComputeTargetPoolDelete(d *schema.ResourceData, meta interface{}) error {
   382  	config := meta.(*Config)
   383  
   384  	region, err := getRegion(d, config)
   385  	if err != nil {
   386  		return err
   387  	}
   388  
   389  	project, err := getProject(d, config)
   390  	if err != nil {
   391  		return err
   392  	}
   393  
   394  	// Delete the TargetPool
   395  	op, err := config.clientCompute.TargetPools.Delete(
   396  		project, region, d.Id()).Do()
   397  	if err != nil {
   398  		return fmt.Errorf("Error deleting TargetPool: %s", err)
   399  	}
   400  
   401  	err = computeOperationWaitRegion(config, op, region, "Deleting Target Pool")
   402  	if err != nil {
   403  		return err
   404  	}
   405  	d.SetId("")
   406  	return nil
   407  }