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 }