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