open-vault/vault/core_metrics_test.go

180 lines
4.2 KiB
Go
Raw Normal View History

package vault
import (
"strings"
"testing"
"time"
"github.com/armon/go-metrics"
logicalKv "github.com/hashicorp/vault-plugin-secrets-kv"
"github.com/hashicorp/vault/helper/metricsutil"
"github.com/hashicorp/vault/helper/namespace"
"github.com/hashicorp/vault/sdk/logical"
)
func TestCoreMetrics_KvSecretGauge(t *testing.T) {
// Use the real KV implementation instead of Passthrough
AddTestLogicalBackend("kv", logicalKv.Factory)
// Clean up for the next test-- is there a better way?
defer func() {
delete(testLogicalBackends, "kv")
}()
core, _, root := TestCoreUnsealed(t)
testMounts := []struct {
Path string
Version string
ExpectedCount int
}{
{"secret/", "2", 0},
{"secret1/", "1", 3},
{"secret2/", "1", 0},
{"secret3/", "2", 4},
{"prefix/secret3/", "2", 0},
{"prefix/secret4/", "2", 5},
}
ctx := namespace.RootContext(nil)
// skip 0, secret/ is already mounted
for _, tm := range testMounts[1:] {
me := &MountEntry{
Table: mountTableType,
Path: sanitizeMountPath(tm.Path),
Type: "kv",
Options: map[string]string{"version": tm.Version},
}
err := core.mount(ctx, me)
if err != nil {
t.Fatalf("err: %v", err)
}
}
v1secrets := []string{
"secret1/a", // 3
"secret1/b",
"secret1/c/d",
}
v2secrets := []string{
"secret3/data/a", // 4
"secret3/data/b",
"secret3/data/c/d",
"secret3/data/c/e",
"prefix/secret4/data/a/secret", // 5
"prefix/secret4/data/a/secret2",
"prefix/secret4/data/a/b/c/secret",
"prefix/secret4/data/a/b/c/secret2",
"prefix/secret4/data/a/b/c/d/secret3",
}
for _, p := range v1secrets {
req := logical.TestRequest(t, logical.CreateOperation, p)
req.Data["foo"] = "bar"
req.ClientToken = root
resp, err := core.HandleRequest(ctx, req)
if err != nil {
t.Fatalf("err: %v", err)
}
if resp != nil {
t.Fatalf("bad: %#v", resp)
}
}
for _, p := range v2secrets {
req := logical.TestRequest(t, logical.CreateOperation, p)
req.Data["data"] = map[string]interface{}{"foo": "bar"}
req.ClientToken = root
resp, err := core.HandleRequest(ctx, req)
if err != nil {
t.Fatalf("err: %v", err)
}
if resp.Error() != nil {
t.Fatalf("bad: %#v", resp)
}
}
values, err := core.kvSecretGaugeCollector(ctx)
if err != nil {
t.Fatalf("err: %v", err)
}
if len(values) != len(testMounts) {
t.Errorf("Got %v values but expected %v mounts", len(values), len(testMounts))
}
for _, glv := range values {
mountPoint := ""
for _, l := range glv.Labels {
if l.Name == "mount_point" {
mountPoint = l.Value
} else if l.Name == "namespace" {
if l.Value != "root" {
t.Errorf("Namespace is %v, not root", l.Value)
}
} else {
t.Errorf("Unexpected label %v", l.Name)
}
}
if mountPoint == "" {
t.Errorf("No mount point in labels %v", glv.Labels)
continue
}
found := false
for _, tm := range testMounts {
if tm.Path == mountPoint {
found = true
if glv.Value != float32(tm.ExpectedCount) {
t.Errorf("Mount %v reported %v, not %v",
tm.Path, glv.Value, tm.ExpectedCount)
}
break
}
}
if !found {
t.Errorf("Unexpected mount point %v", mountPoint)
}
}
}
func TestCoreMetrics_KvSecretGaugeError(t *testing.T) {
core := TestCore(t)
// Replace metricSink before unsealing
inmemSink := metrics.NewInmemSink(
1000000*time.Hour,
2000000*time.Hour)
core.metricSink = metricsutil.NewClusterMetricSink("test-cluster", inmemSink)
testCoreUnsealed(t, core)
ctx := namespace.RootContext(nil)
badKvMount := &kvMount{
Namespace: namespace.RootNamespace,
MountPoint: "bad/path",
Version: "1",
NumSecrets: 0,
}
core.walkKvMountSecrets(ctx, badKvMount)
intervals := inmemSink.Data()
// Test crossed an interval boundary, don't try to deal with it.
if len(intervals) > 1 {
t.Skip("Detected interval crossing.")
}
// Should be an error
keyPrefix := "metrics.collection.error"
var counter *metrics.SampledValue = nil
for _, c := range intervals[0].Counters {
if strings.HasPrefix(c.Name, keyPrefix) {
counter = &c
break
}
}
if counter == nil {
t.Fatal("No metrics.collection.error counter found.")
}
if counter.Count != 1 {
t.Errorf("Counter number of samples %v is not 1.", counter.Count)
}
}