From c4eedb55b77715d60af9db7eb3fb7d5ad6d82a49 Mon Sep 17 00:00:00 2001 From: Nathan Coad Date: Mon, 30 Sep 2024 10:36:23 +1000 Subject: [PATCH] implement vc inventory scanning --- db/queries/query.sql | 4 + db/queries/query.sql.go | 48 +++++ internal/tasks/monitorVcenter.go | 188 ++++++++++++++++++++ internal/tasks/processEvents.go | 26 +-- internal/vcenter/vcenter.go | 292 ++++++++++++++++++++++++++++--- main.go | 5 +- server/handler/vmModifyEvent.go | 4 +- settings.yaml | 3 +- 8 files changed, 533 insertions(+), 37 deletions(-) diff --git a/db/queries/query.sql b/db/queries/query.sql index 094ddf2..601cc47 100644 --- a/db/queries/query.sql +++ b/db/queries/query.sql @@ -10,6 +10,10 @@ ORDER BY "CreationTime"; SELECT * FROM "Inventory" WHERE "Name" = ?; +-- name: GetInventoryByVcenter :many +SELECT * FROM "Inventory" +WHERE "Vcenter" = ?; + -- name: GetInventoryVmId :one SELECT * FROM "Inventory" WHERE "VmId" = sqlc.arg('vmId') AND "Datacenter" = sqlc.arg('datacenterName'); diff --git a/db/queries/query.sql.go b/db/queries/query.sql.go index 19c2368..53270ca 100644 --- a/db/queries/query.sql.go +++ b/db/queries/query.sql.go @@ -262,6 +262,54 @@ func (q *Queries) GetInventoryByName(ctx context.Context, name string) ([]Invent return items, nil } +const getInventoryByVcenter = `-- name: GetInventoryByVcenter :many +SELECT Iid, Name, Vcenter, VmId, EventKey, CloudId, CreationTime, DeletionTime, ResourcePool, VmType, Datacenter, Cluster, Folder, ProvisionedDisk, InitialVcpus, InitialRam, IsTemplate, PoweredOn, SrmPlaceholder FROM "Inventory" +WHERE "Vcenter" = ? +` + +func (q *Queries) GetInventoryByVcenter(ctx context.Context, vcenter string) ([]Inventory, error) { + rows, err := q.db.QueryContext(ctx, getInventoryByVcenter, vcenter) + if err != nil { + return nil, err + } + defer rows.Close() + var items []Inventory + for rows.Next() { + var i Inventory + if err := rows.Scan( + &i.Iid, + &i.Name, + &i.Vcenter, + &i.VmId, + &i.EventKey, + &i.CloudId, + &i.CreationTime, + &i.DeletionTime, + &i.ResourcePool, + &i.VmType, + &i.Datacenter, + &i.Cluster, + &i.Folder, + &i.ProvisionedDisk, + &i.InitialVcpus, + &i.InitialRam, + &i.IsTemplate, + &i.PoweredOn, + &i.SrmPlaceholder, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + const getInventoryEventId = `-- name: GetInventoryEventId :one SELECT Iid, Name, Vcenter, VmId, EventKey, CloudId, CreationTime, DeletionTime, ResourcePool, VmType, Datacenter, Cluster, Folder, ProvisionedDisk, InitialVcpus, InitialRam, IsTemplate, PoweredOn, SrmPlaceholder FROM "Inventory" WHERE "CloudId" = ? LIMIT 1 diff --git a/internal/tasks/monitorVcenter.go b/internal/tasks/monitorVcenter.go index f807663..af95e37 100644 --- a/internal/tasks/monitorVcenter.go +++ b/internal/tasks/monitorVcenter.go @@ -2,10 +2,198 @@ package tasks import ( "context" + "database/sql" + "errors" + "fmt" "log/slog" + "vctp/db/queries" + "vctp/internal/vcenter" + + "github.com/vmware/govmomi/vim25/mo" + "github.com/vmware/govmomi/vim25/types" ) // use gocron to check vcenters for VMs or updates we don't know about func (c *CronTask) RunVcenterPoll(ctx context.Context, logger *slog.Logger) error { + var matchFound bool + for _, url := range c.Settings.Settings.VcenterAddresses { + c.Logger.Debug("connecting to vcenter", "url", url) + vc := vcenter.New(c.Logger, c.VcCreds) + vc.Login(url) + + // Get list of VMs from vcenter + vms, err := vc.GetAllVmReferences() + + // Get list of VMs from inventory table + c.Logger.Debug("Querying inventory table") + results, err := c.Database.Queries().GetInventoryByVcenter(ctx, url) + if err != nil { + c.Logger.Error("Unable to query inventory table", "error", err) + return err + } + + if len(results) == 0 { + c.Logger.Error("Empty inventory results") + return fmt.Errorf("Empty inventory results") + } + + // Iterate VMs from vcenter and see if they were in the database + for _, vm := range vms { + matchFound = false + for _, dbvm := range results { + if dbvm.VmId.String == vm.Reference().Value { + c.Logger.Debug("Found match for VM", "name", dbvm.Name, "id", dbvm.VmId.String) + matchFound = true + break + } + } + + if !matchFound { + c.Logger.Debug("Need to add VM to inventory table", "MoRef", vm.Reference()) + vmObj, err := vc.ConvertObjToMoVM(vm) + if err != nil { + c.Logger.Error("Received error", "error", err) + continue + } + + // retrieve VM properties and insert into inventory + c.AddVmToInventory(vmObj, vc, ctx) + } + } + + vc.Logout() + } + return nil } + +func (c *CronTask) AddVmToInventory(vmObject *mo.VirtualMachine, vc *vcenter.Vcenter, ctx context.Context) error { + var ( + numVcpus int32 + numRam int32 + totalDiskGB float64 + creationTS int64 + srmPlaceholder string + foundVmConfig bool + isTemplate string + poweredOn string + folderPath string + clusterName string + err error + ) + + if vmObject == nil { + return errors.New("can't process empty vm object") + } + + c.Logger.Debug("found VM") + srmPlaceholder = "FALSE" // Default assumption + //prettyPrint(vmObject) + + // calculate VM properties we want to store + if vmObject.Config != nil { + numRam = vmObject.Config.Hardware.MemoryMB + numVcpus = vmObject.Config.Hardware.NumCPU + + // Calculate creation date + creationTS = vmObject.Config.CreateDate.Unix() + + // Calculate disk size + var totalDiskBytes int64 + + // Calculate the total disk allocated in GB + for _, device := range vmObject.Config.Hardware.Device { + if disk, ok := device.(*types.VirtualDisk); ok { + + // Print the filename of the backing device + if backing, ok := disk.Backing.(*types.VirtualDiskFlatVer2BackingInfo); ok { + c.Logger.Debug("Adding disk", "size_bytes", disk.CapacityInBytes, "backing_file", backing.FileName) + } else { + c.Logger.Debug("Adding disk, unknown backing type", "size_bytes", disk.CapacityInBytes) + } + + totalDiskBytes += disk.CapacityInBytes + //totalDiskGB += float64(disk.CapacityInBytes / 1024 / 1024 / 1024) // Convert from bytes to GB + } + } + totalDiskGB = float64(totalDiskBytes / 1024 / 1024 / 1024) + c.Logger.Debug("Converted total disk size", "bytes", totalDiskBytes, "GB", totalDiskGB) + + // Determine if the VM is a normal VM or an SRM placeholder + if vmObject.Config.ManagedBy != nil && vmObject.Config.ManagedBy.Type == "com.vmware.vcDr" { + c.Logger.Debug("VM ManagedBy indicates managed by SRM") + srmPlaceholder = "TRUE" + } + + if vmObject.Config.Template { + isTemplate = "TRUE" + } else { + isTemplate = "FALSE" + } + + // Retrieve the full folder path of the VM + folderPath, err = vc.GetVMFolderPath(*vmObject) + if err != nil { + c.Logger.Error("failed to get vm folder path", "error", err) + folderPath = "" + } else { + c.Logger.Debug("Found vm folder path", "folder_path", folderPath) + } + + foundVmConfig = true + } else { + c.Logger.Error("Empty VM config") + } + + c.Logger.Debug("VM has runtime data", "power_state", vmObject.Runtime.PowerState) + if vmObject.Runtime.PowerState == "poweredOff" { + poweredOn = "FALSE" + } else { + poweredOn = "TRUE" + } + + rpName, err := vc.GetVmResourcePool(*vmObject) + + // Get VM's host and use that to determine cluster + c.Logger.Debug("Checking for VM host by runtime data", "runtime", vmObject.Runtime) + clusterName, err = vc.GetClusterFromHost(vmObject.Runtime.Host) + c.Logger.Debug("cluster", "name", clusterName) + + dcName, err := vc.GetDatacenterForVM(*vmObject) + c.Logger.Debug("dc", "name", dcName) + + if foundVmConfig { + c.Logger.Debug("Adding to Inventory table", "vm_name", vmObject.Name, "vcpus", numVcpus, "ram", numRam) + + params := queries.CreateInventoryParams{ + Name: vmObject.Name, + Vcenter: vc.Vurl, + VmId: sql.NullString{String: vmObject.Reference().Value, Valid: vmObject.Reference().Value != ""}, + Datacenter: sql.NullString{String: dcName, Valid: dcName != ""}, + Cluster: sql.NullString{String: clusterName, Valid: clusterName != ""}, + CreationTime: sql.NullInt64{Int64: creationTS, Valid: creationTS > 0}, + InitialVcpus: sql.NullInt64{Int64: int64(numVcpus), Valid: numVcpus > 0}, + InitialRam: sql.NullInt64{Int64: int64(numRam), Valid: numRam > 0}, + ProvisionedDisk: sql.NullFloat64{Float64: totalDiskGB, Valid: totalDiskGB > 0}, + Folder: sql.NullString{String: folderPath, Valid: folderPath != ""}, + ResourcePool: sql.NullString{String: rpName, Valid: rpName != ""}, + SrmPlaceholder: srmPlaceholder, + IsTemplate: isTemplate, + PoweredOn: poweredOn, + } + + c.Logger.Debug("database params", "params", params) + // Insert the new inventory record into the database + result, err := c.Database.Queries().CreateInventory(ctx, params) + if err != nil { + c.Logger.Error("unable to perform database insert", "error", err) + } else { + c.Logger.Debug("created database record", "insert_result", result) + } + } else { + c.Logger.Debug("Not adding to Inventory due to missing vcenter config property", "vm_name", vmObject.Name) + } + + return nil + +} diff --git a/internal/tasks/processEvents.go b/internal/tasks/processEvents.go index fa3e592..1def465 100644 --- a/internal/tasks/processEvents.go +++ b/internal/tasks/processEvents.go @@ -22,6 +22,7 @@ func (c *CronTask) RunVmCheck(ctx context.Context, logger *slog.Logger) error { isTemplate string poweredOn string folderPath string + rpName string ) dateCmp := time.Now().AddDate(0, 0, -1).Unix() @@ -65,13 +66,13 @@ func (c *CronTask) RunVmCheck(ctx context.Context, logger *slog.Logger) error { //prettyPrint(vmObject) // calculate VM properties we want to store - if vmObject.Vm.Config != nil { - numRam = vmObject.Vm.Config.Hardware.MemoryMB - numVcpus = vmObject.Vm.Config.Hardware.NumCPU + if vmObject.Config != nil { + numRam = vmObject.Config.Hardware.MemoryMB + numVcpus = vmObject.Config.Hardware.NumCPU var totalDiskBytes int64 // Calculate the total disk allocated in GB - for _, device := range vmObject.Vm.Config.Hardware.Device { + for _, device := range vmObject.Config.Hardware.Device { if disk, ok := device.(*types.VirtualDisk); ok { // Print the filename of the backing device @@ -89,19 +90,19 @@ func (c *CronTask) RunVmCheck(ctx context.Context, logger *slog.Logger) error { c.Logger.Debug("Converted total disk size", "bytes", totalDiskBytes, "GB", totalDiskGB) // Determine if the VM is a normal VM or an SRM placeholder - if vmObject.Vm.Config.ManagedBy != nil && vmObject.Vm.Config.ManagedBy.Type == "com.vmware.vcDr" { + if vmObject.Config.ManagedBy != nil && vmObject.Config.ManagedBy.Type == "com.vmware.vcDr" { c.Logger.Debug("VM ManagedBy indicates managed by SRM") srmPlaceholder = "TRUE" } - if vmObject.Vm.Config.Template { + if vmObject.Config.Template { isTemplate = "TRUE" } else { isTemplate = "FALSE" } // Retrieve the full folder path of the VM - folderPath, err = vc.GetVMFolderPath(vmObject.Vm) + folderPath, err = vc.GetVMFolderPath(*vmObject) if err != nil { c.Logger.Error("failed to get vm folder path", "error", err) folderPath = "" @@ -109,13 +110,16 @@ func (c *CronTask) RunVmCheck(ctx context.Context, logger *slog.Logger) error { c.Logger.Debug("Found vm folder path", "folder_path", folderPath) } + // Retrieve the resource pool of the VM + rpName, _ = vc.GetVmResourcePool(*vmObject) + foundVm = true } else { c.Logger.Error("Empty VM config") } - c.Logger.Debug("VM has runtime data", "power_state", vmObject.Vm.Runtime.PowerState) - if vmObject.Vm.Runtime.PowerState == "poweredOff" { + c.Logger.Debug("VM has runtime data", "power_state", vmObject.Runtime.PowerState) + if vmObject.Runtime.PowerState == "poweredOff" { poweredOn = "FALSE" } else { poweredOn = "TRUE" @@ -131,7 +135,7 @@ func (c *CronTask) RunVmCheck(ctx context.Context, logger *slog.Logger) error { c.Logger.Debug("Adding to Inventory table", "vm_name", evt.VmName.String, "vcpus", numVcpus, "ram", numRam, "dc", evt.DatacenterId.String) params := queries.CreateInventoryParams{ - Name: vmObject.Vm.Name, + Name: vmObject.Name, Vcenter: evt.Source, CloudId: sql.NullString{String: evt.CloudId, Valid: evt.CloudId != ""}, EventKey: sql.NullString{String: evt.EventKey.String, Valid: evt.EventKey.Valid}, @@ -143,7 +147,7 @@ func (c *CronTask) RunVmCheck(ctx context.Context, logger *slog.Logger) error { InitialRam: sql.NullInt64{Int64: int64(numRam), Valid: numRam > 0}, ProvisionedDisk: sql.NullFloat64{Float64: totalDiskGB, Valid: totalDiskGB > 0}, Folder: sql.NullString{String: folderPath, Valid: folderPath != ""}, - ResourcePool: sql.NullString{String: vmObject.ResourcePool, Valid: vmObject.ResourcePool != ""}, + ResourcePool: sql.NullString{String: rpName, Valid: rpName != ""}, SrmPlaceholder: srmPlaceholder, IsTemplate: isTemplate, PoweredOn: poweredOn, diff --git a/internal/vcenter/vcenter.go b/internal/vcenter/vcenter.go index a5f1c00..3de070a 100644 --- a/internal/vcenter/vcenter.go +++ b/internal/vcenter/vcenter.go @@ -8,6 +8,7 @@ import ( "net/url" "os" "path" + "strings" "github.com/vmware/govmomi" "github.com/vmware/govmomi/find" @@ -20,6 +21,7 @@ import ( type Vcenter struct { Logger *slog.Logger + Vurl string ctx context.Context client *govmomi.Client credentials *VcenterLogin @@ -61,6 +63,7 @@ func (v *Vcenter) Login(vUrl string) error { if err != nil { log.Fatalf("Error parsing vCenter URL: %s", err) } + v.Vurl = vUrl u.User = url.UserPassword(v.credentials.Username, v.credentials.Password) @@ -108,6 +111,236 @@ func (v *Vcenter) Logout() 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) + if err != nil { + return nil, err + } + defer vms.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) + } + + 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) + } + + } + + v.Logger.Debug("Found VM references", "count", len(results)) + + return results, err +} + +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) + } + + // 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) + if err != nil { + return nil, fmt.Errorf("failed to retrieve VM %s in datacenter %s: %w", vmObj.Name(), datacenterName, 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) + } + + // 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) + if err != nil { + return nil, fmt.Errorf("failed to retrieve Host %s in datacenter %s: %w", hostObj.Name(), datacenterName, err) + } + + // Return the found mo.HostSystem object + v.Logger.Debug("Found Host in datacenter", "host_name", moHost.Name, "dc_name", datacenterName) + 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) + } + + 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 +} + +// Function to find the cluster or compute resource from a host reference +func (v *Vcenter) GetClusterFromHost(hostRef *types.ManagedObjectReference) (string, error) { + // Get the host object + host, err := v.GetHostSystemObject(*hostRef) + if err != nil { + v.Logger.Error("cant get host", "error", err) + return "", err + } + + v.Logger.Debug("host parent", "parent", host.Parent) + + if 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 + } + + return "", 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) + if err != nil { + return nil, fmt.Errorf("failed to retrieve parent of object: %w", err) + } + + // Return the parent reference + if obj.Parent != nil { + return obj.Parent, nil + } + return nil, nil +} + func (v *Vcenter) FindVMByName(vmName string) ([]mo.VirtualMachine, error) { m := view.NewManager(v.client.Client) @@ -183,10 +416,9 @@ func (v *Vcenter) FindVMByID(vmID string) (*VmProperties, error) { return nil, fmt.Errorf("VM with ID %s not found in any datacenter", vmID) } -func (v *Vcenter) FindVMByIDWithDatacenter(vmID string, dcID string) (*VmProperties, error) { - //var dcName string +func (v *Vcenter) FindVMByIDWithDatacenter(vmID string, dcID string) (*mo.VirtualMachine, error) { var err error - resourcePool := "" + //resourcePool := "" v.Logger.Debug("searching for vm id", "vm_id", vmID, "datacenter_id", dcID) finder := find.NewFinder(v.client.Client, true) @@ -218,24 +450,28 @@ func (v *Vcenter) FindVMByIDWithDatacenter(vmID string, dcID string) (*VmPropert if err == nil { v.Logger.Debug("Found VM") - // Retrieve the resource pool the VM is in - if vm.ResourcePool != nil { - rp := object.NewResourcePool(v.client.Client, *vm.ResourcePool) - rpName, err := rp.ObjectName(v.ctx) - if err != nil { - v.Logger.Error("failed to get resource pool name", "error", err) - } else { - v.Logger.Debug("Found resource pool name", "rp_name", rpName) - resourcePool = rpName + /* + // Retrieve the resource pool the VM is in + if vm.ResourcePool != nil { + rp := object.NewResourcePool(v.client.Client, *vm.ResourcePool) + rpName, err := rp.ObjectName(v.ctx) + if err != nil { + v.Logger.Error("failed to get resource pool name", "error", err) + } else { + v.Logger.Debug("Found resource pool name", "rp_name", rpName) + resourcePool = rpName + } } + */ - } - - return &VmProperties{ - //Datacenter: dcName, - Vm: vm, - ResourcePool: resourcePool, - }, nil + return &vm, nil + /* + return &VmProperties{ + //Datacenter: dcName, + Vm: vm, + ResourcePool: resourcePool, + }, 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) @@ -244,9 +480,23 @@ func (v *Vcenter) FindVMByIDWithDatacenter(vmID string, dcID string) (*VmPropert } else { return nil, fmt.Errorf("failed to retrieve VM: %w", err) } +} - //v.Logger.Info("Unable to find vm in datacenter", "vm_id", vmID, "datacenter_id", dcID) - //return nil, nil +// Helper function to retrieve the resource pool for the VM +func (v *Vcenter) GetVmResourcePool(vm mo.VirtualMachine) (string, error) { + var resourcePool string + if vm.ResourcePool != nil { + rp := object.NewResourcePool(v.client.Client, *vm.ResourcePool) + rpName, err := rp.ObjectName(v.ctx) + if err != nil { + v.Logger.Error("failed to get resource pool name", "error", err) + return resourcePool, err + } else { + v.Logger.Debug("Found resource pool name", "rp_name", rpName) + resourcePool = rpName + } + } + return resourcePool, nil } // Helper function to retrieve the full folder path for the VM diff --git a/main.go b/main.go index b0f039e..7904587 100644 --- a/main.go +++ b/main.go @@ -123,7 +123,8 @@ func main() { } vcPass, err := a.Decrypt(vcEp) if err != nil { - logger.Error("failed to decrypt vcenter credentials", "error", err) + logger.Error("failed to decrypt vcenter credentials. Assuming un-encrypted", "error", err) + vcPass = []byte(vcEp) //os.Exit(1) } @@ -188,7 +189,7 @@ func main() { logger.Debug("Created event processing cron job", "job", job.ID()) // start background checks of vcenter inventory - startsAt2 := time.Now().Add(time.Second * 300) + startsAt2 := time.Now().Add(time.Second * 30) job2, err := c.NewJob( gocron.DurationJob(cronInvFrequency), gocron.NewTask(func() { diff --git a/server/handler/vmModifyEvent.go b/server/handler/vmModifyEvent.go index b7f60a6..e1e9d52 100644 --- a/server/handler/vmModifyEvent.go +++ b/server/handler/vmModifyEvent.go @@ -262,11 +262,11 @@ func (h *Handler) calculateNewDiskSize(event models.CloudEventReceived) float64 if err != nil { h.Logger.Error("Can't locate vm in vCenter", "vmID", event.CloudEvent.Data.VM.VM.Value, "error", err) } else { - if vmObject.Vm.Config != nil { + if vmObject.Config != nil { h.Logger.Debug("Found VM with config, calculating new total disk size", "vmID", event.CloudEvent.Data.VM.VM.Value) // Calculate the total disk allocated in GB - for _, device := range vmObject.Vm.Config.Hardware.Device { + for _, device := range vmObject.Config.Hardware.Device { if disk, ok := device.(*types.VirtualDisk); ok { // Print the filename of the backing device diff --git a/settings.yaml b/settings.yaml index dfd3d28..bf2db33 100644 --- a/settings.yaml +++ b/settings.yaml @@ -4,4 +4,5 @@ settings: node_charge_clusters: - ".*CMD.*" srm_activeactive_vms: - vcenter_addresses: \ No newline at end of file + vcenter_addresses: + - "https://vc.lab.local/sdk" \ No newline at end of file