Skip to content

Commit

Permalink
feat: keyperfmetrics collector infrastructure (#3078)
Browse files Browse the repository at this point in the history
* feat: keyperfmetrics collector infrastructure

* feat: keyperfmetrics collector infrastructure

* feat: keyperfmetrics collector infrastructure (#3079)

* feat: keyperfmetrics collector infrastructure

* feat: keyperfmetrics collector infrastructure

* feat: change to use KeyPerf name

---------

Co-authored-by: Chris Grindstaff <[email protected]>
  • Loading branch information
rahulguptajss and cgrinds authored Aug 2, 2024
1 parent 24cdce6 commit aa822f3
Show file tree
Hide file tree
Showing 23 changed files with 2,364 additions and 38 deletions.
457 changes: 457 additions & 0 deletions cmd/collectors/keyperf/keyperf.go

Large diffs are not rendered by default.

213 changes: 213 additions & 0 deletions cmd/collectors/keyperf/keyperf_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,213 @@
package keyperf

import (
"fmt"
"github.com/netapp/harvest/v2/cmd/collectors"
"github.com/netapp/harvest/v2/cmd/poller/collector"
"github.com/netapp/harvest/v2/cmd/poller/options"
"github.com/netapp/harvest/v2/pkg/conf"
"github.com/netapp/harvest/v2/pkg/matrix"
"github.com/netapp/harvest/v2/pkg/tree"
"github.com/netapp/harvest/v2/pkg/tree/node"
"sort"
"testing"
"time"
)

const (
pollerName = "test"
)

func TestPartialAggregationSequence(t *testing.T) {
conf.TestLoadHarvestConfig("testdata/config.yml")
kp := newKeyPerf("Volume", "volume.yaml")

// First Poll
t.Log("Running First Poll")
kp.testPollInstanceAndDataWithMetrics(t, "testdata/partialAggregation/volume-poll-1.json", 0, 0)

// Complete Poll
t.Log("Running Complete Poll")
kp.testPollInstanceAndDataWithMetrics(t, "testdata/partialAggregation/volume-poll-2.json", 4, 48)

// Partial Poll
t.Log("Running Partial Poll")
kp.testPollInstanceAndDataWithMetrics(t, "testdata/partialAggregation/volume-poll-partial.json", 4, 36)

// Partial Poll 2
t.Log("Running Partial Poll 2")
kp.testPollInstanceAndDataWithMetrics(t, "testdata/partialAggregation/volume-poll-partial.json", 4, 36)
if t.Failed() {
t.Fatal("Partial Poll 2 failed")
}

// First Complete Poll After Partial
t.Log("Running First Complete Poll After Partial")
kp.testPollInstanceAndDataWithMetrics(t, "testdata/partialAggregation/volume-poll-3.json", 4, 36)
if t.Failed() {
t.Fatal("First Complete Poll After Partial failed")
}

// Second Complete Poll After Partial
t.Log("Running First Complete Poll After Partial")
kp.testPollInstanceAndDataWithMetrics(t, "testdata/partialAggregation/volume-poll-3.json", 4, 48)
if t.Failed() {
t.Fatal("First Complete Poll After Partial failed")
}

// Partial Poll 3
t.Log("Running Partial Poll 3")
kp.testPollInstanceAndDataWithMetrics(t, "testdata/partialAggregation/volume-poll-partial-2.json", 4, 36)
if t.Failed() {
t.Fatal("Partial Poll 3 failed")
}
}

func (kp *KeyPerf) testPollInstanceAndDataWithMetrics(t *testing.T, pollDataFile string, expectedExportedInst, expectedExportedMetrics int) *matrix.Matrix {
// Additional logic to count metrics
pollData := collectors.JSONToGson(pollDataFile, true)
now := time.Now().Truncate(time.Second)
data, err := kp.pollData(now, pollData, nil)
if err != nil {
t.Fatal(err)
}

totalMetrics := 0
exportableInstance := 0
mat := data[kp.Object]
if mat != nil {
for _, instance := range mat.GetInstances() {
if instance.IsExportable() {
exportableInstance++
}
}
for _, met := range mat.GetMetrics() {
if !met.IsExportable() {
continue
}
records := met.GetRecords()
for _, v := range records {
if v {
totalMetrics++
}
}
}
}

if exportableInstance != expectedExportedInst {
t.Errorf("Exported instances got=%d, expected=%d", exportableInstance, expectedExportedInst)
}

// Check if the total number of metrics matches the expected value
if totalMetrics != expectedExportedMetrics {
t.Errorf("Total metrics got=%d, expected=%d", totalMetrics, expectedExportedMetrics)
}
return mat
}

func TestKeyPerf_pollData(t *testing.T) {
conf.TestLoadHarvestConfig("testdata/config.yml")
tests := []struct {
name string
wantErr bool
pollDataPath1 string
pollDataPath2 string
counter string
sum int64
numInstances int
numMetrics int
record bool
}{
{
name: "statistics.iops_raw.read",
counter: "statistics.iops_raw.read",
pollDataPath1: "testdata/volume-poll-1.json",
pollDataPath2: "testdata/volume-poll-2.json",
numInstances: 4,
numMetrics: 48,
sum: 4608,
record: true,
},
{
name: "statistics.latency_raw.read",
counter: "statistics.latency_raw.read",
pollDataPath1: "testdata/volume-poll-1.json",
pollDataPath2: "testdata/volume-poll-2.json",
numInstances: 4,
numMetrics: 48,
sum: 1114,
record: true,
},
{
name: "statistics.latency_raw.read",
counter: "statistics.latency_raw.read",
pollDataPath1: "testdata/missingStats/volume-poll-1.json",
pollDataPath2: "testdata/missingStats/volume-poll-2.json",
numInstances: 1,
numMetrics: 0,
sum: 0,
record: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {

kp := newKeyPerf("Volume", "volume.yaml")
// First poll data
kp.testPollInstanceAndDataWithMetrics(t, tt.pollDataPath1, 0, 0)
// Complete Poll
m := kp.testPollInstanceAndDataWithMetrics(t, tt.pollDataPath2, tt.numInstances, tt.numMetrics)

var sum int64
var names []string
for n := range m.GetInstances() {
names = append(names, n)
}
sort.Strings(names)
metric := m.GetMetric(tt.counter)
for _, name := range names {
i := m.GetInstance(name)
val, recorded := metric.GetValueInt64(i)
if recorded != tt.record {
t.Errorf("pollData() recorded got=%v, want=%v", recorded, tt.record)
}
sum += val
}
if sum != tt.sum {
t.Errorf("pollData() sum got=%v, want=%v", sum, tt.sum)
}
})
}
}

func newKeyPerf(object string, path string) *KeyPerf {
var err error
opts := options.New(options.WithConfPath("testdata/conf"))
opts.Poller = pollerName
opts.HomePath = "testdata"
opts.IsTest = true

ac := collector.New("KeyPerf", object, opts, params(object, path), nil)
kp := KeyPerf{}
err = kp.Init(ac)
if err != nil {
panic(err)
}
return &kp
}

func params(object string, path string) *node.Node {
yml := `
schedule:
- counter: 9999h
- data: 9999h
objects:
%s: %s
`
yml = fmt.Sprintf(yml, object, path)
root, err := tree.LoadYaml([]byte(yml))
if err != nil {
panic(err)
}
return root
}
32 changes: 32 additions & 0 deletions cmd/collectors/keyperf/testdata/conf/keyperf/9.15.0/volume.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
name: Volume
query: api/storage/volumes
object: volume

counters:
- ^^name => volume
- ^^svm.name => svm
- ^style => style
- ^statistics.status => status
- statistics.timestamp(timestamp) => timestamp
- statistics.latency_raw.other => other_latency
- statistics.latency_raw.total => total_latency
- statistics.latency_raw.read => read_latency
- statistics.latency_raw.write => write_latency
- statistics.iops_raw.other => other_ops
- statistics.iops_raw.total => total_ops
- statistics.iops_raw.read => read_ops
- statistics.iops_raw.write => write_ops
- statistics.throughput_raw.other => other_data
- statistics.throughput_raw.total => total_data
- statistics.throughput_raw.read => read_data
- statistics.throughput_raw.write => write_data
- hidden_fields:
- statistics

export_options:
instance_keys:
- aggr
- node
- style
- svm
- volume
14 changes: 14 additions & 0 deletions cmd/collectors/keyperf/testdata/config.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
Exporters:
prometheus:
exporter: Prometheus
port: 12990

Defaults:
collectors:
- KeyPerf
exporters:
- prometheus

Pollers:
test:
addr: localhost
28 changes: 28 additions & 0 deletions cmd/collectors/keyperf/testdata/missingStats/volume-poll-1.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
{
"records": [
{
"uuid": "02d42517-2777-11ed-8553-00a098d390f2",
"name": "astra_302_m1",
"aggregates": [
{
"name": "test1",
"uuid": "c1931ba8-bb35-4b12-84dc-1e0643487144"
}
],
"svm": {
"name": "astra_302"
},
"_links": {
"self": {
"href": "/api/storage/volumes/02d42517-2777-11ed-8553-00a098d390f2"
}
}
}
],
"num_records": 1,
"_links": {
"self": {
"href": "/api/storage/volumes?return_records=true&fields=uuid,statistics,svm.name,aggregates&name=astra_302_m1"
}
}
}
28 changes: 28 additions & 0 deletions cmd/collectors/keyperf/testdata/missingStats/volume-poll-2.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
{
"records": [
{
"uuid": "02d42517-2777-11ed-8553-00a098d390f2",
"name": "astra_302_m1",
"aggregates": [
{
"name": "test1",
"uuid": "c1931ba8-bb35-4b12-84dc-1e0643487144"
}
],
"svm": {
"name": "astra_302"
},
"_links": {
"self": {
"href": "/api/storage/volumes/02d42517-2777-11ed-8553-00a098d390f2"
}
}
}
],
"num_records": 1,
"_links": {
"self": {
"href": "/api/storage/volumes?return_records=true&fields=uuid,statistics,svm.name,aggregates&name=astra_302_m1"
}
}
}
Loading

0 comments on commit aa822f3

Please sign in to comment.