summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--internal/daemon/upload.go23
-rw-r--r--internal/goprecords/aggregate_test.go12
-rw-r--r--internal/goprecords/db_test.go8
-rw-r--r--internal/goprecords/report.go10
-rw-r--r--internal/goprecords/report_test.go62
-rw-r--r--internal/goprecords/types.go22
-rw-r--r--internal/goprecords/types_test.go24
7 files changed, 89 insertions, 72 deletions
diff --git a/internal/daemon/upload.go b/internal/daemon/upload.go
index 71bffd0..832019e 100644
--- a/internal/daemon/upload.go
+++ b/internal/daemon/upload.go
@@ -14,12 +14,21 @@ import (
const maxUploadBytes = 8 << 20
-var uploadKinds = map[string]string{
- "txt": ".txt",
- "cur.txt": ".cur.txt",
- "records": ".records",
- "os.txt": ".os.txt",
- "cpuinfo.txt": ".cpuinfo.txt",
+func uploadKindExtension(kind string) (ext string, ok bool) {
+ switch kind {
+ case "txt":
+ return ".txt", true
+ case "cur.txt":
+ return ".cur.txt", true
+ case "records":
+ return ".records", true
+ case "os.txt":
+ return ".os.txt", true
+ case "cpuinfo.txt":
+ return ".cpuinfo.txt", true
+ default:
+ return "", false
+ }
}
func uploadHandler(statsDir string, store *authkeys.Store) http.Handler {
@@ -38,7 +47,7 @@ func serveUploadPut(w http.ResponseWriter, r *http.Request, statsDir string, sto
http.Error(w, "bad path", http.StatusBadRequest)
return
}
- ext, ok := uploadKinds[kind]
+ ext, ok := uploadKindExtension(kind)
if !ok {
http.Error(w, "unknown file kind", http.StatusBadRequest)
return
diff --git a/internal/goprecords/aggregate_test.go b/internal/goprecords/aggregate_test.go
index c7e75b4..d675b4f 100644
--- a/internal/goprecords/aggregate_test.go
+++ b/internal/goprecords/aggregate_test.go
@@ -26,7 +26,7 @@ func TestNewAggregatorMatchesDirFS(t *testing.T) {
if len(a.Host) != 1 || len(b.Host) != 1 {
t.Fatalf("hosts: a=%d b=%d", len(a.Host), len(b.Host))
}
- if a.Host["h1"].Boots != b.Host["h1"].Boots || a.Host["h1"].Uptime != b.Host["h1"].Uptime {
+ if a.Host["h1"].Stats.Boots != b.Host["h1"].Stats.Boots || a.Host["h1"].Stats.Uptime != b.Host["h1"].Stats.Uptime {
t.Fatalf("mismatch: %#v vs %#v", a.Host["h1"], b.Host["h1"])
}
}
@@ -53,7 +53,7 @@ func TestAggregateMapFS(t *testing.T) {
t.Fatalf("Aggregate: %v", err)
}
h := aggs.Host["box"]
- if h == nil || h.Boots != 2 || h.LastKernel != "Linux 5.11.0-test" {
+ if h == nil || h.Stats.Boots != 2 || h.LastKernel != "Linux 5.11.0-test" {
t.Fatalf("host box: %#v", h)
}
}
@@ -109,10 +109,10 @@ func TestAggregateFixturesContent(t *testing.T) {
// Check a specific host
if host, ok := aggregates.Host["earth"]; ok {
- if host.Boots == 0 {
+ if host.Stats.Boots == 0 {
t.Error("expected non-zero boots for earth")
}
- if host.Uptime == 0 {
+ if host.Stats.Uptime == 0 {
t.Error("expected non-zero uptime for earth")
}
if host.LastKernel == "" {
@@ -200,8 +200,8 @@ func TestProcessRecordsFile(t *testing.T) {
t.Fatalf("failed to process records: %v", err)
}
- if aggs.Host["test"].Boots != 2 {
- t.Errorf("expected 2 boots, got %d", aggs.Host["test"].Boots)
+ if aggs.Host["test"].Stats.Boots != 2 {
+ t.Errorf("expected 2 boots, got %d", aggs.Host["test"].Stats.Boots)
}
}
diff --git a/internal/goprecords/db_test.go b/internal/goprecords/db_test.go
index 3d6b788..44ee2f1 100644
--- a/internal/goprecords/db_test.go
+++ b/internal/goprecords/db_test.go
@@ -53,11 +53,11 @@ func TestLoadAggregates(t *testing.T) {
}
if host, ok := aggs.Host["host1"]; ok {
- if host.Boots != 2 {
- t.Errorf("expected 2 boots, got %d", host.Boots)
+ if host.Stats.Boots != 2 {
+ t.Errorf("expected 2 boots, got %d", host.Stats.Boots)
}
- if host.Uptime != 3000 {
- t.Errorf("expected uptime 3000, got %d", host.Uptime)
+ if host.Stats.Uptime != 3000 {
+ t.Errorf("expected uptime 3000, got %d", host.Stats.Uptime)
}
if host.LastKernel != "Linux 5.11" {
t.Errorf("LastKernel = %q, want %q (latest boot_time row)", host.LastKernel, "Linux 5.11")
diff --git a/internal/goprecords/report.go b/internal/goprecords/report.go
index 11c809a..a512407 100644
--- a/internal/goprecords/report.go
+++ b/internal/goprecords/report.go
@@ -14,17 +14,17 @@ type metricExtractor struct {
}
var uptimeMetricExtractor = metricExtractor{
- hostSortKey: func(h *HostAggregate) uint64 { return h.Uptime },
+ hostSortKey: func(h *HostAggregate) uint64 { return h.Stats.Uptime },
aggSortKey: func(a *Aggregate) uint64 { return a.Uptime },
- hostHuman: func(h *HostAggregate) string { return formatDuration(h.Uptime) },
+ hostHuman: func(h *HostAggregate) string { return formatDuration(h.Stats.Uptime) },
aggHuman: func(a *Aggregate) string { return formatDuration(a.Uptime) },
}
var metricExtractors = map[Metric]metricExtractor{
MetricBoots: {
- hostSortKey: func(h *HostAggregate) uint64 { return h.Boots },
+ hostSortKey: func(h *HostAggregate) uint64 { return h.Stats.Boots },
aggSortKey: func(a *Aggregate) uint64 { return a.Boots },
- hostHuman: func(h *HostAggregate) string { return formatInt(h.Boots) },
+ hostHuman: func(h *HostAggregate) string { return formatInt(h.Stats.Boots) },
aggHuman: func(a *Aggregate) string { return formatInt(a.Boots) },
},
MetricUptime: uptimeMetricExtractor,
@@ -215,7 +215,7 @@ func (r reportBuilder) buildHostTable() ([]tableRow, bool) {
}
rows = append(rows, tableRow{
Pos: fmt.Sprintf("%d.", i+1),
- Name: active + h.Name,
+ Name: active + h.Stats.Name,
Value: r.humanStrHost(h),
LastKernel: h.LastKernel,
})
diff --git a/internal/goprecords/report_test.go b/internal/goprecords/report_test.go
index a227528..1469942 100644
--- a/internal/goprecords/report_test.go
+++ b/internal/goprecords/report_test.go
@@ -72,10 +72,10 @@ func TestReportWithData(t *testing.T) {
// Add a host
hagg := NewHostAggregate("host1", "Linux 5.10")
- hagg.Uptime = 86400000
- hagg.Boots = 10
- hagg.FirstBoot = 1000
- hagg.LastSeen = 86401000
+ hagg.Stats.Uptime = 86400000
+ hagg.Stats.Boots = 10
+ hagg.Stats.FirstBoot = 1000
+ hagg.Stats.LastSeen = 86401000
aggs.Host["host1"] = hagg
reporter := NewReporter(aggs, CategoryHost, 20, MetricUptime, FormatPlaintext, 1)
@@ -101,10 +101,10 @@ func TestReportHTML(t *testing.T) {
}
hagg := NewHostAggregate("host1", "Linux 5.10")
- hagg.Uptime = 86400000
- hagg.Boots = 10
- hagg.FirstBoot = 1000
- hagg.LastSeen = 86401000
+ hagg.Stats.Uptime = 86400000
+ hagg.Stats.Boots = 10
+ hagg.Stats.FirstBoot = 1000
+ hagg.Stats.LastSeen = 86401000
aggs.Host["host1"] = hagg
reporter := NewReporter(aggs, CategoryHost, 20, MetricUptime, FormatHTML, 2)
@@ -130,10 +130,10 @@ func TestReportMarkdown(t *testing.T) {
}
hagg := NewHostAggregate("host1", "Linux 5.10")
- hagg.Uptime = 86400000
- hagg.Boots = 10
- hagg.FirstBoot = 1000
- hagg.LastSeen = 86401000
+ hagg.Stats.Uptime = 86400000
+ hagg.Stats.Boots = 10
+ hagg.Stats.FirstBoot = 1000
+ hagg.Stats.LastSeen = 86401000
aggs.Host["host1"] = hagg
reporter := NewReporter(aggs, CategoryHost, 20, MetricUptime, FormatMarkdown, 2)
@@ -156,10 +156,10 @@ func TestReportGemtext(t *testing.T) {
}
hagg := NewHostAggregate("host1", "Linux 5.10")
- hagg.Uptime = 86400000
- hagg.Boots = 10
- hagg.FirstBoot = 1000
- hagg.LastSeen = 86401000
+ hagg.Stats.Uptime = 86400000
+ hagg.Stats.Boots = 10
+ hagg.Stats.FirstBoot = 1000
+ hagg.Stats.LastSeen = 86401000
aggs.Host["host1"] = hagg
reporter := NewReporter(aggs, CategoryHost, 20, MetricUptime, FormatGemtext, 2)
@@ -175,21 +175,21 @@ func TestReportGemtext(t *testing.T) {
func TestExtractorForUnknownMetricFallsBackToUptime(t *testing.T) {
h := NewHostAggregate("h", "k")
- h.Uptime = 999
- h.Boots = 1
+ h.Stats.Uptime = 999
+ h.Stats.Boots = 1
a := NewAggregate("k")
a.Uptime = 888
a.Boots = 2
unknown := Metric(255)
ex := extractorFor(unknown)
- if got := ex.hostSortKey(h); got != h.Uptime {
- t.Errorf("host sort key: got %d want %d", got, h.Uptime)
+ if got := ex.hostSortKey(h); got != h.Stats.Uptime {
+ t.Errorf("host sort key: got %d want %d", got, h.Stats.Uptime)
}
if got := ex.aggSortKey(a); got != a.Uptime {
t.Errorf("agg sort key: got %d want %d", got, a.Uptime)
}
- if got := ex.hostHuman(h); got != formatDuration(h.Uptime) {
- t.Errorf("host human: got %q want %q", got, formatDuration(h.Uptime))
+ if got := ex.hostHuman(h); got != formatDuration(h.Stats.Uptime) {
+ t.Errorf("host human: got %q want %q", got, formatDuration(h.Stats.Uptime))
}
if got := ex.aggHuman(a); got != formatDuration(a.Uptime) {
t.Errorf("agg human: got %q want %q", got, formatDuration(a.Uptime))
@@ -220,10 +220,10 @@ func TestReportMetrics(t *testing.T) {
}
hagg := NewHostAggregate("host1", "Linux 5.10")
- hagg.Uptime = 86400000
- hagg.Boots = 10
- hagg.FirstBoot = 1000
- hagg.LastSeen = 86401000
+ hagg.Stats.Uptime = 86400000
+ hagg.Stats.Boots = 10
+ hagg.Stats.FirstBoot = 1000
+ hagg.Stats.LastSeen = 86401000
aggs.Host["host1"] = hagg
metrics := []Metric{MetricBoots, MetricUptime, MetricScore, MetricDowntime, MetricLifespan}
@@ -274,7 +274,7 @@ func TestReportLimit(t *testing.T) {
for i := 0; i < 10; i++ {
host := hostName(i)
hagg := NewHostAggregate(host, "Linux")
- hagg.Uptime = uint64(86400000 * (10 - i))
+ hagg.Stats.Uptime = uint64(86400000 * (10 - i))
aggs.Host[host] = hagg
}
@@ -361,10 +361,10 @@ func testAggregates() *Aggregates {
KernelName: make(map[string]*Aggregate),
}
hagg := NewHostAggregate("host1", "Linux 5.10")
- hagg.Uptime = 86400000
- hagg.Boots = 10
- hagg.FirstBoot = 1000
- hagg.LastSeen = 86401000
+ hagg.Stats.Uptime = 86400000
+ hagg.Stats.Boots = 10
+ hagg.Stats.FirstBoot = 1000
+ hagg.Stats.LastSeen = 86401000
aggs.Host["host1"] = hagg
kernel := NewAggregate("Linux 5.10")
kernel.Uptime = 86400000
diff --git a/internal/goprecords/types.go b/internal/goprecords/types.go
index 343f7e0..418d269 100644
--- a/internal/goprecords/types.go
+++ b/internal/goprecords/types.go
@@ -64,18 +64,26 @@ func NewAggregate(name string) *Aggregate {
// HostAggregate adds last-kernel and lifespan/downtime for host reports.
type HostAggregate struct {
- Aggregate
+ Stats Aggregate
LastKernel string
}
// NewHostAggregate constructs a HostAggregate.
func NewHostAggregate(name, lastKernel string) *HostAggregate {
return &HostAggregate{
- Aggregate: Aggregate{Name: name},
+ Stats: Aggregate{Name: name},
LastKernel: lastKernel,
}
}
+func (h *HostAggregate) AddRecord(uptimeSec, bootTime uint64) {
+ h.Stats.AddRecord(uptimeSec, bootTime)
+}
+
+func (h *HostAggregate) IsActive(limitDays uint) bool {
+ return h.Stats.IsActive(limitDays)
+}
+
// tableRow is one row in the report table.
type tableRow struct {
Pos string
@@ -178,24 +186,24 @@ func (a *Aggregate) MetaScore() uint64 {
// Lifespan returns last-seen minus first-boot.
func (h *HostAggregate) Lifespan() uint64 {
- if h.LastSeen < h.FirstBoot {
+ if h.Stats.LastSeen < h.Stats.FirstBoot {
return 0
}
- return h.LastSeen - h.FirstBoot
+ return h.Stats.LastSeen - h.Stats.FirstBoot
}
// Downtime returns lifespan minus uptime.
func (h *HostAggregate) Downtime() uint64 {
life := h.Lifespan()
- if h.Uptime > life {
+ if h.Stats.Uptime > life {
return 0
}
- return life - h.Uptime
+ return life - h.Stats.Uptime
}
// MetaScore returns the host-specific score (includes downtime component).
func (h *HostAggregate) MetaScore() uint64 {
- return uint64(h.Downtime()/2000000) + h.Aggregate.MetaScore()
+ return uint64(h.Downtime()/2000000) + h.Stats.MetaScore()
}
// MetricDescription returns the description text for a metric.
diff --git a/internal/goprecords/types_test.go b/internal/goprecords/types_test.go
index 245cead..61ccbce 100644
--- a/internal/goprecords/types_test.go
+++ b/internal/goprecords/types_test.go
@@ -17,8 +17,8 @@ func TestNewAggregate(t *testing.T) {
func TestNewHostAggregate(t *testing.T) {
hagg := NewHostAggregate("testhost", "Linux 5.10.0")
- if hagg.Name != "testhost" {
- t.Errorf("got %q, want %q", hagg.Name, "testhost")
+ if hagg.Stats.Name != "testhost" {
+ t.Errorf("got %q, want %q", hagg.Stats.Name, "testhost")
}
if hagg.LastKernel != "Linux 5.10.0" {
t.Errorf("got %q, want %q", hagg.LastKernel, "Linux 5.10.0")
@@ -92,8 +92,8 @@ func TestMetaScore(t *testing.T) {
func TestHostAggregateLifespan(t *testing.T) {
hagg := NewHostAggregate("host1", "Linux 5.10")
- hagg.FirstBoot = 1000
- hagg.LastSeen = 5000
+ hagg.Stats.FirstBoot = 1000
+ hagg.Stats.LastSeen = 5000
lifespan := hagg.Lifespan()
if lifespan != 4000 {
@@ -103,9 +103,9 @@ func TestHostAggregateLifespan(t *testing.T) {
func TestHostAggregateDowntime(t *testing.T) {
hagg := NewHostAggregate("host1", "Linux 5.10")
- hagg.FirstBoot = 1000
- hagg.LastSeen = 5000
- hagg.Uptime = 3000
+ hagg.Stats.FirstBoot = 1000
+ hagg.Stats.LastSeen = 5000
+ hagg.Stats.Uptime = 3000
downtime := hagg.Downtime()
if downtime != 1000 {
@@ -115,8 +115,8 @@ func TestHostAggregateDowntime(t *testing.T) {
func TestHostAggregateLifespanUnderflow(t *testing.T) {
hagg := NewHostAggregate("host1", "Linux 5.10")
- hagg.FirstBoot = 5000
- hagg.LastSeen = 1000
+ hagg.Stats.FirstBoot = 5000
+ hagg.Stats.LastSeen = 1000
if got := hagg.Lifespan(); got != 0 {
t.Errorf("Lifespan() = %d, want 0 when LastSeen < FirstBoot", got)
@@ -137,9 +137,9 @@ func TestHostAggregateDowntimeUnderflow(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
hagg := NewHostAggregate("host1", "Linux 5.10")
- hagg.FirstBoot = tt.firstBoot
- hagg.LastSeen = tt.lastSeen
- hagg.Uptime = tt.uptime
+ hagg.Stats.FirstBoot = tt.firstBoot
+ hagg.Stats.LastSeen = tt.lastSeen
+ hagg.Stats.Uptime = tt.uptime
if got := hagg.Downtime(); got != 0 {
t.Errorf("Downtime() = %d, want 0", got)
}