diff --git a/CHANGELOG.md b/CHANGELOG.md index 5ab313099..3982388a1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,13 @@ for all networks types for NSX-V and NSX-T backed VDCs [#354](https://github.com * Added `NsxtImportableSwitch` structure with `GetNsxtImportableSwitchByName` and `GetAllNsxtImportableSwitches` to lookup NSX-T segments for use in NSX-T Imported networks [#354](https://github.com/vmware/go-vcloud-director/pull/354) * Added `vdc.IsNsxt` and `vdc.IsNsxv` methods to verify if VDC is backed by NSX-T or NSX-V [#354](https://github.com/vmware/go-vcloud-director/pull/354) +* Added types `types.CreateVmParams` and `types.InstantiateVmTemplateParams` +* Added Vdc methods `CreateStandaloneVMFromTemplate`, `CreateStandaloneVMFromTemplateAsync` `CreateStandaloneVm`, `CreateStandaloneVmAsync` +* Added Vdc methods `QueryVmByName`, `QueryVmById`, `QueryVmList` +* Added VM methods `Delete`, `DeleteAsync` + +BREAKING CHANGES: +* Renamed `types.VM` to `types.Vm` to facilitate implementation of standalone VM BUGS FIXED: * Made IPAddress field for IPAddresses struct to array [#350](https://github.com/vmware/go-vcloud-director/pull/350) diff --git a/govcd/api.go b/govcd/api.go index 107d65ffe..449d5cfa9 100644 --- a/govcd/api.go +++ b/govcd/api.go @@ -1,5 +1,5 @@ /* - * Copyright 2019 VMware, Inc. All rights reserved. Licensed under the Apache v2 License. + * Copyright 2021 VMware, Inc. All rights reserved. Licensed under the Apache v2 License. */ // Package govcd provides a simple binding for vCloud Director REST APIs. diff --git a/govcd/api_vcd_test.go b/govcd/api_vcd_test.go index 4a66dbf9e..424af06f4 100644 --- a/govcd/api_vcd_test.go +++ b/govcd/api_vcd_test.go @@ -1,7 +1,7 @@ // +build api openapi functional catalog vapp gateway network org query extnetwork task vm vdc system disk lb lbAppRule lbAppProfile lbServerPool lbServiceMonitor lbVirtualServer user search nsxv nsxt auth affinity ALL /* - * Copyright 2019 VMware, Inc. All rights reserved. Licensed under the Apache v2 License. + * Copyright 2021 VMware, Inc. All rights reserved. Licensed under the Apache v2 License. */ package govcd @@ -1033,6 +1033,24 @@ func (vcd *TestVCD) removeLeftoverEntities(entity CleanupEntity) { vcd.infoCleanup(notDeletedMsg, entity.EntityType, entity.Name, err) } return + case "standaloneVm": + vm, err := vcd.vdc.QueryVmById(entity.Name) // The VM ID must be passed as Name + if IsNotFound(err) { + vcd.infoCleanup(notFoundMsg, entity.EntityType, entity.Name) + return + } + if err != nil { + vcd.infoCleanup("removeLeftoverEntries: [ERROR] retrieving standalone VM '%s'. %s\n", + entity.Name, err) + return + } + err = vm.Delete() + if err != nil { + vcd.infoCleanup("removeLeftoverEntries: [ERROR] deleting VM '%s' : %s\n", + entity.Name, err) + return + } + vcd.infoCleanup(removedMsg, entity.EntityType, entity.Name, entity.CreatedBy) case "vm": vapp, err := vcd.vdc.GetVAppByName(entity.Parent, true) if err != nil { @@ -1635,13 +1653,13 @@ func Test_splitParent(t *testing.T) { } } -func (vcd *TestVCD) findFirstVm(vapp VApp) (types.VM, string) { +func (vcd *TestVCD) findFirstVm(vapp VApp) (types.Vm, string) { for _, vm := range vapp.VApp.Children.VM { if vm.Name != "" { return *vm, vm.Name } } - return types.VM{}, "" + return types.Vm{}, "" } func (vcd *TestVCD) findFirstVapp() VApp { diff --git a/govcd/entity_test.go b/govcd/entity_test.go index ed8fd814f..112a8e64d 100644 --- a/govcd/entity_test.go +++ b/govcd/entity_test.go @@ -9,6 +9,7 @@ package govcd import ( "fmt" "reflect" + "strings" . "gopkg.in/check.v1" ) @@ -148,7 +149,7 @@ func (vcd *TestVCD) testFinderGetGenericEntity(def getterTestDefinition, check * fmt.Printf("# Detected entity type %s\n", reflect.TypeOf(entity1)) } - check.Assert(reflect.TypeOf(entity1).String(), Equals, wantedType) + check.Assert(strings.ToLower(reflect.TypeOf(entity1).String()), Equals, strings.ToLower(wantedType)) check.Assert(entity1, NotNil) check.Assert(entity1.name(), Equals, entityName) @@ -165,7 +166,7 @@ func (vcd *TestVCD) testFinderGetGenericEntity(def getterTestDefinition, check * check.Assert(entity2, NotNil) check.Assert(entity2.name(), Equals, entityName) check.Assert(entity2.id(), Equals, entityId) - check.Assert(reflect.TypeOf(entity2).String(), Equals, wantedType) + check.Assert(strings.ToLower(reflect.TypeOf(entity2).String()), Equals, strings.ToLower(wantedType)) // 3. Get the entity by Name or ID, using a known ID if testVerbose { @@ -178,7 +179,7 @@ func (vcd *TestVCD) testFinderGetGenericEntity(def getterTestDefinition, check * check.Assert(entity3, NotNil) check.Assert(entity3.name(), Equals, entityName) check.Assert(entity3.id(), Equals, entityId) - check.Assert(reflect.TypeOf(entity3).String(), Equals, wantedType) + check.Assert(strings.ToLower(reflect.TypeOf(entity3).String()), Equals, strings.ToLower(wantedType)) // 4. Get the entity by Name or ID, using the entity name if testVerbose { @@ -191,7 +192,7 @@ func (vcd *TestVCD) testFinderGetGenericEntity(def getterTestDefinition, check * check.Assert(entity4, NotNil) check.Assert(entity4.name(), Equals, entityName) check.Assert(entity4.id(), Equals, entityId) - check.Assert(reflect.TypeOf(entity4).String(), Equals, wantedType) + check.Assert(strings.ToLower(reflect.TypeOf(entity4).String()), Equals, strings.ToLower(wantedType)) // 5. Attempting a search by name with an invalid name if testVerbose { diff --git a/govcd/filter_interface.go b/govcd/filter_interface.go index d49b566f9..d45b99d9a 100644 --- a/govcd/filter_interface.go +++ b/govcd/filter_interface.go @@ -176,7 +176,7 @@ func (vapp QueryVapp) GetMetadataValue(key string) string { // -------------------------------------------------------------- func (vm QueryVm) GetHref() string { return vm.HREF } func (vm QueryVm) GetName() string { return vm.Name } -func (vm QueryVm) GetType() string { return "VM" } +func (vm QueryVm) GetType() string { return "Vm" } func (vm QueryVm) GetIp() string { return vm.IpAddress } func (vm QueryVm) GetDate() string { return vm.DateCreated } func (vm QueryVm) GetParentName() string { return vm.ContainerName } diff --git a/govcd/monitor.go b/govcd/monitor.go index 5b9a15326..c20a02688 100644 --- a/govcd/monitor.go +++ b/govcd/monitor.go @@ -1,5 +1,5 @@ /* - * Copyright 2019 VMware, Inc. All rights reserved. Licensed under the Apache v2 License. + * Copyright 2021 VMware, Inc. All rights reserved. Licensed under the Apache v2 License. */ // Contains auxiliary functions to show library entities structure. @@ -30,6 +30,7 @@ import ( // network // externalNetwork // vapp +// vm // task // Edge Gateway service configuration @@ -53,6 +54,15 @@ func prettyVapp(vapp types.VApp) string { return "" } +// Returns a VM structure as JSON +func prettyVm(vm types.Vm) string { + byteBuf, err := json.MarshalIndent(vm, " ", " ") + if err == nil { + return fmt.Sprintf("%s\n", string(byteBuf)) + } + return "" +} + // Returns an OrgUser structure as JSON func prettyUser(user types.User) string { byteBuf, err := json.MarshalIndent(user, " ", " ") @@ -187,6 +197,13 @@ func ShowVapp(vapp types.VApp) { out("screen", prettyVapp(vapp)) } +func LogVm(vm types.Vm) { + out("log", prettyVm(vm)) +} + +func ShowVm(vm types.Vm) { + out("screen", prettyVm(vm)) +} func ShowOrg(org types.Org) { out("screen", prettyOrg(org)) } diff --git a/govcd/vapp.go b/govcd/vapp.go index b026de1e7..c1103f17d 100644 --- a/govcd/vapp.go +++ b/govcd/vapp.go @@ -253,7 +253,6 @@ func addNewVMW(vapp *VApp, name string, vappTemplate VAppTemplate, // https://github.com/vmware/go-vcloud-director/issues/252 // ====================================================================== func (vapp *VApp) RemoveVM(vm VM) error { - err := vapp.Refresh() if err != nil { return fmt.Errorf("error refreshing vApp before removing VM: %s", err) @@ -574,7 +573,7 @@ func (vapp *VApp) ChangeStorageProfile(name string) (Task, error) { return Task{}, fmt.Errorf("error retrieving storage profile %s for vApp %s", name, vapp.VApp.Name) } - newProfile := &types.VM{ + newProfile := &types.Vm{ Name: vapp.VApp.Children.VM[0].Name, StorageProfile: &storageProfileRef, Xmlns: types.XMLNamespaceVCloud, @@ -596,7 +595,7 @@ func (vapp *VApp) ChangeVMName(name string) (Task, error) { return Task{}, fmt.Errorf("vApp doesn't contain any children, interrupting customization") } - newName := &types.VM{ + newName := &types.Vm{ Name: name, Xmlns: types.XMLNamespaceVCloud, } diff --git a/govcd/vapp_test.go b/govcd/vapp_test.go index 24574dcfe..c27478737 100644 --- a/govcd/vapp_test.go +++ b/govcd/vapp_test.go @@ -737,7 +737,7 @@ func (vcd *TestVCD) Test_GetVM(check *C) { var def = getterTestDefinition{ parentType: "VApp", parentName: vapp.VApp.Name, - entityType: "VM", + entityType: "Vm", entityName: vmName, getByName: getByName, getById: getById, diff --git a/govcd/vdc.go b/govcd/vdc.go index 6a86bd2dd..b518f54e0 100644 --- a/govcd/vdc.go +++ b/govcd/vdc.go @@ -1,5 +1,5 @@ /* - * Copyright 2019 VMware, Inc. All rights reserved. Licensed under the Apache v2 License. + * Copyright 2021 VMware, Inc. All rights reserved. Licensed under the Apache v2 License. */ package govcd @@ -901,6 +901,169 @@ func (vdc *Vdc) GetVappList() []*types.ResourceReference { return list } +// CreateStandaloneVmAsync starts a standalone VM creation without a template, returning a task +func (vdc *Vdc) CreateStandaloneVmAsync(params *types.CreateVmParams) (Task, error) { + util.Logger.Printf("[TRACE] Vdc.CreateStandaloneVmAsync - Creating VM ") + + if vdc.Vdc.HREF == "" { + return Task{}, fmt.Errorf("cannot create VM, Object VDC is empty") + } + + href := "" + for _, link := range vdc.Vdc.Link { + if link.Type == types.MimeCreateVmParams && link.Rel == "add" { + href = link.HREF + break + } + } + if href == "" { + return Task{}, fmt.Errorf("error retrieving VM creation link from VDC %s", vdc.Vdc.Name) + } + if params == nil { + return Task{}, fmt.Errorf("empty parameters passed to standalone VM creation") + } + params.XmlnsOvf = types.XMLNamespaceOVF + + return vdc.client.ExecuteTaskRequest(href, http.MethodPost, types.MimeCreateVmParams, "error creating standalone VM: %s", params) +} + +// getVmFromTask finds a VM from a running standalone VM creation task +// It retrieves the VM owner (the hidden vApp), and from that one finds the new VM +func (vdc *Vdc) getVmFromTask(task Task, name string) (*VM, error) { + owner := task.Task.Owner.HREF + if owner == "" { + return nil, fmt.Errorf("task owner is null for VM %s", name) + } + vapp, err := vdc.GetVAppByHref(owner) + if err != nil { + return nil, err + } + if vapp.VApp.Children == nil { + return nil, ErrorEntityNotFound + } + if len(vapp.VApp.Children.VM) == 0 { + return nil, fmt.Errorf("vApp %s contains no VMs", vapp.VApp.Name) + } + if len(vapp.VApp.Children.VM) > 1 { + return nil, fmt.Errorf("vApp %s contains more than one VM", vapp.VApp.Name) + } + for _, child := range vapp.VApp.Children.VM { + util.Logger.Printf("[TRACE] Looking at: %s", child.Name) + return vapp.client.GetVMByHref(child.HREF) + } + return nil, ErrorEntityNotFound +} + +// CreateStandaloneVm creates a standalone VM without a template +func (vdc *Vdc) CreateStandaloneVm(params *types.CreateVmParams) (*VM, error) { + + task, err := vdc.CreateStandaloneVmAsync(params) + if err != nil { + return nil, err + } + err = task.WaitTaskCompletion() + if err != nil { + return nil, err + } + return vdc.getVmFromTask(task, params.Name) +} + +// QueryVmByName finds a standalone VM by name +// The search fails either if there are more VMs with the wanted name, or if there are none +// It can also retrieve a standard VM (created from vApp) +func (vdc *Vdc) QueryVmByName(name string) (*VM, error) { + vmList, err := vdc.QueryVmList(types.VmQueryFilterOnlyDeployed) + if err != nil { + return nil, err + } + var foundVM []*types.QueryResultVMRecordType + for _, vm := range vmList { + if vm.Name == name { + foundVM = append(foundVM, vm) + } + } + if len(foundVM) == 0 { + return nil, ErrorEntityNotFound + } + if len(foundVM) > 1 { + return nil, fmt.Errorf("more than one VM found with name %s", name) + } + return vdc.client.GetVMByHref(foundVM[0].HREF) +} + +// QueryVmById retrieves a standalone VM by ID +// It can also retrieve a standard VM (created from vApp) +func (vdc *Vdc) QueryVmById(id string) (*VM, error) { + vmList, err := vdc.QueryVmList(types.VmQueryFilterOnlyDeployed) + if err != nil { + return nil, err + } + var foundVM []*types.QueryResultVMRecordType + for _, vm := range vmList { + if equalIds(id, vm.ID, vm.HREF) { + foundVM = append(foundVM, vm) + } + } + if len(foundVM) == 0 { + return nil, ErrorEntityNotFound + } + if len(foundVM) > 1 { + return nil, fmt.Errorf("more than one VM found with ID %s", id) + } + return vdc.client.GetVMByHref(foundVM[0].HREF) +} + +// CreateStandaloneVMFromTemplateAsync starts a standalone VM creation using a template +func (vdc *Vdc) CreateStandaloneVMFromTemplateAsync(params *types.InstantiateVmTemplateParams) (Task, error) { + + util.Logger.Printf("[TRACE] Vdc.CreateStandaloneVMFromTemplateAsync - Creating VM") + + if vdc.Vdc.HREF == "" { + return Task{}, fmt.Errorf("cannot create VM, provided VDC is empty") + } + + href := "" + for _, link := range vdc.Vdc.Link { + if link.Type == types.MimeInstantiateVmTemplateParams && link.Rel == "add" { + href = link.HREF + break + } + } + if href == "" { + return Task{}, fmt.Errorf("error retrieving VM instantiate from template link from VDC %s", vdc.Vdc.Name) + } + + if params.Name == "" { + return Task{}, fmt.Errorf("[CreateStandaloneVMFromTemplateAsync] missing VM name") + } + if params.SourcedVmTemplateItem == nil { + return Task{}, fmt.Errorf("[CreateStandaloneVMFromTemplateAsync] missing SourcedVmTemplateItem") + } + if params.SourcedVmTemplateItem.Source == nil { + return Task{}, fmt.Errorf("[CreateStandaloneVMFromTemplateAsync] missing vApp template Source") + } + if params.SourcedVmTemplateItem.Source.HREF == "" { + return Task{}, fmt.Errorf("[CreateStandaloneVMFromTemplateAsync] empty HREF in vApp template Source") + } + params.XmlnsOvf = types.XMLNamespaceOVF + + return vdc.client.ExecuteTaskRequest(href, http.MethodPost, types.MimeInstantiateVmTemplateParams, "error creating standalone VM from template: %s", params) +} + +// CreateStandaloneVMFromTemplate creates a standalone VM from a template +func (vdc *Vdc) CreateStandaloneVMFromTemplate(params *types.InstantiateVmTemplateParams) (*VM, error) { + + task, err := vdc.CreateStandaloneVMFromTemplateAsync(params) + if err != nil { + return nil, err + } + err = task.WaitTaskCompletion() + if err != nil { + return nil, err + } + return vdc.getVmFromTask(task, params.Name) +} + // GetCapabilities allows to retrieve a list of VDC capabilities. It has a list of values. Some particularly useful are: // * networkProvider - overlay stack responsible for providing network functionality. (NSX_V or NSX_T) // * crossVdc - supports cross vDC network creation diff --git a/govcd/vdccomputepolicy.go b/govcd/vdccomputepolicy.go index fd11cde8e..ddd5db134 100644 --- a/govcd/vdccomputepolicy.go +++ b/govcd/vdccomputepolicy.go @@ -15,6 +15,7 @@ import ( // In UI called VM sizing policy. In API VDC compute policy type VdcComputePolicy struct { VdcComputePolicy *types.VdcComputePolicy + Href string client *Client } @@ -48,6 +49,7 @@ func getVdcComputePolicyById(client *Client, id string) (*VdcComputePolicy, erro vdcComputePolicy := &VdcComputePolicy{ VdcComputePolicy: &types.VdcComputePolicy{}, + Href: urlRef.String(), client: client, } diff --git a/govcd/vm.go b/govcd/vm.go index 9f52d622a..285a61d8c 100644 --- a/govcd/vm.go +++ b/govcd/vm.go @@ -1,11 +1,10 @@ /* - * Copyright 2019 VMware, Inc. All rights reserved. Licensed under the Apache v2 License. + * Copyright 2021 VMware, Inc. All rights reserved. Licensed under the Apache v2 License. */ package govcd import ( - "encoding/xml" "errors" "fmt" "net" @@ -20,7 +19,7 @@ import ( ) type VM struct { - VM *types.VM + VM *types.Vm client *Client } @@ -31,7 +30,7 @@ type VMRecord struct { func NewVM(cli *Client) *VM { return &VM{ - VM: new(types.VM), + VM: new(types.Vm), client: cli, } } @@ -71,7 +70,7 @@ func (vm *VM) Refresh() error { // Empty struct before a new unmarshal, otherwise we end up with duplicate // elements in slices. - vm.VM = &types.VM{} + vm.VM = &types.Vm{} _, err := vm.client.ExecuteRequestWithApiVersion(refreshUrl, http.MethodGet, "", "error refreshing VM: %s", nil, vm.VM, @@ -495,7 +494,7 @@ func (vm *VM) Undeploy() (Task, error) { } // 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. +// 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, // https://vdc-download.vmware.com/vmwb-repository/dcr-public/1b6cf07d-adb3-4dba-8c47-9c1c92b04857/ // 241956dd-e128-4fcc-8131-bf66e1edd895/vcloud_sp_api_guide_30_0.pdf @@ -686,7 +685,7 @@ func validateMediaParams(mediaParams *types.MediaInsertOrEjectParams) error { } // Insert or eject a media for VM -// Use the vm/action/insert or vm/action/eject links in a Vm to insert or eject media. +// Use the vm/action/insert or vm/action/eject links in a VM to insert or eject media. // Reference: // https://code.vmware.com/apis/287/vcloud#/doc/doc/operations/POST-InsertCdRom.html // https://code.vmware.com/apis/287/vcloud#/doc/doc/operations/POST-EjectCdRom.html @@ -1349,7 +1348,6 @@ func (vm *VM) UpdateInternalDisksAsync(disksSettingToUpdate *types.VmSpecSection return vm.client.ExecuteTaskRequest(vm.VM.HREF+"/action/reconfigureVm", http.MethodPost, types.MimeVM, "error updating VM disks: %s", &types.VMDiskChange{ - XMLName: xml.Name{}, Xmlns: types.XMLNamespaceVCloud, Ovf: types.XMLNamespaceOVF, Name: vm.VM.Name, @@ -1451,7 +1449,7 @@ func (vm *VM) UpdateVmSpecSectionAsync(vmSettingsToUpdate *types.VmSpecSection, vmSpecSectionModified := true vmSettingsToUpdate.Modified = &vmSpecSectionModified - // `reconfigureVm` updates Vm name, Description, and any or all of the following sections. + // `reconfigureVm` updates VM name, Description, and any or all of the following sections. // VirtualHardwareSection // OperatingSystemSection // NetworkConnectionSection @@ -1459,8 +1457,7 @@ func (vm *VM) UpdateVmSpecSectionAsync(vmSettingsToUpdate *types.VmSpecSection, // Sections not included in the request body will not be updated. return vm.client.ExecuteTaskRequest(vm.VM.HREF+"/action/reconfigureVm", http.MethodPost, - types.MimeVM, "error updating VM spec section: %s", &types.VM{ - XMLName: xml.Name{}, + types.MimeVM, "error updating VM spec section: %s", &types.Vm{ Xmlns: types.XMLNamespaceVCloud, Ovf: types.XMLNamespaceOVF, Name: vm.VM.Name, @@ -1496,7 +1493,7 @@ func (vm *VM) UpdateComputePolicyAsync(computePolicy *types.VdcComputePolicy) (T return Task{}, fmt.Errorf("cannot update VM compute policy, VM HREF is unset") } - // `reconfigureVm` updates Vm name, Description, and any or all of the following sections. + // `reconfigureVm` updates VM name, Description, and any or all of the following sections. // VirtualHardwareSection // OperatingSystemSection // NetworkConnectionSection @@ -1512,8 +1509,7 @@ func (vm *VM) UpdateComputePolicyAsync(computePolicy *types.VdcComputePolicy) (T } return vm.client.ExecuteTaskRequest(vm.VM.HREF+"/action/reconfigureVm", http.MethodPost, - types.MimeVM, "error updating VM spec section: %s", &types.VM{ - XMLName: xml.Name{}, + types.MimeVM, "error updating VM spec section: %s", &types.Vm{ Xmlns: types.XMLNamespaceVCloud, Ovf: types.XMLNamespaceOVF, Name: vm.VM.Name, @@ -1544,6 +1540,35 @@ func (client *Client) QueryVmList(filter types.VmQueryFilter) ([]*types.QueryRes return vmList, nil } +// QueryVmList returns a list of all VMs in a given VDC +func (vdc *Vdc) QueryVmList(filter types.VmQueryFilter) ([]*types.QueryResultVMRecordType, error) { + var vmList []*types.QueryResultVMRecordType + queryType := vdc.client.GetQueryType(types.QtVm) + params := map[string]string{ + "type": queryType, + "filterEncoded": "true", + } + filterText := "" + if filter.String() != "" { + filterText = filter.String() + } + if filterText == "" { + filterText = fmt.Sprintf("vdc==%s", vdc.Vdc.HREF) + } else { + filterText = fmt.Sprintf("%s;vdc==%s", filterText, vdc.Vdc.HREF) + } + params["filter"] = filterText + vmResult, err := vdc.client.cumulativeQuery(queryType, nil, params) + if err != nil { + return nil, fmt.Errorf("error getting VM list : %s", err) + } + vmList = vmResult.Results.VMRecord + if vdc.client.IsSysAdmin { + vmList = vmResult.Results.AdminVMRecord + } + return vmList, nil +} + // UpdateVmCpuAndMemoryHotAdd updates VM Capabilities and returns refreshed VM or error. func (vm *VM) UpdateVmCpuAndMemoryHotAdd(cpuAdd, memoryAdd bool) (*VM, error) { task, err := vm.UpdateVmCpuAndMemoryHotAddAsync(cpuAdd, memoryAdd) @@ -1820,15 +1845,14 @@ func (vm *VM) UpdateStorageProfileAsync(storageProfileHref string) (Task, error) return Task{}, fmt.Errorf("cannot update VM storage profile, storage profile HREF is unset") } - // `reconfigureVm` updates Vm name, Description, and any or all of the following sections. + // `reconfigureVm` updates VM name, Description, and any or all of the following sections. // VirtualHardwareSection // OperatingSystemSection // NetworkConnectionSection // GuestCustomizationSection // Sections not included in the request body will not be updated. return vm.client.ExecuteTaskRequest(vm.VM.HREF+"/action/reconfigureVm", http.MethodPost, - types.MimeVM, "error updating VM spec section: %s", &types.VM{ - XMLName: xml.Name{}, + types.MimeVM, "error updating VM spec section: %s", &types.Vm{ Xmlns: types.XMLNamespaceVCloud, Ovf: types.XMLNamespaceOVF, Name: vm.VM.Name, @@ -1836,3 +1860,29 @@ func (vm *VM) UpdateStorageProfileAsync(storageProfileHref string) (Task, error) StorageProfile: &types.Reference{HREF: storageProfileHref}, }) } + +// DeleteAsync starts a standalone VM deletion, returning a task +func (vm *VM) DeleteAsync() (Task, error) { + if vm.VM.HREF == "" { + return Task{}, fmt.Errorf("no HREF found for this VM") + } + + task, err := vm.Undeploy() + if err == nil { + err = task.WaitTaskCompletion() + if err != nil { + return Task{}, err + } + } + return vm.client.ExecuteTaskRequest(vm.VM.HREF, http.MethodDelete, + "", "error deleting VM: %s", nil) +} + +// Delete deletes a standalone VM +func (vm *VM) Delete() error { + task, err := vm.DeleteAsync() + if err != nil { + return err + } + return task.WaitTaskCompletion() +} diff --git a/govcd/vm_affinity_rule.go b/govcd/vm_affinity_rule.go index 0c16d9304..41693e20b 100644 --- a/govcd/vm_affinity_rule.go +++ b/govcd/vm_affinity_rule.go @@ -1,7 +1,7 @@ package govcd /* - * Copyright 2020 VMware, Inc. All rights reserved. Licensed under the Apache v2 License. + * Copyright 2021 VMware, Inc. All rights reserved. Licensed under the Apache v2 License. */ import ( diff --git a/govcd/vm_affinity_rule_test.go b/govcd/vm_affinity_rule_test.go index feae1917d..99cc632a6 100644 --- a/govcd/vm_affinity_rule_test.go +++ b/govcd/vm_affinity_rule_test.go @@ -81,8 +81,8 @@ func (vcd *TestVCD) testGetVmAffinityRule(vdc *Vdc, check *C) { type affinityRuleData struct { name string polarity string - creationVms []*types.VM - updateVms []*types.VM + creationVms []*types.Vm + updateVms []*types.Vm } // testCRUDVmAffinityRule tests creation, update, deletion, and read for VM affinity rules @@ -234,11 +234,11 @@ func (vcd *TestVCD) Test_VmAffinityRule(check *C) { vcd.testCRUDVmAffinityRule(org.Org.Name, vdc, affinityRuleData{ name: "Test_VmAffinityRule1", polarity: types.PolarityAffinity, - creationVms: []*types.VM{ + creationVms: []*types.Vm{ vappList[0].VApp.Children.VM[0], vappList[0].VApp.Children.VM[1], }, - updateVms: []*types.VM{ + updateVms: []*types.Vm{ vappList[1].VApp.Children.VM[0], vappList[1].VApp.Children.VM[1], }, @@ -247,12 +247,12 @@ func (vcd *TestVCD) Test_VmAffinityRule(check *C) { vcd.testCRUDVmAffinityRule(org.Org.Name, vdc, affinityRuleData{ name: "Test_VmAffinityRule2", polarity: types.PolarityAffinity, - creationVms: []*types.VM{ + creationVms: []*types.Vm{ vappList[0].VApp.Children.VM[0], vappList[0].VApp.Children.VM[1], vappList[1].VApp.Children.VM[0], }, - updateVms: []*types.VM{ + updateVms: []*types.Vm{ vappList[2].VApp.Children.VM[0], vappList[2].VApp.Children.VM[1], }, @@ -261,11 +261,11 @@ func (vcd *TestVCD) Test_VmAffinityRule(check *C) { vcd.testCRUDVmAffinityRule(org.Org.Name, vdc, affinityRuleData{ name: "Test_VmAffinityRule3", polarity: types.PolarityAntiAffinity, - creationVms: []*types.VM{ + creationVms: []*types.Vm{ vappList[0].VApp.Children.VM[0], vappList[1].VApp.Children.VM[0], }, - updateVms: []*types.VM{ + updateVms: []*types.Vm{ vappList[2].VApp.Children.VM[0], }, }, check) diff --git a/govcd/vm_test.go b/govcd/vm_test.go index 548813a46..4313299c3 100644 --- a/govcd/vm_test.go +++ b/govcd/vm_test.go @@ -1,7 +1,7 @@ // +build vm functional ALL /* -* Copyright 2019 VMware, Inc. All rights reserved. Licensed under the Apache v2 License. +* Copyright 2021 VMware, Inc. All rights reserved. Licensed under the Apache v2 License. * Copyright 2016 Skyscape Cloud Services. All rights reserved. Licensed under the Apache v2 License. */ @@ -12,9 +12,11 @@ import ( "strings" "time" + "github.com/kr/pretty" . "gopkg.in/check.v1" "github.com/vmware/go-vcloud-director/v2/types/v56" + "github.com/vmware/go-vcloud-director/v2/util" ) func init() { @@ -1300,7 +1302,6 @@ func (vcd *TestVCD) Test_AddNewEmptyVMMultiNIC(check *C) { NumCoresPerSocket: takeIntAddress(1), CpuResourceMhz: &types.CpuResourceMhz{Configured: 1}, MemoryResourceMb: &types.MemoryResourceMb{Configured: 1024}, - MediaSection: nil, DiskSection: &types.DiskSection{DiskSettings: []*types.DiskSettings{&newDisk}}, HardwareVersion: &types.HardwareVersion{Value: "vmx-13"}, // need support older version vCD VmToolsVersion: "", @@ -1405,7 +1406,7 @@ func (vcd *TestVCD) Test_QueryVmList(check *C) { } for filter := range []types.VmQueryFilter{types.VmQueryFilterOnlyDeployed, types.VmQueryFilterAll} { - list, err := vcd.client.Client.QueryVmList(types.VmQueryFilter(filter)) + list, err := vcd.vdc.QueryVmList(types.VmQueryFilter(filter)) check.Assert(err, IsNil) check.Assert(list, NotNil) foundVm := false @@ -1655,3 +1656,177 @@ func (vcd *TestVCD) Test_VMUpdateStorageProfile(check *C) { check.Assert(err, IsNil) check.Assert(task.Task.Status, Equals, "success") } + +func (vcd *TestVCD) getNetworkConnection() *types.NetworkConnectionSection { + + if vcd.config.VCD.Network.Net1 == "" { + return nil + } + return &types.NetworkConnectionSection{ + Info: "Network Configuration for VM", + PrimaryNetworkConnectionIndex: 0, + NetworkConnection: []*types.NetworkConnection{ + &types.NetworkConnection{ + Network: vcd.config.VCD.Network.Net1, + NeedsCustomization: false, + NetworkConnectionIndex: 0, + IPAddress: "any", + IsConnected: true, + IPAddressAllocationMode: "DHCP", + NetworkAdapterType: "VMXNET3", + }, + }, + Link: nil, + } +} + +func (vcd *TestVCD) Test_CreateStandaloneVM(check *C) { + adminOrg, err := vcd.client.GetAdminOrgByName(vcd.org.Org.Name) + check.Assert(err, IsNil) + check.Assert(adminOrg, NotNil) + + vdc, err := adminOrg.GetVDCByName(vcd.vdc.Vdc.Name, false) + check.Assert(err, IsNil) + check.Assert(vdc, NotNil) + description := "created by " + check.TestName() + params := types.CreateVmParams{ + Name: "testStandaloneVm", + PowerOn: false, + Description: description, + CreateVm: &types.Vm{ + Name: "testStandaloneVm", + VirtualHardwareSection: nil, + NetworkConnectionSection: vcd.getNetworkConnection(), + VmSpecSection: &types.VmSpecSection{ + Modified: takeBoolPointer(true), + Info: "Virtual Machine specification", + OsType: "debian10Guest", + NumCpus: takeIntAddress(1), + NumCoresPerSocket: takeIntAddress(1), + CpuResourceMhz: &types.CpuResourceMhz{ + Configured: 0, + }, + MemoryResourceMb: &types.MemoryResourceMb{ + Configured: 512, + }, + DiskSection: &types.DiskSection{ + DiskSettings: []*types.DiskSettings{ + &types.DiskSettings{ + SizeMb: 1024, + UnitNumber: 0, + BusNumber: 0, + AdapterType: "5", + ThinProvisioned: takeBoolPointer(true), + OverrideVmDefault: false, + }, + }, + }, + + HardwareVersion: &types.HardwareVersion{Value: "vmx-14"}, + VmToolsVersion: "", + VirtualCpuType: "VM32", + }, + GuestCustomizationSection: &types.GuestCustomizationSection{ + Info: "Specifies Guest OS Customization Settings", + ComputerName: "standalone1", + }, + }, + Xmlns: types.XMLNamespaceVCloud, + } + vappList := vdc.GetVappList() + vappNum := len(vappList) + vm, err := vdc.CreateStandaloneVm(¶ms) + check.Assert(err, IsNil) + check.Assert(vm, NotNil) + AddToCleanupList(vm.VM.ID, "standaloneVm", "", check.TestName()) + check.Assert(vm.VM.Description, Equals, description) + + _ = vdc.Refresh() + vappList = vdc.GetVappList() + check.Assert(len(vappList), Equals, vappNum+1) + for _, vapp := range vappList { + printVerbose("vapp: %s\n", vapp.Name) + } + err = vm.Delete() + check.Assert(err, IsNil) + _ = vdc.Refresh() + vappList = vdc.GetVappList() + check.Assert(len(vappList), Equals, vappNum) +} + +func (vcd *TestVCD) Test_CreateStandaloneVMFromTemplate(check *C) { + + if vcd.config.VCD.Catalog.Name == "" { + check.Skip("no catalog was defined") + } + if vcd.config.VCD.Catalog.CatalogItem == "" { + check.Skip("no catalog item was defined") + } + adminOrg, err := vcd.client.GetAdminOrgByName(vcd.org.Org.Name) + check.Assert(err, IsNil) + check.Assert(adminOrg, NotNil) + + vdc, err := adminOrg.GetVDCByName(vcd.vdc.Vdc.Name, false) + check.Assert(err, IsNil) + check.Assert(vdc, NotNil) + + catalog, err := adminOrg.GetCatalogByName(vcd.config.VCD.Catalog.Name, false) + check.Assert(err, IsNil) + check.Assert(catalog, NotNil) + + catalogItem, err := catalog.GetCatalogItemByName(vcd.config.VCD.Catalog.CatalogItem, false) + check.Assert(err, IsNil) + check.Assert(catalogItem, NotNil) + + vappTemplate, err := catalog.GetVappTemplateByHref(catalogItem.CatalogItem.Entity.HREF) + check.Assert(err, IsNil) + check.Assert(vappTemplate, NotNil) + check.Assert(vappTemplate.VAppTemplate.Children, NotNil) + check.Assert(len(vappTemplate.VAppTemplate.Children.VM), Not(Equals), 0) + + vmTemplate := vappTemplate.VAppTemplate.Children.VM[0] + check.Assert(vmTemplate.HREF, Not(Equals), "") + check.Assert(vmTemplate.ID, Not(Equals), "") + check.Assert(vmTemplate.Type, Not(Equals), "") + check.Assert(vmTemplate.Name, Not(Equals), "") + + params := types.InstantiateVmTemplateParams{ + Xmlns: types.XMLNamespaceVCloud, + Name: "testStandaloneTemplate", + PowerOn: true, + AllEULAsAccepted: true, + SourcedVmTemplateItem: &types.SourcedVmTemplateParams{ + LocalityParams: nil, + Source: &types.Reference{ + HREF: vmTemplate.HREF, + ID: vmTemplate.ID, + Type: vmTemplate.Type, + Name: vmTemplate.Name, + }, + StorageProfile: nil, + VmCapabilities: nil, + VmGeneralParams: nil, + VmTemplateInstantiationParams: nil, + }, + } + vappList := vdc.GetVappList() + vappNum := len(vappList) + util.Logger.Printf("%# v", pretty.Formatter(params)) + vm, err := vdc.CreateStandaloneVMFromTemplate(¶ms) + check.Assert(err, IsNil) + check.Assert(vm, NotNil) + AddToCleanupList(vm.VM.ID, "standaloneVm", "", check.TestName()) + + _ = vdc.Refresh() + vappList = vdc.GetVappList() + check.Assert(len(vappList), Equals, vappNum+1) + for _, vapp := range vappList { + printVerbose("vapp: %s\n", vapp.Name) + } + + err = vm.Delete() + check.Assert(err, IsNil) + _ = vdc.Refresh() + vappList = vdc.GetVappList() + check.Assert(len(vappList), Equals, vappNum) +} diff --git a/types/v56/constants.go b/types/v56/constants.go index 1f05336e0..35f4531e5 100644 --- a/types/v56/constants.go +++ b/types/v56/constants.go @@ -1,5 +1,5 @@ /* - * Copyright 2019 VMware, Inc. All rights reserved. Licensed under the Apache v2 License. + * Copyright 2021 VMware, Inc. All rights reserved. Licensed under the Apache v2 License. */ package types @@ -127,6 +127,10 @@ const ( MimeVdcComputePolicyReferences = "application/vnd.vmware.vcloud.vdcComputePolicyReferences+xml" // Mime for Storage profile MimeStorageProfile = "application/vnd.vmware.admin.vdcStorageProfile+xml " + // Mime for create VM Params + MimeCreateVmParams = "application/vnd.vmware.vcloud.CreateVmParams+xml" + // Mime for instantiate VM Params from template + MimeInstantiateVmTemplateParams = "application/vnd.vmware.vcloud.instantiateVmTemplateParams+xml" ) const ( diff --git a/types/v56/types.go b/types/v56/types.go index d293098b3..83c9c0c2f 100644 --- a/types/v56/types.go +++ b/types/v56/types.go @@ -1,5 +1,5 @@ /* - * Copyright 2019 VMware, Inc. All rights reserved. Licensed under the Apache v2 License. + * Copyright 2021 VMware, Inc. All rights reserved. Licensed under the Apache v2 License. */ // Package types/v56 provider all types which are used by govcd package in order to perform API @@ -12,7 +12,7 @@ import ( "sort" ) -// Maps status Attribute Values for VAppTemplate, VApp, Vm, and Media Objects +// Maps status Attribute Values for VAppTemplate, VApp, VM, and Media Objects var VAppStatuses = map[int]string{ -1: "FAILED_CREATION", 0: "UNRESOLVED", @@ -1163,7 +1163,7 @@ type ComposeVAppParams struct { Description string `xml:"Description,omitempty"` // Optional description. VAppParent *Reference `xml:"VAppParent,omitempty"` // Reserved. Unimplemented. InstantiationParams *InstantiationParams `xml:"InstantiationParams,omitempty"` // Instantiation parameters for the composed vApp. - SourcedItem *SourcedCompositionItemParam `xml:"SourcedItem,omitempty"` // Composition item. One of: vApp vAppTemplate Vm. + SourcedItem *SourcedCompositionItemParam `xml:"SourcedItem,omitempty"` // Composition item. One of: vApp vAppTemplate VM. AllEULAsAccepted bool `xml:"AllEULAsAccepted,omitempty"` // True confirms acceptance of all EULAs in a vApp template. Instantiation fails if this element is missing, empty, or set to false and one or more EulaSection elements are present. } @@ -1181,7 +1181,7 @@ type ReComposeVAppParams struct { Description string `xml:"Description,omitempty"` // Optional description. VAppParent *Reference `xml:"VAppParent,omitempty"` // Reserved. Unimplemented. InstantiationParams *InstantiationParams `xml:"InstantiationParams,omitempty"` // Instantiation parameters for the composed vApp. - SourcedItem *SourcedCompositionItemParam `xml:"SourcedItem,omitempty"` // Composition item. One of: vApp vAppTemplate Vm. + SourcedItem *SourcedCompositionItemParam `xml:"SourcedItem,omitempty"` // Composition item. One of: vApp vAppTemplate VM. AllEULAsAccepted bool `xml:"AllEULAsAccepted,omitempty"` DeleteItem *DeleteItem `xml:"DeleteItem,omitempty"` } @@ -1190,10 +1190,10 @@ type DeleteItem struct { HREF string `xml:"href,attr,omitempty"` } -// SourcedCompositionItemParam represents a vApp, vApp template or Vm to include in a composed vApp. +// SourcedCompositionItemParam represents a vApp, vApp template or VM to include in a composed vApp. // Type: SourcedCompositionItemParamType // Namespace: http://www.vmware.com/vcloud/v1.5 -// Description: Represents a vApp, vApp template or Vm to include in a composed vApp. +// Description: Represents a vApp, vApp template or VM to include in a composed vApp. // Since: 0.9 type SourcedCompositionItemParam struct { // Attributes @@ -1201,10 +1201,10 @@ type SourcedCompositionItemParam struct { // Elements Source *Reference `xml:"Source"` // Reference to a vApp, vApp template or virtual machine to include in the composition. Changing the name of the newly created VM by specifying name attribute is deprecated. Include VmGeneralParams element instead. VMGeneralParams *VMGeneralParams `xml:"VmGeneralParams,omitempty"` // Specify name, description, and other properties of a VM during instantiation. - VAppScopedLocalID string `xml:"VAppScopedLocalId,omitempty"` // If Source references a Vm, this value provides a unique identifier for the Vm in the scope of the composed vApp. - InstantiationParams *InstantiationParams `xml:"InstantiationParams,omitempty"` // If Source references a Vm this can include any of the following OVF sections: VirtualHardwareSection OperatingSystemSection NetworkConnectionSection GuestCustomizationSection. - NetworkAssignment []*NetworkAssignment `xml:"NetworkAssignment,omitempty"` // If Source references a Vm, this element maps a network name specified in the Vm to the network name of a vApp network defined in the composed vApp. - StorageProfile *Reference `xml:"StorageProfile,omitempty"` // If Source references a Vm, this element contains a reference to a storage profile to be used for the Vm. The specified storage profile must exist in the organization vDC that contains the composed vApp. If not specified, the default storage profile for the vDC is used. + VAppScopedLocalID string `xml:"VAppScopedLocalId,omitempty"` // If Source references a VM, this value provides a unique identifier for the VM in the scope of the composed vApp. + InstantiationParams *InstantiationParams `xml:"InstantiationParams,omitempty"` // If Source references a VM this can include any of the following OVF sections: VirtualHardwareSection OperatingSystemSection NetworkConnectionSection GuestCustomizationSection. + NetworkAssignment []*NetworkAssignment `xml:"NetworkAssignment,omitempty"` // If Source references a VM, this element maps a network name specified in the VM to the network name of a vApp network defined in the composed vApp. + StorageProfile *Reference `xml:"StorageProfile,omitempty"` // If Source references a VM, this element contains a reference to a storage profile to be used for the VM. The specified storage profile must exist in the organization vDC that contains the composed vApp. If not specified, the default storage profile for the vDC is used. LocalityParams *LocalityParams `xml:"LocalityParams,omitempty"` // Represents locality parameters. Locality parameters provide a hint that may help the placement engine optimize placement of a VM and an independent a Disk so that the VM can make efficient use of the disk. ComputePolicy *ComputePolicy `xml:"ComputePolicy,omitempty"` // accessible only from version API 33.0 } @@ -1219,14 +1219,14 @@ type LocalityParams struct { ResourceEntity *Reference `xml:"ResourceEntity,omitempty"` // Reference to a Disk, or a VM. } -// NetworkAssignment maps a network name specified in a Vm to the network name of a vApp network defined in the VApp that contains the Vm +// NetworkAssignment maps a network name specified in a VM to the network name of a vApp network defined in the VApp that contains the VM // Type: NetworkAssignmentType // Namespace: http://www.vmware.com/vcloud/v1.5 -// Description: Maps a network name specified in a Vm to the network name of a vApp network defined in the VApp that contains the Vm +// Description: Maps a network name specified in a VM to the network name of a vApp network defined in the VApp that contains the VM // Since: 0.9 type NetworkAssignment struct { // Attributes - InnerNetwork string `xml:"innerNetwork,attr"` // Name of the network as specified in the Vm. + InnerNetwork string `xml:"innerNetwork,attr"` // Name of the network as specified in the VM. ContainerNetwork string `xml:"containerNetwork,attr"` // Name of the vApp network to map to. } @@ -1269,6 +1269,7 @@ type VApp struct { // Section OVF_Section `xml:"Section"` DateCreated string `xml:"DateCreated,omitempty"` // Creation date/time of the vApp. Owner *Owner `xml:"Owner,omitempty"` // vApp owner. + IsAutoNature bool `xml:"autoNature,omitempty"` // True if the vApp is auto generated with a standalone VM InMaintenanceMode bool `xml:"InMaintenanceMode,omitempty"` // True if this vApp is in maintenance mode. Prevents users from changing vApp metadata. Children *VAppChildren `xml:"Children,omitempty"` // Container for virtual machines included in this vApp. ProductSection *ProductSection `xml:"ProductSection,omitempty"` @@ -1353,7 +1354,7 @@ type MetadataEntry struct { // Description: Container for virtual machines included in this vApp. // Since: 0.9 type VAppChildren struct { - VM []*VM `xml:"Vm,omitempty"` // Represents a virtual machine. + VM []*Vm `xml:"Vm,omitempty"` // Represents a virtual machine. } // TasksInProgress is a list of queued, running, or recently completed tasks. @@ -1398,7 +1399,7 @@ type VAppTemplate struct { Files *FilesList `xml:"Files,omitempty"` // Represents a list of files to be transferred (uploaded or downloaded). Each File in the list is part of the ResourceEntity. Owner *Owner `xml:"Owner,omitempty"` // vAppTemplate owner. Children *VAppTemplateChildren `xml:"Children,omitempty"` // Container for virtual machines included in this vApp template. - VAppScopedLocalID string `xml:"VAppScopedLocalId"` // A unique identifier for the Vm in the scope of the vApp template. + VAppScopedLocalID string `xml:"VAppScopedLocalId"` // A unique identifier for the VM in the scope of the vApp template. DefaultStorageProfile string `xml:"DefaultStorageProfile,omitempty"` // The name of the storage profile to be used for this object. The named storage profile must exist in the organization vDC that contains the object. If not specified, the default storage profile for the vDC is used. DateCreated string `xml:"DateCreated,omitempty"` // Creation date/time of the template. // FIXME: Upstream bug? Missing NetworkConfigSection, LeaseSettingSection and @@ -1428,12 +1429,12 @@ type VMDiskChange struct { VmSpecSection *VmSpecSection `xml:"VmSpecSection,omitempty"` // Container for the specification of this virtual machine. This is an alternative to using ovf:VirtualHardwareSection + ovf:OperatingSystemSection } -// DiskSection from VM/VmSpecSection struct +// DiskSection from Vm/VmSpecSection struct type DiskSection struct { DiskSettings []*DiskSettings `xml:"DiskSettings"` } -// DiskSettings from VM/VmSpecSection/DiskSection struct +// DiskSettings from Vm/VmSpecSection/DiskSection struct type DiskSettings struct { DiskId string `xml:"DiskId,omitempty"` // Specifies a unique identifier for this disk in the scope of the corresponding VM. This element is optional when creating a VM, but if it is provided it should be unique. This element is mandatory when updating an existing disk. SizeMb int64 `xml:"SizeMb"` // The size of the disk in MB. @@ -1449,12 +1450,12 @@ type DiskSettings struct { VirtualQuantityUnit string `xml:"VirtualQuantityUnit,omitempty"` // The units in which VirtualQuantity is measured. } -// MediaSection from VM/VmSpecSection struct +// MediaSection from Vm/VmSpecSection struct type MediaSection struct { MediaSettings []*MediaSettings `xml:"MediaSettings"` } -// MediaSettings from VM/VmSpecSection/MediaSection struct +// MediaSettings from Vm/VmSpecSection/MediaSection struct type MediaSettings struct { DeviceId string `xml:"DeviceId,omitempty"` // Describes the media device whose media mount is being specified here. This deviceId must match the RASD.InstanceID attribute in the VirtualHardwareSection of the vApp's OVF description. MediaImage *Reference `xml:"MediaImage,omitempty"` // The media image that is mounted onto the device. This property can be 'null' which represents that no media is mounted on the device. @@ -1465,7 +1466,7 @@ type MediaSettings struct { AdapterType string `xml:"AdapterType,omitempty"` // The type of controller, e.g. IDE vs SCSI and if SCSI bus-logic vs LSI logic } -// CpuResourceMhz from VM/VmSpecSection struct +// CpuResourceMhz from Vm/VmSpecSection struct type CpuResourceMhz struct { Configured int64 `xml:"Configured"` // The amount of resource configured on the virtual machine. Reservation *int64 `xml:"Reservation,omitempty"` // The amount of reservation of this resource on the underlying virtualization infrastructure. @@ -1474,7 +1475,7 @@ type CpuResourceMhz struct { Shares *int `xml:"Shares,omitempty"` // Custom priority for the resource. This field is read-only, unless the shares level is CUSTOM. } -// MemoryResourceMb from VM/VmSpecSection struct +// MemoryResourceMb from Vm/VmSpecSection struct type MemoryResourceMb struct { Configured int64 `xml:"Configured"` // The amount of resource configured on the virtual machine. Reservation *int64 `xml:"Reservation,omitempty"` // The amount of reservation of this resource on the underlying virtualization infrastructure. @@ -1483,14 +1484,14 @@ type MemoryResourceMb struct { Shares *int `xml:"Shares,omitempty"` // Custom priority for the resource. This is a read-only, unless the share level is CUSTOM. } -// HardwareVersion from VM/VmSpecSection struct +// HardwareVersion from Vm/VmSpecSection struct type HardwareVersion struct { HREF string `xml:"href,attr"` Type string `xml:"type,attr,omitempty"` Value string `xml:",chardata"` } -// ovf:VirtualHardwareSection from VM struct +// ovf:VirtualHardwareSection from Vm struct type VirtualHardwareSection struct { // Extends OVF Section_Type XMLName xml.Name `xml:"VirtualHardwareSection"` @@ -1548,7 +1549,7 @@ type VirtualHardwareHostResource struct { //OsType string `xml:"osType,attr,omitempty"` } -// SnapshotSection from VM struct +// SnapshotSection from Vm struct type SnapshotSection struct { // Extends OVF Section_Type XMLName xml.Name `xml:"SnapshotSection"` @@ -1667,7 +1668,7 @@ type InstantiateVAppTemplateParams struct { InstantiationParams *InstantiationParams `xml:"InstantiationParams,omitempty"` // Instantiation parameters for the composed vApp. Source *Reference `xml:"Source"` // A reference to a source object such as a vApp or vApp template. IsSourceDelete bool `xml:"IsSourceDelete,omitempty"` // Set to true to delete the source object after the operation completes. - SourcedItem *SourcedCompositionItemParam `xml:"SourcedItem,omitempty"` // Composition item. One of: vApp vAppTemplate Vm. + SourcedItem *SourcedCompositionItemParam `xml:"SourcedItem,omitempty"` // Composition item. One of: vApp vAppTemplate VM. AllEULAsAccepted bool `xml:"AllEULAsAccepted,omitempty"` // True confirms acceptance of all EULAs in a vApp template. Instantiation fails if this element is missing, empty, or set to false and one or more EulaSection elements are present. } @@ -1977,7 +1978,7 @@ type FirewallRule struct { SourcePort int `xml:"SourcePort,omitempty"` // Destination port to which this rule applies. A value of -1 matches any port. SourcePortRange string `xml:"SourcePortRange,omitempty"` // Source port range to which this rule applies. SourceIP string `xml:"SourceIp,omitempty"` // Source IP address to which the rule applies. A value of Any matches any IP address. - SourceVM *VMSelection `xml:"SourceVm,omitempty"` // Details of the source Vm + SourceVM *VMSelection `xml:"SourceVm,omitempty"` // Details of the source VM Direction string `xml:"Direction,omitempty"` // Direction of traffic to which rule applies. One of: in (rule applies to incoming traffic. This is the default value), out (rule applies to outgoing traffic). EnableLogging bool `xml:"EnableLogging"` // Used to enable or disable firewall rule logging. Default value is false. } diff --git a/types/v56/vm_types.go b/types/v56/vm_types.go index efeba61bd..718d72bd9 100644 --- a/types/v56/vm_types.go +++ b/types/v56/vm_types.go @@ -1,18 +1,24 @@ +/* + * Copyright 2021 VMware, Inc. All rights reserved. Licensed under the Apache v2 License. + */ package types import "encoding/xml" -// VM represents a virtual machine +// Vm represents a virtual machine // Type: VmType // Namespace: http://www.vmware.com/vcloud/v1.5 // Description: Represents a virtual machine. // Since: 0.9 -type VM struct { +// This structure used to be called `VM`, and needed an XMLName to adjust the XML entity name upon marshalling. +// We have renamed it to `Vm` to remove the ambiguity and avoid XMLName conflicts when embedding this type +// into another structure. +// Now, there is no need for XMLName, as the name of the structure is the same as the XML entity +type Vm struct { // Attributes - XMLName xml.Name `xml:"Vm"` - Ovf string `xml:"xmlns:ovf,attr,omitempty"` - Xsi string `xml:"xmlns:xsi,attr,omitempty"` - Xmlns string `xml:"xmlns,attr,omitempty"` + Ovf string `xml:"xmlns:ovf,attr,omitempty"` + Xsi string `xml:"xmlns:xsi,attr,omitempty"` + Xmlns string `xml:"xmlns,attr,omitempty"` HREF string `xml:"href,attr,omitempty"` // The URI of the entity. Type string `xml:"type,attr,omitempty"` // The MIME type of the entity. @@ -59,7 +65,7 @@ type VM struct { Media *Reference `xml:"Media,omitempty"` // Reference to the media object to insert in a new VM. } -// VmSpecSection from VM struct +// VmSpecSection from Vm struct type VmSpecSection struct { Modified *bool `xml:"Modified,attr,omitempty"` Info string `xml:"ovf:Info"` @@ -107,3 +113,38 @@ type ComputePolicy struct { VmSizingPolicy *Reference `xml:"VmSizingPolicy,omitempty"` // VdcComputePolicy that defines VM's sizing and resource allocation. VmSizingPolicyFinal *bool `xml:"VmSizingPolicyFinal,omitempty"` // True indicates that the sizing policy cannot be removed from a VM that is instantiated with it. This value defaults to false. } + +// CreateVmParams is used to create a standalone VM without a template +type CreateVmParams struct { + XMLName xml.Name `xml:"CreateVmParams"` + XmlnsOvf string `xml:"xmlns:ovf,attr"` + Xmlns string `xml:"xmlns,attr,omitempty"` + Name string `xml:"name,attr,omitempty"` // Typically used to name or identify the subject of the request. For example, the name of the object being created or modified. + PowerOn bool `xml:"powerOn,attr,omitempty"` // True if the VM should be powered-on after creation. Defaults to false. + Description string `xml:"Description,omitempty"` // Optional description + CreateVm *Vm `xml:"CreateVm"` // Read-only information about the VM to create. This information appears in the Task returned by a createVm request. + Media *Reference `xml:"Media,omitempty"` // Reference to the media object to insert in the new VM. +} + +// InstantiateVmTemplateParams is used to create a standalone VM with a template +type InstantiateVmTemplateParams struct { + XMLName xml.Name `xml:"InstantiateVmTemplateParams"` + XmlnsOvf string `xml:"xmlns:ovf,attr"` + Xmlns string `xml:"xmlns,attr,omitempty"` + Name string `xml:"name,attr,omitempty"` // Typically used to name or identify the subject of the request. For example, the name of the object being created or modified. + PowerOn bool `xml:"powerOn,attr,omitempty"` // True if the VM should be powered-on after creation. Defaults to false. + Description string `xml:"Description,omitempty"` // Optional description + SourcedVmTemplateItem *SourcedVmTemplateParams `xml:"SourcedVmTemplateItem,omitempty"` // Represents virtual machine instantiation parameters. + AllEULAsAccepted bool `xml:"AllEULAsAccepted,omitempty"` // True confirms acceptance of all EULAs in a vApp template. Instantiation fails if this element is missing, empty, or set to false and one or more EulaSection elements are present. + ComputePolicy *ComputePolicy `xml:"ComputePolicy,omitempty"` // A reference to a vdc compute policy. This contains VM's actual vdc compute policy reference and also optionally an add-on policy which always defines VM's sizing. +} + +// SourcedVmTemplateParams represents the standalone VM instantiation parameters +type SourcedVmTemplateParams struct { + LocalityParams *LocalityParams `xml:"LocalityParams,omitempty"` // Locality parameters provide a hint that may help optimize placement of a VM and an independent a Disk so that the VM can make efficient use of the disk. + Source *Reference `xml:"Source"` // A reference to an existing VM template + VmCapabilities *VmCapabilities `xml:"VmCapabilities,omitempty"` // Describes the capabilities (hot swap, etc.) the instantiated VM should have. + VmGeneralParams *VMGeneralParams `xml:"VMGeneralParams,omitempty"` // Specify name, description, and other properties of a VM during instantiation. + VmTemplateInstantiationParams *InstantiationParams `xml:"VmTemplateInstantiationParams,omitempty"` // Same as InstantiationParams used for VMs within a vApp + StorageProfile *Reference `xml:"StorageProfile,omitempty"` // A reference to a storage profile to be used for the VM. The specified storage profile must exist in the organization vDC that contains the composed vApp. If not specified, the default storage profile for the vDC is used. +}