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