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