func resizeServer(t *testing.T, client *gophercloud.ServiceClient, server *servers.Server, choices *ComputeChoices) { if err := waitForStatus(client, server, "ACTIVE"); err != nil { t.Fatal(err) } t.Logf("Attempting to resize server [%s]", server.ID) opts := &servers.ResizeOpts{ FlavorRef: choices.FlavorIDResize, } if res := servers.Resize(client, server.ID, opts); res.Err != nil { t.Fatal(res.Err) } if err := waitForStatus(client, server, "VERIFY_RESIZE"); err != nil { t.Fatal(err) } }
func resourceComputeInstanceV2Update(d *schema.ResourceData, meta interface{}) error { config := meta.(*Config) computeClient, err := config.computeV2Client(d.Get("region").(string)) if err != nil { return fmt.Errorf("Error creating OpenStack compute client: %s", err) } var updateOpts servers.UpdateOpts if d.HasChange("name") { updateOpts.Name = d.Get("name").(string) } if updateOpts != (servers.UpdateOpts{}) { _, err := servers.Update(computeClient, d.Id(), updateOpts).Extract() if err != nil { return fmt.Errorf("Error updating OpenStack server: %s", err) } } if d.HasChange("metadata") { var metadataOpts servers.MetadataOpts metadataOpts = make(servers.MetadataOpts) newMetadata := d.Get("metadata").(map[string]interface{}) for k, v := range newMetadata { metadataOpts[k] = v.(string) } _, err := servers.UpdateMetadata(computeClient, d.Id(), metadataOpts).Extract() if err != nil { return fmt.Errorf("Error updating OpenStack server (%s) metadata: %s", d.Id(), err) } } if d.HasChange("security_groups") { oldSGRaw, newSGRaw := d.GetChange("security_groups") oldSGSet := oldSGRaw.(*schema.Set) newSGSet := newSGRaw.(*schema.Set) secgroupsToAdd := newSGSet.Difference(oldSGSet) secgroupsToRemove := oldSGSet.Difference(newSGSet) log.Printf("[DEBUG] Security groups to add: %v", secgroupsToAdd) log.Printf("[DEBUG] Security groups to remove: %v", secgroupsToRemove) for _, g := range secgroupsToRemove.List() { err := secgroups.RemoveServerFromGroup(computeClient, d.Id(), g.(string)).ExtractErr() if err != nil { errCode, ok := err.(*gophercloud.UnexpectedResponseCodeError) if !ok { return fmt.Errorf("Error removing security group from OpenStack server (%s): %s", d.Id(), err) } if errCode.Actual == 404 { continue } else { return fmt.Errorf("Error removing security group from OpenStack server (%s): %s", d.Id(), err) } } else { log.Printf("[DEBUG] Removed security group (%s) from instance (%s)", g.(string), d.Id()) } } for _, g := range secgroupsToAdd.List() { err := secgroups.AddServerToGroup(computeClient, d.Id(), g.(string)).ExtractErr() if err != nil { return fmt.Errorf("Error adding security group to OpenStack server (%s): %s", d.Id(), err) } log.Printf("[DEBUG] Added security group (%s) to instance (%s)", g.(string), d.Id()) } } if d.HasChange("admin_pass") { if newPwd, ok := d.Get("admin_pass").(string); ok { err := servers.ChangeAdminPassword(computeClient, d.Id(), newPwd).ExtractErr() if err != nil { return fmt.Errorf("Error changing admin password of OpenStack server (%s): %s", d.Id(), err) } } } if d.HasChange("floating_ip") { oldFIP, newFIP := d.GetChange("floating_ip") log.Printf("[DEBUG] Old Floating IP: %v", oldFIP) log.Printf("[DEBUG] New Floating IP: %v", newFIP) if oldFIP.(string) != "" { log.Printf("[DEBUG] Attempting to disassociate %s from %s", oldFIP, d.Id()) if err := disassociateFloatingIPFromInstance(computeClient, oldFIP.(string), d.Id(), ""); err != nil { return fmt.Errorf("Error disassociating Floating IP during update: %s", err) } } if newFIP.(string) != "" { log.Printf("[DEBUG] Attempting to associate %s to %s", newFIP, d.Id()) if err := associateFloatingIPToInstance(computeClient, newFIP.(string), d.Id(), ""); err != nil { return fmt.Errorf("Error associating Floating IP during update: %s", err) } } } if d.HasChange("network") { oldNetworks, newNetworks := d.GetChange("network") oldNetworkList := oldNetworks.([]interface{}) newNetworkList := newNetworks.([]interface{}) for i, oldNet := range oldNetworkList { oldNetRaw := oldNet.(map[string]interface{}) oldFIP := oldNetRaw["floating_ip"].(string) oldFixedIP := oldNetRaw["fixed_ip_v4"].(string) newNetRaw := newNetworkList[i].(map[string]interface{}) newFIP := newNetRaw["floating_ip"].(string) newFixedIP := newNetRaw["fixed_ip_v4"].(string) // Only changes to the floating IP are supported if oldFIP != newFIP { log.Printf("[DEBUG] Attempting to disassociate %s from %s", oldFIP, d.Id()) if err := disassociateFloatingIPFromInstance(computeClient, oldFIP, d.Id(), oldFixedIP); err != nil { return fmt.Errorf("Error disassociating Floating IP during update: %s", err) } log.Printf("[DEBUG] Attempting to associate %s to %s", newFIP, d.Id()) if err := associateFloatingIPToInstance(computeClient, newFIP, d.Id(), newFixedIP); err != nil { return fmt.Errorf("Error associating Floating IP during update: %s", err) } } } } if d.HasChange("volume") { // ensure the volume configuration is correct if err := checkVolumeConfig(d); err != nil { return err } // old attachments and new attachments oldAttachments, newAttachments := d.GetChange("volume") // for each old attachment, detach the volume oldAttachmentSet := oldAttachments.(*schema.Set).List() if blockClient, err := config.blockStorageV1Client(d.Get("region").(string)); err != nil { return err } else { if err := detachVolumesFromInstance(computeClient, blockClient, d.Id(), oldAttachmentSet); err != nil { return err } } // for each new attachment, attach the volume newAttachmentSet := newAttachments.(*schema.Set).List() if blockClient, err := config.blockStorageV1Client(d.Get("region").(string)); err != nil { return err } else { if err := attachVolumesToInstance(computeClient, blockClient, d.Id(), newAttachmentSet); err != nil { return err } } d.SetPartial("volume") } if d.HasChange("flavor_id") || d.HasChange("flavor_name") { flavorId, err := getFlavorID(computeClient, d) if err != nil { return err } resizeOpts := &servers.ResizeOpts{ FlavorRef: flavorId, } log.Printf("[DEBUG] Resize configuration: %#v", resizeOpts) err = servers.Resize(computeClient, d.Id(), resizeOpts).ExtractErr() if err != nil { return fmt.Errorf("Error resizing OpenStack server: %s", err) } // Wait for the instance to finish resizing. log.Printf("[DEBUG] Waiting for instance (%s) to finish resizing", d.Id()) stateConf := &resource.StateChangeConf{ Pending: []string{"RESIZE"}, Target: []string{"VERIFY_RESIZE"}, Refresh: ServerV2StateRefreshFunc(computeClient, d.Id()), Timeout: 3 * time.Minute, Delay: 10 * time.Second, MinTimeout: 3 * time.Second, } _, err = stateConf.WaitForState() if err != nil { return fmt.Errorf("Error waiting for instance (%s) to resize: %s", d.Id(), err) } // Confirm resize. log.Printf("[DEBUG] Confirming resize") err = servers.ConfirmResize(computeClient, d.Id()).ExtractErr() if err != nil { return fmt.Errorf("Error confirming resize of OpenStack server: %s", err) } stateConf = &resource.StateChangeConf{ Pending: []string{"VERIFY_RESIZE"}, Target: []string{"ACTIVE"}, Refresh: ServerV2StateRefreshFunc(computeClient, d.Id()), Timeout: 3 * time.Minute, Delay: 10 * time.Second, MinTimeout: 3 * time.Second, } _, err = stateConf.WaitForState() if err != nil { return fmt.Errorf("Error waiting for instance (%s) to confirm resize: %s", d.Id(), err) } } return resourceComputeInstanceV2Read(d, meta) }
// Resize instructs the provider to change the flavor of the server. // Note that this implies rebuilding it. // Unfortunately, one cannot pass rebuild parameters to the resize function. // When the resize completes, the server will be in RESIZE_VERIFY state. // While in this state, you can explore the use of the new server's configuration. // If you like it, call ConfirmResize() to commit the resize permanently. // Otherwise, call RevertResize() to restore the old configuration. func Resize(client *gophercloud.ServiceClient, id string, opts os.ResizeOptsBuilder) os.ActionResult { return os.Resize(client, id, opts) }