Refactor code to use 'any' type and improve context handling
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
This commit is contained in:
@@ -238,7 +238,7 @@ func CreateUpdatesReport(logger *slog.Logger, Database db.Database, ctx context.
|
||||
}
|
||||
|
||||
// Helper function to get the actual value of sql.Null types
|
||||
func getFieldValue(field reflect.Value) interface{} {
|
||||
func getFieldValue(field reflect.Value) any {
|
||||
switch field.Kind() {
|
||||
case reflect.Struct:
|
||||
// Handle sql.Null types based on their concrete type
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
"math"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"slices"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
@@ -844,8 +845,8 @@ func addTotalsChartSheet(logger *slog.Logger, database db.Database, ctx context.
|
||||
if logger == nil {
|
||||
logger = slog.Default()
|
||||
}
|
||||
if strings.HasPrefix(tableName, "inventory_daily_summary_") {
|
||||
suffix := strings.TrimPrefix(tableName, "inventory_daily_summary_")
|
||||
if after, ok := strings.CutPrefix(tableName, "inventory_daily_summary_"); ok {
|
||||
suffix := after
|
||||
dayStart, err := time.ParseInLocation("20060102", suffix, time.Local)
|
||||
if err != nil {
|
||||
logger.Debug("hourly totals skip: invalid daily summary suffix", "table", tableName, "suffix", suffix, "error", err)
|
||||
@@ -878,8 +879,8 @@ func addTotalsChartSheet(logger *slog.Logger, database db.Database, ctx context.
|
||||
return
|
||||
}
|
||||
|
||||
if strings.HasPrefix(tableName, "inventory_monthly_summary_") {
|
||||
suffix := strings.TrimPrefix(tableName, "inventory_monthly_summary_")
|
||||
if after, ok := strings.CutPrefix(tableName, "inventory_monthly_summary_"); ok {
|
||||
suffix := after
|
||||
monthStart, err := time.ParseInLocation("200601", suffix, time.Local)
|
||||
if err != nil {
|
||||
logger.Debug("daily totals skip: invalid monthly summary suffix", "table", tableName, "suffix", suffix, "error", err)
|
||||
@@ -1001,10 +1002,7 @@ func titleCellFromPivotRange(pivotRange, fallback string) string {
|
||||
if err != nil {
|
||||
return fallback
|
||||
}
|
||||
titleRow := row - 2
|
||||
if titleRow < 1 {
|
||||
titleRow = 1
|
||||
}
|
||||
titleRow := max(row-2, 1)
|
||||
cell, err := excelize.CoordinatesToCellName(col, titleRow)
|
||||
if err != nil {
|
||||
return fallback
|
||||
@@ -1356,16 +1354,16 @@ func reportTypeFromTable(tableName string) string {
|
||||
}
|
||||
|
||||
func reportWindowFromTable(tableName string) (time.Time, time.Time, bool) {
|
||||
if strings.HasPrefix(tableName, "inventory_daily_summary_") {
|
||||
suffix := strings.TrimPrefix(tableName, "inventory_daily_summary_")
|
||||
if after, ok := strings.CutPrefix(tableName, "inventory_daily_summary_"); ok {
|
||||
suffix := after
|
||||
dayStart, err := time.ParseInLocation("20060102", suffix, time.Local)
|
||||
if err != nil {
|
||||
return time.Time{}, time.Time{}, false
|
||||
}
|
||||
return dayStart, dayStart.AddDate(0, 0, 1), true
|
||||
}
|
||||
if strings.HasPrefix(tableName, "inventory_monthly_summary_") {
|
||||
suffix := strings.TrimPrefix(tableName, "inventory_monthly_summary_")
|
||||
if after, ok := strings.CutPrefix(tableName, "inventory_monthly_summary_"); ok {
|
||||
suffix := after
|
||||
monthStart, err := time.ParseInLocation("200601", suffix, time.Local)
|
||||
if err != nil {
|
||||
return time.Time{}, time.Time{}, false
|
||||
@@ -1383,7 +1381,7 @@ func addReportMetadataSheet(logger *slog.Logger, xlsx *excelize.File, meta repor
|
||||
}
|
||||
rows := []struct {
|
||||
key string
|
||||
value interface{}
|
||||
value any
|
||||
}{
|
||||
{"ReportTable", meta.TableName},
|
||||
{"ReportType", meta.ReportType},
|
||||
@@ -1398,28 +1396,28 @@ func addReportMetadataSheet(logger *slog.Logger, xlsx *excelize.File, meta repor
|
||||
rows = append(rows,
|
||||
struct {
|
||||
key string
|
||||
value interface{}
|
||||
value any
|
||||
}{"DataWindowStart", meta.WindowStart.Format(time.RFC3339)},
|
||||
struct {
|
||||
key string
|
||||
value interface{}
|
||||
value any
|
||||
}{"DataWindowEnd", meta.WindowEnd.Format(time.RFC3339)},
|
||||
struct {
|
||||
key string
|
||||
value interface{}
|
||||
value any
|
||||
}{"DataWindowTimezone", time.Local.String()},
|
||||
)
|
||||
}
|
||||
if meta.DBDriver != "" {
|
||||
rows = append(rows, struct {
|
||||
key string
|
||||
value interface{}
|
||||
value any
|
||||
}{"DatabaseDriver", meta.DBDriver})
|
||||
}
|
||||
if meta.Duration > 0 && meta.RowCount > 0 {
|
||||
rows = append(rows, struct {
|
||||
key string
|
||||
value interface{}
|
||||
value any
|
||||
}{"RowsPerSecond", math.Round((float64(meta.RowCount)/meta.Duration.Seconds())*1000) / 1000})
|
||||
}
|
||||
for i, row := range rows {
|
||||
@@ -1433,9 +1431,9 @@ func addReportMetadataSheet(logger *slog.Logger, xlsx *excelize.File, meta repor
|
||||
}
|
||||
}
|
||||
|
||||
func scanRowValues(rows *sqlx.Rows, columnCount int) ([]interface{}, error) {
|
||||
rawValues := make([]interface{}, columnCount)
|
||||
scanArgs := make([]interface{}, columnCount)
|
||||
func scanRowValues(rows *sqlx.Rows, columnCount int) ([]any, error) {
|
||||
rawValues := make([]any, columnCount)
|
||||
scanArgs := make([]any, columnCount)
|
||||
for i := range rawValues {
|
||||
scanArgs[i] = &rawValues[i]
|
||||
}
|
||||
@@ -1445,7 +1443,7 @@ func scanRowValues(rows *sqlx.Rows, columnCount int) ([]interface{}, error) {
|
||||
return rawValues, nil
|
||||
}
|
||||
|
||||
func normalizeCellValue(value interface{}) interface{} {
|
||||
func normalizeCellValue(value any) any {
|
||||
switch v := value.(type) {
|
||||
case nil:
|
||||
return ""
|
||||
@@ -1749,14 +1747,14 @@ FROM diag, agg_diag
|
||||
DeletedInInterval int64 `db:"deleted_in_interval"`
|
||||
PartialPresence int64 `db:"partial_presence"`
|
||||
}
|
||||
overlapArgs := []interface{}{
|
||||
overlapArgs := []any{
|
||||
hourEndUnix, hourEndUnix,
|
||||
hourStartUnix, hourStartUnix,
|
||||
hourEndUnix, hourEndUnix,
|
||||
hourStartUnix, hourStartUnix,
|
||||
durationSeconds,
|
||||
}
|
||||
args := make([]interface{}, 0, len(overlapArgs)*3+6)
|
||||
args := make([]any, 0, len(overlapArgs)*3+6)
|
||||
args = append(args, overlapArgs...)
|
||||
args = append(args, overlapArgs...)
|
||||
args = append(args, hourStartUnix, hourEndUnix)
|
||||
@@ -1847,7 +1845,7 @@ func estimateSnapshotInterval(records []SnapshotRecord) time.Duration {
|
||||
if len(diffs) == 0 {
|
||||
return time.Hour
|
||||
}
|
||||
sort.Slice(diffs, func(i, j int) bool { return diffs[i] < diffs[j] })
|
||||
slices.Sort(diffs)
|
||||
median := diffs[len(diffs)/2]
|
||||
if median <= 0 {
|
||||
return time.Hour
|
||||
@@ -2032,7 +2030,7 @@ func writeTotalsChart(logger *slog.Logger, xlsx *excelize.File, sheetName string
|
||||
makeChart("K52", "F", "G", "H", "I")
|
||||
}
|
||||
|
||||
func formatEpochHuman(value interface{}) string {
|
||||
func formatEpochHuman(value any) string {
|
||||
var epoch int64
|
||||
switch v := value.(type) {
|
||||
case nil:
|
||||
|
||||
@@ -21,7 +21,7 @@ func TestAddSummaryPivotSheetCreatesPivotTables(t *testing.T) {
|
||||
t.Fatalf("SetSheetRow header failed: %v", err)
|
||||
}
|
||||
|
||||
row1 := []interface{}{"vm-1", "dc-1", "pool-1", 4.0, 16.0, 1.0}
|
||||
row1 := []any{"vm-1", "dc-1", "pool-1", 4.0, 16.0, 1.0}
|
||||
if err := xlsx.SetSheetRow(dataSheet, "A2", &row1); err != nil {
|
||||
t.Fatalf("SetSheetRow data failed: %v", err)
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ import (
|
||||
"strings"
|
||||
"vctp/internal/utils"
|
||||
|
||||
"gopkg.in/yaml.v2"
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
var (
|
||||
|
||||
@@ -180,7 +180,7 @@ WHERE job_name = ?
|
||||
return err
|
||||
}
|
||||
|
||||
func nullableString(s string) interface{} {
|
||||
func nullableString(s string) any {
|
||||
if s == "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ import (
|
||||
"log/slog"
|
||||
"os"
|
||||
"runtime"
|
||||
"sort"
|
||||
"slices"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
@@ -295,7 +295,7 @@ func (c *CronTask) aggregateDailySummaryGo(ctx context.Context, dayStart, dayEnd
|
||||
for _, snap := range hourlySnapshots {
|
||||
snapTimes = append(snapTimes, snap.SnapshotTime.Unix())
|
||||
}
|
||||
sort.Slice(snapTimes, func(i, j int) bool { return snapTimes[i] < snapTimes[j] })
|
||||
slices.Sort(snapTimes)
|
||||
}
|
||||
|
||||
lifecycleDeletions := c.applyLifecycleDeletions(ctx, aggMap, dayStart, dayEnd)
|
||||
@@ -353,7 +353,7 @@ LIMIT 1
|
||||
for t := range set {
|
||||
times = append(times, t)
|
||||
}
|
||||
sort.Slice(times, func(i, j int) bool { return times[i] < times[j] })
|
||||
slices.Sort(times)
|
||||
vcenterSnapTimes[vcenter] = times
|
||||
}
|
||||
|
||||
@@ -843,20 +843,12 @@ func (c *CronTask) applyInventoryCreations(ctx context.Context, agg map[dailyAgg
|
||||
func (c *CronTask) scanHourlyTablesParallel(ctx context.Context, snapshots []report.SnapshotRecord) (map[dailyAggKey]*dailyAggVal, error) {
|
||||
agg := make(map[dailyAggKey]*dailyAggVal, 1024)
|
||||
mu := sync.Mutex{}
|
||||
workers := runtime.NumCPU()
|
||||
if workers < 2 {
|
||||
workers = 2
|
||||
}
|
||||
if workers > len(snapshots) {
|
||||
workers = len(snapshots)
|
||||
}
|
||||
workers := min(max(runtime.NumCPU(), 2), len(snapshots))
|
||||
|
||||
jobs := make(chan report.SnapshotRecord, len(snapshots))
|
||||
wg := sync.WaitGroup{}
|
||||
for i := 0; i < workers; i++ {
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
wg.Go(func() {
|
||||
for snap := range jobs {
|
||||
rows, err := c.scanHourlyTable(ctx, snap)
|
||||
if err != nil {
|
||||
@@ -873,7 +865,7 @@ func (c *CronTask) scanHourlyTablesParallel(ctx context.Context, snapshots []rep
|
||||
}
|
||||
mu.Unlock()
|
||||
}
|
||||
}()
|
||||
})
|
||||
}
|
||||
for _, snap := range snapshots {
|
||||
jobs <- snap
|
||||
@@ -1114,7 +1106,7 @@ WHERE "SnapshotTime" >= ? AND "SnapshotTime" < ?`
|
||||
for t := range timeSet {
|
||||
snapTimes = append(snapTimes, t)
|
||||
}
|
||||
sort.Slice(snapTimes, func(i, j int) bool { return snapTimes[i] < snapTimes[j] })
|
||||
slices.Sort(snapTimes)
|
||||
return agg, snapTimes, rows.Err()
|
||||
}
|
||||
|
||||
@@ -1166,7 +1158,7 @@ INSERT INTO %s (
|
||||
silverPct = float64(v.silverHits) * 100 / float64(v.samples)
|
||||
goldPct = float64(v.goldHits) * 100 / float64(v.samples)
|
||||
}
|
||||
args := []interface{}{
|
||||
args := []any{
|
||||
v.key.Name,
|
||||
v.key.Vcenter,
|
||||
nullIfEmpty(v.key.VmId),
|
||||
@@ -1214,7 +1206,7 @@ func int64OrZero(v sql.NullInt64) int64 {
|
||||
return 0
|
||||
}
|
||||
|
||||
func nullIfEmpty(s string) interface{} {
|
||||
func nullIfEmpty(s string) any {
|
||||
if strings.TrimSpace(s) == "" {
|
||||
return nil
|
||||
}
|
||||
@@ -1224,13 +1216,13 @@ func nullIfEmpty(s string) interface{} {
|
||||
func makePlaceholders(driver string, n int) string {
|
||||
if driver == "sqlite" {
|
||||
parts := make([]string, n)
|
||||
for i := 0; i < n; i++ {
|
||||
for i := range n {
|
||||
parts[i] = "?"
|
||||
}
|
||||
return strings.Join(parts, ",")
|
||||
}
|
||||
parts := make([]string, n)
|
||||
for i := 0; i < n; i++ {
|
||||
for i := range n {
|
||||
parts[i] = fmt.Sprintf("$%d", i+1)
|
||||
}
|
||||
return strings.Join(parts, ",")
|
||||
|
||||
@@ -61,7 +61,7 @@ func insertHourlyCache(ctx context.Context, dbConn *sqlx.DB, rows []InventorySna
|
||||
defer stmt.Close()
|
||||
|
||||
for _, r := range rows {
|
||||
args := []interface{}{
|
||||
args := []any{
|
||||
r.SnapshotTime, r.Vcenter, r.VmId, r.VmUuid, r.Name, r.CreationTime, r.DeletionTime, r.ResourcePool,
|
||||
r.Datacenter, r.Cluster, r.Folder, r.ProvisionedDisk, r.VcpuCount, r.RamGB, r.IsTemplate, r.PoweredOn, r.SrmPlaceholder,
|
||||
}
|
||||
@@ -105,7 +105,7 @@ func insertHourlyBatch(ctx context.Context, dbConn *sqlx.DB, tableName string, r
|
||||
}
|
||||
defer stmt.Close()
|
||||
for _, row := range rows {
|
||||
args := []interface{}{
|
||||
args := []any{
|
||||
row.InventoryId,
|
||||
row.Name,
|
||||
row.Vcenter,
|
||||
@@ -138,7 +138,7 @@ func insertHourlyBatch(ctx context.Context, dbConn *sqlx.DB, tableName string, r
|
||||
defer stmt.Close()
|
||||
|
||||
for _, row := range rows {
|
||||
args := []interface{}{
|
||||
args := []any{
|
||||
row.InventoryId,
|
||||
row.Name,
|
||||
row.Vcenter,
|
||||
|
||||
@@ -27,7 +27,7 @@ func acquireSnapshotProbe(ctx context.Context) (func(), error) {
|
||||
}
|
||||
}
|
||||
|
||||
func boolStringFromInterface(value interface{}) string {
|
||||
func boolStringFromInterface(value any) string {
|
||||
switch v := value.(type) {
|
||||
case nil:
|
||||
return ""
|
||||
@@ -164,7 +164,7 @@ func SnapshotTooSoon(prevUnix, currUnix int64, expectedSeconds int64) bool {
|
||||
}
|
||||
|
||||
// querySnapshotRows builds a SELECT with proper rebind for the given table/columns/where.
|
||||
func querySnapshotRows(ctx context.Context, dbConn *sqlx.DB, table string, columns []string, where string, args ...interface{}) (*sqlx.Rows, error) {
|
||||
func querySnapshotRows(ctx context.Context, dbConn *sqlx.DB, table string, columns []string, where string, args ...any) (*sqlx.Rows, error) {
|
||||
if err := db.ValidateTableName(table); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -24,8 +24,6 @@ import (
|
||||
"github.com/vmware/govmomi/vim25/types"
|
||||
)
|
||||
|
||||
type ctxLoggerKey struct{}
|
||||
|
||||
type deletionCandidate struct {
|
||||
vmID string
|
||||
vmUUID string
|
||||
@@ -42,10 +40,7 @@ type vcenterResources struct {
|
||||
}
|
||||
|
||||
func loggerFromCtx(ctx context.Context, fallback *slog.Logger) *slog.Logger {
|
||||
if ctx == nil {
|
||||
return fallback
|
||||
}
|
||||
if l, ok := ctx.Value(ctxLoggerKey{}).(*slog.Logger); ok && l != nil {
|
||||
if l := db.LoggerFromContext(ctx); l != nil {
|
||||
return l
|
||||
}
|
||||
return fallback
|
||||
@@ -132,10 +127,7 @@ func (c *CronTask) RunVcenterSnapshotHourly(ctx context.Context, logger *slog.Lo
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
minIntervalSeconds := intWithDefault(c.Settings.Values.Settings.VcenterInventorySnapshotSeconds, 3600) / 3
|
||||
if minIntervalSeconds < 1 {
|
||||
minIntervalSeconds = 1
|
||||
}
|
||||
minIntervalSeconds := max(intWithDefault(c.Settings.Values.Settings.VcenterInventorySnapshotSeconds, 3600)/3, 1)
|
||||
if !lastSnapshot.IsZero() && startTime.Sub(lastSnapshot) < time.Duration(minIntervalSeconds)*time.Second {
|
||||
c.Logger.Info("Skipping hourly snapshot, last snapshot too recent",
|
||||
"last_snapshot", lastSnapshot,
|
||||
@@ -217,7 +209,7 @@ func (c *CronTask) RunVcenterSnapshotHourly(ctx context.Context, logger *slog.Lo
|
||||
|
||||
metrics.RecordHourlySnapshot(startTime, rowCount, err)
|
||||
var deferredTables []string
|
||||
deferredReportTables.Range(func(key, _ interface{}) bool {
|
||||
deferredReportTables.Range(func(key, _ any) bool {
|
||||
name, ok := key.(string)
|
||||
if ok && strings.TrimSpace(name) != "" && name != tableName {
|
||||
deferredTables = append(deferredTables, name)
|
||||
@@ -488,10 +480,7 @@ func buildUnionQuery(tables []string, columns []string, whereClause string) (str
|
||||
batches := make([]string, 0, (len(tables)/maxCompoundTerms)+1)
|
||||
batchIndex := 0
|
||||
for start := 0; start < len(tables); start += maxCompoundTerms {
|
||||
end := start + maxCompoundTerms
|
||||
if end > len(tables) {
|
||||
end = len(tables)
|
||||
}
|
||||
end := min(start+maxCompoundTerms, len(tables))
|
||||
queries := make([]string, 0, end-start)
|
||||
for _, table := range tables[start:end] {
|
||||
safeName, err := db.SafeTableName(table)
|
||||
@@ -1337,7 +1326,7 @@ func (c *CronTask) initVcenterResources(ctx context.Context, log *slog.Logger, u
|
||||
|
||||
func (c *CronTask) captureHourlySnapshotForVcenter(ctx context.Context, startTime time.Time, tableName string, url string, deferredReportTables *sync.Map) error {
|
||||
log := c.Logger.With("vcenter", url)
|
||||
ctx = context.WithValue(ctx, ctxLoggerKey{}, log)
|
||||
ctx = db.WithLoggerContext(ctx, log)
|
||||
started := time.Now()
|
||||
log.Debug("connecting to vcenter for hourly snapshot", "url", url)
|
||||
vc, resources, cleanup, err := c.initVcenterResources(ctx, log, url, startTime, started)
|
||||
|
||||
@@ -7,7 +7,7 @@ import (
|
||||
"log/slog"
|
||||
"os"
|
||||
"runtime"
|
||||
"sort"
|
||||
"slices"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
@@ -246,7 +246,7 @@ func (c *CronTask) aggregateMonthlySummaryGoHourly(ctx context.Context, monthSta
|
||||
for _, snap := range hourlySnapshots {
|
||||
snapTimes = append(snapTimes, snap.SnapshotTime.Unix())
|
||||
}
|
||||
sort.Slice(snapTimes, func(i, j int) bool { return snapTimes[i] < snapTimes[j] })
|
||||
slices.Sort(snapTimes)
|
||||
}
|
||||
|
||||
lifecycleDeletions := c.applyLifecycleDeletions(ctx, aggMap, monthStart, monthEnd)
|
||||
@@ -394,20 +394,12 @@ func (c *CronTask) aggregateMonthlySummaryGo(ctx context.Context, monthStart, mo
|
||||
func (c *CronTask) scanDailyTablesParallel(ctx context.Context, snapshots []report.SnapshotRecord) (map[monthlyAggKey]*monthlyAggVal, error) {
|
||||
agg := make(map[monthlyAggKey]*monthlyAggVal, 1024)
|
||||
mu := sync.Mutex{}
|
||||
workers := runtime.NumCPU()
|
||||
if workers < 2 {
|
||||
workers = 2
|
||||
}
|
||||
if workers > len(snapshots) {
|
||||
workers = len(snapshots)
|
||||
}
|
||||
workers := min(max(runtime.NumCPU(), 2), len(snapshots))
|
||||
|
||||
jobs := make(chan report.SnapshotRecord, len(snapshots))
|
||||
wg := sync.WaitGroup{}
|
||||
for i := 0; i < workers; i++ {
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
wg.Go(func() {
|
||||
for snap := range jobs {
|
||||
rows, err := c.scanDailyTable(ctx, snap)
|
||||
if err != nil {
|
||||
@@ -424,7 +416,7 @@ func (c *CronTask) scanDailyTablesParallel(ctx context.Context, snapshots []repo
|
||||
}
|
||||
mu.Unlock()
|
||||
}
|
||||
}()
|
||||
})
|
||||
}
|
||||
for _, snap := range snapshots {
|
||||
jobs <- snap
|
||||
|
||||
Reference in New Issue
Block a user