implement vc inventory scanning
Some checks are pending
CI / Lint (push) Waiting to run
CI / Test (push) Waiting to run
CI / End-to-End (push) Waiting to run
CI / Publish Docker (push) Blocked by required conditions
continuous-integration/drone/push Build is passing

This commit is contained in:
2024-09-30 10:36:23 +10:00
parent a91642b450
commit c4eedb55b7
8 changed files with 533 additions and 37 deletions

View File

@@ -10,6 +10,10 @@ ORDER BY "CreationTime";
SELECT * FROM "Inventory" SELECT * FROM "Inventory"
WHERE "Name" = ?; WHERE "Name" = ?;
-- name: GetInventoryByVcenter :many
SELECT * FROM "Inventory"
WHERE "Vcenter" = ?;
-- name: GetInventoryVmId :one -- name: GetInventoryVmId :one
SELECT * FROM "Inventory" SELECT * FROM "Inventory"
WHERE "VmId" = sqlc.arg('vmId') AND "Datacenter" = sqlc.arg('datacenterName'); WHERE "VmId" = sqlc.arg('vmId') AND "Datacenter" = sqlc.arg('datacenterName');

View File

@@ -262,6 +262,54 @@ func (q *Queries) GetInventoryByName(ctx context.Context, name string) ([]Invent
return items, nil 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 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" 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 WHERE "CloudId" = ? LIMIT 1

View File

@@ -2,10 +2,198 @@ package tasks
import ( import (
"context" "context"
"database/sql"
"errors"
"fmt"
"log/slog" "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 // 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 { 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 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
}

View File

@@ -22,6 +22,7 @@ func (c *CronTask) RunVmCheck(ctx context.Context, logger *slog.Logger) error {
isTemplate string isTemplate string
poweredOn string poweredOn string
folderPath string folderPath string
rpName string
) )
dateCmp := time.Now().AddDate(0, 0, -1).Unix() 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) //prettyPrint(vmObject)
// calculate VM properties we want to store // calculate VM properties we want to store
if vmObject.Vm.Config != nil { if vmObject.Config != nil {
numRam = vmObject.Vm.Config.Hardware.MemoryMB numRam = vmObject.Config.Hardware.MemoryMB
numVcpus = vmObject.Vm.Config.Hardware.NumCPU numVcpus = vmObject.Config.Hardware.NumCPU
var totalDiskBytes int64 var totalDiskBytes int64
// Calculate the total disk allocated in GB // 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 { if disk, ok := device.(*types.VirtualDisk); ok {
// Print the filename of the backing device // 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) c.Logger.Debug("Converted total disk size", "bytes", totalDiskBytes, "GB", totalDiskGB)
// Determine if the VM is a normal VM or an SRM placeholder // 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") c.Logger.Debug("VM ManagedBy indicates managed by SRM")
srmPlaceholder = "TRUE" srmPlaceholder = "TRUE"
} }
if vmObject.Vm.Config.Template { if vmObject.Config.Template {
isTemplate = "TRUE" isTemplate = "TRUE"
} else { } else {
isTemplate = "FALSE" isTemplate = "FALSE"
} }
// Retrieve the full folder path of the VM // Retrieve the full folder path of the VM
folderPath, err = vc.GetVMFolderPath(vmObject.Vm) folderPath, err = vc.GetVMFolderPath(*vmObject)
if err != nil { if err != nil {
c.Logger.Error("failed to get vm folder path", "error", err) c.Logger.Error("failed to get vm folder path", "error", err)
folderPath = "" 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) c.Logger.Debug("Found vm folder path", "folder_path", folderPath)
} }
// Retrieve the resource pool of the VM
rpName, _ = vc.GetVmResourcePool(*vmObject)
foundVm = true foundVm = true
} else { } else {
c.Logger.Error("Empty VM config") c.Logger.Error("Empty VM config")
} }
c.Logger.Debug("VM has runtime data", "power_state", vmObject.Vm.Runtime.PowerState) c.Logger.Debug("VM has runtime data", "power_state", vmObject.Runtime.PowerState)
if vmObject.Vm.Runtime.PowerState == "poweredOff" { if vmObject.Runtime.PowerState == "poweredOff" {
poweredOn = "FALSE" poweredOn = "FALSE"
} else { } else {
poweredOn = "TRUE" 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) c.Logger.Debug("Adding to Inventory table", "vm_name", evt.VmName.String, "vcpus", numVcpus, "ram", numRam, "dc", evt.DatacenterId.String)
params := queries.CreateInventoryParams{ params := queries.CreateInventoryParams{
Name: vmObject.Vm.Name, Name: vmObject.Name,
Vcenter: evt.Source, Vcenter: evt.Source,
CloudId: sql.NullString{String: evt.CloudId, Valid: evt.CloudId != ""}, CloudId: sql.NullString{String: evt.CloudId, Valid: evt.CloudId != ""},
EventKey: sql.NullString{String: evt.EventKey.String, Valid: evt.EventKey.Valid}, 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}, InitialRam: sql.NullInt64{Int64: int64(numRam), Valid: numRam > 0},
ProvisionedDisk: sql.NullFloat64{Float64: totalDiskGB, Valid: totalDiskGB > 0}, ProvisionedDisk: sql.NullFloat64{Float64: totalDiskGB, Valid: totalDiskGB > 0},
Folder: sql.NullString{String: folderPath, Valid: folderPath != ""}, 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, SrmPlaceholder: srmPlaceholder,
IsTemplate: isTemplate, IsTemplate: isTemplate,
PoweredOn: poweredOn, PoweredOn: poweredOn,

View File

@@ -8,6 +8,7 @@ import (
"net/url" "net/url"
"os" "os"
"path" "path"
"strings"
"github.com/vmware/govmomi" "github.com/vmware/govmomi"
"github.com/vmware/govmomi/find" "github.com/vmware/govmomi/find"
@@ -20,6 +21,7 @@ import (
type Vcenter struct { type Vcenter struct {
Logger *slog.Logger Logger *slog.Logger
Vurl string
ctx context.Context ctx context.Context
client *govmomi.Client client *govmomi.Client
credentials *VcenterLogin credentials *VcenterLogin
@@ -61,6 +63,7 @@ func (v *Vcenter) Login(vUrl string) error {
if err != nil { if err != nil {
log.Fatalf("Error parsing vCenter URL: %s", err) log.Fatalf("Error parsing vCenter URL: %s", err)
} }
v.Vurl = vUrl
u.User = url.UserPassword(v.credentials.Username, v.credentials.Password) 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) { func (v *Vcenter) FindVMByName(vmName string) ([]mo.VirtualMachine, error) {
m := view.NewManager(v.client.Client) 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) return nil, fmt.Errorf("VM with ID %s not found in any datacenter", vmID)
} }
func (v *Vcenter) FindVMByIDWithDatacenter(vmID string, dcID string) (*VmProperties, error) { func (v *Vcenter) FindVMByIDWithDatacenter(vmID string, dcID string) (*mo.VirtualMachine, error) {
//var dcName string
var err error var err error
resourcePool := "" //resourcePool := ""
v.Logger.Debug("searching for vm id", "vm_id", vmID, "datacenter_id", dcID) v.Logger.Debug("searching for vm id", "vm_id", vmID, "datacenter_id", dcID)
finder := find.NewFinder(v.client.Client, true) finder := find.NewFinder(v.client.Client, true)
@@ -218,24 +450,28 @@ func (v *Vcenter) FindVMByIDWithDatacenter(vmID string, dcID string) (*VmPropert
if err == nil { if err == nil {
v.Logger.Debug("Found VM") v.Logger.Debug("Found VM")
// Retrieve the resource pool the VM is in /*
if vm.ResourcePool != nil { // Retrieve the resource pool the VM is in
rp := object.NewResourcePool(v.client.Client, *vm.ResourcePool) if vm.ResourcePool != nil {
rpName, err := rp.ObjectName(v.ctx) rp := object.NewResourcePool(v.client.Client, *vm.ResourcePool)
if err != nil { rpName, err := rp.ObjectName(v.ctx)
v.Logger.Error("failed to get resource pool name", "error", err) if err != nil {
} else { v.Logger.Error("failed to get resource pool name", "error", err)
v.Logger.Debug("Found resource pool name", "rp_name", rpName) } else {
resourcePool = rpName v.Logger.Debug("Found resource pool name", "rp_name", rpName)
resourcePool = rpName
}
} }
*/
} return &vm, nil
/*
return &VmProperties{ return &VmProperties{
//Datacenter: dcName, //Datacenter: dcName,
Vm: vm, Vm: vm,
ResourcePool: resourcePool, ResourcePool: resourcePool,
}, nil }, nil
*/
} else if _, ok := err.(*find.NotFoundError); !ok { } else if _, ok := err.(*find.NotFoundError); !ok {
// If the error is not a NotFoundError, return it // 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) //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 { } else {
return nil, fmt.Errorf("failed to retrieve VM: %w", err) 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) // Helper function to retrieve the resource pool for the VM
//return nil, nil 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 // Helper function to retrieve the full folder path for the VM

View File

@@ -123,7 +123,8 @@ func main() {
} }
vcPass, err := a.Decrypt(vcEp) vcPass, err := a.Decrypt(vcEp)
if err != nil { 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) //os.Exit(1)
} }
@@ -188,7 +189,7 @@ func main() {
logger.Debug("Created event processing cron job", "job", job.ID()) logger.Debug("Created event processing cron job", "job", job.ID())
// start background checks of vcenter inventory // start background checks of vcenter inventory
startsAt2 := time.Now().Add(time.Second * 300) startsAt2 := time.Now().Add(time.Second * 30)
job2, err := c.NewJob( job2, err := c.NewJob(
gocron.DurationJob(cronInvFrequency), gocron.DurationJob(cronInvFrequency),
gocron.NewTask(func() { gocron.NewTask(func() {

View File

@@ -262,11 +262,11 @@ func (h *Handler) calculateNewDiskSize(event models.CloudEventReceived) float64
if err != nil { if err != nil {
h.Logger.Error("Can't locate vm in vCenter", "vmID", event.CloudEvent.Data.VM.VM.Value, "error", err) h.Logger.Error("Can't locate vm in vCenter", "vmID", event.CloudEvent.Data.VM.VM.Value, "error", err)
} else { } 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) 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 // 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 { if disk, ok := device.(*types.VirtualDisk); ok {
// Print the filename of the backing device // Print the filename of the backing device

View File

@@ -5,3 +5,4 @@ settings:
- ".*CMD.*" - ".*CMD.*"
srm_activeactive_vms: srm_activeactive_vms:
vcenter_addresses: vcenter_addresses:
- "https://vc.lab.local/sdk"