provider/vsphere: added update function with support for vcpu and memory (#6356)

* added update function with support for vcpu and memory

* waiting for vmware tools redundant with WaitForIP

* proper error handling of PowerOn task

* added test cases for update memory and vcpu

* reboot flag
This commit is contained in:
thetuxkeeper 2016-05-03 17:58:33 +02:00 committed by Paul Stack
parent b005709ed1
commit bb73c74414
2 changed files with 314 additions and 2 deletions

View File

@ -105,6 +105,7 @@ func resourceVSphereVirtualMachine() *schema.Resource {
return &schema.Resource{
Create: resourceVSphereVirtualMachineCreate,
Read: resourceVSphereVirtualMachineRead,
Update: resourceVSphereVirtualMachineUpdate,
Delete: resourceVSphereVirtualMachineDelete,
Schema: map[string]*schema.Schema{
@ -123,13 +124,11 @@ func resourceVSphereVirtualMachine() *schema.Resource {
"vcpu": &schema.Schema{
Type: schema.TypeInt,
Required: true,
ForceNew: true,
},
"memory": &schema.Schema{
Type: schema.TypeInt,
Required: true,
ForceNew: true,
},
"memory_reservation": &schema.Schema{
@ -401,6 +400,93 @@ func resourceVSphereVirtualMachine() *schema.Resource {
}
}
func resourceVSphereVirtualMachineUpdate(d *schema.ResourceData, meta interface{}) error {
// flag if changes have to be applied
hasChanges := false
// flag if changes have to be done when powered off
rebootRequired := false
// make config spec
configSpec := types.VirtualMachineConfigSpec{}
if d.HasChange("vcpu") {
configSpec.NumCPUs = d.Get("vcpu").(int)
hasChanges = true
rebootRequired = true
}
if d.HasChange("memory") {
configSpec.MemoryMB = int64(d.Get("memory").(int))
hasChanges = true
rebootRequired = true
}
// do nothing if there are no changes
if !hasChanges {
return nil
}
client := meta.(*govmomi.Client)
dc, err := getDatacenter(client, d.Get("datacenter").(string))
if err != nil {
return err
}
finder := find.NewFinder(client.Client, true)
finder = finder.SetDatacenter(dc)
vm, err := finder.VirtualMachine(context.TODO(), vmPath(d.Get("folder").(string), d.Get("name").(string)))
if err != nil {
return err
}
log.Printf("[DEBUG] virtual machine config spec: %v", configSpec)
if rebootRequired {
log.Printf("[INFO] Shutting down virtual machine: %s", d.Id())
task, err := vm.PowerOff(context.TODO())
if err != nil {
return err
}
err = task.Wait(context.TODO())
if err != nil {
return err
}
}
log.Printf("[INFO] Reconfiguring virtual machine: %s", d.Id())
task, err := vm.Reconfigure(context.TODO(), configSpec)
if err != nil {
log.Printf("[ERROR] %s", err)
}
err = task.Wait(context.TODO())
if err != nil {
log.Printf("[ERROR] %s", err)
}
if rebootRequired {
task, err = vm.PowerOn(context.TODO())
if err != nil {
return err
}
err = task.Wait(context.TODO())
if err != nil {
log.Printf("[ERROR] %s", err)
}
}
ip, err := vm.WaitForIP(context.TODO())
if err != nil {
return err
}
log.Printf("[DEBUG] ip address: %v", ip)
return resourceVSphereVirtualMachineRead(d, meta)
}
func resourceVSphereVirtualMachineCreate(d *schema.ResourceData, meta interface{}) error {
client := meta.(*govmomi.Client)

View File

@ -517,6 +517,168 @@ func TestAccVSphereVirtualMachine_createWithExistingVmdk(t *testing.T) {
})
}
func TestAccVSphereVirtualMachine_updateMemory(t *testing.T) {
var vm virtualMachine
var locationOpt string
var datastoreOpt string
if v := os.Getenv("VSPHERE_DATACENTER"); v != "" {
locationOpt += fmt.Sprintf(" datacenter = \"%s\"\n", v)
}
if v := os.Getenv("VSPHERE_CLUSTER"); v != "" {
locationOpt += fmt.Sprintf(" cluster = \"%s\"\n", v)
}
if v := os.Getenv("VSPHERE_RESOURCE_POOL"); v != "" {
locationOpt += fmt.Sprintf(" resource_pool = \"%s\"\n", v)
}
if v := os.Getenv("VSPHERE_DATASTORE"); v != "" {
datastoreOpt = fmt.Sprintf(" datastore = \"%s\"\n", v)
}
template := os.Getenv("VSPHERE_TEMPLATE")
label := os.Getenv("VSPHERE_NETWORK_LABEL_DHCP")
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckVSphereVirtualMachineDestroy,
Steps: []resource.TestStep{
resource.TestStep{
Config: fmt.Sprintf(
testAccCheckVSphereVirtualMachineConfig_updateMemoryInitial,
locationOpt,
label,
datastoreOpt,
template,
),
Check: resource.ComposeTestCheckFunc(
testAccCheckVSphereVirtualMachineExists("vsphere_virtual_machine.bar", &vm),
resource.TestCheckResourceAttr(
"vsphere_virtual_machine.bar", "name", "terraform-test"),
resource.TestCheckResourceAttr(
"vsphere_virtual_machine.bar", "vcpu", "2"),
resource.TestCheckResourceAttr(
"vsphere_virtual_machine.bar", "memory", "4096"),
resource.TestCheckResourceAttr(
"vsphere_virtual_machine.bar", "disk.#", "1"),
resource.TestCheckResourceAttr(
"vsphere_virtual_machine.bar", "disk.0.template", template),
resource.TestCheckResourceAttr(
"vsphere_virtual_machine.bar", "network_interface.#", "1"),
resource.TestCheckResourceAttr(
"vsphere_virtual_machine.bar", "network_interface.0.label", label),
),
},
resource.TestStep{
Config: fmt.Sprintf(
testAccCheckVSphereVirtualMachineConfig_updateMemoryUpdate,
locationOpt,
label,
datastoreOpt,
template,
),
Check: resource.ComposeTestCheckFunc(
testAccCheckVSphereVirtualMachineExists("vsphere_virtual_machine.bar", &vm),
resource.TestCheckResourceAttr(
"vsphere_virtual_machine.bar", "name", "terraform-test"),
resource.TestCheckResourceAttr(
"vsphere_virtual_machine.bar", "vcpu", "2"),
resource.TestCheckResourceAttr(
"vsphere_virtual_machine.bar", "memory", "2048"),
resource.TestCheckResourceAttr(
"vsphere_virtual_machine.bar", "disk.#", "1"),
resource.TestCheckResourceAttr(
"vsphere_virtual_machine.bar", "disk.0.template", template),
resource.TestCheckResourceAttr(
"vsphere_virtual_machine.bar", "network_interface.#", "1"),
resource.TestCheckResourceAttr(
"vsphere_virtual_machine.bar", "network_interface.0.label", label),
),
},
},
})
}
func TestAccVSphereVirtualMachine_updateVcpu(t *testing.T) {
var vm virtualMachine
var locationOpt string
var datastoreOpt string
if v := os.Getenv("VSPHERE_DATACENTER"); v != "" {
locationOpt += fmt.Sprintf(" datacenter = \"%s\"\n", v)
}
if v := os.Getenv("VSPHERE_CLUSTER"); v != "" {
locationOpt += fmt.Sprintf(" cluster = \"%s\"\n", v)
}
if v := os.Getenv("VSPHERE_RESOURCE_POOL"); v != "" {
locationOpt += fmt.Sprintf(" resource_pool = \"%s\"\n", v)
}
if v := os.Getenv("VSPHERE_DATASTORE"); v != "" {
datastoreOpt = fmt.Sprintf(" datastore = \"%s\"\n", v)
}
template := os.Getenv("VSPHERE_TEMPLATE")
label := os.Getenv("VSPHERE_NETWORK_LABEL_DHCP")
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckVSphereVirtualMachineDestroy,
Steps: []resource.TestStep{
resource.TestStep{
Config: fmt.Sprintf(
testAccCheckVSphereVirtualMachineConfig_updateVcpuInitial,
locationOpt,
label,
datastoreOpt,
template,
),
Check: resource.ComposeTestCheckFunc(
testAccCheckVSphereVirtualMachineExists("vsphere_virtual_machine.bar", &vm),
resource.TestCheckResourceAttr(
"vsphere_virtual_machine.bar", "name", "terraform-test"),
resource.TestCheckResourceAttr(
"vsphere_virtual_machine.bar", "vcpu", "2"),
resource.TestCheckResourceAttr(
"vsphere_virtual_machine.bar", "memory", "4096"),
resource.TestCheckResourceAttr(
"vsphere_virtual_machine.bar", "disk.#", "1"),
resource.TestCheckResourceAttr(
"vsphere_virtual_machine.bar", "disk.0.template", template),
resource.TestCheckResourceAttr(
"vsphere_virtual_machine.bar", "network_interface.#", "1"),
resource.TestCheckResourceAttr(
"vsphere_virtual_machine.bar", "network_interface.0.label", label),
),
},
resource.TestStep{
Config: fmt.Sprintf(
testAccCheckVSphereVirtualMachineConfig_updateVcpuUpdate,
locationOpt,
label,
datastoreOpt,
template,
),
Check: resource.ComposeTestCheckFunc(
testAccCheckVSphereVirtualMachineExists("vsphere_virtual_machine.bar", &vm),
resource.TestCheckResourceAttr(
"vsphere_virtual_machine.bar", "name", "terraform-test"),
resource.TestCheckResourceAttr(
"vsphere_virtual_machine.bar", "vcpu", "4"),
resource.TestCheckResourceAttr(
"vsphere_virtual_machine.bar", "memory", "4096"),
resource.TestCheckResourceAttr(
"vsphere_virtual_machine.bar", "disk.#", "1"),
resource.TestCheckResourceAttr(
"vsphere_virtual_machine.bar", "disk.0.template", template),
resource.TestCheckResourceAttr(
"vsphere_virtual_machine.bar", "network_interface.#", "1"),
resource.TestCheckResourceAttr(
"vsphere_virtual_machine.bar", "network_interface.0.label", label),
),
},
},
})
}
func testAccCheckVSphereVirtualMachineDestroy(s *terraform.State) error {
client := testAccProvider.Meta().(*govmomi.Client)
finder := find.NewFinder(client.Client, true)
@ -853,3 +1015,67 @@ resource "vsphere_virtual_machine" "with_existing_vmdk" {
}
}
`
const testAccCheckVSphereVirtualMachineConfig_updateMemoryInitial = `
resource "vsphere_virtual_machine" "bar" {
name = "terraform-test"
%s
vcpu = 2
memory = 4096
network_interface {
label = "%s"
}
disk {
%s
template = "%s"
}
}
`
const testAccCheckVSphereVirtualMachineConfig_updateMemoryUpdate = `
resource "vsphere_virtual_machine" "bar" {
name = "terraform-test"
%s
vcpu = 2
memory = 2048
network_interface {
label = "%s"
}
disk {
%s
template = "%s"
}
}
`
const testAccCheckVSphereVirtualMachineConfig_updateVcpuInitial = `
resource "vsphere_virtual_machine" "bar" {
name = "terraform-test"
%s
vcpu = 2
memory = 4096
network_interface {
label = "%s"
}
disk {
%s
template = "%s"
}
}
`
const testAccCheckVSphereVirtualMachineConfig_updateVcpuUpdate = `
resource "vsphere_virtual_machine" "bar" {
name = "terraform-test"
%s
vcpu = 4
memory = 4096
network_interface {
label = "%s"
}
disk {
%s
template = "%s"
}
}
`