Add vCenter reference cache tables and update related functions
All checks were successful
continuous-integration/drone/push Build is passing

This commit is contained in:
2026-02-13 14:45:13 +11:00
parent 5cd8f9c2a1
commit 18be1fbe06
4 changed files with 420 additions and 45 deletions

View File

@@ -682,7 +682,7 @@ func (c *CronTask) generateReport(ctx context.Context, tableName string) error {
return err
}
func snapshotFromVM(vmObject *mo.VirtualMachine, vc *vcenter.Vcenter, snapshotTime time.Time, inv *queries.Inventory, hostLookup map[string]vcenter.HostLookup, folderLookup vcenter.FolderLookup, rpLookup map[string]string) (InventorySnapshotRow, error) {
func snapshotFromVM(ctx context.Context, dbConn *sqlx.DB, vmObject *mo.VirtualMachine, vc *vcenter.Vcenter, snapshotTime time.Time, inv *queries.Inventory, hostLookup map[string]vcenter.HostLookup, folderLookup vcenter.FolderLookup, rpLookup map[string]string) (InventorySnapshotRow, error) {
if vmObject == nil {
return InventorySnapshotRow{}, fmt.Errorf("missing VM object")
}
@@ -772,23 +772,93 @@ func snapshotFromVM(vmObject *mo.VirtualMachine, vc *vcenter.Vcenter, snapshotTi
}
if row.ResourcePool.String == "" && vmObject.ResourcePool != nil {
resourcePoolRef := vmObject.ResourcePool.Value
if rpLookup != nil {
if rpName, ok := rpLookup[vmObject.ResourcePool.Value]; ok {
row.ResourcePool = sql.NullString{String: normalizeResourcePool(rpName), Valid: rpName != ""}
if rpName, ok := rpLookup[resourcePoolRef]; ok {
rpName = normalizeResourcePool(rpName)
row.ResourcePool = sql.NullString{String: rpName, Valid: rpName != ""}
}
}
if row.ResourcePool.String == "" {
rpName, err := vc.GetResourcePoolNameByRef(*vmObject.ResourcePool)
if err != nil {
if vc.Logger != nil {
vc.Logger.Warn("failed to resolve resource pool from vcenter", "vm_id", vmObject.Reference().Value, "resource_pool_ref", resourcePoolRef, "error", err)
}
} else {
rpName = normalizeResourcePool(rpName)
row.ResourcePool = sql.NullString{String: rpName, Valid: rpName != ""}
if rpLookup != nil && rpName != "" {
rpLookup[resourcePoolRef] = rpName
}
if dbConn != nil && rpName != "" {
if err := db.UpsertVcenterResourcePoolCache(ctx, dbConn, vc.Vurl, resourcePoolRef, rpName, snapshotTime.Unix()); err != nil && vc.Logger != nil {
vc.Logger.Warn("failed to persist resource pool cache", "vcenter", vc.Vurl, "resource_pool_ref", resourcePoolRef, "error", err)
}
}
}
}
}
if row.Folder.String == "" {
if folderPath, ok := vc.GetVMFolderPathFromLookup(*vmObject, folderLookup); ok {
row.Folder = sql.NullString{String: folderPath, Valid: folderPath != ""}
} else {
// Unable to resolve folder path from lookup; leave empty.
folderRef := ""
if vmObject.Parent != nil {
folderRef = vmObject.Parent.Value
}
if folderRef != "" && folderLookup != nil {
if folderPath, ok := folderLookup[folderRef]; ok {
row.Folder = sql.NullString{String: folderPath, Valid: folderPath != ""}
}
}
if row.Folder.String == "" {
folderPath, err := vc.GetVMFolderPath(*vmObject)
if err != nil {
if vc.Logger != nil {
vc.Logger.Warn("failed to resolve folder path from vcenter", "vm_id", vmObject.Reference().Value, "error", err)
}
} else {
row.Folder = sql.NullString{String: folderPath, Valid: folderPath != ""}
if folderLookup != nil && folderRef != "" && folderPath != "" {
folderLookup[folderRef] = folderPath
}
if dbConn != nil && folderRef != "" && folderPath != "" {
if err := db.UpsertVcenterFolderCache(ctx, dbConn, vc.Vurl, folderRef, folderPath, snapshotTime.Unix()); err != nil && vc.Logger != nil {
vc.Logger.Warn("failed to persist folder cache", "vcenter", vc.Vurl, "folder_ref", folderRef, "error", err)
}
}
}
}
}
if vmObject.Runtime.Host != nil && hostLookup != nil {
if lookup, ok := hostLookup[vmObject.Runtime.Host.Value]; ok {
hostRef := ""
if vmObject.Runtime.Host != nil {
hostRef = vmObject.Runtime.Host.Value
}
if hostRef != "" {
lookup, found := vcenter.HostLookup{}, false
if hostLookup != nil {
lookup, found = hostLookup[hostRef]
}
if !found {
resolved, err := vc.GetHostLookupByRef(*vmObject.Runtime.Host)
if err != nil {
if vc.Logger != nil {
vc.Logger.Warn("failed to resolve host lookup from vcenter", "vm_id", vmObject.Reference().Value, "host_ref", hostRef, "error", err)
}
} else {
lookup = resolved
found = true
if hostLookup != nil {
hostLookup[hostRef] = resolved
}
if dbConn != nil && (resolved.Cluster != "" || resolved.Datacenter != "") {
if err := db.UpsertVcenterHostCache(ctx, dbConn, vc.Vurl, hostRef, resolved.Cluster, resolved.Datacenter, snapshotTime.Unix()); err != nil && vc.Logger != nil {
vc.Logger.Warn("failed to persist host cache", "vcenter", vc.Vurl, "host_ref", hostRef, "error", err)
}
}
}
}
if found {
if row.Cluster.String == "" && lookup.Cluster != "" {
row.Cluster = sql.NullString{String: lookup.Cluster, Valid: true}
}
@@ -801,6 +871,15 @@ func snapshotFromVM(vmObject *mo.VirtualMachine, vc *vcenter.Vcenter, snapshotTi
if row.Cluster.String == "" && vmObject.Runtime.Host != nil {
if clusterName, err := vc.GetClusterFromHost(vmObject.Runtime.Host); err == nil {
row.Cluster = sql.NullString{String: clusterName, Valid: clusterName != ""}
if dbConn != nil && hostRef != "" && clusterName != "" {
dc := ""
if row.Datacenter.Valid {
dc = row.Datacenter.String
}
if err := db.UpsertVcenterHostCache(ctx, dbConn, vc.Vurl, hostRef, clusterName, dc, snapshotTime.Unix()); err != nil && vc.Logger != nil {
vc.Logger.Warn("failed to persist host cluster cache", "vcenter", vc.Vurl, "host_ref", hostRef, "error", err)
}
}
} else if vc.Logger != nil {
vc.Logger.Warn("failed to resolve cluster from host", "vm_id", vmObject.Reference().Value, "error", err)
}
@@ -809,6 +888,15 @@ func snapshotFromVM(vmObject *mo.VirtualMachine, vc *vcenter.Vcenter, snapshotTi
if row.Datacenter.String == "" {
if dcName, err := vc.GetDatacenterForVM(*vmObject); err == nil {
row.Datacenter = sql.NullString{String: dcName, Valid: dcName != ""}
if dbConn != nil && hostRef != "" && dcName != "" {
clusterName := ""
if row.Cluster.Valid {
clusterName = row.Cluster.String
}
if err := db.UpsertVcenterHostCache(ctx, dbConn, vc.Vurl, hostRef, clusterName, dcName, snapshotTime.Unix()); err != nil && vc.Logger != nil {
vc.Logger.Warn("failed to persist host datacenter cache", "vcenter", vc.Vurl, "host_ref", hostRef, "error", err)
}
}
}
}
@@ -958,7 +1046,7 @@ func (c *CronTask) buildPresentSnapshots(ctx context.Context, dbConn *sqlx.DB, v
inv = &existingCopy
}
row, err := snapshotFromVM(&vm, vc, startTime, inv, hostLookup, folderLookup, rpLookup)
row, err := snapshotFromVM(ctx, dbConn, &vm, vc, startTime, inv, hostLookup, folderLookup, rpLookup)
if err != nil {
log.Error("unable to build snapshot for VM", "vm_id", vm.Reference().Value, "error", err)
continue
@@ -1025,27 +1113,40 @@ func (c *CronTask) initVcenterResources(ctx context.Context, log *slog.Logger, u
if err := db.EnsureVmIdentityTables(ctx, c.Database.DB()); err != nil {
log.Warn("failed to ensure vm identity tables", "error", err)
}
if err := db.EnsureVcenterReferenceCacheTables(ctx, c.Database.DB()); err != nil {
log.Warn("failed to ensure vcenter reference cache tables", "error", err)
}
hostLookup, err := vc.BuildHostLookup()
hostLookup := make(map[string]vcenter.HostLookup)
cachedHosts, err := db.LoadVcenterHostCache(ctx, c.Database.DB(), url)
if err != nil {
log.Warn("failed to build host lookup", "url", url, "error", err)
hostLookup = nil
log.Warn("failed to load host lookup cache", "url", url, "error", err)
} else {
log.Debug("built host lookup", "url", url, "hosts", len(hostLookup))
for hostRef, entry := range cachedHosts {
hostLookup[hostRef] = vcenter.HostLookup{
Cluster: entry.Cluster,
Datacenter: entry.Datacenter,
}
}
log.Debug("loaded host lookup cache", "url", url, "hosts", len(hostLookup))
}
folderLookup, err := vc.BuildFolderPathLookup()
folderLookup := make(map[string]string)
cachedFolders, err := db.LoadVcenterFolderCache(ctx, c.Database.DB(), url)
if err != nil {
log.Warn("failed to build folder lookup", "url", url, "error", err)
folderLookup = nil
log.Warn("failed to load folder lookup cache", "url", url, "error", err)
} else {
log.Debug("built folder lookup", "url", url, "folders", len(folderLookup))
folderLookup = cachedFolders
log.Debug("loaded folder lookup cache", "url", url, "folders", len(folderLookup))
}
rpLookup, err := vc.BuildResourcePoolLookup()
rpLookup := make(map[string]string)
cachedPools, err := db.LoadVcenterResourcePoolCache(ctx, c.Database.DB(), url)
if err != nil {
log.Warn("failed to build resource pool lookup", "url", url, "error", err)
rpLookup = nil
log.Warn("failed to load resource pool cache", "url", url, "error", err)
} else {
log.Debug("built resource pool lookup", "url", url, "pools", len(rpLookup))
rpLookup = cachedPools
log.Debug("loaded resource pool cache", "url", url, "pools", len(rpLookup))
}
res.vms = vms