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