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

     1  package google
     2  
     3  import (
     4  	"fmt"
     5  	"log"
     6  	"strings"
     7  
     8  	"google.golang.org/api/compute/v1"
     9  	"google.golang.org/api/googleapi"
    10  
    11  	"github.com/hashicorp/terraform/helper/schema"
    12  )
    13  
    14  func resourceComputeInstanceGroupManager() *schema.Resource {
    15  	return &schema.Resource{
    16  		Create: resourceComputeInstanceGroupManagerCreate,
    17  		Read:   resourceComputeInstanceGroupManagerRead,
    18  		Update: resourceComputeInstanceGroupManagerUpdate,
    19  		Delete: resourceComputeInstanceGroupManagerDelete,
    20  
    21  		Schema: map[string]*schema.Schema{
    22  			"base_instance_name": &schema.Schema{
    23  				Type:     schema.TypeString,
    24  				Required: true,
    25  				ForceNew: true,
    26  			},
    27  
    28  			"instance_template": &schema.Schema{
    29  				Type:     schema.TypeString,
    30  				Required: true,
    31  			},
    32  
    33  			"name": &schema.Schema{
    34  				Type:     schema.TypeString,
    35  				Required: true,
    36  				ForceNew: true,
    37  			},
    38  
    39  			"zone": &schema.Schema{
    40  				Type:     schema.TypeString,
    41  				Required: true,
    42  				ForceNew: true,
    43  			},
    44  
    45  			"description": &schema.Schema{
    46  				Type:     schema.TypeString,
    47  				Optional: true,
    48  				ForceNew: true,
    49  			},
    50  
    51  			"fingerprint": &schema.Schema{
    52  				Type:     schema.TypeString,
    53  				Computed: true,
    54  			},
    55  
    56  			"instance_group": &schema.Schema{
    57  				Type:     schema.TypeString,
    58  				Computed: true,
    59  			},
    60  
    61  			"named_port": &schema.Schema{
    62  				Type:     schema.TypeList,
    63  				Optional: true,
    64  				Elem: &schema.Resource{
    65  					Schema: map[string]*schema.Schema{
    66  						"name": &schema.Schema{
    67  							Type:     schema.TypeString,
    68  							Required: true,
    69  						},
    70  
    71  						"port": &schema.Schema{
    72  							Type:     schema.TypeInt,
    73  							Required: true,
    74  						},
    75  					},
    76  				},
    77  			},
    78  
    79  			"project": &schema.Schema{
    80  				Type:     schema.TypeString,
    81  				Optional: true,
    82  				ForceNew: true,
    83  			},
    84  
    85  			"self_link": &schema.Schema{
    86  				Type:     schema.TypeString,
    87  				Computed: true,
    88  			},
    89  
    90  			"update_strategy": &schema.Schema{
    91  				Type:     schema.TypeString,
    92  				Optional: true,
    93  				Default:  "RESTART",
    94  			},
    95  
    96  			"target_pools": &schema.Schema{
    97  				Type:     schema.TypeSet,
    98  				Optional: true,
    99  				Elem:     &schema.Schema{Type: schema.TypeString},
   100  				Set:      schema.HashString,
   101  			},
   102  
   103  			"target_size": &schema.Schema{
   104  				Type:     schema.TypeInt,
   105  				Computed: true,
   106  				Optional: true,
   107  			},
   108  		},
   109  	}
   110  }
   111  
   112  func getNamedPorts(nps []interface{}) []*compute.NamedPort {
   113  	namedPorts := make([]*compute.NamedPort, 0, len(nps))
   114  	for _, v := range nps {
   115  		np := v.(map[string]interface{})
   116  		namedPorts = append(namedPorts, &compute.NamedPort{
   117  			Name: np["name"].(string),
   118  			Port: int64(np["port"].(int)),
   119  		})
   120  	}
   121  	return namedPorts
   122  }
   123  
   124  func resourceComputeInstanceGroupManagerCreate(d *schema.ResourceData, meta interface{}) error {
   125  	config := meta.(*Config)
   126  
   127  	project, err := getProject(d, config)
   128  	if err != nil {
   129  		return err
   130  	}
   131  
   132  	// Get group size, default to 1 if not given
   133  	var target_size int64 = 1
   134  	if v, ok := d.GetOk("target_size"); ok {
   135  		target_size = int64(v.(int))
   136  	}
   137  
   138  	// Build the parameter
   139  	manager := &compute.InstanceGroupManager{
   140  		Name:             d.Get("name").(string),
   141  		BaseInstanceName: d.Get("base_instance_name").(string),
   142  		InstanceTemplate: d.Get("instance_template").(string),
   143  		TargetSize:       target_size,
   144  	}
   145  
   146  	// Set optional fields
   147  	if v, ok := d.GetOk("description"); ok {
   148  		manager.Description = v.(string)
   149  	}
   150  
   151  	if v, ok := d.GetOk("named_port"); ok {
   152  		manager.NamedPorts = getNamedPorts(v.([]interface{}))
   153  	}
   154  
   155  	if attr := d.Get("target_pools").(*schema.Set); attr.Len() > 0 {
   156  		var s []string
   157  		for _, v := range attr.List() {
   158  			s = append(s, v.(string))
   159  		}
   160  		manager.TargetPools = s
   161  	}
   162  
   163  	updateStrategy := d.Get("update_strategy").(string)
   164  	if !(updateStrategy == "NONE" || updateStrategy == "RESTART") {
   165  		return fmt.Errorf("Update strategy must be \"NONE\" or \"RESTART\"")
   166  	}
   167  
   168  	log.Printf("[DEBUG] InstanceGroupManager insert request: %#v", manager)
   169  	op, err := config.clientCompute.InstanceGroupManagers.Insert(
   170  		project, d.Get("zone").(string), manager).Do()
   171  	if err != nil {
   172  		return fmt.Errorf("Error creating InstanceGroupManager: %s", err)
   173  	}
   174  
   175  	// It probably maybe worked, so store the ID now
   176  	d.SetId(manager.Name)
   177  
   178  	// Wait for the operation to complete
   179  	err = computeOperationWaitZone(config, op, d.Get("zone").(string), "Creating InstanceGroupManager")
   180  	if err != nil {
   181  		return err
   182  	}
   183  
   184  	return resourceComputeInstanceGroupManagerRead(d, meta)
   185  }
   186  
   187  func resourceComputeInstanceGroupManagerRead(d *schema.ResourceData, meta interface{}) error {
   188  	config := meta.(*Config)
   189  
   190  	project, err := getProject(d, config)
   191  	if err != nil {
   192  		return err
   193  	}
   194  
   195  	manager, err := config.clientCompute.InstanceGroupManagers.Get(
   196  		project, d.Get("zone").(string), d.Id()).Do()
   197  	if err != nil {
   198  		if gerr, ok := err.(*googleapi.Error); ok && gerr.Code == 404 {
   199  			log.Printf("[WARN] Removing Instance Group Manager %q because it's gone", d.Get("name").(string))
   200  			// The resource doesn't exist anymore
   201  			d.SetId("")
   202  
   203  			return nil
   204  		}
   205  
   206  		return fmt.Errorf("Error reading instance group manager: %s", err)
   207  	}
   208  
   209  	// Set computed fields
   210  	d.Set("named_port", manager.NamedPorts)
   211  	d.Set("fingerprint", manager.Fingerprint)
   212  	d.Set("instance_group", manager.InstanceGroup)
   213  	d.Set("target_size", manager.TargetSize)
   214  	d.Set("self_link", manager.SelfLink)
   215  
   216  	return nil
   217  }
   218  func resourceComputeInstanceGroupManagerUpdate(d *schema.ResourceData, meta interface{}) error {
   219  	config := meta.(*Config)
   220  
   221  	project, err := getProject(d, config)
   222  	if err != nil {
   223  		return err
   224  	}
   225  
   226  	d.Partial(true)
   227  
   228  	// If target_pools changes then update
   229  	if d.HasChange("target_pools") {
   230  		var targetPools []string
   231  		if attr := d.Get("target_pools").(*schema.Set); attr.Len() > 0 {
   232  			for _, v := range attr.List() {
   233  				targetPools = append(targetPools, v.(string))
   234  			}
   235  		}
   236  
   237  		// Build the parameter
   238  		setTargetPools := &compute.InstanceGroupManagersSetTargetPoolsRequest{
   239  			Fingerprint: d.Get("fingerprint").(string),
   240  			TargetPools: targetPools,
   241  		}
   242  
   243  		op, err := config.clientCompute.InstanceGroupManagers.SetTargetPools(
   244  			project, d.Get("zone").(string), d.Id(), setTargetPools).Do()
   245  		if err != nil {
   246  			return fmt.Errorf("Error updating InstanceGroupManager: %s", err)
   247  		}
   248  
   249  		// Wait for the operation to complete
   250  		err = computeOperationWaitZone(config, op, d.Get("zone").(string), "Updating InstanceGroupManager")
   251  		if err != nil {
   252  			return err
   253  		}
   254  
   255  		d.SetPartial("target_pools")
   256  	}
   257  
   258  	// If instance_template changes then update
   259  	if d.HasChange("instance_template") {
   260  		// Build the parameter
   261  		setInstanceTemplate := &compute.InstanceGroupManagersSetInstanceTemplateRequest{
   262  			InstanceTemplate: d.Get("instance_template").(string),
   263  		}
   264  
   265  		op, err := config.clientCompute.InstanceGroupManagers.SetInstanceTemplate(
   266  			project, d.Get("zone").(string), d.Id(), setInstanceTemplate).Do()
   267  		if err != nil {
   268  			return fmt.Errorf("Error updating InstanceGroupManager: %s", err)
   269  		}
   270  
   271  		// Wait for the operation to complete
   272  		err = computeOperationWaitZone(config, op, d.Get("zone").(string), "Updating InstanceGroupManager")
   273  		if err != nil {
   274  			return err
   275  		}
   276  
   277  		if d.Get("update_strategy").(string) == "RESTART" {
   278  			managedInstances, err := config.clientCompute.InstanceGroupManagers.ListManagedInstances(
   279  				project, d.Get("zone").(string), d.Id()).Do()
   280  
   281  			managedInstanceCount := len(managedInstances.ManagedInstances)
   282  			instances := make([]string, managedInstanceCount)
   283  			for i, v := range managedInstances.ManagedInstances {
   284  				instances[i] = v.Instance
   285  			}
   286  
   287  			recreateInstances := &compute.InstanceGroupManagersRecreateInstancesRequest{
   288  				Instances: instances,
   289  			}
   290  
   291  			op, err = config.clientCompute.InstanceGroupManagers.RecreateInstances(
   292  				project, d.Get("zone").(string), d.Id(), recreateInstances).Do()
   293  
   294  			if err != nil {
   295  				return fmt.Errorf("Error restarting instance group managers instances: %s", err)
   296  			}
   297  
   298  			// Wait for the operation to complete
   299  			err = computeOperationWaitZoneTime(config, op, d.Get("zone").(string),
   300  				managedInstanceCount*4, "Restarting InstanceGroupManagers instances")
   301  			if err != nil {
   302  				return err
   303  			}
   304  		}
   305  
   306  		d.SetPartial("instance_template")
   307  	}
   308  
   309  	// If named_port changes then update:
   310  	if d.HasChange("named_port") {
   311  
   312  		// Build the parameters for a "SetNamedPorts" request:
   313  		namedPorts := getNamedPorts(d.Get("named_port").([]interface{}))
   314  		setNamedPorts := &compute.InstanceGroupsSetNamedPortsRequest{
   315  			NamedPorts: namedPorts,
   316  		}
   317  
   318  		// Make the request:
   319  		op, err := config.clientCompute.InstanceGroups.SetNamedPorts(
   320  			project, d.Get("zone").(string), d.Id(), setNamedPorts).Do()
   321  		if err != nil {
   322  			return fmt.Errorf("Error updating InstanceGroupManager: %s", err)
   323  		}
   324  
   325  		// Wait for the operation to complete:
   326  		err = computeOperationWaitZone(config, op, d.Get("zone").(string), "Updating InstanceGroupManager")
   327  		if err != nil {
   328  			return err
   329  		}
   330  
   331  		d.SetPartial("named_port")
   332  	}
   333  
   334  	// If size changes trigger a resize
   335  	if d.HasChange("target_size") {
   336  		if v, ok := d.GetOk("target_size"); ok {
   337  			// Only do anything if the new size is set
   338  			target_size := int64(v.(int))
   339  
   340  			op, err := config.clientCompute.InstanceGroupManagers.Resize(
   341  				project, d.Get("zone").(string), d.Id(), target_size).Do()
   342  			if err != nil {
   343  				return fmt.Errorf("Error updating InstanceGroupManager: %s", err)
   344  			}
   345  
   346  			// Wait for the operation to complete
   347  			err = computeOperationWaitZone(config, op, d.Get("zone").(string), "Updating InstanceGroupManager")
   348  			if err != nil {
   349  				return err
   350  			}
   351  		}
   352  
   353  		d.SetPartial("target_size")
   354  	}
   355  
   356  	d.Partial(false)
   357  
   358  	return resourceComputeInstanceGroupManagerRead(d, meta)
   359  }
   360  
   361  func resourceComputeInstanceGroupManagerDelete(d *schema.ResourceData, meta interface{}) error {
   362  	config := meta.(*Config)
   363  
   364  	project, err := getProject(d, config)
   365  	if err != nil {
   366  		return err
   367  	}
   368  
   369  	zone := d.Get("zone").(string)
   370  	op, err := config.clientCompute.InstanceGroupManagers.Delete(project, zone, d.Id()).Do()
   371  	if err != nil {
   372  		return fmt.Errorf("Error deleting instance group manager: %s", err)
   373  	}
   374  
   375  	currentSize := int64(d.Get("target_size").(int))
   376  
   377  	// Wait for the operation to complete
   378  	err = computeOperationWaitZone(config, op, d.Get("zone").(string), "Deleting InstanceGroupManager")
   379  
   380  	for err != nil && currentSize > 0 {
   381  		if !strings.Contains(err.Error(), "timeout") {
   382  			return err
   383  		}
   384  
   385  		instanceGroup, err := config.clientCompute.InstanceGroups.Get(
   386  			project, d.Get("zone").(string), d.Id()).Do()
   387  
   388  		if err != nil {
   389  			return fmt.Errorf("Error getting instance group size: %s", err)
   390  		}
   391  
   392  		if instanceGroup.Size >= currentSize {
   393  			return fmt.Errorf("Error, instance group isn't shrinking during delete")
   394  		}
   395  
   396  		log.Printf("[INFO] timeout occured, but instance group is shrinking (%d < %d)", instanceGroup.Size, currentSize)
   397  
   398  		currentSize = instanceGroup.Size
   399  
   400  		err = computeOperationWaitZone(config, op, d.Get("zone").(string), "Deleting InstanceGroupManager")
   401  	}
   402  
   403  	d.SetId("")
   404  	return nil
   405  }