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