lifecycle diagnostics
All checks were successful
continuous-integration/drone/push Build is passing

This commit is contained in:
2026-02-09 14:27:41 +11:00
parent 59b16db04f
commit 6dcbb9caef
8 changed files with 498 additions and 134 deletions

View File

@@ -38,7 +38,7 @@ func Header() templ.Component {
var templ_7745c5c3_Var2 string
templ_7745c5c3_Var2, templ_7745c5c3_Err = templ.JoinStringErrs("/assets/js/web3-charts.js?v=" + version.Value)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `core/header.templ`, Line: 15, Col: 62}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/core/header.templ`, Line: 15, Col: 62}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var2))
if templ_7745c5c3_Err != nil {
@@ -51,7 +51,7 @@ func Header() templ.Component {
var templ_7745c5c3_Var3 templ.SafeURL
templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinURLErrs("/assets/css/output@" + version.Value + ".css")
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `core/header.templ`, Line: 16, Col: 61}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/core/header.templ`, Line: 16, Col: 61}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3))
if templ_7745c5c3_Err != nil {

View File

@@ -54,7 +54,7 @@ func Index(info BuildInfo) templ.Component {
var templ_7745c5c3_Var2 string
templ_7745c5c3_Var2, templ_7745c5c3_Err = templ.JoinStringErrs(info.BuildTime)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `views/index.templ`, Line: 40, Col: 59}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/views/index.templ`, Line: 40, Col: 59}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var2))
if templ_7745c5c3_Err != nil {
@@ -67,7 +67,7 @@ func Index(info BuildInfo) templ.Component {
var templ_7745c5c3_Var3 string
templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(info.SHA1Ver)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `views/index.templ`, Line: 44, Col: 57}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/views/index.templ`, Line: 44, Col: 57}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3))
if templ_7745c5c3_Err != nil {
@@ -80,7 +80,7 @@ func Index(info BuildInfo) templ.Component {
var templ_7745c5c3_Var4 string
templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(info.GoVersion)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `views/index.templ`, Line: 48, Col: 59}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/views/index.templ`, Line: 48, Col: 59}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var4))
if templ_7745c5c3_Err != nil {

View File

@@ -166,7 +166,7 @@ func SnapshotListPage(title string, subtitle string, entries []SnapshotEntry) te
var templ_7745c5c3_Var5 string
templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.JoinStringErrs(title)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `views/snapshots.templ`, Line: 60, Col: 50}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/views/snapshots.templ`, Line: 60, Col: 50}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var5))
if templ_7745c5c3_Err != nil {
@@ -179,7 +179,7 @@ func SnapshotListPage(title string, subtitle string, entries []SnapshotEntry) te
var templ_7745c5c3_Var6 string
templ_7745c5c3_Var6, templ_7745c5c3_Err = templ.JoinStringErrs(subtitle)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `views/snapshots.templ`, Line: 61, Col: 56}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/views/snapshots.templ`, Line: 61, Col: 56}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var6))
if templ_7745c5c3_Err != nil {
@@ -192,7 +192,7 @@ func SnapshotListPage(title string, subtitle string, entries []SnapshotEntry) te
var templ_7745c5c3_Var7 string
templ_7745c5c3_Var7, templ_7745c5c3_Err = templ.JoinStringErrs(len(entries))
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `views/snapshots.templ`, Line: 69, Col: 45}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/views/snapshots.templ`, Line: 69, Col: 45}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var7))
if templ_7745c5c3_Err != nil {
@@ -211,7 +211,7 @@ func SnapshotListPage(title string, subtitle string, entries []SnapshotEntry) te
var templ_7745c5c3_Var8 string
templ_7745c5c3_Var8, templ_7745c5c3_Err = templ.JoinStringErrs(entry.Group)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `views/snapshots.templ`, Line: 84, Col: 77}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/views/snapshots.templ`, Line: 84, Col: 77}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var8))
if templ_7745c5c3_Err != nil {
@@ -229,7 +229,7 @@ func SnapshotListPage(title string, subtitle string, entries []SnapshotEntry) te
var templ_7745c5c3_Var9 string
templ_7745c5c3_Var9, templ_7745c5c3_Err = templ.JoinStringErrs(entry.Label)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `views/snapshots.templ`, Line: 90, Col: 76}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/views/snapshots.templ`, Line: 90, Col: 76}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var9))
if templ_7745c5c3_Err != nil {
@@ -242,7 +242,7 @@ func SnapshotListPage(title string, subtitle string, entries []SnapshotEntry) te
var templ_7745c5c3_Var10 string
templ_7745c5c3_Var10, templ_7745c5c3_Err = templ.JoinStringErrs(entry.Count)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `views/snapshots.templ`, Line: 94, Col: 49}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/views/snapshots.templ`, Line: 94, Col: 49}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var10))
if templ_7745c5c3_Err != nil {
@@ -255,7 +255,7 @@ func SnapshotListPage(title string, subtitle string, entries []SnapshotEntry) te
var templ_7745c5c3_Var11 templ.SafeURL
templ_7745c5c3_Var11, templ_7745c5c3_Err = templ.JoinURLErrs(entry.Link)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `views/snapshots.templ`, Line: 97, Col: 49}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/views/snapshots.templ`, Line: 97, Col: 49}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var11))
if templ_7745c5c3_Err != nil {
@@ -318,7 +318,7 @@ func VcenterList(links []VcenterLink) templ.Component {
var templ_7745c5c3_Var13 string
templ_7745c5c3_Var13, templ_7745c5c3_Err = templ.JoinStringErrs(len(links))
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `views/snapshots.templ`, Line: 130, Col: 43}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/views/snapshots.templ`, Line: 130, Col: 43}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var13))
if templ_7745c5c3_Err != nil {
@@ -336,7 +336,7 @@ func VcenterList(links []VcenterLink) templ.Component {
var templ_7745c5c3_Var14 string
templ_7745c5c3_Var14, templ_7745c5c3_Err = templ.JoinStringErrs(link.Name)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `views/snapshots.templ`, Line: 143, Col: 62}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/views/snapshots.templ`, Line: 143, Col: 62}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var14))
if templ_7745c5c3_Err != nil {
@@ -349,7 +349,7 @@ func VcenterList(links []VcenterLink) templ.Component {
var templ_7745c5c3_Var15 templ.SafeURL
templ_7745c5c3_Var15, templ_7745c5c3_Err = templ.JoinURLErrs(link.Link)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `views/snapshots.templ`, Line: 145, Col: 48}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/views/snapshots.templ`, Line: 145, Col: 48}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var15))
if templ_7745c5c3_Err != nil {
@@ -412,7 +412,7 @@ func VcenterTotalsPage(vcenter string, entries []VcenterTotalsEntry, chart Vcent
var templ_7745c5c3_Var17 string
templ_7745c5c3_Var17, templ_7745c5c3_Err = templ.JoinStringErrs(vcenter)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `views/snapshots.templ`, Line: 169, Col: 63}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/views/snapshots.templ`, Line: 169, Col: 63}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var17))
if templ_7745c5c3_Err != nil {
@@ -425,7 +425,7 @@ func VcenterTotalsPage(vcenter string, entries []VcenterTotalsEntry, chart Vcent
var templ_7745c5c3_Var18 string
templ_7745c5c3_Var18, templ_7745c5c3_Err = templ.JoinStringErrs(meta.TypeLabel)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `views/snapshots.templ`, Line: 170, Col: 62}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/views/snapshots.templ`, Line: 170, Col: 62}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var18))
if templ_7745c5c3_Err != nil {
@@ -447,7 +447,7 @@ func VcenterTotalsPage(vcenter string, entries []VcenterTotalsEntry, chart Vcent
var templ_7745c5c3_Var20 string
templ_7745c5c3_Var20, templ_7745c5c3_Err = templ.JoinStringErrs(templ.CSSClasses(templ_7745c5c3_Var19).String())
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `views/snapshots.templ`, Line: 1, Col: 0}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/views/snapshots.templ`, Line: 1, Col: 0}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var20))
if templ_7745c5c3_Err != nil {
@@ -460,7 +460,7 @@ func VcenterTotalsPage(vcenter string, entries []VcenterTotalsEntry, chart Vcent
var templ_7745c5c3_Var21 templ.SafeURL
templ_7745c5c3_Var21, templ_7745c5c3_Err = templ.JoinURLErrs(meta.HourlyLink)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `views/snapshots.templ`, Line: 178, Col: 59}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/views/snapshots.templ`, Line: 178, Col: 59}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var21))
if templ_7745c5c3_Err != nil {
@@ -482,7 +482,7 @@ func VcenterTotalsPage(vcenter string, entries []VcenterTotalsEntry, chart Vcent
var templ_7745c5c3_Var23 string
templ_7745c5c3_Var23, templ_7745c5c3_Err = templ.JoinStringErrs(templ.CSSClasses(templ_7745c5c3_Var22).String())
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `views/snapshots.templ`, Line: 1, Col: 0}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/views/snapshots.templ`, Line: 1, Col: 0}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var23))
if templ_7745c5c3_Err != nil {
@@ -495,7 +495,7 @@ func VcenterTotalsPage(vcenter string, entries []VcenterTotalsEntry, chart Vcent
var templ_7745c5c3_Var24 templ.SafeURL
templ_7745c5c3_Var24, templ_7745c5c3_Err = templ.JoinURLErrs(meta.DailyLink)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `views/snapshots.templ`, Line: 179, Col: 57}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/views/snapshots.templ`, Line: 179, Col: 57}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var24))
if templ_7745c5c3_Err != nil {
@@ -508,7 +508,7 @@ func VcenterTotalsPage(vcenter string, entries []VcenterTotalsEntry, chart Vcent
var templ_7745c5c3_Var25 string
templ_7745c5c3_Var25, templ_7745c5c3_Err = templ.JoinStringErrs(meta.TypeLabel)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `views/snapshots.templ`, Line: 184, Col: 56}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/views/snapshots.templ`, Line: 184, Col: 56}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var25))
if templ_7745c5c3_Err != nil {
@@ -521,7 +521,7 @@ func VcenterTotalsPage(vcenter string, entries []VcenterTotalsEntry, chart Vcent
var templ_7745c5c3_Var26 string
templ_7745c5c3_Var26, templ_7745c5c3_Err = templ.JoinStringErrs(len(entries))
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `views/snapshots.templ`, Line: 185, Col: 45}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/views/snapshots.templ`, Line: 185, Col: 45}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var26))
if templ_7745c5c3_Err != nil {
@@ -539,7 +539,7 @@ func VcenterTotalsPage(vcenter string, entries []VcenterTotalsEntry, chart Vcent
var templ_7745c5c3_Var27 string
templ_7745c5c3_Var27, templ_7745c5c3_Err = templ.JoinStringErrs(chart.ConfigJSON)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `views/snapshots.templ`, Line: 190, Col: 145}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/views/snapshots.templ`, Line: 190, Col: 145}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var27))
if templ_7745c5c3_Err != nil {
@@ -562,7 +562,7 @@ func VcenterTotalsPage(vcenter string, entries []VcenterTotalsEntry, chart Vcent
var templ_7745c5c3_Var28 string
templ_7745c5c3_Var28, templ_7745c5c3_Err = templ.JoinStringErrs(entry.Snapshot)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `views/snapshots.templ`, Line: 214, Col: 30}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/views/snapshots.templ`, Line: 214, Col: 30}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var28))
if templ_7745c5c3_Err != nil {
@@ -575,7 +575,7 @@ func VcenterTotalsPage(vcenter string, entries []VcenterTotalsEntry, chart Vcent
var templ_7745c5c3_Var29 string
templ_7745c5c3_Var29, templ_7745c5c3_Err = templ.JoinStringErrs(entry.VmCount)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `views/snapshots.templ`, Line: 215, Col: 48}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/views/snapshots.templ`, Line: 215, Col: 48}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var29))
if templ_7745c5c3_Err != nil {
@@ -588,7 +588,7 @@ func VcenterTotalsPage(vcenter string, entries []VcenterTotalsEntry, chart Vcent
var templ_7745c5c3_Var30 string
templ_7745c5c3_Var30, templ_7745c5c3_Err = templ.JoinStringErrs(entry.VcpuTotal)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `views/snapshots.templ`, Line: 216, Col: 50}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/views/snapshots.templ`, Line: 216, Col: 50}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var30))
if templ_7745c5c3_Err != nil {
@@ -601,7 +601,7 @@ func VcenterTotalsPage(vcenter string, entries []VcenterTotalsEntry, chart Vcent
var templ_7745c5c3_Var31 string
templ_7745c5c3_Var31, templ_7745c5c3_Err = templ.JoinStringErrs(entry.RamTotalGB)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `views/snapshots.templ`, Line: 217, Col: 51}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/views/snapshots.templ`, Line: 217, Col: 51}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var31))
if templ_7745c5c3_Err != nil {

View File

@@ -33,7 +33,17 @@ type VmTraceMeta struct {
DailyClass string
}
templ VmTracePage(query string, display_query string, vm_id string, vm_uuid string, vm_name string, creationLabel string, deletionLabel string, creationApprox bool, entries []VmTraceEntry, chart VmTraceChart, meta VmTraceMeta) {
type VmTraceDiagnosticLine struct {
Label string
Value string
}
type VmTraceDiagnostics struct {
Visible bool
Lines []VmTraceDiagnosticLine
}
templ VmTracePage(query string, display_query string, vm_id string, vm_uuid string, vm_name string, creationLabel string, deletionLabel string, creationApprox bool, entries []VmTraceEntry, chart VmTraceChart, meta VmTraceMeta, diagnostics VmTraceDiagnostics) {
<!DOCTYPE html>
<html lang="en">
@core.Header()
@@ -107,6 +117,23 @@ templ VmTracePage(query string, display_query string, vm_id string, vm_uuid stri
<p class="mt-2 text-base font-semibold text-slate-800">{deletionLabel}</p>
</div>
</div>
if diagnostics.Visible && len(diagnostics.Lines) > 0 {
<details class="web2-card mb-4">
<summary class="cursor-pointer text-sm font-semibold text-slate-700">Lifecycle diagnostics</summary>
<div class="mt-3 overflow-hidden border border-slate-200 rounded">
<table class="web2-table">
<tbody>
for _, line := range diagnostics.Lines {
<tr>
<td class="font-semibold text-slate-700 w-72">{ line.Label }</td>
<td class="text-slate-600">{ line.Value }</td>
</tr>
}
</tbody>
</table>
</div>
</details>
}
<div class="overflow-hidden border border-slate-200 rounded">
<table class="web2-table">
<thead>

View File

@@ -41,7 +41,17 @@ type VmTraceMeta struct {
DailyClass string
}
func VmTracePage(query string, display_query string, vm_id string, vm_uuid string, vm_name string, creationLabel string, deletionLabel string, creationApprox bool, entries []VmTraceEntry, chart VmTraceChart, meta VmTraceMeta) templ.Component {
type VmTraceDiagnosticLine struct {
Label string
Value string
}
type VmTraceDiagnostics struct {
Visible bool
Lines []VmTraceDiagnosticLine
}
func VmTracePage(query string, display_query string, vm_id string, vm_uuid string, vm_name string, creationLabel string, deletionLabel string, creationApprox bool, entries []VmTraceEntry, chart VmTraceChart, meta VmTraceMeta, diagnostics VmTraceDiagnostics) templ.Component {
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
@@ -77,7 +87,7 @@ func VmTracePage(query string, display_query string, vm_id string, vm_uuid strin
var templ_7745c5c3_Var2 string
templ_7745c5c3_Var2, templ_7745c5c3_Err = templ.JoinStringErrs(display_query)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `views/vm_trace.templ`, Line: 46, Col: 74}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/views/vm_trace.templ`, Line: 56, Col: 74}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var2))
if templ_7745c5c3_Err != nil {
@@ -90,7 +100,7 @@ func VmTracePage(query string, display_query string, vm_id string, vm_uuid strin
var templ_7745c5c3_Var3 string
templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(meta.TypeLabel)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `views/vm_trace.templ`, Line: 47, Col: 119}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/views/vm_trace.templ`, Line: 57, Col: 119}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3))
if templ_7745c5c3_Err != nil {
@@ -103,7 +113,7 @@ func VmTracePage(query string, display_query string, vm_id string, vm_uuid strin
var templ_7745c5c3_Var4 string
templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(meta.ViewType)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `views/vm_trace.templ`, Line: 54, Col: 61}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/views/vm_trace.templ`, Line: 64, Col: 61}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var4))
if templ_7745c5c3_Err != nil {
@@ -116,7 +126,7 @@ func VmTracePage(query string, display_query string, vm_id string, vm_uuid strin
var templ_7745c5c3_Var5 string
templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.JoinStringErrs(vm_id)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `views/vm_trace.templ`, Line: 57, Col: 123}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/views/vm_trace.templ`, Line: 67, Col: 123}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var5))
if templ_7745c5c3_Err != nil {
@@ -129,7 +139,7 @@ func VmTracePage(query string, display_query string, vm_id string, vm_uuid strin
var templ_7745c5c3_Var6 string
templ_7745c5c3_Var6, templ_7745c5c3_Err = templ.JoinStringErrs(vm_uuid)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `views/vm_trace.templ`, Line: 61, Col: 129}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/views/vm_trace.templ`, Line: 71, Col: 129}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var6))
if templ_7745c5c3_Err != nil {
@@ -142,7 +152,7 @@ func VmTracePage(query string, display_query string, vm_id string, vm_uuid strin
var templ_7745c5c3_Var7 string
templ_7745c5c3_Var7, templ_7745c5c3_Err = templ.JoinStringErrs(vm_name)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `views/vm_trace.templ`, Line: 65, Col: 123}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/views/vm_trace.templ`, Line: 75, Col: 123}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var7))
if templ_7745c5c3_Err != nil {
@@ -164,7 +174,7 @@ func VmTracePage(query string, display_query string, vm_id string, vm_uuid strin
var templ_7745c5c3_Var9 string
templ_7745c5c3_Var9, templ_7745c5c3_Err = templ.JoinStringErrs(templ.CSSClasses(templ_7745c5c3_Var8).String())
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `views/vm_trace.templ`, Line: 1, Col: 0}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/views/vm_trace.templ`, Line: 1, Col: 0}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var9))
if templ_7745c5c3_Err != nil {
@@ -177,7 +187,7 @@ func VmTracePage(query string, display_query string, vm_id string, vm_uuid strin
var templ_7745c5c3_Var10 templ.SafeURL
templ_7745c5c3_Var10, templ_7745c5c3_Err = templ.JoinURLErrs(meta.HourlyLink)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `views/vm_trace.templ`, Line: 73, Col: 59}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/views/vm_trace.templ`, Line: 83, Col: 59}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var10))
if templ_7745c5c3_Err != nil {
@@ -199,7 +209,7 @@ func VmTracePage(query string, display_query string, vm_id string, vm_uuid strin
var templ_7745c5c3_Var12 string
templ_7745c5c3_Var12, templ_7745c5c3_Err = templ.JoinStringErrs(templ.CSSClasses(templ_7745c5c3_Var11).String())
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `views/vm_trace.templ`, Line: 1, Col: 0}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/views/vm_trace.templ`, Line: 1, Col: 0}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var12))
if templ_7745c5c3_Err != nil {
@@ -212,7 +222,7 @@ func VmTracePage(query string, display_query string, vm_id string, vm_uuid strin
var templ_7745c5c3_Var13 templ.SafeURL
templ_7745c5c3_Var13, templ_7745c5c3_Err = templ.JoinURLErrs(meta.DailyLink)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `views/vm_trace.templ`, Line: 74, Col: 57}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/views/vm_trace.templ`, Line: 84, Col: 57}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var13))
if templ_7745c5c3_Err != nil {
@@ -225,7 +235,7 @@ func VmTracePage(query string, display_query string, vm_id string, vm_uuid strin
var templ_7745c5c3_Var14 string
templ_7745c5c3_Var14, templ_7745c5c3_Err = templ.JoinStringErrs(meta.TypeLabel)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `views/vm_trace.templ`, Line: 80, Col: 56}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/views/vm_trace.templ`, Line: 90, Col: 56}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var14))
if templ_7745c5c3_Err != nil {
@@ -238,7 +248,7 @@ func VmTracePage(query string, display_query string, vm_id string, vm_uuid strin
var templ_7745c5c3_Var15 string
templ_7745c5c3_Var15, templ_7745c5c3_Err = templ.JoinStringErrs(len(entries))
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `views/vm_trace.templ`, Line: 81, Col: 44}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/views/vm_trace.templ`, Line: 91, Col: 44}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var15))
if templ_7745c5c3_Err != nil {
@@ -256,7 +266,7 @@ func VmTracePage(query string, display_query string, vm_id string, vm_uuid strin
var templ_7745c5c3_Var16 string
templ_7745c5c3_Var16, templ_7745c5c3_Err = templ.JoinStringErrs(chart.ConfigJSON)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `views/vm_trace.templ`, Line: 86, Col: 133}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/views/vm_trace.templ`, Line: 96, Col: 133}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var16))
if templ_7745c5c3_Err != nil {
@@ -274,7 +284,7 @@ func VmTracePage(query string, display_query string, vm_id string, vm_uuid strin
var templ_7745c5c3_Var17 string
templ_7745c5c3_Var17, templ_7745c5c3_Err = templ.JoinStringErrs(creationLabel)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `views/vm_trace.templ`, Line: 100, Col: 76}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/views/vm_trace.templ`, Line: 110, Col: 76}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var17))
if templ_7745c5c3_Err != nil {
@@ -297,140 +307,186 @@ func VmTracePage(query string, display_query string, vm_id string, vm_uuid strin
var templ_7745c5c3_Var18 string
templ_7745c5c3_Var18, templ_7745c5c3_Err = templ.JoinStringErrs(deletionLabel)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `views/vm_trace.templ`, Line: 107, Col: 76}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/views/vm_trace.templ`, Line: 117, Col: 76}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var18))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 23, "</p></div></div><div class=\"overflow-hidden border border-slate-200 rounded\"><table class=\"web2-table\"><thead><tr><th>Snapshot</th><th>VM Name</th><th>VmId</th><th>VmUuid</th><th>Vcenter</th><th>Resource Pool</th><th class=\"text-right\">vCPUs</th><th class=\"text-right\">RAM (GB)</th><th class=\"text-right\">Disk</th></tr></thead> <tbody>")
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 23, "</p></div></div>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
for _, e := range entries {
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 24, "<tr><td>")
if diagnostics.Visible && len(diagnostics.Lines) > 0 {
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 24, "<details class=\"web2-card mb-4\"><summary class=\"cursor-pointer text-sm font-semibold text-slate-700\">Lifecycle diagnostics</summary><div class=\"mt-3 overflow-hidden border border-slate-200 rounded\"><table class=\"web2-table\"><tbody>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
for _, line := range diagnostics.Lines {
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 25, "<tr><td class=\"font-semibold text-slate-700 w-72\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var19 string
templ_7745c5c3_Var19, templ_7745c5c3_Err = templ.JoinStringErrs(e.Snapshot)
templ_7745c5c3_Var19, templ_7745c5c3_Err = templ.JoinStringErrs(line.Label)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `views/vm_trace.templ`, Line: 128, Col: 25}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/views/vm_trace.templ`, Line: 128, Col: 70}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var19))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 25, "</td><td>")
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 26, "</td><td class=\"text-slate-600\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var20 string
templ_7745c5c3_Var20, templ_7745c5c3_Err = templ.JoinStringErrs(e.Name)
templ_7745c5c3_Var20, templ_7745c5c3_Err = templ.JoinStringErrs(line.Value)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `views/vm_trace.templ`, Line: 129, Col: 21}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/views/vm_trace.templ`, Line: 129, Col: 51}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var20))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 26, "</td><td>")
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 27, "</td></tr>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 28, "</tbody></table></div></details>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 29, "<div class=\"overflow-hidden border border-slate-200 rounded\"><table class=\"web2-table\"><thead><tr><th>Snapshot</th><th>VM Name</th><th>VmId</th><th>VmUuid</th><th>Vcenter</th><th>Resource Pool</th><th class=\"text-right\">vCPUs</th><th class=\"text-right\">RAM (GB)</th><th class=\"text-right\">Disk</th></tr></thead> <tbody>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
for _, e := range entries {
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 30, "<tr><td>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var21 string
templ_7745c5c3_Var21, templ_7745c5c3_Err = templ.JoinStringErrs(e.VmId)
templ_7745c5c3_Var21, templ_7745c5c3_Err = templ.JoinStringErrs(e.Snapshot)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `views/vm_trace.templ`, Line: 130, Col: 21}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/views/vm_trace.templ`, Line: 155, Col: 25}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var21))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 27, "</td><td>")
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 31, "</td><td>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var22 string
templ_7745c5c3_Var22, templ_7745c5c3_Err = templ.JoinStringErrs(e.VmUuid)
templ_7745c5c3_Var22, templ_7745c5c3_Err = templ.JoinStringErrs(e.Name)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `views/vm_trace.templ`, Line: 131, Col: 23}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/views/vm_trace.templ`, Line: 156, Col: 21}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var22))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 28, "</td><td>")
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 32, "</td><td>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var23 string
templ_7745c5c3_Var23, templ_7745c5c3_Err = templ.JoinStringErrs(e.Vcenter)
templ_7745c5c3_Var23, templ_7745c5c3_Err = templ.JoinStringErrs(e.VmId)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `views/vm_trace.templ`, Line: 132, Col: 24}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/views/vm_trace.templ`, Line: 157, Col: 21}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var23))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 29, "</td><td>")
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 33, "</td><td>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var24 string
templ_7745c5c3_Var24, templ_7745c5c3_Err = templ.JoinStringErrs(e.ResourcePool)
templ_7745c5c3_Var24, templ_7745c5c3_Err = templ.JoinStringErrs(e.VmUuid)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `views/vm_trace.templ`, Line: 133, Col: 29}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/views/vm_trace.templ`, Line: 158, Col: 23}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var24))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 30, "</td><td class=\"text-right\">")
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 34, "</td><td>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var25 string
templ_7745c5c3_Var25, templ_7745c5c3_Err = templ.JoinStringErrs(e.VcpuCount)
templ_7745c5c3_Var25, templ_7745c5c3_Err = templ.JoinStringErrs(e.Vcenter)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `views/vm_trace.templ`, Line: 134, Col: 45}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/views/vm_trace.templ`, Line: 159, Col: 24}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var25))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 31, "</td><td class=\"text-right\">")
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 35, "</td><td>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var26 string
templ_7745c5c3_Var26, templ_7745c5c3_Err = templ.JoinStringErrs(e.RamGB)
templ_7745c5c3_Var26, templ_7745c5c3_Err = templ.JoinStringErrs(e.ResourcePool)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `views/vm_trace.templ`, Line: 135, Col: 41}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/views/vm_trace.templ`, Line: 160, Col: 29}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var26))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 32, "</td><td class=\"text-right\">")
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 36, "</td><td class=\"text-right\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var27 string
templ_7745c5c3_Var27, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("%.1f", e.ProvisionedDisk))
templ_7745c5c3_Var27, templ_7745c5c3_Err = templ.JoinStringErrs(e.VcpuCount)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `views/vm_trace.templ`, Line: 136, Col: 72}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/views/vm_trace.templ`, Line: 161, Col: 45}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var27))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 33, "</td></tr>")
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 37, "</td><td class=\"text-right\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var28 string
templ_7745c5c3_Var28, templ_7745c5c3_Err = templ.JoinStringErrs(e.RamGB)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/views/vm_trace.templ`, Line: 162, Col: 41}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var28))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 38, "</td><td class=\"text-right\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var29 string
templ_7745c5c3_Var29, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("%.1f", e.ProvisionedDisk))
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/views/vm_trace.templ`, Line: 163, Col: 72}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var29))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 39, "</td></tr>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 34, "</tbody></table></div></section></main></body>")
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 40, "</tbody></table></div></section></main></body>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
@@ -438,7 +494,7 @@ func VmTracePage(query string, display_query string, vm_id string, vm_uuid strin
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 35, "</html>")
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 41, "</html>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}

View File

@@ -1672,6 +1672,33 @@ type VmLifecycle struct {
DeletionTime int64
}
// VmLifecycleSourceDiagnostics captures how one lifecycle source contributed to the final lifecycle decision.
type VmLifecycleSourceDiagnostics struct {
Source string
Used bool
Error string
MatchedRows int64
FirstSeen int64
LastSeen int64
CreationTime int64
CreationApprox bool
DeletionRows int64
DeletionMin int64
DeletionMax int64
SelectedDeletionTime int64
StaleDeletionIgnored bool
}
// VmLifecycleDiagnostics captures per-source lifecycle diagnostics for a VM lookup.
type VmLifecycleDiagnostics struct {
LookupField string
LookupValue string
HourlyCache VmLifecycleSourceDiagnostics
LifecycleCache VmLifecycleSourceDiagnostics
SnapshotFallback VmLifecycleSourceDiagnostics
FinalLifecycle VmLifecycle
}
func vmLookupPredicate(vmID, vmUUID, name string) (string, []interface{}, bool) {
vmID = strings.TrimSpace(vmID)
vmUUID = strings.TrimSpace(vmUUID)
@@ -1688,6 +1715,22 @@ func vmLookupPredicate(vmID, vmUUID, name string) (string, []interface{}, bool)
}
}
func vmLookupDescriptor(vmID, vmUUID, name string) (string, string) {
vmID = strings.TrimSpace(vmID)
vmUUID = strings.TrimSpace(vmUUID)
name = strings.TrimSpace(name)
switch {
case vmID != "":
return "vm_id", vmID
case vmUUID != "":
return "vm_uuid", vmUUID
case name != "":
return "name", name
default:
return "", ""
}
}
// FetchVmTrace returns combined hourly snapshot records for a VM (by id/uuid/name) ordered by snapshot time.
// It prefers the shared vm_hourly_stats history table and falls back to per-snapshot tables.
func FetchVmTrace(ctx context.Context, dbConn *sqlx.DB, vmID, vmUUID, name string) ([]VmTraceRow, error) {
@@ -1892,36 +1935,75 @@ WHERE %s
// FetchVmLifecycle walks VM history data to determine lifecycle bounds for a VM.
// It prefers vm_hourly_stats + vm_lifecycle_cache and falls back to per-snapshot table probes.
func FetchVmLifecycle(ctx context.Context, dbConn *sqlx.DB, vmID, vmUUID, name string) (VmLifecycle, error) {
lifecycle, _, err := FetchVmLifecycleWithDiagnostics(ctx, dbConn, vmID, vmUUID, name)
return lifecycle, err
}
// FetchVmLifecycleWithDiagnostics returns lifecycle details plus source-level diagnostics.
func FetchVmLifecycleWithDiagnostics(ctx context.Context, dbConn *sqlx.DB, vmID, vmUUID, name string) (VmLifecycle, VmLifecycleDiagnostics, error) {
lookupField, lookupValue := vmLookupDescriptor(vmID, vmUUID, name)
diagnostics := VmLifecycleDiagnostics{
LookupField: lookupField,
LookupValue: lookupValue,
HourlyCache: VmLifecycleSourceDiagnostics{
Source: "vm_hourly_stats",
},
LifecycleCache: VmLifecycleSourceDiagnostics{
Source: "vm_lifecycle_cache",
},
SnapshotFallback: VmLifecycleSourceDiagnostics{
Source: "snapshot_registry/hourly_tables",
},
}
if TableExists(ctx, dbConn, "vm_hourly_stats") {
lifecycle, found, err := fetchVmLifecycleFromHourlyCache(ctx, dbConn, vmID, vmUUID, name)
lifecycle, sourceDiag, found, err := fetchVmLifecycleFromHourlyCache(ctx, dbConn, vmID, vmUUID, name)
diagnostics.HourlyCache = sourceDiag
if err != nil {
diagnostics.HourlyCache.Error = err.Error()
slog.Warn("vm lifecycle cache query failed; falling back to hourly tables", "error", err)
} else if found {
diagnostics.HourlyCache.Used = true
if TableExists(ctx, dbConn, "vm_lifecycle_cache") {
cached, cachedFound, cacheErr := fetchVmLifecycleFromLifecycleCache(ctx, dbConn, vmID, vmUUID, name)
cached, cachedDiag, cachedFound, cacheErr := fetchVmLifecycleFromLifecycleCache(ctx, dbConn, vmID, vmUUID, name)
diagnostics.LifecycleCache = cachedDiag
if cacheErr != nil {
diagnostics.LifecycleCache.Error = cacheErr.Error()
slog.Warn("vm lifecycle cache lookup failed", "error", cacheErr)
} else if cachedFound {
diagnostics.LifecycleCache.Used = true
lifecycle = mergeVmLifecycle(lifecycle, cached)
}
}
return lifecycle, nil
diagnostics.FinalLifecycle = lifecycle
return lifecycle, diagnostics, nil
}
}
return fetchVmLifecycleFromSnapshotTables(ctx, dbConn, vmID, vmUUID, name)
lifecycle, fallbackDiag, err := fetchVmLifecycleFromSnapshotTables(ctx, dbConn, vmID, vmUUID, name)
diagnostics.SnapshotFallback = fallbackDiag
if err != nil {
diagnostics.SnapshotFallback.Error = err.Error()
return lifecycle, diagnostics, err
}
diagnostics.SnapshotFallback.Used = true
diagnostics.FinalLifecycle = lifecycle
return lifecycle, diagnostics, nil
}
func fetchVmLifecycleFromHourlyCache(ctx context.Context, dbConn *sqlx.DB, vmID, vmUUID, name string) (VmLifecycle, bool, error) {
func fetchVmLifecycleFromHourlyCache(ctx context.Context, dbConn *sqlx.DB, vmID, vmUUID, name string) (VmLifecycle, VmLifecycleSourceDiagnostics, bool, error) {
diag := VmLifecycleSourceDiagnostics{Source: "vm_hourly_stats"}
matchWhere, args, ok := vmLookupPredicate(vmID, vmUUID, name)
if !ok {
return VmLifecycle{}, false, nil
return VmLifecycle{}, diag, false, nil
}
var row struct {
Rows int64 `db:"rows"`
Creation sql.NullInt64 `db:"creation_time"`
FirstSeen sql.NullInt64 `db:"first_seen"`
LastSeen sql.NullInt64 `db:"last_seen"`
Deletion sql.NullInt64 `db:"deletion_time"`
DeletionRows int64 `db:"deletion_rows"`
DeletionMin sql.NullInt64 `db:"deletion_min"`
DeletionMax sql.NullInt64 `db:"deletion_max"`
}
query := `
SELECT
@@ -1929,16 +2011,29 @@ SELECT
MIN(NULLIF("CreationTime",0)) AS creation_time,
MIN("SnapshotTime") AS first_seen,
MAX("SnapshotTime") AS last_seen,
MIN(NULLIF("DeletionTime",0)) AS deletion_time
SUM(CASE WHEN COALESCE("DeletionTime",0) > 0 THEN 1 ELSE 0 END) AS deletion_rows,
MIN(NULLIF("DeletionTime",0)) AS deletion_min,
MAX(NULLIF("DeletionTime",0)) AS deletion_max
FROM vm_hourly_stats
WHERE ` + matchWhere + `
`
query = dbConn.Rebind(query)
if err := getLog(ctx, dbConn, &row, query, args...); err != nil {
return VmLifecycle{}, false, err
diag.Error = err.Error()
return VmLifecycle{}, diag, false, err
}
diag.MatchedRows = row.Rows
diag.FirstSeen = row.FirstSeen.Int64
diag.LastSeen = row.LastSeen.Int64
diag.DeletionRows = row.DeletionRows
if row.DeletionMin.Valid {
diag.DeletionMin = row.DeletionMin.Int64
}
if row.DeletionMax.Valid {
diag.DeletionMax = row.DeletionMax.Int64
}
if row.Rows == 0 {
return VmLifecycle{}, false, nil
return VmLifecycle{}, diag, false, nil
}
lifecycle := VmLifecycle{
FirstSeen: row.FirstSeen.Int64,
@@ -1951,38 +2046,70 @@ WHERE ` + matchWhere + `
lifecycle.CreationTime = row.FirstSeen.Int64
lifecycle.CreationApprox = true
}
if row.Deletion.Valid && row.Deletion.Int64 > 0 {
lifecycle.DeletionTime = row.Deletion.Int64
diag.CreationTime = lifecycle.CreationTime
diag.CreationApprox = lifecycle.CreationApprox
if row.DeletionMax.Valid && row.DeletionMax.Int64 > 0 {
if row.LastSeen.Valid && row.LastSeen.Int64 > 0 && row.DeletionMax.Int64 <= row.LastSeen.Int64 {
diag.StaleDeletionIgnored = true
slog.Warn("ignoring stale VM deletion from hourly cache",
"vm_id", vmID,
"vm_uuid", vmUUID,
"name", name,
"deletion_rows", row.DeletionRows,
"deletion_min", row.DeletionMin.Int64,
"deletion_max", row.DeletionMax.Int64,
"last_seen", row.LastSeen.Int64,
)
} else {
lifecycle.DeletionTime = row.DeletionMax.Int64
}
return lifecycle, true, nil
}
diag.SelectedDeletionTime = lifecycle.DeletionTime
return lifecycle, diag, true, nil
}
func fetchVmLifecycleFromLifecycleCache(ctx context.Context, dbConn *sqlx.DB, vmID, vmUUID, name string) (VmLifecycle, bool, error) {
func fetchVmLifecycleFromLifecycleCache(ctx context.Context, dbConn *sqlx.DB, vmID, vmUUID, name string) (VmLifecycle, VmLifecycleSourceDiagnostics, bool, error) {
diag := VmLifecycleSourceDiagnostics{Source: "vm_lifecycle_cache"}
matchWhere, args, ok := vmLookupPredicate(vmID, vmUUID, name)
if !ok {
return VmLifecycle{}, false, nil
return VmLifecycle{}, diag, false, nil
}
var row struct {
Rows int64 `db:"rows"`
FirstSeen sql.NullInt64 `db:"first_seen"`
LastSeen sql.NullInt64 `db:"last_seen"`
Deletion sql.NullInt64 `db:"deletion_time"`
DeletionRows int64 `db:"deletion_rows"`
DeletionMin sql.NullInt64 `db:"deletion_min"`
DeletionMax sql.NullInt64 `db:"deletion_max"`
}
query := `
SELECT
COUNT(1) AS rows,
MIN(NULLIF("FirstSeen",0)) AS first_seen,
MAX(NULLIF("LastSeen",0)) AS last_seen,
MIN(NULLIF("DeletedAt",0)) AS deletion_time
SUM(CASE WHEN COALESCE("DeletedAt",0) > 0 THEN 1 ELSE 0 END) AS deletion_rows,
MIN(NULLIF("DeletedAt",0)) AS deletion_min,
MAX(NULLIF("DeletedAt",0)) AS deletion_max
FROM vm_lifecycle_cache
WHERE ` + matchWhere + `
`
query = dbConn.Rebind(query)
if err := getLog(ctx, dbConn, &row, query, args...); err != nil {
return VmLifecycle{}, false, err
diag.Error = err.Error()
return VmLifecycle{}, diag, false, err
}
diag.MatchedRows = row.Rows
diag.FirstSeen = row.FirstSeen.Int64
diag.LastSeen = row.LastSeen.Int64
diag.DeletionRows = row.DeletionRows
if row.DeletionMin.Valid {
diag.DeletionMin = row.DeletionMin.Int64
}
if row.DeletionMax.Valid {
diag.DeletionMax = row.DeletionMax.Int64
}
if row.Rows == 0 {
return VmLifecycle{}, false, nil
return VmLifecycle{}, diag, false, nil
}
lifecycle := VmLifecycle{
FirstSeen: row.FirstSeen.Int64,
@@ -1992,10 +2119,26 @@ WHERE ` + matchWhere + `
lifecycle.CreationTime = row.FirstSeen.Int64
lifecycle.CreationApprox = true
}
if row.Deletion.Valid && row.Deletion.Int64 > 0 {
lifecycle.DeletionTime = row.Deletion.Int64
diag.CreationTime = lifecycle.CreationTime
diag.CreationApprox = lifecycle.CreationApprox
if row.DeletionMax.Valid && row.DeletionMax.Int64 > 0 {
if row.LastSeen.Valid && row.LastSeen.Int64 > 0 && row.DeletionMax.Int64 <= row.LastSeen.Int64 {
diag.StaleDeletionIgnored = true
slog.Warn("ignoring stale VM deletion from lifecycle cache",
"vm_id", vmID,
"vm_uuid", vmUUID,
"name", name,
"deletion_rows", row.DeletionRows,
"deletion_min", row.DeletionMin.Int64,
"deletion_max", row.DeletionMax.Int64,
"last_seen", row.LastSeen.Int64,
)
} else {
lifecycle.DeletionTime = row.DeletionMax.Int64
}
return lifecycle, true, nil
}
diag.SelectedDeletionTime = lifecycle.DeletionTime
return lifecycle, diag, true, nil
}
func mergeVmLifecycle(base, overlay VmLifecycle) VmLifecycle {
@@ -2006,7 +2149,7 @@ func mergeVmLifecycle(base, overlay VmLifecycle) VmLifecycle {
if overlay.LastSeen > out.LastSeen {
out.LastSeen = overlay.LastSeen
}
if overlay.DeletionTime > 0 && (out.DeletionTime == 0 || overlay.DeletionTime < out.DeletionTime) {
if overlay.DeletionTime > 0 && (out.DeletionTime == 0 || overlay.DeletionTime > out.DeletionTime) {
out.DeletionTime = overlay.DeletionTime
}
if overlay.CreationTime > 0 {
@@ -2021,14 +2164,18 @@ func mergeVmLifecycle(base, overlay VmLifecycle) VmLifecycle {
out.CreationTime = out.FirstSeen
out.CreationApprox = true
}
if out.DeletionTime > 0 && out.LastSeen > 0 && out.DeletionTime <= out.LastSeen {
out.DeletionTime = 0
}
return out
}
func fetchVmLifecycleFromSnapshotTables(ctx context.Context, dbConn *sqlx.DB, vmID, vmUUID, name string) (VmLifecycle, error) {
func fetchVmLifecycleFromSnapshotTables(ctx context.Context, dbConn *sqlx.DB, vmID, vmUUID, name string) (VmLifecycle, VmLifecycleSourceDiagnostics, error) {
var lifecycle VmLifecycle
diag := VmLifecycleSourceDiagnostics{Source: "snapshot_registry/hourly_tables"}
matchWhere, args, ok := vmLookupPredicate(vmID, vmUUID, name)
if !ok {
return lifecycle, nil
return lifecycle, diag, nil
}
var tables []struct {
TableName string `db:"table_name"`
@@ -2040,11 +2187,14 @@ FROM snapshot_registry
WHERE snapshot_type = 'hourly'
ORDER BY snapshot_time
`); err != nil {
return lifecycle, err
diag.Error = err.Error()
return lifecycle, diag, err
}
minCreation := int64(0)
consecutiveMissing := 0
firstMissingAfterLastSeen := int64(0)
matchedRows := int64(0)
for _, t := range tables {
if err := ValidateTableName(t.TableName); err != nil {
continue
@@ -2063,11 +2213,18 @@ WHERE %s
continue
}
if probe.Cnt > 0 {
matchedRows++
if lifecycle.FirstSeen == 0 {
lifecycle.FirstSeen = t.SnapshotTime
}
if lifecycle.DeletionTime > 0 && t.SnapshotTime > lifecycle.DeletionTime {
diag.StaleDeletionIgnored = true
slog.Warn("ignoring stale VM deletion from snapshot-table fallback", "vm_id", vmID, "vm_uuid", vmUUID, "name", name, "deletion_time", lifecycle.DeletionTime, "seen_again_at", t.SnapshotTime)
lifecycle.DeletionTime = 0
}
lifecycle.LastSeen = t.SnapshotTime
consecutiveMissing = 0
firstMissingAfterLastSeen = 0
if probe.MinCreation.Valid {
if minCreation == 0 || probe.MinCreation.Int64 < minCreation {
minCreation = probe.MinCreation.Int64
@@ -2075,12 +2232,15 @@ WHERE %s
}
} else if lifecycle.LastSeen > 0 && lifecycle.DeletionTime == 0 && t.SnapshotTime > lifecycle.LastSeen {
consecutiveMissing++
if firstMissingAfterLastSeen == 0 {
firstMissingAfterLastSeen = t.SnapshotTime
}
if consecutiveMissing >= 2 {
lifecycle.DeletionTime = t.SnapshotTime
break
lifecycle.DeletionTime = firstMissingAfterLastSeen
}
} else {
consecutiveMissing = 0
firstMissingAfterLastSeen = 0
}
}
if minCreation > 0 {
@@ -2090,7 +2250,13 @@ WHERE %s
lifecycle.CreationTime = lifecycle.FirstSeen
lifecycle.CreationApprox = true
}
return lifecycle, nil
diag.MatchedRows = matchedRows
diag.FirstSeen = lifecycle.FirstSeen
diag.LastSeen = lifecycle.LastSeen
diag.CreationTime = lifecycle.CreationTime
diag.CreationApprox = lifecycle.CreationApprox
diag.SelectedDeletionTime = lifecycle.DeletionTime
return lifecycle, diag, nil
}
// SyncVcenterTotalsFromSnapshots backfills vcenter_totals using hourly snapshot tables in snapshot_registry.

View File

@@ -278,6 +278,60 @@ VALUES (?,?,?,?,?,?,?,?,?,?)
}
}
func TestFetchVmLifecycleIgnoresStaleDeletionFromHourlyCache(t *testing.T) {
ctx := context.Background()
dbConn := newTestSQLiteDB(t)
if err := EnsureVmHourlyStats(ctx, dbConn); err != nil {
t.Fatalf("failed to ensure vm_hourly_stats: %v", err)
}
insertSQL := `
INSERT INTO vm_hourly_stats (
"SnapshotTime","Vcenter","VmId","VmUuid","Name","CreationTime","DeletionTime","ResourcePool",
"Datacenter","Cluster","Folder","ProvisionedDisk","VcpuCount","RamGB","IsTemplate","PoweredOn","SrmPlaceholder"
) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)
`
// First row carries an old deletion marker, later row proves VM is still present.
rows := [][]interface{}{
{int64(1700000000), "vc-a", "vm-1", "uuid-1", "demo-vm", int64(1699999000), int64(1700003600), "Tin", "dc", "cluster", "folder", 100.0, int64(2), int64(4), "FALSE", "TRUE", "FALSE"},
{int64(1700100000), "vc-a", "vm-1", "uuid-1", "demo-vm", int64(1699999000), int64(0), "Gold", "dc", "cluster", "folder", 120.0, int64(4), int64(8), "FALSE", "TRUE", "FALSE"},
}
for _, args := range rows {
if _, err := dbConn.ExecContext(ctx, insertSQL, args...); err != nil {
t.Fatalf("failed to insert hourly cache row: %v", err)
}
}
lifecycle, err := FetchVmLifecycle(ctx, dbConn, "vm-1", "", "")
if err != nil {
t.Fatalf("FetchVmLifecycle failed: %v", err)
}
if lifecycle.LastSeen != 1700100000 {
t.Fatalf("expected LastSeen=1700100000, got %d", lifecycle.LastSeen)
}
if lifecycle.DeletionTime != 0 {
t.Fatalf("expected stale deletion to be ignored, got %d", lifecycle.DeletionTime)
}
lifecycleDiag, diag, err := FetchVmLifecycleWithDiagnostics(ctx, dbConn, "vm-1", "", "")
if err != nil {
t.Fatalf("FetchVmLifecycleWithDiagnostics failed: %v", err)
}
if lifecycleDiag.DeletionTime != 0 {
t.Fatalf("expected stale deletion to be ignored in diagnostics path, got %d", lifecycleDiag.DeletionTime)
}
if !diag.HourlyCache.StaleDeletionIgnored {
t.Fatalf("expected hourly cache diagnostics to flag stale deletion ignore, got %#v", diag.HourlyCache)
}
if diag.HourlyCache.DeletionMax != 1700003600 {
t.Fatalf("expected hourly cache deletion max 1700003600, got %d", diag.HourlyCache.DeletionMax)
}
if diag.FinalLifecycle.LastSeen != 1700100000 || diag.FinalLifecycle.DeletionTime != 0 {
t.Fatalf("unexpected final diagnostics lifecycle: %#v", diag.FinalLifecycle)
}
}
func TestParseHourlySnapshotUnix(t *testing.T) {
cases := []struct {
table string

View File

@@ -35,6 +35,7 @@ func (h *Handler) VmTrace(w http.ResponseWriter, r *http.Request) {
var entries []views.VmTraceEntry
chart := views.VmTraceChart{}
diagnostics := views.VmTraceDiagnostics{}
queryLabel := firstNonEmpty(vmID, vmUUID, name)
displayQuery := ""
if queryLabel != "" {
@@ -47,10 +48,11 @@ func (h *Handler) VmTrace(w http.ResponseWriter, r *http.Request) {
// Only fetch data when a query is provided; otherwise render empty page with form.
if vmID != "" || vmUUID != "" || name != "" {
h.Logger.Info("vm trace request", "view", viewType, "vm_id", vmID, "vm_uuid", vmUUID, "name", name)
lifecycle, lifeErr := db.FetchVmLifecycle(ctx, h.Database.DB(), vmID, vmUUID, name)
lifecycle, lifecycleDiag, lifeErr := db.FetchVmLifecycleWithDiagnostics(ctx, h.Database.DB(), vmID, vmUUID, name)
if lifeErr != nil {
h.Logger.Warn("failed to fetch VM lifecycle", "error", lifeErr)
}
diagnostics = buildVmTraceDiagnostics(lifecycleDiag)
var (
rows []db.VmTraceRow
err error
@@ -114,7 +116,7 @@ func (h *Handler) VmTrace(w http.ResponseWriter, r *http.Request) {
}
w.Header().Set("Content-Type", "text/html; charset=utf-8")
if err := views.VmTracePage(queryLabel, displayQuery, vmID, vmUUID, name, creationLabel, deletionLabel, creationApprox, entries, chart, meta).Render(ctx, w); err != nil {
if err := views.VmTracePage(queryLabel, displayQuery, vmID, vmUUID, name, creationLabel, deletionLabel, creationApprox, entries, chart, meta, diagnostics).Render(ctx, w); err != nil {
http.Error(w, "Failed to render template", http.StatusInternalServerError)
}
}
@@ -155,6 +157,65 @@ func buildVmTraceMeta(viewType, vmID, vmUUID, name string) views.VmTraceMeta {
return meta
}
func buildVmTraceDiagnostics(diag db.VmLifecycleDiagnostics) views.VmTraceDiagnostics {
lines := make([]views.VmTraceDiagnosticLine, 0, 24)
lookup := "-"
if diag.LookupField != "" {
lookup = diag.LookupField + "=" + diag.LookupValue
}
lines = append(lines, views.VmTraceDiagnosticLine{Label: "Lookup", Value: lookup})
lines = append(lines, views.VmTraceDiagnosticLine{Label: "Final First Seen", Value: formatDiagUnix(diag.FinalLifecycle.FirstSeen)})
lines = append(lines, views.VmTraceDiagnosticLine{Label: "Final Last Seen", Value: formatDiagUnix(diag.FinalLifecycle.LastSeen)})
lines = append(lines, views.VmTraceDiagnosticLine{Label: "Final Creation Time", Value: formatDiagUnix(diag.FinalLifecycle.CreationTime)})
lines = append(lines, views.VmTraceDiagnosticLine{Label: "Final Creation Approx", Value: fmt.Sprintf("%t", diag.FinalLifecycle.CreationApprox)})
lines = append(lines, views.VmTraceDiagnosticLine{Label: "Final Deletion Time", Value: formatDiagUnix(diag.FinalLifecycle.DeletionTime)})
lines = append(lines, summarizeLifecycleSource(diag.HourlyCache)...)
lines = append(lines, summarizeLifecycleSource(diag.LifecycleCache)...)
lines = append(lines, summarizeLifecycleSource(diag.SnapshotFallback)...)
return views.VmTraceDiagnostics{
Visible: len(lines) > 0,
Lines: lines,
}
}
func summarizeLifecycleSource(src db.VmLifecycleSourceDiagnostics) []views.VmTraceDiagnosticLine {
prefix := src.Source
if strings.TrimSpace(prefix) == "" {
prefix = "source"
}
out := []views.VmTraceDiagnosticLine{
{Label: prefix + " used", Value: fmt.Sprintf("%t", src.Used)},
{Label: prefix + " error", Value: defaultString(src.Error, "-")},
{Label: prefix + " matched rows", Value: fmt.Sprintf("%d", src.MatchedRows)},
{Label: prefix + " first seen", Value: formatDiagUnix(src.FirstSeen)},
{Label: prefix + " last seen", Value: formatDiagUnix(src.LastSeen)},
{Label: prefix + " creation", Value: formatDiagUnix(src.CreationTime)},
{Label: prefix + " creation approx", Value: fmt.Sprintf("%t", src.CreationApprox)},
{Label: prefix + " deletion rows", Value: fmt.Sprintf("%d", src.DeletionRows)},
{Label: prefix + " deletion min", Value: formatDiagUnix(src.DeletionMin)},
{Label: prefix + " deletion max", Value: formatDiagUnix(src.DeletionMax)},
{Label: prefix + " selected deletion", Value: formatDiagUnix(src.SelectedDeletionTime)},
{Label: prefix + " stale deletion ignored", Value: fmt.Sprintf("%t", src.StaleDeletionIgnored)},
}
return out
}
func formatDiagUnix(ts int64) string {
if ts <= 0 {
return "-"
}
return fmt.Sprintf("%s (%d)", time.Unix(ts, 0).Local().Format("2006-01-02 15:04:05"), ts)
}
func defaultString(value string, fallback string) string {
if strings.TrimSpace(value) == "" {
return fallback
}
return value
}
func buildVmTraceChart(entries []views.VmTraceEntry) views.VmTraceChart {
if len(entries) == 0 {
return views.VmTraceChart{}