mirror of
https://github.com/clastix/kamaji.git
synced 2026-08-26 00:47:20 +00:00
- Add DefaultKubernetesVersion constant in api/v1alpha1 - Update e2e tests to use the constant - Update deploy/*.env and config/samples/*.yaml files
400 lines
12 KiB
Go
400 lines
12 KiB
Go
// Copyright 2022 Clastix Labs
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
package metrics
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"github.com/prometheus/client_golang/prometheus"
|
|
io_prometheus_client "github.com/prometheus/client_model/go"
|
|
"sigs.k8s.io/controller-runtime/pkg/metrics"
|
|
|
|
kamajiv1alpha1 "github.com/clastix/kamaji/api/v1alpha1"
|
|
)
|
|
|
|
func testRecorder() *Recorder {
|
|
return DefaultRecorder()
|
|
}
|
|
|
|
func TestKamajiMetricRegistration(t *testing.T) {
|
|
t.Helper()
|
|
recorder := testRecorder()
|
|
|
|
recorder.ResetDatastoresReadyAndDriverCounts()
|
|
recorder.SetDatastoresReadyAndDriverCounts("default", map[string]map[string]int{
|
|
ReadyLabelTrue: {
|
|
string(kamajiv1alpha1.EtcdDriver): 1,
|
|
},
|
|
})
|
|
|
|
recorder.ResetCertificatesStatusCounts()
|
|
recorder.SetCertificatesStatusCounts("default", "k8s-133", map[string]map[string]int{
|
|
CertificateStatusValid: {
|
|
CertificateStrategyX509: 1,
|
|
},
|
|
})
|
|
|
|
wanted := map[string]struct{}{
|
|
"kamaji_build_info": {},
|
|
"kamaji_tenant_control_planes_current": {},
|
|
"kamaji_datastores_current": {},
|
|
"kamaji_certificates_current": {},
|
|
}
|
|
|
|
families, err := metrics.Registry.Gather()
|
|
if err != nil {
|
|
t.Fatalf("failed to gather metrics: %v", err)
|
|
}
|
|
|
|
seen := map[string]struct{}{}
|
|
for _, family := range families {
|
|
if _, ok := wanted[family.GetName()]; ok {
|
|
seen[family.GetName()] = struct{}{}
|
|
}
|
|
}
|
|
|
|
for name := range wanted {
|
|
if _, ok := seen[name]; !ok {
|
|
t.Fatalf("metric %s not registered", name)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestNewRecorderWithCustomRegistry(t *testing.T) {
|
|
t.Helper()
|
|
|
|
registry := prometheus.NewRegistry()
|
|
recorder := NewRecorder(registry)
|
|
recorder.SetTenantControlPlanesReadyCounts(map[string]int{
|
|
ReadyLabelTrue: 1,
|
|
ReadyLabelFalse: 0,
|
|
})
|
|
|
|
family := mustMetricFamilyFromGatherer(t, registry, "kamaji_tenant_control_planes_current")
|
|
if got := gaugeValueByLabels(t, family, map[string]string{"ready": ReadyLabelTrue}); got != 1 {
|
|
t.Fatalf("expected ready control planes gauge to be 1 on custom registry, got %v", got)
|
|
}
|
|
}
|
|
|
|
func TestTenantControlPlanesCountGaugeByStatus(t *testing.T) {
|
|
t.Helper()
|
|
recorder := testRecorder()
|
|
|
|
recorder.SetTenantControlPlanesReadyCounts(map[string]int{
|
|
ReadyLabelTrue: 2,
|
|
ReadyLabelFalse: 1,
|
|
})
|
|
|
|
family := mustMetricFamily(t, "kamaji_tenant_control_planes_current")
|
|
if len(family.GetMetric()) != len(readyLabelValues) {
|
|
t.Fatalf("expected %d ready-only gauge metrics, got %d", len(readyLabelValues), len(family.GetMetric()))
|
|
}
|
|
|
|
if got := gaugeValueByLabels(t, family, map[string]string{"ready": ReadyLabelTrue}); got != 2 {
|
|
t.Fatalf("expected ready control planes gauge to be 2, got %v", got)
|
|
}
|
|
|
|
if got := gaugeValueByLabels(t, family, map[string]string{"ready": ReadyLabelFalse}); got != 1 {
|
|
t.Fatalf("expected not-ready control planes gauge to be 1, got %v", got)
|
|
}
|
|
}
|
|
|
|
func TestDatastoresCountGaugeByStatus(t *testing.T) {
|
|
t.Helper()
|
|
recorder := testRecorder()
|
|
|
|
recorder.ResetDatastoresReadyAndDriverCounts()
|
|
|
|
recorder.SetDatastoresReadyAndDriverCounts("default", map[string]map[string]int{
|
|
ReadyLabelTrue: {
|
|
string(kamajiv1alpha1.EtcdDriver): 1,
|
|
},
|
|
ReadyLabelFalse: {
|
|
string(kamajiv1alpha1.EtcdDriver): 0,
|
|
},
|
|
})
|
|
recorder.SetDatastoresReadyAndDriverCounts("secondary", map[string]map[string]int{
|
|
ReadyLabelTrue: {
|
|
string(kamajiv1alpha1.KineMySQLDriver): 1,
|
|
},
|
|
ReadyLabelFalse: {
|
|
string(kamajiv1alpha1.KineMySQLDriver): 0,
|
|
},
|
|
})
|
|
|
|
family := mustMetricFamily(t, "kamaji_datastores_current")
|
|
if len(family.GetMetric()) != 4 {
|
|
t.Fatalf("expected 4 name-ready-driver gauge metrics, got %d", len(family.GetMetric()))
|
|
}
|
|
|
|
assertMetricFamilyHasLabels(t, family, "datastore_name", "ready", "driver")
|
|
assertMetricFamilyDoesNotHaveLabels(t, family, "namespace")
|
|
|
|
if got := gaugeValueByLabels(t, family, map[string]string{"datastore_name": "default", "ready": ReadyLabelTrue, "driver": string(kamajiv1alpha1.EtcdDriver)}); got != 1 {
|
|
t.Fatalf("expected ready datastores gauge to be 1, got %v", got)
|
|
}
|
|
|
|
if got := gaugeValueByLabels(t, family, map[string]string{"datastore_name": "default", "ready": ReadyLabelFalse, "driver": string(kamajiv1alpha1.EtcdDriver)}); got != 0 {
|
|
t.Fatalf("expected not_ready/etcd datastores gauge to be 0, got %v", got)
|
|
}
|
|
|
|
if got := gaugeValueByLabels(t, family, map[string]string{"datastore_name": "secondary", "ready": ReadyLabelTrue, "driver": string(kamajiv1alpha1.KineMySQLDriver)}); got != 1 {
|
|
t.Fatalf("expected secondary/mysql ready datastores gauge to be 1, got %v", got)
|
|
}
|
|
|
|
if got := gaugeValueByLabels(t, family, map[string]string{"datastore_name": "secondary", "ready": ReadyLabelFalse, "driver": string(kamajiv1alpha1.KineMySQLDriver)}); got != 0 {
|
|
t.Fatalf("expected secondary/mysql not-ready datastores gauge to be 0, got %v", got)
|
|
}
|
|
}
|
|
|
|
func TestDataStoreInfoMetric(t *testing.T) {
|
|
t.Helper()
|
|
recorder := testRecorder()
|
|
|
|
recorder.ResetDataStoreInfo()
|
|
recorder.SetDataStoreInfo("default", string(kamajiv1alpha1.EtcdDriver))
|
|
|
|
family := mustMetricFamily(t, "kamaji_datastore_info")
|
|
if len(family.GetMetric()) != 1 {
|
|
t.Fatalf("expected one datastore_info sample, got %d", len(family.GetMetric()))
|
|
}
|
|
|
|
labels := map[string]string{
|
|
"datastore_name": "default",
|
|
"driver": string(kamajiv1alpha1.EtcdDriver),
|
|
}
|
|
|
|
assertMetricFamilyHasLabels(t, family, "datastore_name", "driver")
|
|
assertMetricFamilyDoesNotHaveLabels(t, family, "tls", "basic_auth")
|
|
|
|
if got := gaugeValueByLabels(t, family, labels); got != 1 {
|
|
t.Fatalf("expected datastore_info value to be 1, got %v", got)
|
|
}
|
|
}
|
|
|
|
func TestDataStoreStatusMetric(t *testing.T) {
|
|
t.Helper()
|
|
recorder := testRecorder()
|
|
|
|
recorder.ResetDataStoreStatus()
|
|
recorder.SetDataStoreStatus("default", DataStoreStatusTrue, ReadyLabelTrue)
|
|
|
|
family := mustMetricFamily(t, "kamaji_datastore_status")
|
|
if len(family.GetMetric()) != 1 {
|
|
t.Fatalf("expected one datastore_status sample, got %d", len(family.GetMetric()))
|
|
}
|
|
|
|
labels := map[string]string{
|
|
"datastore_name": "default",
|
|
"status": DataStoreStatusTrue,
|
|
"ready": ReadyLabelTrue,
|
|
}
|
|
|
|
if got := gaugeValueByLabels(t, family, labels); got != 1 {
|
|
t.Fatalf("expected datastore_status value to be 1, got %v", got)
|
|
}
|
|
}
|
|
|
|
func TestBuildInfoMetricHasSingleSample(t *testing.T) {
|
|
t.Helper()
|
|
|
|
family := mustMetricFamily(t, "kamaji_build_info")
|
|
if len(family.GetMetric()) != 1 {
|
|
t.Fatalf("expected a single build info metric, got %d", len(family.GetMetric()))
|
|
}
|
|
|
|
if got := family.GetMetric()[0].GetGauge().GetValue(); got != 1 {
|
|
t.Fatalf("expected build info gauge to be 1, got %v", got)
|
|
}
|
|
}
|
|
|
|
func TestTenantControlPlaneInfoMetric(t *testing.T) {
|
|
t.Helper()
|
|
recorder := testRecorder()
|
|
|
|
recorder.ResetTenantControlPlaneInfo()
|
|
recorder.SetTenantControlPlaneInfo("default", "test", kamajiv1alpha1.DefaultKubernetesVersion, string(kamajiv1alpha1.EtcdDriver), "https://203.0.113.10:6443", TenantControlPlaneExposureService)
|
|
|
|
family := mustMetricFamily(t, "kamaji_tenant_control_plane_info")
|
|
if len(family.GetMetric()) != 1 {
|
|
t.Fatalf("expected one tenant_control_plane_info sample, got %d", len(family.GetMetric()))
|
|
}
|
|
|
|
labels := map[string]string{
|
|
"tcp_namespace": "default",
|
|
"tcp_name": "test",
|
|
"kubernetes_version": kamajiv1alpha1.DefaultKubernetesVersion,
|
|
"datastore_driver": string(kamajiv1alpha1.EtcdDriver),
|
|
"address": "https://203.0.113.10:6443",
|
|
"exposure_strategy": TenantControlPlaneExposureService,
|
|
}
|
|
|
|
assertMetricFamilyHasLabels(t, family, "tcp_namespace", "tcp_name", "kubernetes_version", "datastore_driver", "address", "exposure_strategy")
|
|
assertMetricFamilyDoesNotHaveLabels(t, family, "namespace", "name")
|
|
|
|
if got := gaugeValueByLabels(t, family, labels); got != 1 {
|
|
t.Fatalf("expected tenant_control_plane_info value to be 1, got %v", got)
|
|
}
|
|
}
|
|
|
|
func TestTenantControlPlaneStatusMetric(t *testing.T) {
|
|
t.Helper()
|
|
recorder := testRecorder()
|
|
|
|
recorder.ResetTenantControlPlaneStatus()
|
|
recorder.SetTenantControlPlaneStatus("default", "test", string(kamajiv1alpha1.VersionReady), ReadyLabelTrue)
|
|
|
|
family := mustMetricFamily(t, "kamaji_tenant_control_plane_status")
|
|
if len(family.GetMetric()) != 1 {
|
|
t.Fatalf("expected one tenant_control_plane_status sample, got %d", len(family.GetMetric()))
|
|
}
|
|
|
|
labels := map[string]string{
|
|
"tcp_namespace": "default",
|
|
"tcp_name": "test",
|
|
"status": string(kamajiv1alpha1.VersionReady),
|
|
"ready": ReadyLabelTrue,
|
|
}
|
|
|
|
assertMetricFamilyHasLabels(t, family, "tcp_namespace", "tcp_name", "status", "ready")
|
|
assertMetricFamilyDoesNotHaveLabels(t, family, "namespace", "name")
|
|
|
|
if got := gaugeValueByLabels(t, family, labels); got != 1 {
|
|
t.Fatalf("expected tenant_control_plane_status value to be 1, got %v", got)
|
|
}
|
|
}
|
|
|
|
func TestCertificatesCountGaugeByStatusAndStrategy(t *testing.T) {
|
|
t.Helper()
|
|
recorder := testRecorder()
|
|
|
|
recorder.ResetCertificatesStatusCounts()
|
|
|
|
recorder.SetCertificatesStatusCounts("default", "k8s-133", map[string]map[string]int{
|
|
CertificateStatusValid: {
|
|
CertificateStrategyX509: 4,
|
|
CertificateStrategyKubeconfig: 1,
|
|
},
|
|
CertificateStatusExpiring: {
|
|
CertificateStrategyX509: 2,
|
|
CertificateStrategyKubeconfig: 0,
|
|
},
|
|
CertificateStatusInvalid: {
|
|
CertificateStrategyX509: 1,
|
|
CertificateStrategyKubeconfig: 3,
|
|
},
|
|
})
|
|
|
|
family := mustMetricFamily(t, "kamaji_certificates_current")
|
|
if len(family.GetMetric()) != len(certificateStatuses)*len(certificateStrategies) {
|
|
t.Fatalf("expected %d tcp_namespace-tcp_name-status-strategy gauge metrics, got %d", len(certificateStatuses)*len(certificateStrategies), len(family.GetMetric()))
|
|
}
|
|
|
|
assertMetricFamilyHasLabels(t, family, "tcp_namespace", "tcp_name", "status", "strategy")
|
|
assertMetricFamilyDoesNotHaveLabels(t, family, "namespace", "name")
|
|
|
|
if got := gaugeValueByLabels(t, family, map[string]string{"tcp_namespace": "default", "tcp_name": "k8s-133", "status": CertificateStatusValid, "strategy": CertificateStrategyX509}); got != 4 {
|
|
t.Fatalf("expected valid/x509 certificates gauge to be 4, got %v", got)
|
|
}
|
|
|
|
if got := gaugeValueByLabels(t, family, map[string]string{"tcp_namespace": "default", "tcp_name": "k8s-133", "status": CertificateStatusInvalid, "strategy": CertificateStrategyKubeconfig}); got != 3 {
|
|
t.Fatalf("expected invalid/kubeconfig certificates gauge to be 3, got %v", got)
|
|
}
|
|
}
|
|
|
|
func assertMetricFamilyHasLabels(t *testing.T, family *io_prometheus_client.MetricFamily, labels ...string) {
|
|
t.Helper()
|
|
|
|
if len(family.GetMetric()) == 0 {
|
|
t.Fatalf("metric family %s has no samples", family.GetName())
|
|
}
|
|
|
|
present := map[string]struct{}{}
|
|
for _, label := range family.GetMetric()[0].GetLabel() {
|
|
present[label.GetName()] = struct{}{}
|
|
}
|
|
|
|
for _, expected := range labels {
|
|
if _, ok := present[expected]; !ok {
|
|
t.Fatalf("metric family %s missing label %s", family.GetName(), expected)
|
|
}
|
|
}
|
|
}
|
|
|
|
func assertMetricFamilyDoesNotHaveLabels(t *testing.T, family *io_prometheus_client.MetricFamily, labels ...string) {
|
|
t.Helper()
|
|
|
|
if len(family.GetMetric()) == 0 {
|
|
t.Fatalf("metric family %s has no samples", family.GetName())
|
|
}
|
|
|
|
present := map[string]struct{}{}
|
|
for _, label := range family.GetMetric()[0].GetLabel() {
|
|
present[label.GetName()] = struct{}{}
|
|
}
|
|
|
|
for _, forbidden := range labels {
|
|
if _, ok := present[forbidden]; ok {
|
|
t.Fatalf("metric family %s unexpectedly contains label %s", family.GetName(), forbidden)
|
|
}
|
|
}
|
|
}
|
|
|
|
func mustMetricFamily(t *testing.T, name string) *io_prometheus_client.MetricFamily {
|
|
t.Helper()
|
|
|
|
return mustMetricFamilyFromGatherer(t, metrics.Registry, name)
|
|
}
|
|
|
|
func mustMetricFamilyFromGatherer(t *testing.T, gatherer prometheus.Gatherer, name string) *io_prometheus_client.MetricFamily {
|
|
t.Helper()
|
|
|
|
families, err := gatherer.Gather()
|
|
if err != nil {
|
|
t.Fatalf("failed to gather metrics: %v", err)
|
|
}
|
|
|
|
for _, family := range families {
|
|
if family.GetName() == name {
|
|
return family
|
|
}
|
|
}
|
|
|
|
t.Fatalf("metric family %s not found", name)
|
|
|
|
return nil
|
|
}
|
|
|
|
func gaugeValueByLabels(t *testing.T, family *io_prometheus_client.MetricFamily, labels map[string]string) float64 {
|
|
t.Helper()
|
|
|
|
for _, metric := range family.GetMetric() {
|
|
allMatch := true
|
|
for name, value := range labels {
|
|
matched := false
|
|
for _, label := range metric.GetLabel() {
|
|
if label.GetName() == name && label.GetValue() == value {
|
|
matched = true
|
|
|
|
break
|
|
}
|
|
}
|
|
|
|
if !matched {
|
|
allMatch = false
|
|
|
|
break
|
|
}
|
|
}
|
|
|
|
if allMatch {
|
|
return metric.GetGauge().GetValue()
|
|
}
|
|
}
|
|
|
|
t.Fatalf("metric with labels %v not found", labels)
|
|
|
|
return 0
|
|
}
|