github.com/IBM-Cloud/terraform@v0.6.4-0.20170726051544-8872b87621df/builtin/providers/google/resource_compute_instance_group.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 resourceComputeInstanceGroup() *schema.Resource {
    15  	return &schema.Resource{
    16  		Create: resourceComputeInstanceGroupCreate,
    17  		Read:   resourceComputeInstanceGroupRead,
    18  		Update: resourceComputeInstanceGroupUpdate,
    19  		Delete: resourceComputeInstanceGroupDelete,
    20  
    21  		SchemaVersion: 1,
    22  
    23  		Schema: map[string]*schema.Schema{
    24  			"name": &schema.Schema{
    25  				Type:     schema.TypeString,
    26  				Required: true,
    27  				ForceNew: true,
    28  			},
    29  
    30  			"zone": &schema.Schema{
    31  				Type:     schema.TypeString,
    32  				Required: true,
    33  				ForceNew: true,
    34  			},
    35  
    36  			"description": &schema.Schema{
    37  				Type:     schema.TypeString,
    38  				Optional: true,
    39  				ForceNew: true,
    40  			},
    41  
    42  			"instances": &schema.Schema{
    43  				Type:     schema.TypeSet,
    44  				Optional: true,
    45  				Elem:     &schema.Schema{Type: schema.TypeString},
    46  				Set:      schema.HashString,
    47  			},
    48  
    49  			"named_port": &schema.Schema{
    50  				Type:     schema.TypeList,
    51  				Optional: true,
    52  				Elem: &schema.Resource{
    53  					Schema: map[string]*schema.Schema{
    54  						"name": &schema.Schema{
    55  							Type:     schema.TypeString,
    56  							Required: true,
    57  						},
    58  
    59  						"port": &schema.Schema{
    60  							Type:     schema.TypeInt,
    61  							Required: true,
    62  						},
    63  					},
    64  				},
    65  			},
    66  
    67  			"network": &schema.Schema{
    68  				Type:     schema.TypeString,
    69  				Computed: true,
    70  			},
    71  
    72  			"project": &schema.Schema{
    73  				Type:     schema.TypeString,
    74  				Optional: true,
    75  				ForceNew: true,
    76  			},
    77  
    78  			"self_link": &schema.Schema{
    79  				Type:     schema.TypeString,
    80  				Computed: true,
    81  			},
    82  
    83  			"size": &schema.Schema{
    84  				Type:     schema.TypeInt,
    85  				Computed: true,
    86  			},
    87  		},
    88  	}
    89  }
    90  
    91  func getInstanceReferences(instanceUrls []string) (refs []*compute.InstanceReference) {
    92  	for _, v := range instanceUrls {
    93  		refs = append(refs, &compute.InstanceReference{
    94  			Instance: v,
    95  		})
    96  	}
    97  	return refs
    98  }
    99  
   100  func validInstanceURLs(instanceUrls []string) bool {
   101  	for _, v := range instanceUrls {
   102  		if !strings.HasPrefix(v, "https://www.googleapis.com/compute/v1/") {
   103  			return false
   104  		}
   105  	}
   106  	return true
   107  }
   108  
   109  func resourceComputeInstanceGroupCreate(d *schema.ResourceData, meta interface{}) error {
   110  	config := meta.(*Config)
   111  
   112  	project, err := getProject(d, config)
   113  	if err != nil {
   114  		return err
   115  	}
   116  
   117  	// Build the parameter
   118  	instanceGroup := &compute.InstanceGroup{
   119  		Name: d.Get("name").(string),
   120  	}
   121  
   122  	// Set optional fields
   123  	if v, ok := d.GetOk("description"); ok {
   124  		instanceGroup.Description = v.(string)
   125  	}
   126  
   127  	if v, ok := d.GetOk("named_port"); ok {
   128  		instanceGroup.NamedPorts = getNamedPorts(v.([]interface{}))
   129  	}
   130  
   131  	log.Printf("[DEBUG] InstanceGroup insert request: %#v", instanceGroup)
   132  	op, err := config.clientCompute.InstanceGroups.Insert(
   133  		project, d.Get("zone").(string), instanceGroup).Do()
   134  	if err != nil {
   135  		return fmt.Errorf("Error creating InstanceGroup: %s", err)
   136  	}
   137  
   138  	// It probably maybe worked, so store the ID now
   139  	d.SetId(instanceGroup.Name)
   140  
   141  	// Wait for the operation to complete
   142  	err = computeOperationWaitZone(config, op, project, d.Get("zone").(string), "Creating InstanceGroup")
   143  	if err != nil {
   144  		return err
   145  	}
   146  
   147  	if v, ok := d.GetOk("instances"); ok {
   148  		instanceUrls := convertStringArr(v.(*schema.Set).List())
   149  		if !validInstanceURLs(instanceUrls) {
   150  			return fmt.Errorf("Error invalid instance URLs: %v", instanceUrls)
   151  		}
   152  
   153  		addInstanceReq := &compute.InstanceGroupsAddInstancesRequest{
   154  			Instances: getInstanceReferences(instanceUrls),
   155  		}
   156  
   157  		log.Printf("[DEBUG] InstanceGroup add instances request: %#v", addInstanceReq)
   158  		op, err := config.clientCompute.InstanceGroups.AddInstances(
   159  			project, d.Get("zone").(string), d.Id(), addInstanceReq).Do()
   160  		if err != nil {
   161  			return fmt.Errorf("Error adding instances to InstanceGroup: %s", err)
   162  		}
   163  
   164  		// Wait for the operation to complete
   165  		err = computeOperationWaitZone(config, op, project, d.Get("zone").(string), "Adding instances to InstanceGroup")
   166  		if err != nil {
   167  			return err
   168  		}
   169  	}
   170  
   171  	return resourceComputeInstanceGroupRead(d, meta)
   172  }
   173  
   174  func resourceComputeInstanceGroupRead(d *schema.ResourceData, meta interface{}) error {
   175  	config := meta.(*Config)
   176  
   177  	project, err := getProject(d, config)
   178  	if err != nil {
   179  		return err
   180  	}
   181  
   182  	// retreive instance group
   183  	instanceGroup, err := config.clientCompute.InstanceGroups.Get(
   184  		project, d.Get("zone").(string), d.Id()).Do()
   185  	if err != nil {
   186  		return handleNotFoundError(err, d, fmt.Sprintf("Instance Group %q", d.Get("name").(string)))
   187  	}
   188  
   189  	// retreive instance group members
   190  	var memberUrls []string
   191  	members, err := config.clientCompute.InstanceGroups.ListInstances(
   192  		project, d.Get("zone").(string), d.Id(), &compute.InstanceGroupsListInstancesRequest{
   193  			InstanceState: "ALL",
   194  		}).Do()
   195  	if err != nil {
   196  		if gerr, ok := err.(*googleapi.Error); ok && gerr.Code == 404 {
   197  			// The resource doesn't have any instances
   198  			d.Set("instances", nil)
   199  		} else {
   200  			// any other errors return them
   201  			return fmt.Errorf("Error reading InstanceGroup Members: %s", err)
   202  		}
   203  	} else {
   204  		for _, member := range members.Items {
   205  			memberUrls = append(memberUrls, member.Instance)
   206  		}
   207  		log.Printf("[DEBUG] InstanceGroup members: %v", memberUrls)
   208  		d.Set("instances", memberUrls)
   209  	}
   210  
   211  	// Set computed fields
   212  	d.Set("network", instanceGroup.Network)
   213  	d.Set("size", instanceGroup.Size)
   214  	d.Set("self_link", instanceGroup.SelfLink)
   215  
   216  	return nil
   217  }
   218  func resourceComputeInstanceGroupUpdate(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  	// refresh the state incase referenced instances have been removed earlier in the run
   227  	err = resourceComputeInstanceGroupRead(d, meta)
   228  	if err != nil {
   229  		return fmt.Errorf("Error reading InstanceGroup: %s", err)
   230  	}
   231  
   232  	d.Partial(true)
   233  
   234  	if d.HasChange("instances") {
   235  		// to-do check for no instances
   236  		from_, to_ := d.GetChange("instances")
   237  
   238  		from := convertStringArr(from_.(*schema.Set).List())
   239  		to := convertStringArr(to_.(*schema.Set).List())
   240  
   241  		if !validInstanceURLs(from) {
   242  			return fmt.Errorf("Error invalid instance URLs: %v", from)
   243  		}
   244  		if !validInstanceURLs(to) {
   245  			return fmt.Errorf("Error invalid instance URLs: %v", to)
   246  		}
   247  
   248  		add, remove := calcAddRemove(from, to)
   249  
   250  		if len(remove) > 0 {
   251  			removeReq := &compute.InstanceGroupsRemoveInstancesRequest{
   252  				Instances: getInstanceReferences(remove),
   253  			}
   254  
   255  			log.Printf("[DEBUG] InstanceGroup remove instances request: %#v", removeReq)
   256  			removeOp, err := config.clientCompute.InstanceGroups.RemoveInstances(
   257  				project, d.Get("zone").(string), d.Id(), removeReq).Do()
   258  			if err != nil {
   259  				return fmt.Errorf("Error removing instances from InstanceGroup: %s", err)
   260  			}
   261  
   262  			// Wait for the operation to complete
   263  			err = computeOperationWaitZone(config, removeOp, project, d.Get("zone").(string), "Updating InstanceGroup")
   264  			if err != nil {
   265  				return err
   266  			}
   267  		}
   268  
   269  		if len(add) > 0 {
   270  
   271  			addReq := &compute.InstanceGroupsAddInstancesRequest{
   272  				Instances: getInstanceReferences(add),
   273  			}
   274  
   275  			log.Printf("[DEBUG] InstanceGroup adding instances request: %#v", addReq)
   276  			addOp, err := config.clientCompute.InstanceGroups.AddInstances(
   277  				project, d.Get("zone").(string), d.Id(), addReq).Do()
   278  			if err != nil {
   279  				return fmt.Errorf("Error adding instances from InstanceGroup: %s", err)
   280  			}
   281  
   282  			// Wait for the operation to complete
   283  			err = computeOperationWaitZone(config, addOp, project, d.Get("zone").(string), "Updating InstanceGroup")
   284  			if err != nil {
   285  				return err
   286  			}
   287  		}
   288  
   289  		d.SetPartial("instances")
   290  	}
   291  
   292  	if d.HasChange("named_port") {
   293  		namedPorts := getNamedPorts(d.Get("named_port").([]interface{}))
   294  
   295  		namedPortsReq := &compute.InstanceGroupsSetNamedPortsRequest{
   296  			NamedPorts: namedPorts,
   297  		}
   298  
   299  		log.Printf("[DEBUG] InstanceGroup updating named ports request: %#v", namedPortsReq)
   300  		op, err := config.clientCompute.InstanceGroups.SetNamedPorts(
   301  			project, d.Get("zone").(string), d.Id(), namedPortsReq).Do()
   302  		if err != nil {
   303  			return fmt.Errorf("Error updating named ports for InstanceGroup: %s", err)
   304  		}
   305  
   306  		err = computeOperationWaitZone(config, op, project, d.Get("zone").(string), "Updating InstanceGroup")
   307  		if err != nil {
   308  			return err
   309  		}
   310  		d.SetPartial("named_port")
   311  	}
   312  
   313  	d.Partial(false)
   314  
   315  	return resourceComputeInstanceGroupRead(d, meta)
   316  }
   317  
   318  func resourceComputeInstanceGroupDelete(d *schema.ResourceData, meta interface{}) error {
   319  	config := meta.(*Config)
   320  
   321  	project, err := getProject(d, config)
   322  	if err != nil {
   323  		return err
   324  	}
   325  
   326  	zone := d.Get("zone").(string)
   327  	op, err := config.clientCompute.InstanceGroups.Delete(project, zone, d.Id()).Do()
   328  	if err != nil {
   329  		return fmt.Errorf("Error deleting InstanceGroup: %s", err)
   330  	}
   331  
   332  	err = computeOperationWaitZone(config, op, project, zone, "Deleting InstanceGroup")
   333  	if err != nil {
   334  		return err
   335  	}
   336  
   337  	d.SetId("")
   338  	return nil
   339  }