Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add vm.Shutdown() function and tests #496

Merged
merged 12 commits into from
Aug 23, 2022
1 change: 1 addition & 0 deletions .changes/v2.17.0/413-improvements.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
* Added method `VM.Shutdown` to shut down guest OS [GH-413], [GH-496]
19 changes: 19 additions & 0 deletions govcd/vm.go
Original file line number Diff line number Diff line change
Expand Up @@ -492,6 +492,25 @@ func (vm *VM) Undeploy() (Task, error) {
types.MimeUndeployVappParams, "error undeploy VM: %s", vu)
}

// Shutdown triggers a VM undeploy and shutdown action. "Shut Down Guest OS" action in UI behaves
// this way.
//
// Note. Success of this operation depends on the VM having Guest Tools installed.
func (vm *VM) Shutdown() (Task, error) {

vu := &types.UndeployVAppParams{
Xmlns: types.XMLNamespaceVCloud,
UndeployPowerAction: "shutdown",
}

apiEndpoint := urlParseRequestURI(vm.VM.HREF)
apiEndpoint.Path += "/action/undeploy"

// Return the task
return vm.client.ExecuteTaskRequest(apiEndpoint.String(), http.MethodPost,
types.MimeUndeployVappParams, "error undeploy VM: %s", vu)
}

// Attach or detach an independent disk
// Use the disk/action/attach or disk/action/detach links in a VM to attach or detach an independent disk.
// Reference: vCloud API Programming Guide for Service Providers vCloud API 30.0 PDF Page 164 - 165,
Expand Down
64 changes: 64 additions & 0 deletions govcd/vm_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -710,6 +710,70 @@ func (vcd *TestVCD) Test_VMPowerOnPowerOff(check *C) {
check.Assert(vmStatus, Equals, "POWERED_OFF")
}

func (vcd *TestVCD) Test_VmShutdown(check *C) {
if vcd.skipVappTests {
check.Skip("Skipping test because vapp was not successfully created at setup")
}
vapp := vcd.findFirstVapp()
existingVm, vmName := vcd.findFirstVm(vapp)
if vmName == "" {
check.Skip("skipping test because no VM is found")
}
vm, err := vcd.client.Client.GetVMByHref(existingVm.HREF)
check.Assert(err, IsNil)

vdc, err := vm.GetParentVdc()
check.Assert(err, IsNil)

// Ensure VM is not powered on
vmStatus, err := vm.GetStatus()
check.Assert(err, IsNil)
fmt.Println("VM status: ", vmStatus)

if vmStatus != "POWERED_ON" {
task, err := vm.PowerOn()
check.Assert(err, IsNil)
err = task.WaitTaskCompletion()
check.Assert(err, IsNil)
check.Assert(task.Task.Status, Equals, "success")
}

// Wait until Guest Tools gets to `REBOOT_PENDING` or `GC_COMPLETE` as there is no real way to
// check if VM has Guest Tools operating
for {
err = vm.Refresh()
check.Assert(err, IsNil)

vmQuery, err := vdc.QueryVM(vapp.VApp.Name, vm.VM.Name)
check.Assert(err, IsNil)

printVerbose("VM Tools Status: %s\n", vmQuery.VM.GcStatus)
if vmQuery.VM.GcStatus == "GC_COMPLETE" || vmQuery.VM.GcStatus == "REBOOT_PENDING" {
break
}

time.Sleep(3 * time.Second)
}
printVerbose("Shuting down VM:\n")

task, err := vm.Shutdown()
check.Assert(err, IsNil)
err = task.WaitTaskCompletion()
check.Assert(err, IsNil)
check.Assert(task.Task.Status, Equals, "success")

newStatus, err := vm.GetStatus()
check.Assert(err, IsNil)
printVerbose("New VM status: %s\n", newStatus)
check.Assert(newStatus, Equals, "POWERED_OFF")

// End of test - power on the VM to leave it running
task, err = vm.PowerOn()
check.Assert(err, IsNil)
err = task.WaitTaskCompletion()
check.Assert(err, IsNil)
}

func (vcd *TestVCD) Test_GetNetworkConnectionSection(check *C) {
if vcd.skipVappTests {
check.Skip("Skipping test because vapp was not successfully created at setup")
Expand Down
12 changes: 12 additions & 0 deletions types/v56/vm_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ type Vm struct {
// Section ovf:VirtualHardwareSection
VirtualHardwareSection *VirtualHardwareSection `xml:"VirtualHardwareSection,omitempty"`

RuntimeInfoSection *RuntimeInfoSection `xml:"RuntimeInfoSection,omitempty"`

// FIXME: Upstream bug? Missing NetworkConnectionSection
NetworkConnectionSection *NetworkConnectionSection `xml:"NetworkConnectionSection,omitempty"`

Expand All @@ -65,6 +67,16 @@ type Vm struct {
Media *Reference `xml:"Media,omitempty"` // Reference to the media object to insert in a new VM.
}

type RuntimeInfoSection struct {
Ns10 string `xml:"ns10,attr"`
Type string `xml:"type,attr"`
Href string `xml:"href,attr"`
Info string `xml:"Info"`
VMWareTools struct {
Version string `xml:"version,attr"`
} `xml:"VMWareTools"`
}

// VmSpecSection from Vm struct
type VmSpecSection struct {
Modified *bool `xml:"Modified,attr,omitempty"`
Expand Down