This commit is contained in:
@@ -5,8 +5,6 @@ import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
"vctp/db/queries"
|
||||
@@ -33,8 +31,8 @@ type inventorySnapshotRow struct {
|
||||
Cluster sql.NullString
|
||||
Folder sql.NullString
|
||||
ProvisionedDisk sql.NullFloat64
|
||||
InitialVcpus sql.NullInt64
|
||||
InitialRam sql.NullInt64
|
||||
VcpuCount sql.NullInt64
|
||||
RamGB sql.NullInt64
|
||||
IsTemplate string
|
||||
PoweredOn string
|
||||
SrmPlaceholder string
|
||||
@@ -46,7 +44,7 @@ type inventorySnapshotRow struct {
|
||||
// RunVcenterSnapshotHourly records hourly inventory snapshots into a daily table.
|
||||
func (c *CronTask) RunVcenterSnapshotHourly(ctx context.Context, logger *slog.Logger) error {
|
||||
startTime := time.Now()
|
||||
tableName, err := dailyInventoryTableName(startTime)
|
||||
tableName, err := hourlyInventoryTableName(startTime)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -55,6 +53,12 @@ func (c *CronTask) RunVcenterSnapshotHourly(ctx context.Context, logger *slog.Lo
|
||||
if err := ensureDailyInventoryTable(ctx, dbConn, tableName); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := report.EnsureSnapshotRegistry(ctx, c.Database); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := report.RegisterSnapshot(ctx, c.Database, "hourly", tableName, startTime); err != nil {
|
||||
c.Logger.Warn("failed to register hourly snapshot", "error", err, "table", tableName)
|
||||
}
|
||||
|
||||
// reload settings in case vcenter list has changed
|
||||
c.Settings.ReadYMLSettings()
|
||||
@@ -62,7 +66,10 @@ func (c *CronTask) RunVcenterSnapshotHourly(ctx context.Context, logger *slog.Lo
|
||||
for _, url := range c.Settings.Values.Settings.VcenterAddresses {
|
||||
c.Logger.Debug("connecting to vcenter for hourly snapshot", "url", url)
|
||||
vc := vcenter.New(c.Logger, c.VcCreds)
|
||||
vc.Login(url)
|
||||
if err := vc.Login(url); err != nil {
|
||||
c.Logger.Error("unable to connect to vcenter for hourly snapshot", "error", err, "url", url)
|
||||
continue
|
||||
}
|
||||
|
||||
vcVms, err := vc.GetAllVmReferences()
|
||||
if err != nil {
|
||||
@@ -70,6 +77,10 @@ func (c *CronTask) RunVcenterSnapshotHourly(ctx context.Context, logger *slog.Lo
|
||||
vc.Logout()
|
||||
continue
|
||||
}
|
||||
canDetectMissing := len(vcVms) > 0
|
||||
if !canDetectMissing {
|
||||
c.Logger.Warn("no VMs returned from vcenter; skipping missing VM detection", "url", url)
|
||||
}
|
||||
|
||||
inventoryRows, err := c.Database.Queries().GetInventoryByVcenter(ctx, url)
|
||||
if err != nil {
|
||||
@@ -116,8 +127,8 @@ func (c *CronTask) RunVcenterSnapshotHourly(ctx context.Context, logger *slog.Lo
|
||||
presentSnapshots[vm.Reference().Value] = row
|
||||
|
||||
totals.VmCount++
|
||||
totals.VcpuTotal += nullInt64ToInt(row.InitialVcpus)
|
||||
totals.RamTotal += nullInt64ToInt(row.InitialRam)
|
||||
totals.VcpuTotal += nullInt64ToInt(row.VcpuCount)
|
||||
totals.RamTotal += nullInt64ToInt(row.RamGB)
|
||||
totals.DiskTotal += nullFloat64ToFloat(row.ProvisionedDisk)
|
||||
}
|
||||
|
||||
@@ -127,7 +138,15 @@ func (c *CronTask) RunVcenterSnapshotHourly(ctx context.Context, logger *slog.Lo
|
||||
}
|
||||
}
|
||||
|
||||
if !canDetectMissing {
|
||||
vc.Logout()
|
||||
continue
|
||||
}
|
||||
|
||||
for _, inv := range inventoryRows {
|
||||
if strings.HasPrefix(inv.Name, "vCLS-") {
|
||||
continue
|
||||
}
|
||||
vmID := inv.VmId.String
|
||||
if vmID != "" {
|
||||
if _, ok := presentSnapshots[vmID]; ok {
|
||||
@@ -137,6 +156,17 @@ func (c *CronTask) RunVcenterSnapshotHourly(ctx context.Context, logger *slog.Lo
|
||||
|
||||
row := snapshotFromInventory(inv, startTime)
|
||||
row.IsPresent = "FALSE"
|
||||
if !row.DeletionTime.Valid {
|
||||
deletionTime := startTime.Unix()
|
||||
row.DeletionTime = sql.NullInt64{Int64: deletionTime, Valid: true}
|
||||
if err := c.Database.Queries().InventoryMarkDeleted(ctx, queries.InventoryMarkDeletedParams{
|
||||
DeletionTime: row.DeletionTime,
|
||||
VmId: inv.VmId,
|
||||
DatacenterName: inv.Datacenter,
|
||||
}); err != nil {
|
||||
c.Logger.Warn("failed to mark inventory record deleted", "error", err, "vm_id", row.VmId.String)
|
||||
}
|
||||
}
|
||||
if err := insertDailyInventoryRow(ctx, dbConn, tableName, row); err != nil {
|
||||
c.Logger.Error("failed to insert missing VM snapshot", "error", err, "vm_id", row.VmId.String)
|
||||
}
|
||||
@@ -148,7 +178,7 @@ func (c *CronTask) RunVcenterSnapshotHourly(ctx context.Context, logger *slog.Lo
|
||||
"vcenter", url,
|
||||
"vm_count", totals.VmCount,
|
||||
"vcpu_total", totals.VcpuTotal,
|
||||
"ram_total_mb", totals.RamTotal,
|
||||
"ram_total_gb", totals.RamTotal,
|
||||
"disk_total_gb", totals.DiskTotal,
|
||||
)
|
||||
}
|
||||
@@ -160,7 +190,7 @@ func (c *CronTask) RunVcenterSnapshotHourly(ctx context.Context, logger *slog.Lo
|
||||
// RunVcenterDailyAggregate summarizes hourly snapshots into a daily summary table.
|
||||
func (c *CronTask) RunVcenterDailyAggregate(ctx context.Context, logger *slog.Logger) error {
|
||||
targetTime := time.Now().Add(-time.Minute)
|
||||
sourceTable, err := dailyInventoryTableName(targetTime)
|
||||
sourceTable, err := hourlyInventoryTableName(targetTime)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -173,6 +203,9 @@ func (c *CronTask) RunVcenterDailyAggregate(ctx context.Context, logger *slog.Lo
|
||||
if err := ensureDailySummaryTable(ctx, dbConn, summaryTable); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := report.EnsureSnapshotRegistry(ctx, c.Database); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
currentTotals, err := snapshotTotalsForTable(ctx, dbConn, sourceTable)
|
||||
if err != nil {
|
||||
@@ -182,12 +215,12 @@ func (c *CronTask) RunVcenterDailyAggregate(ctx context.Context, logger *slog.Lo
|
||||
"table", sourceTable,
|
||||
"vm_count", currentTotals.VmCount,
|
||||
"vcpu_total", currentTotals.VcpuTotal,
|
||||
"ram_total_mb", currentTotals.RamTotal,
|
||||
"ram_total_gb", currentTotals.RamTotal,
|
||||
"disk_total_gb", currentTotals.DiskTotal,
|
||||
)
|
||||
}
|
||||
|
||||
prevTable, _ := dailyInventoryTableName(targetTime.AddDate(0, 0, -1))
|
||||
prevTable, _ := hourlyInventoryTableName(targetTime.AddDate(0, 0, -1))
|
||||
if prevTable != "" && tableExists(ctx, dbConn, prevTable) {
|
||||
prevTotals, err := snapshotTotalsForTable(ctx, dbConn, prevTable)
|
||||
if err != nil {
|
||||
@@ -198,7 +231,7 @@ func (c *CronTask) RunVcenterDailyAggregate(ctx context.Context, logger *slog.Lo
|
||||
"previous_table", prevTable,
|
||||
"vm_delta", currentTotals.VmCount-prevTotals.VmCount,
|
||||
"vcpu_delta", currentTotals.VcpuTotal-prevTotals.VcpuTotal,
|
||||
"ram_delta_mb", currentTotals.RamTotal-prevTotals.RamTotal,
|
||||
"ram_delta_gb", currentTotals.RamTotal-prevTotals.RamTotal,
|
||||
"disk_delta_gb", currentTotals.DiskTotal-prevTotals.DiskTotal,
|
||||
)
|
||||
}
|
||||
@@ -207,19 +240,19 @@ func (c *CronTask) RunVcenterDailyAggregate(ctx context.Context, logger *slog.Lo
|
||||
insertQuery := fmt.Sprintf(`
|
||||
INSERT INTO %s (
|
||||
"InventoryId", "Name", "Vcenter", "VmId", "EventKey", "CloudId", "CreationTime", "DeletionTime",
|
||||
"ResourcePool", "VmType", "Datacenter", "Cluster", "Folder", "ProvisionedDisk", "InitialVcpus",
|
||||
"InitialRam", "IsTemplate", "PoweredOn", "SrmPlaceholder", "VmUuid",
|
||||
"SamplesPresent", "AvgVcpus", "AvgRam", "AvgDisk", "AvgIsPresent",
|
||||
"ResourcePool", "VmType", "Datacenter", "Cluster", "Folder", "ProvisionedDisk", "VcpuCount",
|
||||
"RamGB", "IsTemplate", "PoweredOn", "SrmPlaceholder", "VmUuid",
|
||||
"SamplesPresent", "AvgVcpuCount", "AvgRamGB", "AvgProvisionedDisk", "AvgIsPresent",
|
||||
"PoolTinPct", "PoolBronzePct", "PoolSilverPct", "PoolGoldPct"
|
||||
)
|
||||
SELECT
|
||||
"InventoryId", "Name", "Vcenter", "VmId", "EventKey", "CloudId", "CreationTime", "DeletionTime",
|
||||
"ResourcePool", "VmType", "Datacenter", "Cluster", "Folder", "ProvisionedDisk", "InitialVcpus",
|
||||
"InitialRam", "IsTemplate", "PoweredOn", "SrmPlaceholder", "VmUuid",
|
||||
"ResourcePool", "VmType", "Datacenter", "Cluster", "Folder", "ProvisionedDisk", "VcpuCount",
|
||||
"RamGB", "IsTemplate", "PoweredOn", "SrmPlaceholder", "VmUuid",
|
||||
SUM(CASE WHEN "IsPresent" = 'TRUE' THEN 1 ELSE 0 END) AS "SamplesPresent",
|
||||
AVG(CASE WHEN "IsPresent" = 'TRUE' AND "InitialVcpus" IS NOT NULL THEN "InitialVcpus" END) AS "AvgVcpus",
|
||||
AVG(CASE WHEN "IsPresent" = 'TRUE' AND "InitialRam" IS NOT NULL THEN "InitialRam" END) AS "AvgRam",
|
||||
AVG(CASE WHEN "IsPresent" = 'TRUE' AND "ProvisionedDisk" IS NOT NULL THEN "ProvisionedDisk" END) AS "AvgDisk",
|
||||
AVG(CASE WHEN "IsPresent" = 'TRUE' AND "VcpuCount" IS NOT NULL THEN "VcpuCount" END) AS "AvgVcpuCount",
|
||||
AVG(CASE WHEN "IsPresent" = 'TRUE' AND "RamGB" IS NOT NULL THEN "RamGB" END) AS "AvgRamGB",
|
||||
AVG(CASE WHEN "IsPresent" = 'TRUE' AND "ProvisionedDisk" IS NOT NULL THEN "ProvisionedDisk" END) AS "AvgProvisionedDisk",
|
||||
AVG(CASE WHEN "IsPresent" = 'TRUE' THEN 1 ELSE 0 END) AS "AvgIsPresent",
|
||||
100.0 * SUM(CASE WHEN "IsPresent" = 'TRUE' AND LOWER("ResourcePool") = 'tin' THEN 1 ELSE 0 END)
|
||||
/ NULLIF(SUM(CASE WHEN "IsPresent" = 'TRUE' THEN 1 ELSE 0 END), 0) AS "PoolTinPct",
|
||||
@@ -232,14 +265,17 @@ SELECT
|
||||
FROM %s
|
||||
GROUP BY
|
||||
"InventoryId", "Name", "Vcenter", "VmId", "EventKey", "CloudId", "CreationTime", "DeletionTime",
|
||||
"ResourcePool", "VmType", "Datacenter", "Cluster", "Folder", "ProvisionedDisk", "InitialVcpus",
|
||||
"InitialRam", "IsTemplate", "PoweredOn", "SrmPlaceholder", "VmUuid";
|
||||
"ResourcePool", "VmType", "Datacenter", "Cluster", "Folder", "ProvisionedDisk", "VcpuCount",
|
||||
"RamGB", "IsTemplate", "PoweredOn", "SrmPlaceholder", "VmUuid";
|
||||
`, summaryTable, sourceTable)
|
||||
|
||||
if _, err := dbConn.ExecContext(ctx, insertQuery); err != nil {
|
||||
c.Logger.Error("failed to aggregate daily inventory", "error", err, "source_table", sourceTable)
|
||||
return err
|
||||
}
|
||||
if err := report.RegisterSnapshot(ctx, c.Database, "daily", summaryTable, targetTime); err != nil {
|
||||
c.Logger.Warn("failed to register daily snapshot", "error", err, "table", summaryTable)
|
||||
}
|
||||
|
||||
c.Logger.Debug("Finished daily inventory aggregation", "source_table", sourceTable, "summary_table", summaryTable)
|
||||
return nil
|
||||
@@ -251,7 +287,7 @@ func (c *CronTask) RunVcenterMonthlyAggregate(ctx context.Context, logger *slog.
|
||||
firstOfThisMonth := time.Date(now.Year(), now.Month(), 1, 0, 0, 0, 0, now.Location())
|
||||
targetMonth := firstOfThisMonth.AddDate(0, -1, 0)
|
||||
|
||||
monthPrefix := fmt.Sprintf("inventory_daily_%s", targetMonth.Format("200601"))
|
||||
monthPrefix := fmt.Sprintf("inventory_hourly_%s", targetMonth.Format("200601"))
|
||||
dailyTables, err := report.ListTablesByPrefix(ctx, c.Database, monthPrefix)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -269,11 +305,14 @@ func (c *CronTask) RunVcenterMonthlyAggregate(ctx context.Context, logger *slog.
|
||||
if err := ensureMonthlySummaryTable(ctx, dbConn, monthlyTable); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := report.EnsureSnapshotRegistry(ctx, c.Database); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
unionQuery := buildUnionQuery(dailyTables, []string{
|
||||
`"InventoryId"`, `"Name"`, `"Vcenter"`, `"VmId"`, `"EventKey"`, `"CloudId"`, `"CreationTime"`,
|
||||
`"DeletionTime"`, `"ResourcePool"`, `"VmType"`, `"Datacenter"`, `"Cluster"`, `"Folder"`,
|
||||
`"ProvisionedDisk"`, `"InitialVcpus"`, `"InitialRam"`, `"IsTemplate"`, `"PoweredOn"`,
|
||||
`"ProvisionedDisk"`, `"VcpuCount"`, `"RamGB"`, `"IsTemplate"`, `"PoweredOn"`,
|
||||
`"SrmPlaceholder"`, `"VmUuid"`, `"IsPresent"`,
|
||||
})
|
||||
if strings.TrimSpace(unionQuery) == "" {
|
||||
@@ -288,7 +327,7 @@ func (c *CronTask) RunVcenterMonthlyAggregate(ctx context.Context, logger *slog.
|
||||
"month", targetMonth.Format("2006-01"),
|
||||
"vm_count", monthlyTotals.VmCount,
|
||||
"vcpu_total", monthlyTotals.VcpuTotal,
|
||||
"ram_total_mb", monthlyTotals.RamTotal,
|
||||
"ram_total_gb", monthlyTotals.RamTotal,
|
||||
"disk_total_gb", monthlyTotals.DiskTotal,
|
||||
)
|
||||
}
|
||||
@@ -296,18 +335,18 @@ func (c *CronTask) RunVcenterMonthlyAggregate(ctx context.Context, logger *slog.
|
||||
insertQuery := fmt.Sprintf(`
|
||||
INSERT INTO %s (
|
||||
"InventoryId", "Name", "Vcenter", "VmId", "EventKey", "CloudId", "CreationTime", "DeletionTime",
|
||||
"ResourcePool", "VmType", "Datacenter", "Cluster", "Folder", "ProvisionedDisk", "InitialVcpus",
|
||||
"InitialRam", "IsTemplate", "PoweredOn", "SrmPlaceholder", "VmUuid",
|
||||
"AvgVcpus", "AvgRam", "AvgDisk", "AvgIsPresent",
|
||||
"ResourcePool", "VmType", "Datacenter", "Cluster", "Folder", "ProvisionedDisk", "VcpuCount",
|
||||
"RamGB", "IsTemplate", "PoweredOn", "SrmPlaceholder", "VmUuid",
|
||||
"AvgVcpuCount", "AvgRamGB", "AvgProvisionedDisk", "AvgIsPresent",
|
||||
"PoolTinPct", "PoolBronzePct", "PoolSilverPct", "PoolGoldPct"
|
||||
)
|
||||
SELECT
|
||||
"InventoryId", "Name", "Vcenter", "VmId", "EventKey", "CloudId", "CreationTime", "DeletionTime",
|
||||
"ResourcePool", "VmType", "Datacenter", "Cluster", "Folder", "ProvisionedDisk", "InitialVcpus",
|
||||
"InitialRam", "IsTemplate", "PoweredOn", "SrmPlaceholder", "VmUuid",
|
||||
AVG(CASE WHEN "InitialVcpus" IS NOT NULL THEN "InitialVcpus" END) AS "AvgVcpus",
|
||||
AVG(CASE WHEN "InitialRam" IS NOT NULL THEN "InitialRam" END) AS "AvgRam",
|
||||
AVG(CASE WHEN "ProvisionedDisk" IS NOT NULL THEN "ProvisionedDisk" END) AS "AvgDisk",
|
||||
"ResourcePool", "VmType", "Datacenter", "Cluster", "Folder", "ProvisionedDisk", "VcpuCount",
|
||||
"RamGB", "IsTemplate", "PoweredOn", "SrmPlaceholder", "VmUuid",
|
||||
AVG(CASE WHEN "VcpuCount" IS NOT NULL THEN "VcpuCount" END) AS "AvgVcpuCount",
|
||||
AVG(CASE WHEN "RamGB" IS NOT NULL THEN "RamGB" END) AS "AvgRamGB",
|
||||
AVG(CASE WHEN "ProvisionedDisk" IS NOT NULL THEN "ProvisionedDisk" END) AS "AvgProvisionedDisk",
|
||||
AVG(CASE WHEN "IsPresent" = 'TRUE' THEN 1 ELSE 0 END) AS "AvgIsPresent",
|
||||
100.0 * SUM(CASE WHEN "IsPresent" = 'TRUE' AND LOWER("ResourcePool") = 'tin' THEN 1 ELSE 0 END)
|
||||
/ NULLIF(SUM(CASE WHEN "IsPresent" = 'TRUE' THEN 1 ELSE 0 END), 0) AS "PoolTinPct",
|
||||
@@ -322,14 +361,17 @@ FROM (
|
||||
) snapshots
|
||||
GROUP BY
|
||||
"InventoryId", "Name", "Vcenter", "VmId", "EventKey", "CloudId", "CreationTime", "DeletionTime",
|
||||
"ResourcePool", "VmType", "Datacenter", "Cluster", "Folder", "ProvisionedDisk", "InitialVcpus",
|
||||
"InitialRam", "IsTemplate", "PoweredOn", "SrmPlaceholder", "VmUuid";
|
||||
"ResourcePool", "VmType", "Datacenter", "Cluster", "Folder", "ProvisionedDisk", "VcpuCount",
|
||||
"RamGB", "IsTemplate", "PoweredOn", "SrmPlaceholder", "VmUuid";
|
||||
`, monthlyTable, unionQuery)
|
||||
|
||||
if _, err := dbConn.ExecContext(ctx, insertQuery); err != nil {
|
||||
c.Logger.Error("failed to aggregate monthly inventory", "error", err, "month", targetMonth.Format("2006-01"))
|
||||
return err
|
||||
}
|
||||
if err := report.RegisterSnapshot(ctx, c.Database, "monthly", monthlyTable, targetMonth); err != nil {
|
||||
c.Logger.Warn("failed to register monthly snapshot", "error", err, "table", monthlyTable)
|
||||
}
|
||||
|
||||
c.Logger.Debug("Finished monthly inventory aggregation", "summary_table", monthlyTable)
|
||||
return nil
|
||||
@@ -338,15 +380,15 @@ GROUP BY
|
||||
// RunSnapshotCleanup drops hourly and daily snapshot tables older than retention.
|
||||
func (c *CronTask) RunSnapshotCleanup(ctx context.Context, logger *slog.Logger) error {
|
||||
now := time.Now()
|
||||
hourlyMaxDays := getEnvInt("HOURLY_SNAPSHOT_MAX_AGE_DAYS", 60)
|
||||
dailyMaxMonths := getEnvInt("DAILY_SNAPSHOT_MAX_AGE_MONTHS", 12)
|
||||
hourlyMaxDays := intWithDefault(c.Settings.Values.Settings.HourlySnapshotMaxAgeDays, 60)
|
||||
dailyMaxMonths := intWithDefault(c.Settings.Values.Settings.DailySnapshotMaxAgeMonths, 12)
|
||||
|
||||
hourlyCutoff := now.AddDate(0, 0, -hourlyMaxDays)
|
||||
dailyCutoff := now.AddDate(0, -dailyMaxMonths, 0)
|
||||
|
||||
dbConn := c.Database.DB()
|
||||
|
||||
hourlyTables, err := report.ListTablesByPrefix(ctx, c.Database, "inventory_daily_")
|
||||
hourlyTables, err := report.ListTablesByPrefix(ctx, c.Database, "inventory_hourly_")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -356,7 +398,7 @@ func (c *CronTask) RunSnapshotCleanup(ctx context.Context, logger *slog.Logger)
|
||||
if strings.HasPrefix(table, "inventory_daily_summary_") {
|
||||
continue
|
||||
}
|
||||
tableDate, ok := parseSnapshotDate(table, "inventory_daily_", "20060102")
|
||||
tableDate, ok := parseSnapshotDate(table, "inventory_hourly_", "2006010215")
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
@@ -365,6 +407,9 @@ func (c *CronTask) RunSnapshotCleanup(ctx context.Context, logger *slog.Logger)
|
||||
c.Logger.Error("failed to drop hourly snapshot table", "error", err, "table", table)
|
||||
} else {
|
||||
removedHourly++
|
||||
if err := report.DeleteSnapshotRecord(ctx, c.Database, table); err != nil {
|
||||
c.Logger.Warn("failed to remove hourly snapshot registry entry", "error", err, "table", table)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -384,6 +429,9 @@ func (c *CronTask) RunSnapshotCleanup(ctx context.Context, logger *slog.Logger)
|
||||
c.Logger.Error("failed to drop daily snapshot table", "error", err, "table", table)
|
||||
} else {
|
||||
removedDaily++
|
||||
if err := report.DeleteSnapshotRecord(ctx, c.Database, table); err != nil {
|
||||
c.Logger.Warn("failed to remove daily snapshot registry entry", "error", err, "table", table)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -397,8 +445,8 @@ func (c *CronTask) RunSnapshotCleanup(ctx context.Context, logger *slog.Logger)
|
||||
return nil
|
||||
}
|
||||
|
||||
func dailyInventoryTableName(t time.Time) (string, error) {
|
||||
return safeTableName(fmt.Sprintf("inventory_daily_%s", t.Format("20060102")))
|
||||
func hourlyInventoryTableName(t time.Time) (string, error) {
|
||||
return safeTableName(fmt.Sprintf("inventory_hourly_%s", t.Format("2006010215")))
|
||||
}
|
||||
|
||||
func dailySummaryTableName(t time.Time) (string, error) {
|
||||
@@ -435,8 +483,8 @@ func ensureDailyInventoryTable(ctx context.Context, dbConn *sqlx.DB, tableName s
|
||||
"Cluster" TEXT,
|
||||
"Folder" TEXT,
|
||||
"ProvisionedDisk" REAL,
|
||||
"InitialVcpus" BIGINT,
|
||||
"InitialRam" BIGINT,
|
||||
"VcpuCount" BIGINT,
|
||||
"RamGB" BIGINT,
|
||||
"IsTemplate" TEXT,
|
||||
"PoweredOn" TEXT,
|
||||
"SrmPlaceholder" TEXT,
|
||||
@@ -445,8 +493,14 @@ func ensureDailyInventoryTable(ctx context.Context, dbConn *sqlx.DB, tableName s
|
||||
"IsPresent" TEXT NOT NULL
|
||||
);`, tableName)
|
||||
|
||||
_, err := dbConn.ExecContext(ctx, ddl)
|
||||
return err
|
||||
if _, err := dbConn.ExecContext(ctx, ddl); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return ensureSnapshotColumns(ctx, dbConn, tableName, []columnDef{
|
||||
{Name: "VcpuCount", Type: "BIGINT"},
|
||||
{Name: "RamGB", Type: "BIGINT"},
|
||||
})
|
||||
}
|
||||
|
||||
func ensureDailySummaryTable(ctx context.Context, dbConn *sqlx.DB, tableName string) error {
|
||||
@@ -465,16 +519,16 @@ func ensureDailySummaryTable(ctx context.Context, dbConn *sqlx.DB, tableName str
|
||||
"Cluster" TEXT,
|
||||
"Folder" TEXT,
|
||||
"ProvisionedDisk" REAL,
|
||||
"InitialVcpus" BIGINT,
|
||||
"InitialRam" BIGINT,
|
||||
"VcpuCount" BIGINT,
|
||||
"RamGB" BIGINT,
|
||||
"IsTemplate" TEXT,
|
||||
"PoweredOn" TEXT,
|
||||
"SrmPlaceholder" TEXT,
|
||||
"VmUuid" TEXT,
|
||||
"SamplesPresent" BIGINT NOT NULL,
|
||||
"AvgVcpus" REAL,
|
||||
"AvgRam" REAL,
|
||||
"AvgDisk" REAL,
|
||||
"AvgVcpuCount" REAL,
|
||||
"AvgRamGB" REAL,
|
||||
"AvgProvisionedDisk" REAL,
|
||||
"AvgIsPresent" REAL,
|
||||
"PoolTinPct" REAL,
|
||||
"PoolBronzePct" REAL,
|
||||
@@ -487,9 +541,9 @@ func ensureDailySummaryTable(ctx context.Context, dbConn *sqlx.DB, tableName str
|
||||
}
|
||||
|
||||
return ensureSnapshotColumns(ctx, dbConn, tableName, []columnDef{
|
||||
{Name: "AvgVcpus", Type: "REAL"},
|
||||
{Name: "AvgRam", Type: "REAL"},
|
||||
{Name: "AvgDisk", Type: "REAL"},
|
||||
{Name: "AvgVcpuCount", Type: "REAL"},
|
||||
{Name: "AvgRamGB", Type: "REAL"},
|
||||
{Name: "AvgProvisionedDisk", Type: "REAL"},
|
||||
{Name: "AvgIsPresent", Type: "REAL"},
|
||||
{Name: "PoolTinPct", Type: "REAL"},
|
||||
{Name: "PoolBronzePct", Type: "REAL"},
|
||||
@@ -514,15 +568,15 @@ func ensureMonthlySummaryTable(ctx context.Context, dbConn *sqlx.DB, tableName s
|
||||
"Cluster" TEXT,
|
||||
"Folder" TEXT,
|
||||
"ProvisionedDisk" REAL,
|
||||
"InitialVcpus" BIGINT,
|
||||
"InitialRam" BIGINT,
|
||||
"VcpuCount" BIGINT,
|
||||
"RamGB" BIGINT,
|
||||
"IsTemplate" TEXT,
|
||||
"PoweredOn" TEXT,
|
||||
"SrmPlaceholder" TEXT,
|
||||
"VmUuid" TEXT,
|
||||
"AvgVcpus" REAL,
|
||||
"AvgRam" REAL,
|
||||
"AvgDisk" REAL,
|
||||
"AvgVcpuCount" REAL,
|
||||
"AvgRamGB" REAL,
|
||||
"AvgProvisionedDisk" REAL,
|
||||
"AvgIsPresent" REAL,
|
||||
"PoolTinPct" REAL,
|
||||
"PoolBronzePct" REAL,
|
||||
@@ -535,7 +589,10 @@ func ensureMonthlySummaryTable(ctx context.Context, dbConn *sqlx.DB, tableName s
|
||||
}
|
||||
|
||||
return ensureSnapshotColumns(ctx, dbConn, tableName, []columnDef{
|
||||
{Name: "AvgDisk", Type: "REAL"},
|
||||
{Name: "AvgVcpuCount", Type: "REAL"},
|
||||
{Name: "AvgRamGB", Type: "REAL"},
|
||||
{Name: "AvgProvisionedDisk", Type: "REAL"},
|
||||
{Name: "AvgIsPresent", Type: "REAL"},
|
||||
{Name: "PoolTinPct", Type: "REAL"},
|
||||
{Name: "PoolBronzePct", Type: "REAL"},
|
||||
{Name: "PoolSilverPct", Type: "REAL"},
|
||||
@@ -622,8 +679,8 @@ func snapshotTotalsForTable(ctx context.Context, dbConn *sqlx.DB, table string)
|
||||
query := fmt.Sprintf(`
|
||||
SELECT
|
||||
COUNT(DISTINCT "VmId") AS vm_count,
|
||||
COALESCE(SUM(CASE WHEN "InitialVcpus" IS NOT NULL THEN "InitialVcpus" ELSE 0 END), 0) AS vcpu_total,
|
||||
COALESCE(SUM(CASE WHEN "InitialRam" IS NOT NULL THEN "InitialRam" ELSE 0 END), 0) AS ram_total,
|
||||
COALESCE(SUM(CASE WHEN "VcpuCount" IS NOT NULL THEN "VcpuCount" ELSE 0 END), 0) AS vcpu_total,
|
||||
COALESCE(SUM(CASE WHEN "RamGB" IS NOT NULL THEN "RamGB" ELSE 0 END), 0) AS ram_total,
|
||||
COALESCE(SUM(CASE WHEN "ProvisionedDisk" IS NOT NULL THEN "ProvisionedDisk" ELSE 0 END), 0) AS disk_total
|
||||
FROM %s
|
||||
WHERE "IsPresent" = 'TRUE'
|
||||
@@ -640,8 +697,8 @@ func snapshotTotalsForUnion(ctx context.Context, dbConn *sqlx.DB, unionQuery str
|
||||
query := fmt.Sprintf(`
|
||||
SELECT
|
||||
COUNT(DISTINCT "VmId") AS vm_count,
|
||||
COALESCE(SUM(CASE WHEN "InitialVcpus" IS NOT NULL THEN "InitialVcpus" ELSE 0 END), 0) AS vcpu_total,
|
||||
COALESCE(SUM(CASE WHEN "InitialRam" IS NOT NULL THEN "InitialRam" ELSE 0 END), 0) AS ram_total,
|
||||
COALESCE(SUM(CASE WHEN "VcpuCount" IS NOT NULL THEN "VcpuCount" ELSE 0 END), 0) AS vcpu_total,
|
||||
COALESCE(SUM(CASE WHEN "RamGB" IS NOT NULL THEN "RamGB" ELSE 0 END), 0) AS ram_total,
|
||||
COALESCE(SUM(CASE WHEN "ProvisionedDisk" IS NOT NULL THEN "ProvisionedDisk" ELSE 0 END), 0) AS disk_total
|
||||
FROM (
|
||||
%s
|
||||
@@ -694,13 +751,8 @@ func nullFloat64ToFloat(value sql.NullFloat64) float64 {
|
||||
return 0
|
||||
}
|
||||
|
||||
func getEnvInt(key string, fallback int) int {
|
||||
raw := strings.TrimSpace(os.Getenv(key))
|
||||
if raw == "" {
|
||||
return fallback
|
||||
}
|
||||
value, err := strconv.Atoi(raw)
|
||||
if err != nil || value < 0 {
|
||||
func intWithDefault(value int, fallback int) int {
|
||||
if value <= 0 {
|
||||
return fallback
|
||||
}
|
||||
return value
|
||||
@@ -731,8 +783,8 @@ func snapshotFromVM(vmObject *mo.VirtualMachine, vc *vcenter.Vcenter, snapshotTi
|
||||
if !vmObject.Config.CreateDate.IsZero() {
|
||||
row.CreationTime = sql.NullInt64{Int64: vmObject.Config.CreateDate.Unix(), Valid: true}
|
||||
}
|
||||
row.InitialVcpus = sql.NullInt64{Int64: int64(vmObject.Config.Hardware.NumCPU), Valid: vmObject.Config.Hardware.NumCPU > 0}
|
||||
row.InitialRam = sql.NullInt64{Int64: int64(vmObject.Config.Hardware.MemoryMB), Valid: vmObject.Config.Hardware.MemoryMB > 0}
|
||||
row.VcpuCount = sql.NullInt64{Int64: int64(vmObject.Config.Hardware.NumCPU), Valid: vmObject.Config.Hardware.NumCPU > 0}
|
||||
row.RamGB = sql.NullInt64{Int64: int64(vmObject.Config.Hardware.MemoryMB) / 1024, Valid: vmObject.Config.Hardware.MemoryMB > 0}
|
||||
|
||||
totalDiskBytes := int64(0)
|
||||
for _, device := range vmObject.Config.Hardware.Device {
|
||||
@@ -774,11 +826,11 @@ func snapshotFromVM(vmObject *mo.VirtualMachine, vc *vcenter.Vcenter, snapshotTi
|
||||
if !row.ProvisionedDisk.Valid {
|
||||
row.ProvisionedDisk = inv.ProvisionedDisk
|
||||
}
|
||||
if !row.InitialVcpus.Valid {
|
||||
row.InitialVcpus = inv.InitialVcpus
|
||||
if !row.VcpuCount.Valid {
|
||||
row.VcpuCount = inv.InitialVcpus
|
||||
}
|
||||
if !row.InitialRam.Valid {
|
||||
row.InitialRam = inv.InitialRam
|
||||
if !row.RamGB.Valid && inv.InitialRam.Valid {
|
||||
row.RamGB = sql.NullInt64{Int64: inv.InitialRam.Int64 / 1024, Valid: inv.InitialRam.Int64 > 0}
|
||||
}
|
||||
if row.IsTemplate == "" {
|
||||
row.IsTemplate = boolStringFromInterface(inv.IsTemplate)
|
||||
@@ -837,8 +889,8 @@ func snapshotFromInventory(inv queries.Inventory, snapshotTime time.Time) invent
|
||||
Cluster: inv.Cluster,
|
||||
Folder: inv.Folder,
|
||||
ProvisionedDisk: inv.ProvisionedDisk,
|
||||
InitialVcpus: inv.InitialVcpus,
|
||||
InitialRam: inv.InitialRam,
|
||||
VcpuCount: inv.InitialVcpus,
|
||||
RamGB: sql.NullInt64{Int64: inv.InitialRam.Int64 / 1024, Valid: inv.InitialRam.Valid && inv.InitialRam.Int64 > 0},
|
||||
IsTemplate: boolStringFromInterface(inv.IsTemplate),
|
||||
PoweredOn: boolStringFromInterface(inv.PoweredOn),
|
||||
SrmPlaceholder: boolStringFromInterface(inv.SrmPlaceholder),
|
||||
@@ -851,8 +903,8 @@ func insertDailyInventoryRow(ctx context.Context, dbConn *sqlx.DB, tableName str
|
||||
query := fmt.Sprintf(`
|
||||
INSERT INTO %s (
|
||||
"InventoryId", "Name", "Vcenter", "VmId", "EventKey", "CloudId", "CreationTime", "DeletionTime",
|
||||
"ResourcePool", "VmType", "Datacenter", "Cluster", "Folder", "ProvisionedDisk", "InitialVcpus",
|
||||
"InitialRam", "IsTemplate", "PoweredOn", "SrmPlaceholder", "VmUuid", "SnapshotTime", "IsPresent"
|
||||
"ResourcePool", "VmType", "Datacenter", "Cluster", "Folder", "ProvisionedDisk", "VcpuCount",
|
||||
"RamGB", "IsTemplate", "PoweredOn", "SrmPlaceholder", "VmUuid", "SnapshotTime", "IsPresent"
|
||||
)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);
|
||||
`, tableName)
|
||||
@@ -874,8 +926,8 @@ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);
|
||||
row.Cluster,
|
||||
row.Folder,
|
||||
row.ProvisionedDisk,
|
||||
row.InitialVcpus,
|
||||
row.InitialRam,
|
||||
row.VcpuCount,
|
||||
row.RamGB,
|
||||
row.IsTemplate,
|
||||
row.PoweredOn,
|
||||
row.SrmPlaceholder,
|
||||
|
||||
@@ -262,6 +262,11 @@ func (c *CronTask) AddVmToInventory(vmObject *mo.VirtualMachine, vc *vcenter.Vce
|
||||
return errors.New("can't process empty vm object")
|
||||
}
|
||||
|
||||
if strings.HasPrefix(vmObject.Name, "vCLS-") {
|
||||
c.Logger.Debug("Skipping internal vCLS VM", "vm_name", vmObject.Name)
|
||||
return nil
|
||||
}
|
||||
|
||||
c.Logger.Debug("found VM")
|
||||
|
||||
/*
|
||||
|
||||
@@ -83,6 +83,14 @@ func (c *CronTask) RunVmCheck(ctx context.Context, logger *slog.Logger) error {
|
||||
continue
|
||||
}
|
||||
|
||||
if strings.HasPrefix(vmObject.Name, "vCLS-") {
|
||||
c.Logger.Info("Skipping internal vCLS VM event", "vm_name", vmObject.Name)
|
||||
if err := c.Database.Queries().UpdateEventsProcessed(ctx, evt.Eid); err != nil {
|
||||
c.Logger.Error("Unable to mark vCLS event as processed", "event_id", evt.Eid, "error", err)
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
//c.Logger.Debug("found VM")
|
||||
srmPlaceholder = "FALSE" // Default assumption
|
||||
//prettyPrint(vmObject)
|
||||
|
||||
Reference in New Issue
Block a user