pagination of vcenter queries
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
This commit is contained in:
@@ -11,8 +11,10 @@ import (
|
||||
|
||||
"github.com/vmware/govmomi"
|
||||
"github.com/vmware/govmomi/event"
|
||||
"github.com/vmware/govmomi/fault"
|
||||
"github.com/vmware/govmomi/find"
|
||||
"github.com/vmware/govmomi/object"
|
||||
"github.com/vmware/govmomi/property"
|
||||
"github.com/vmware/govmomi/view"
|
||||
"github.com/vmware/govmomi/vim25/mo"
|
||||
"github.com/vmware/govmomi/vim25/soap"
|
||||
@@ -40,6 +42,124 @@ type VmProperties struct {
|
||||
|
||||
var clientUserAgent = "vCTP"
|
||||
|
||||
const (
|
||||
defaultPropertyPageSize int32 = 500
|
||||
)
|
||||
|
||||
func normalizeKinds(kind []string) []string {
|
||||
if len(kind) > 0 {
|
||||
return kind
|
||||
}
|
||||
return []string{"ManagedEntity"}
|
||||
}
|
||||
|
||||
func normalizePageSize(pageSize int32) int32 {
|
||||
if pageSize <= 0 {
|
||||
return defaultPropertyPageSize
|
||||
}
|
||||
return pageSize
|
||||
}
|
||||
|
||||
func buildPropertySpecs(kind []string, props []string) []types.PropertySpec {
|
||||
kinds := normalizeKinds(kind)
|
||||
specs := make([]types.PropertySpec, 0, len(kinds))
|
||||
for _, t := range kinds {
|
||||
spec := types.PropertySpec{Type: t}
|
||||
if len(props) == 0 {
|
||||
spec.All = types.NewBool(true)
|
||||
} else {
|
||||
spec.PathSet = props
|
||||
}
|
||||
specs = append(specs, spec)
|
||||
}
|
||||
return specs
|
||||
}
|
||||
|
||||
func refKey(ref types.ManagedObjectReference) string {
|
||||
return ref.Type + ":" + ref.Value
|
||||
}
|
||||
|
||||
func (v *Vcenter) retrieveContainerViewPaged(ctx context.Context, cv *view.ContainerView, kind []string, props []string, dst any, pageSize int32) error {
|
||||
pc := property.DefaultCollector(v.client.Client)
|
||||
req := types.RetrieveProperties{
|
||||
SpecSet: []types.PropertyFilterSpec{
|
||||
{
|
||||
ObjectSet: []types.ObjectSpec{
|
||||
{
|
||||
Obj: cv.Reference(),
|
||||
Skip: types.NewBool(true),
|
||||
SelectSet: []types.BaseSelectionSpec{
|
||||
&types.TraversalSpec{
|
||||
Type: cv.Reference().Type,
|
||||
Path: "view",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
PropSet: buildPropertySpecs(kind, props),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
res, err := pc.RetrieveProperties(ctx, req, normalizePageSize(pageSize))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if d, ok := dst.(*[]types.ObjectContent); ok {
|
||||
*d = res.Returnval
|
||||
return nil
|
||||
}
|
||||
|
||||
return mo.LoadObjectContent(res.Returnval, dst)
|
||||
}
|
||||
|
||||
func (v *Vcenter) retrieveByRefsPaged(ctx context.Context, refs []types.ManagedObjectReference, props []string, dst any, pageSize int32) error {
|
||||
if len(refs) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
kindSet := make(map[string]struct{}, len(refs))
|
||||
kinds := make([]string, 0, len(refs))
|
||||
for _, ref := range refs {
|
||||
if _, ok := kindSet[ref.Type]; ok {
|
||||
continue
|
||||
}
|
||||
kindSet[ref.Type] = struct{}{}
|
||||
kinds = append(kinds, ref.Type)
|
||||
}
|
||||
|
||||
objectSet := make([]types.ObjectSpec, 0, len(refs))
|
||||
for _, ref := range refs {
|
||||
objectSet = append(objectSet, types.ObjectSpec{
|
||||
Obj: ref,
|
||||
Skip: types.NewBool(false),
|
||||
})
|
||||
}
|
||||
|
||||
pc := property.DefaultCollector(v.client.Client)
|
||||
req := types.RetrieveProperties{
|
||||
SpecSet: []types.PropertyFilterSpec{
|
||||
{
|
||||
ObjectSet: objectSet,
|
||||
PropSet: buildPropertySpecs(kinds, props),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
res, err := pc.RetrieveProperties(ctx, req, normalizePageSize(pageSize))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if d, ok := dst.(*[]types.ObjectContent); ok {
|
||||
*d = res.Returnval
|
||||
return nil
|
||||
}
|
||||
|
||||
return mo.LoadObjectContent(res.Returnval, dst)
|
||||
}
|
||||
|
||||
// SetUserAgent customizes the User-Agent used when talking to vCenter.
|
||||
func SetUserAgent(ua string) {
|
||||
if strings.TrimSpace(ua) != "" {
|
||||
@@ -127,46 +247,25 @@ func (v *Vcenter) Logout(ctx context.Context) error {
|
||||
}
|
||||
|
||||
func (v *Vcenter) GetAllVmReferences() ([]*object.VirtualMachine, error) {
|
||||
var results []*object.VirtualMachine
|
||||
finder := find.NewFinder(v.client.Client, true)
|
||||
|
||||
m := view.NewManager(v.client.Client)
|
||||
|
||||
vms, err := m.CreateContainerView(v.ctx, v.client.ServiceContent.RootFolder, []string{"VirtualMachine"}, true)
|
||||
cv, err := m.CreateContainerView(v.ctx, v.client.ServiceContent.RootFolder, []string{"VirtualMachine"}, true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, fmt.Errorf("failed to create VM container view: %w", err)
|
||||
}
|
||||
defer vms.Destroy(v.ctx)
|
||||
defer cv.Destroy(v.ctx)
|
||||
|
||||
// List all datacenters
|
||||
datacenters, err := finder.DatacenterList(v.ctx, "*")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to list datacenters: %w", err)
|
||||
var content []types.ObjectContent
|
||||
if err := v.retrieveContainerViewPaged(v.ctx, cv, []string{"VirtualMachine"}, []string{"name"}, &content, defaultPropertyPageSize); err != nil {
|
||||
return nil, fmt.Errorf("failed to retrieve VM references: %w", err)
|
||||
}
|
||||
|
||||
for _, dc := range datacenters {
|
||||
v.Logger.Debug("Getting VMs in", "datacenter", dc.Name())
|
||||
// Set the current datacenter
|
||||
finder.SetDatacenter(dc)
|
||||
|
||||
// Get the list of all virtual machines in the current datacenter
|
||||
vms, err := finder.VirtualMachineList(v.ctx, "*")
|
||||
if err != nil {
|
||||
v.Logger.Error("Failed to list VMs in", "datacenter", dc.Name(), "error", err)
|
||||
continue
|
||||
}
|
||||
|
||||
for _, vm := range vms {
|
||||
//vmRef := vm.Reference()
|
||||
//v.Logger.Debug("result", "vm", vm, "MoRef", vmRef, "path", vm.InventoryPath)
|
||||
results = append(results, vm)
|
||||
}
|
||||
|
||||
results := make([]*object.VirtualMachine, 0, len(content))
|
||||
for _, c := range content {
|
||||
results = append(results, object.NewVirtualMachine(v.client.Client, c.Obj))
|
||||
}
|
||||
|
||||
v.Logger.Debug("Found VM references", "count", len(results))
|
||||
|
||||
return results, err
|
||||
return results, nil
|
||||
}
|
||||
|
||||
// GetAllVMsWithProps returns all VMs with the properties needed for snapshotting in a single property-collector call.
|
||||
@@ -191,7 +290,7 @@ func (v *Vcenter) GetAllVMsWithProps() ([]mo.VirtualMachine, error) {
|
||||
"runtime.host",
|
||||
"resourcePool",
|
||||
}
|
||||
if err := cv.Retrieve(v.ctx, []string{"VirtualMachine"}, props, &vms); err != nil {
|
||||
if err := v.retrieveContainerViewPaged(v.ctx, cv, []string{"VirtualMachine"}, props, &vms, defaultPropertyPageSize); err != nil {
|
||||
return nil, fmt.Errorf("failed to retrieve VMs: %w", err)
|
||||
}
|
||||
return vms, nil
|
||||
@@ -413,29 +512,55 @@ func (v *Vcenter) BuildHostLookup() (map[string]HostLookup, error) {
|
||||
v.Logger.Warn("failed to list hosts for datacenter", "datacenter", dc.Name(), "error", err)
|
||||
continue
|
||||
}
|
||||
if len(hosts) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
hostRefs := make([]types.ManagedObjectReference, 0, len(hosts))
|
||||
for _, host := range hosts {
|
||||
ref := host.Reference()
|
||||
var moHost mo.HostSystem
|
||||
if err := v.client.RetrieveOne(v.ctx, ref, []string{"parent"}, &moHost); err != nil {
|
||||
v.Logger.Warn("failed to retrieve host info", "host", host.Name(), "error", err)
|
||||
hostRefs = append(hostRefs, host.Reference())
|
||||
}
|
||||
|
||||
var moHosts []mo.HostSystem
|
||||
if err := v.retrieveByRefsPaged(v.ctx, hostRefs, []string{"parent"}, &moHosts, defaultPropertyPageSize); err != nil {
|
||||
v.Logger.Warn("failed to retrieve host parents for datacenter", "datacenter", dc.Name(), "error", err)
|
||||
continue
|
||||
}
|
||||
|
||||
parentRefs := make([]types.ManagedObjectReference, 0, len(moHosts))
|
||||
parentSeen := make(map[string]struct{})
|
||||
for _, host := range moHosts {
|
||||
if host.Parent == nil {
|
||||
continue
|
||||
}
|
||||
key := refKey(*host.Parent)
|
||||
if _, cached := clusterCache[key]; cached {
|
||||
continue
|
||||
}
|
||||
if _, seen := parentSeen[key]; seen {
|
||||
continue
|
||||
}
|
||||
parentSeen[key] = struct{}{}
|
||||
parentRefs = append(parentRefs, *host.Parent)
|
||||
}
|
||||
|
||||
clusterName := ""
|
||||
if moHost.Parent != nil {
|
||||
if cached, ok := clusterCache[moHost.Parent.Value]; ok {
|
||||
clusterName = cached
|
||||
} else {
|
||||
var moCompute mo.ComputeResource
|
||||
if err := v.client.RetrieveOne(v.ctx, *moHost.Parent, []string{"name"}, &moCompute); err == nil {
|
||||
clusterName = moCompute.Name
|
||||
clusterCache[moHost.Parent.Value] = clusterName
|
||||
}
|
||||
if len(parentRefs) > 0 {
|
||||
var computes []mo.ComputeResource
|
||||
if err := v.retrieveByRefsPaged(v.ctx, parentRefs, []string{"name"}, &computes, defaultPropertyPageSize); err != nil {
|
||||
v.Logger.Warn("failed to retrieve cluster names for datacenter", "datacenter", dc.Name(), "error", err)
|
||||
} else {
|
||||
for _, compute := range computes {
|
||||
clusterCache[refKey(compute.Reference())] = compute.Name
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
lookup[ref.Value] = HostLookup{
|
||||
for _, host := range moHosts {
|
||||
clusterName := ""
|
||||
if host.Parent != nil {
|
||||
clusterName = clusterCache[refKey(*host.Parent)]
|
||||
}
|
||||
lookup[host.Reference().Value] = HostLookup{
|
||||
Cluster: clusterName,
|
||||
Datacenter: dc.Name(),
|
||||
}
|
||||
@@ -454,7 +579,7 @@ func (v *Vcenter) BuildFolderPathLookup() (FolderLookup, error) {
|
||||
defer folders.Destroy(v.ctx)
|
||||
|
||||
var results []mo.Folder
|
||||
if err := folders.Retrieve(v.ctx, []string{"Folder"}, []string{"name", "parent"}, &results); err != nil {
|
||||
if err := v.retrieveContainerViewPaged(v.ctx, folders, []string{"Folder"}, []string{"name", "parent"}, &results, defaultPropertyPageSize); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -509,109 +634,43 @@ func (v *Vcenter) GetVMFolderPathFromLookup(vm mo.VirtualMachine, lookup FolderL
|
||||
}
|
||||
|
||||
func (v *Vcenter) ConvertObjToMoVM(vmObj *object.VirtualMachine) (*mo.VirtualMachine, error) {
|
||||
// Use the InventoryPath to extract the datacenter name and VM path
|
||||
inventoryPath := vmObj.InventoryPath
|
||||
parts := strings.SplitN(inventoryPath, "/", 3)
|
||||
|
||||
if len(parts) < 2 {
|
||||
return nil, fmt.Errorf("invalid InventoryPath: %s", inventoryPath)
|
||||
if vmObj == nil {
|
||||
return nil, fmt.Errorf("vm object is nil")
|
||||
}
|
||||
|
||||
// The first part of the path is the datacenter name
|
||||
datacenterName := parts[1]
|
||||
|
||||
// Finder to search for datacenter and VM
|
||||
finder := find.NewFinder(v.client.Client, true)
|
||||
|
||||
// Find the specific datacenter by name
|
||||
datacenter, err := finder.Datacenter(v.ctx, fmt.Sprintf("/%s", datacenterName))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to find datacenter %s: %w", datacenterName, err)
|
||||
}
|
||||
|
||||
// Set the found datacenter in the finder
|
||||
finder.SetDatacenter(datacenter)
|
||||
|
||||
// Now retrieve the VM using its ManagedObjectReference
|
||||
vmRef := vmObj.Reference()
|
||||
|
||||
// Retrieve the full mo.VirtualMachine object for the reference
|
||||
var moVM mo.VirtualMachine
|
||||
err = v.client.RetrieveOne(v.ctx, vmRef, nil, &moVM)
|
||||
err := v.client.RetrieveOne(v.ctx, vmRef, []string{"name", "config"}, &moVM)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to retrieve VM %s in datacenter %s: %w", vmObj.Name(), datacenterName, err)
|
||||
return nil, fmt.Errorf("failed to retrieve VM %s: %w", vmObj.Name(), err)
|
||||
}
|
||||
|
||||
// Return the found mo.VirtualMachine object
|
||||
//v.Logger.Debug("Found VM in datacenter", "vm_name", moVM.Name, "dc_name", datacenterName)
|
||||
return &moVM, nil
|
||||
}
|
||||
|
||||
func (v *Vcenter) ConvertObjToMoHost(hostObj *object.HostSystem) (*mo.HostSystem, error) {
|
||||
// Use the InventoryPath to extract the datacenter name and Host path
|
||||
inventoryPath := hostObj.InventoryPath
|
||||
parts := strings.SplitN(inventoryPath, "/", 3)
|
||||
v.Logger.Debug("inventory path", "parts", parts)
|
||||
|
||||
if len(parts) < 2 {
|
||||
return nil, fmt.Errorf("invalid InventoryPath: %s", inventoryPath)
|
||||
if hostObj == nil {
|
||||
return nil, fmt.Errorf("host object is nil")
|
||||
}
|
||||
|
||||
// The first part of the path is the datacenter name
|
||||
datacenterName := parts[1]
|
||||
|
||||
// Finder to search for datacenter and VM
|
||||
finder := find.NewFinder(v.client.Client, true)
|
||||
|
||||
// Find the specific datacenter by name
|
||||
datacenter, err := finder.Datacenter(v.ctx, fmt.Sprintf("/%s", datacenterName))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to find datacenter %s: %w", datacenterName, err)
|
||||
}
|
||||
|
||||
// Set the found datacenter in the finder
|
||||
finder.SetDatacenter(datacenter)
|
||||
|
||||
// Now retrieve the VM using its ManagedObjectReference
|
||||
hostRef := hostObj.Reference()
|
||||
|
||||
// Retrieve the full mo.HostSystem object for the reference
|
||||
var moHost mo.HostSystem
|
||||
err = v.client.RetrieveOne(v.ctx, hostRef, nil, &moHost)
|
||||
err := v.client.RetrieveOne(v.ctx, hostRef, []string{"name", "parent"}, &moHost)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to retrieve Host %s in datacenter %s: %w", hostObj.Name(), datacenterName, err)
|
||||
return nil, fmt.Errorf("failed to retrieve host %s: %w", hostObj.Name(), err)
|
||||
}
|
||||
|
||||
// Return the found mo.HostSystem object
|
||||
v.Logger.Debug("Found Host in datacenter", "host_name", moHost.Name, "dc_name", datacenterName)
|
||||
v.Logger.Debug("found host", "host_name", moHost.Name)
|
||||
return &moHost, nil
|
||||
}
|
||||
|
||||
func (v *Vcenter) GetHostSystemObject(hostRef types.ManagedObjectReference) (*mo.HostSystem, error) {
|
||||
finder := find.NewFinder(v.client.Client, true)
|
||||
|
||||
// List all datacenters
|
||||
datacenters, err := finder.DatacenterList(v.ctx, "*")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to list datacenters: %w", err)
|
||||
var hs mo.HostSystem
|
||||
if err := v.client.RetrieveOne(v.ctx, hostRef, []string{"name", "parent"}, &hs); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, dc := range datacenters {
|
||||
v.Logger.Debug("Checking dc for host", "name", dc.Name(), "hostRef", hostRef.String())
|
||||
// Set the current datacenter
|
||||
finder.SetDatacenter(dc)
|
||||
|
||||
var hs mo.HostSystem
|
||||
err := v.client.RetrieveOne(v.ctx, hostRef, nil, &hs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
v.Logger.Debug("Found hostsystem", "name", hs.Name)
|
||||
return &hs, nil
|
||||
}
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
v.Logger.Debug("found hostsystem", "name", hs.Name)
|
||||
return &hs, nil
|
||||
}
|
||||
|
||||
// Function to find the cluster or compute resource from a host reference
|
||||
@@ -620,87 +679,43 @@ func (v *Vcenter) GetClusterFromHost(hostRef *types.ManagedObjectReference) (str
|
||||
v.Logger.Warn("nil hostRef passed to GetClusterFromHost")
|
||||
return "", nil
|
||||
}
|
||||
// Get the host object
|
||||
host, err := v.GetHostSystemObject(*hostRef)
|
||||
var host mo.HostSystem
|
||||
err := v.client.RetrieveOne(v.ctx, *hostRef, []string{"parent"}, &host)
|
||||
if err != nil {
|
||||
v.Logger.Error("cant get host", "error", err)
|
||||
return "", err
|
||||
return "", fmt.Errorf("failed to retrieve host parent: %w", err)
|
||||
}
|
||||
if host == nil {
|
||||
v.Logger.Warn("host lookup returned nil", "host_ref", hostRef)
|
||||
|
||||
if host.Parent == nil {
|
||||
return "", nil
|
||||
}
|
||||
if host.Parent.Type != "ClusterComputeResource" && host.Parent.Type != "ComputeResource" {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
v.Logger.Debug("host parent", "parent", host.Parent)
|
||||
|
||||
if host.Parent != nil && host.Parent.Type == "ClusterComputeResource" {
|
||||
// Retrieve properties of the compute resource
|
||||
var moCompute mo.ComputeResource
|
||||
err = v.client.RetrieveOne(v.ctx, *host.Parent, nil, &moCompute)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to retrieve compute resource: %w", err)
|
||||
}
|
||||
v.Logger.Debug("VM is on host in cluster/compute resource", "name", moCompute.Name)
|
||||
return moCompute.Name, nil
|
||||
var moCompute mo.ComputeResource
|
||||
if err := v.client.RetrieveOne(v.ctx, *host.Parent, []string{"name"}, &moCompute); err != nil {
|
||||
return "", fmt.Errorf("failed to retrieve compute resource: %w", err)
|
||||
}
|
||||
|
||||
return "", nil
|
||||
v.Logger.Debug("vm host parent compute resource resolved", "name", moCompute.Name, "host_ref", hostRef.Value)
|
||||
return moCompute.Name, nil
|
||||
}
|
||||
|
||||
// Function to determine the datacenter a VM belongs to
|
||||
func (v *Vcenter) GetDatacenterForVM(vm mo.VirtualMachine) (string, error) {
|
||||
// Start with the VM's parent reference
|
||||
ref := vm.Reference()
|
||||
|
||||
// Traverse the inventory hierarchy upwards to find the datacenter
|
||||
for {
|
||||
// Get the parent reference of the current object
|
||||
parentRef, err := v.getParent(ref)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to get parent object: %w", err)
|
||||
}
|
||||
|
||||
// If we get a nil parent reference, it means we've hit the root without finding the datacenter
|
||||
if parentRef == nil {
|
||||
return "", fmt.Errorf("failed to find datacenter for VM")
|
||||
}
|
||||
|
||||
// Check if the parent is a Datacenter
|
||||
switch parentRef.Type {
|
||||
case "Datacenter":
|
||||
// If we found a Datacenter, retrieve its properties
|
||||
datacenter := object.NewDatacenter(v.client.Client, *parentRef)
|
||||
var moDC mo.Datacenter
|
||||
err = v.client.RetrieveOne(v.ctx, datacenter.Reference(), nil, &moDC)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to retrieve datacenter: %w", err)
|
||||
}
|
||||
|
||||
//log.Printf("VM is in datacenter: %s", moDC.Name)
|
||||
v.Logger.Debug("VM datacenter found", "vm_name", vm.Name, "dc_name", moDC.Name)
|
||||
return moDC.Name, nil
|
||||
|
||||
default:
|
||||
// Continue traversing upwards if not a Datacenter
|
||||
ref = *parentRef
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Helper function to get the parent ManagedObjectReference of a given object
|
||||
func (v *Vcenter) getParent(ref types.ManagedObjectReference) (*types.ManagedObjectReference, error) {
|
||||
// Retrieve the object's properties
|
||||
var obj mo.ManagedEntity
|
||||
err := v.client.RetrieveOne(v.ctx, ref, []string{"parent"}, &obj)
|
||||
entities, err := mo.Ancestors(v.ctx, v.client.Client, v.client.ServiceContent.PropertyCollector, vm.Reference())
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to retrieve parent of object: %w", err)
|
||||
return "", fmt.Errorf("failed to retrieve VM ancestors: %w", err)
|
||||
}
|
||||
|
||||
// Return the parent reference
|
||||
if obj.Parent != nil {
|
||||
return obj.Parent, nil
|
||||
for _, entity := range entities {
|
||||
if entity.Self.Type != "Datacenter" {
|
||||
continue
|
||||
}
|
||||
if entity.Name == "" {
|
||||
return "", fmt.Errorf("datacenter ancestor found without name for VM %s", vm.Reference().Value)
|
||||
}
|
||||
return entity.Name, nil
|
||||
}
|
||||
return nil, nil
|
||||
return "", fmt.Errorf("failed to find datacenter for VM %s", vm.Reference().Value)
|
||||
}
|
||||
|
||||
func (v *Vcenter) FindVMByName(vmName string) ([]mo.VirtualMachine, error) {
|
||||
@@ -714,7 +729,7 @@ func (v *Vcenter) FindVMByName(vmName string) ([]mo.VirtualMachine, error) {
|
||||
|
||||
var matchingVMs []mo.VirtualMachine
|
||||
|
||||
err = vms.Retrieve(v.ctx, []string{"VirtualMachine"}, []string{"name"}, &matchingVMs)
|
||||
err = v.retrieveContainerViewPaged(v.ctx, vms, []string{"VirtualMachine"}, []string{"name"}, &matchingVMs, defaultPropertyPageSize)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -734,93 +749,39 @@ func (v *Vcenter) FindVMByName(vmName string) ([]mo.VirtualMachine, error) {
|
||||
}
|
||||
|
||||
func (v *Vcenter) FindVMByID(vmID string) (*VmProperties, error) {
|
||||
|
||||
v.Logger.Debug("searching for vm id", "vm_id", vmID)
|
||||
|
||||
finder := find.NewFinder(v.client.Client, true)
|
||||
|
||||
// List all datacenters
|
||||
datacenters, err := finder.DatacenterList(v.ctx, "*")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to list datacenters: %w", err)
|
||||
}
|
||||
|
||||
for _, dc := range datacenters {
|
||||
// Set the current datacenter
|
||||
finder.SetDatacenter(dc)
|
||||
|
||||
// Create a ManagedObjectReference for the VM
|
||||
vmRef := types.ManagedObjectReference{
|
||||
Type: "VirtualMachine",
|
||||
Value: vmID,
|
||||
}
|
||||
|
||||
// Try to find the VM by ID in the current datacenter
|
||||
//vm, err := finder.ObjectReference(v.ctx, vmRef)
|
||||
|
||||
var vm mo.VirtualMachine
|
||||
err := v.client.RetrieveOne(v.ctx, vmRef, []string{"config", "name"}, &vm)
|
||||
|
||||
if err == nil {
|
||||
return &VmProperties{
|
||||
//Datacenter: dc.Name(),
|
||||
Vm: vm,
|
||||
}, nil
|
||||
} else if _, ok := err.(*find.NotFoundError); !ok {
|
||||
// If the error is not a NotFoundError, return it
|
||||
//return nil, fmt.Errorf("failed to retrieve VM with ID %s in datacenter %s: %w", vmID, dc.Name(), err)
|
||||
v.Logger.Debug("Couldn't find vm in datacenter", "vm_id", vmID, "datacenter_name", dc.Name())
|
||||
} else {
|
||||
return nil, fmt.Errorf("failed to retrieve VM: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("VM with ID %s not found in any datacenter", vmID)
|
||||
}
|
||||
|
||||
func (v *Vcenter) FindVMByIDWithDatacenter(vmID string, dcID string) (*mo.VirtualMachine, error) {
|
||||
var err error
|
||||
//v.Logger.Debug("searching for vm id", "vm_id", vmID, "datacenter_id", dcID)
|
||||
|
||||
finder := find.NewFinder(v.client.Client, true)
|
||||
|
||||
// Create a ManagedObjectReference for the datacenter
|
||||
dcRef := types.ManagedObjectReference{
|
||||
Type: "Datacenter",
|
||||
Value: dcID,
|
||||
}
|
||||
|
||||
// Convert the reference to a Datacenter object
|
||||
datacenter := object.NewDatacenter(v.client.Client, dcRef)
|
||||
if datacenter == nil {
|
||||
return nil, fmt.Errorf("Datacenter with id %s not found", dcID)
|
||||
}
|
||||
|
||||
// Use finder.SetDatacenter to set the datacenter
|
||||
finder.SetDatacenter(datacenter)
|
||||
|
||||
// Create a ManagedObjectReference for the VM
|
||||
vmRef := types.ManagedObjectReference{
|
||||
Type: "VirtualMachine",
|
||||
Value: vmID,
|
||||
}
|
||||
|
||||
var vm mo.VirtualMachine
|
||||
//err := v.client.RetrieveOne(v.ctx, vmRef, []string{"config", "name"}, &vm)
|
||||
err = v.client.RetrieveOne(v.ctx, vmRef, nil, &vm)
|
||||
if err == nil {
|
||||
//v.Logger.Debug("Found VM")
|
||||
|
||||
return &vm, nil
|
||||
|
||||
} else if _, ok := err.(*find.NotFoundError); !ok {
|
||||
// If the error is not a NotFoundError, return it
|
||||
//return nil, fmt.Errorf("failed to retrieve VM with ID %s in datacenter %s: %w", vmID, dc.Name(), err)
|
||||
//v.Logger.Debug("Couldn't find vm in datacenter", "vm_id", vmID, "datacenter_id", dcID)
|
||||
return nil, nil
|
||||
} else {
|
||||
return nil, fmt.Errorf("failed to retrieve VM: %w", err)
|
||||
if err := v.client.RetrieveOne(v.ctx, vmRef, []string{"config", "name"}, &vm); err != nil {
|
||||
return nil, fmt.Errorf("failed to retrieve VM %s: %w", vmID, err)
|
||||
}
|
||||
|
||||
return &VmProperties{Vm: vm}, nil
|
||||
}
|
||||
|
||||
func (v *Vcenter) FindVMByIDWithDatacenter(vmID string, dcID string) (*mo.VirtualMachine, error) {
|
||||
if dcID != "" {
|
||||
v.Logger.Debug("searching for vm id in datacenter context", "vm_id", vmID, "datacenter_id", dcID)
|
||||
}
|
||||
vmRef := types.ManagedObjectReference{
|
||||
Type: "VirtualMachine",
|
||||
Value: vmID,
|
||||
}
|
||||
|
||||
var vm mo.VirtualMachine
|
||||
props := []string{"name", "config", "runtime.powerState", "runtime.host", "resourcePool", "parent"}
|
||||
if err := v.client.RetrieveOne(v.ctx, vmRef, props, &vm); err != nil {
|
||||
if fault.Is(err, &types.ManagedObjectNotFound{}) {
|
||||
return nil, nil
|
||||
}
|
||||
return nil, fmt.Errorf("failed to retrieve VM %s: %w", vmID, err)
|
||||
}
|
||||
|
||||
return &vm, nil
|
||||
}
|
||||
|
||||
// Helper function to retrieve the resource pool for the VM
|
||||
@@ -850,7 +811,7 @@ func (v *Vcenter) BuildResourcePoolLookup() (map[string]string, error) {
|
||||
defer cv.Destroy(v.ctx)
|
||||
|
||||
var pools []mo.ResourcePool
|
||||
if err := cv.Retrieve(v.ctx, []string{"ResourcePool"}, []string{"name"}, &pools); err != nil {
|
||||
if err := v.retrieveContainerViewPaged(v.ctx, cv, []string{"ResourcePool"}, []string{"name"}, &pools, defaultPropertyPageSize); err != nil {
|
||||
return nil, fmt.Errorf("failed to retrieve resource pools: %w", err)
|
||||
}
|
||||
|
||||
@@ -863,55 +824,39 @@ func (v *Vcenter) BuildResourcePoolLookup() (map[string]string, error) {
|
||||
|
||||
// Helper function to retrieve the full folder path for the VM
|
||||
func (v *Vcenter) GetVMFolderPath(vm mo.VirtualMachine) (string, error) {
|
||||
//finder := find.NewFinder(v.client.Client, true)
|
||||
|
||||
v.Logger.Debug("Commencing vm folder path search")
|
||||
|
||||
// Start from the VM's parent
|
||||
parentRef := vm.Parent
|
||||
if parentRef == nil {
|
||||
return "", fmt.Errorf("no parent found for the VM")
|
||||
entities, err := mo.Ancestors(v.ctx, v.client.Client, v.client.ServiceContent.PropertyCollector, vm.Reference())
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to retrieve VM ancestors: %w", err)
|
||||
}
|
||||
|
||||
// Traverse the folder hierarchy to build the full folder path
|
||||
folderPath := ""
|
||||
//v.Logger.Debug("parent is", "parent", parentRef)
|
||||
|
||||
maxHops := 128
|
||||
for parentRef != nil && parentRef.Type != "Datacenter" && maxHops > 0 {
|
||||
// Retrieve the parent object
|
||||
//parentObj, err := finder.ObjectReference(v.ctx, *parentRef)
|
||||
//if err != nil {
|
||||
// return "", fmt.Errorf("failed to find parent object in inventory: %w", err)
|
||||
//}
|
||||
|
||||
// Retrieve the folder name
|
||||
|
||||
var parentObj mo.Folder
|
||||
err := v.client.RetrieveOne(v.ctx, *parentRef, nil, &parentObj)
|
||||
if err != nil {
|
||||
v.Logger.Error("Failed to get object for parent reference", "ref", parentRef)
|
||||
break
|
||||
var folderParts []string
|
||||
seenDatacenter := false
|
||||
vmRef := vm.Reference()
|
||||
for _, entity := range entities {
|
||||
switch entity.Self.Type {
|
||||
case "Datacenter":
|
||||
seenDatacenter = true
|
||||
folderParts = folderParts[:0]
|
||||
case "VirtualMachine":
|
||||
if entity.Self == vmRef {
|
||||
goto done
|
||||
}
|
||||
case "Folder":
|
||||
if seenDatacenter {
|
||||
folderParts = append(folderParts, entity.Name)
|
||||
}
|
||||
}
|
||||
}
|
||||
done:
|
||||
|
||||
// Prepend the folder name to the path
|
||||
folderPath = path.Join("/", parentObj.Name, folderPath)
|
||||
|
||||
// Move up to the next parent
|
||||
//if folder, ok := parentObj.(*object.Folder); ok {
|
||||
if parentObj.Parent != nil {
|
||||
parentRef = parentObj.Parent
|
||||
//v.Logger.Debug("Parent uplevel is", "ref", parentRef)
|
||||
} else {
|
||||
return "", fmt.Errorf("unexpected parent type: %s", parentObj.Reference().Type)
|
||||
}
|
||||
//break
|
||||
maxHops--
|
||||
if !seenDatacenter {
|
||||
return "", fmt.Errorf("failed to find datacenter ancestor for VM %s", vm.Reference().Value)
|
||||
}
|
||||
if len(folderParts) == 0 {
|
||||
return "", fmt.Errorf("failed to find folder path for VM %s", vm.Reference().Value)
|
||||
}
|
||||
|
||||
if parentRef == nil || maxHops == 0 {
|
||||
return "", fmt.Errorf("folder traversal terminated early for VM %s", vm.Name)
|
||||
}
|
||||
|
||||
return folderPath, nil
|
||||
return path.Join("/", path.Join(folderParts...)), nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user