From c8bb30c788f1c6b938295c5ffb1146da1571ced3 Mon Sep 17 00:00:00 2001 From: Nathan Coad Date: Tue, 20 Jan 2026 17:18:43 +1100 Subject: [PATCH] better handle skipped inventories --- README.md | 2 +- internal/tasks/inventorySnapshots.go | 35 ++++++++++++++++++++-------- main.go | 6 +++-- server/handler/vmTrace.go | 3 ++- 4 files changed, 32 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index d73f179..eb80478 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,7 @@ If you just want to run a single inventory snapshot across all configured vCente exit (no scheduler/server), use: ```shell -vctp -settings /path/to/vctp.yml -run-inventory-once +vctp -settings /path/to/vctp.yml -run-inventory ``` ### Database Configuration diff --git a/internal/tasks/inventorySnapshots.go b/internal/tasks/inventorySnapshots.go index fccf7f7..339b86d 100644 --- a/internal/tasks/inventorySnapshots.go +++ b/internal/tasks/inventorySnapshots.go @@ -1086,21 +1086,36 @@ func (c *CronTask) captureHourlySnapshotForVcenter(ctx context.Context, startTim c.Logger.Warn("failed to locate previous hourly snapshot for deletion comparison", "error", prevTableErr, "url", url) } + prevSnapshotTime := int64(0) + if prevTableName != "" { + if suffix := strings.TrimPrefix(prevTableName, "inventory_hourly_"); suffix != prevTableName { + if ts, err := strconv.ParseInt(suffix, 10, 64); err == nil { + prevSnapshotTime = ts + } + } + } + if prevTableName != "" { moreMissing := c.markMissingFromPrevious(ctx, dbConn, prevTableName, url, startTime, presentSnapshots, presentByUuid, presentByName, inventoryByVmID, inventoryByUuid, inventoryByName) missingCount += moreMissing - newCount = countNewFromPrevious(ctx, dbConn, prevTableName, url, presentSnapshots) - if newCount > 0 { - newRows := listNewFromPrevious(ctx, dbConn, prevTableName, url, presentSnapshots) - names := make([]string, 0, len(newRows)) - for _, r := range newRows { - if r.Name != "" { - names = append(names, r.Name) - } else if r.VmId.Valid { - names = append(names, r.VmId.String) + // Guard against gaps: if previous snapshot is much older than expected, skip "new" detection to avoid false positives when an hourly run was missed. + snapshotPeriod := durationFromSeconds(c.Settings.Values.Settings.VcenterInventorySnapshotSeconds, time.Hour).Seconds() + if prevSnapshotTime > 0 && startTime.Unix()-prevSnapshotTime > int64(snapshotPeriod*2) { + c.Logger.Info("skipping new-VM detection due to gap between snapshots", "prev_table", prevTableName, "prev_snapshot_unix", prevSnapshotTime, "current_snapshot_unix", startTime.Unix()) + } else { + newCount = countNewFromPrevious(ctx, dbConn, prevTableName, url, presentSnapshots) + if newCount > 0 { + newRows := listNewFromPrevious(ctx, dbConn, prevTableName, url, presentSnapshots) + names := make([]string, 0, len(newRows)) + for _, r := range newRows { + if r.Name != "" { + names = append(names, r.Name) + } else if r.VmId.Valid { + names = append(names, r.VmId.String) + } } + c.Logger.Info("new VMs since previous snapshot", "prev_table", prevTableName, "count", newCount, "names", names) } - c.Logger.Info("new VMs since previous snapshot", "prev_table", prevTableName, "count", newCount, "names", names) } c.Logger.Debug("compared with previous snapshot", "prev_table", prevTableName, "new_since_prev", newCount, "missing_since_prev", missingCount) } else { diff --git a/main.go b/main.go index dbed5f0..0d0e559 100644 --- a/main.go +++ b/main.go @@ -38,7 +38,7 @@ const fallbackEncryptionKey = "5L1l3B5KvwOCzUHMAlCgsgUTRAYMfSpa" func main() { settingsPath := flag.String("settings", "/etc/dtms/vctp.yml", "Path to settings YAML") - runInventoryOnce := flag.Bool("run-inventory", false, "Run a single inventory snapshot across all configured vCenters and exit") + runInventory := flag.Bool("run-inventory", false, "Run a single inventory snapshot across all configured vCenters and exit") flag.Parse() bootstrapLogger := log.New(log.LevelInfo, log.OutputText) @@ -59,6 +59,8 @@ func main() { ) s.Logger = logger + logger.Info("vCTP starting", "build_time", buildTime, "sha1_version", sha1ver, "go_version", runtime.Version(), "settings_file", *settingsPath) + // Configure database dbDriver := strings.TrimSpace(s.Values.Settings.DatabaseDriver) if dbDriver == "" { @@ -181,7 +183,7 @@ func main() { } // One-shot mode: run a single inventory snapshot across all configured vCenters and exit. - if *runInventoryOnce { + if *runInventory { logger.Info("Running one-shot inventory snapshot across all vCenters") ct.RunVcenterSnapshotHourly(ctx, logger) logger.Info("One-shot inventory snapshot complete; exiting") diff --git a/server/handler/vmTrace.go b/server/handler/vmTrace.go index c0fe92e..ca53858 100644 --- a/server/handler/vmTrace.go +++ b/server/handler/vmTrace.go @@ -83,7 +83,8 @@ func (h *Handler) VmTrace(w http.ResponseWriter, r *http.Request) { ts := time.Unix(lifecycle.CreationTime, 0).Local().Format("2006-01-02 15:04:05") if lifecycle.CreationApprox { creationLabel = fmt.Sprintf("%s (approx. earliest snapshot)", ts) - creationApprox = true + // dont double up on the approximate text + //creationApprox = true } else { creationLabel = ts }