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