mirror of
https://github.com/clastix/kamaji.git
synced 2026-04-15 06:56:47 +00:00
138 lines
4.7 KiB
Go
138 lines
4.7 KiB
Go
// Copyright 2022 Clastix Labs
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
package controllers
|
|
|
|
import (
|
|
"crypto/rand"
|
|
"crypto/rsa"
|
|
"crypto/x509"
|
|
"crypto/x509/pkix"
|
|
"encoding/pem"
|
|
"math/big"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/prometheus/client_golang/prometheus"
|
|
corev1 "k8s.io/api/core/v1"
|
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
"k8s.io/apimachinery/pkg/runtime"
|
|
"sigs.k8s.io/controller-runtime/pkg/client/fake"
|
|
|
|
kamajiv1alpha1 "github.com/clastix/kamaji/api/v1alpha1"
|
|
"github.com/clastix/kamaji/internal/constants"
|
|
"github.com/clastix/kamaji/internal/metrics"
|
|
"github.com/clastix/kamaji/internal/utilities"
|
|
)
|
|
|
|
func TestCertificateRefreshMetrics(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
scheme := runtime.NewScheme()
|
|
if err := kamajiv1alpha1.AddToScheme(scheme); err != nil {
|
|
t.Fatalf("failed adding kamaji scheme: %v", err)
|
|
}
|
|
if err := corev1.AddToScheme(scheme); err != nil {
|
|
t.Fatalf("failed adding corev1 scheme: %v", err)
|
|
}
|
|
|
|
validCertPEM, err := testCertificatePEM(time.Now().Add(48 * time.Hour))
|
|
if err != nil {
|
|
t.Fatalf("failed generating valid cert: %v", err)
|
|
}
|
|
expiringCertPEM, err := testCertificatePEM(time.Now().Add(30 * time.Minute))
|
|
if err != nil {
|
|
t.Fatalf("failed generating expiring cert: %v", err)
|
|
}
|
|
|
|
reader := fake.NewClientBuilder().WithScheme(scheme).WithObjects(
|
|
&kamajiv1alpha1.TenantControlPlane{ObjectMeta: metav1.ObjectMeta{Name: "tcp-a", Namespace: "default"}},
|
|
&corev1.Secret{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "cert-valid",
|
|
Namespace: "default",
|
|
Labels: map[string]string{
|
|
constants.ControlPlaneLabelKey: "tcp-a",
|
|
constants.ControllerLabelResource: utilities.CertificateX509Label,
|
|
},
|
|
},
|
|
Data: map[string][]byte{"tls.crt": validCertPEM},
|
|
},
|
|
&corev1.Secret{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "cert-expiring",
|
|
Namespace: "default",
|
|
Labels: map[string]string{
|
|
constants.ControlPlaneLabelKey: "tcp-a",
|
|
constants.ControllerLabelResource: utilities.CertificateX509Label,
|
|
},
|
|
},
|
|
Data: map[string][]byte{"tls.crt": expiringCertPEM},
|
|
},
|
|
&corev1.Secret{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "cert-invalid",
|
|
Namespace: "default",
|
|
Labels: map[string]string{
|
|
constants.ControlPlaneLabelKey: "tcp-a",
|
|
constants.ControllerLabelResource: utilities.CertificateX509Label,
|
|
},
|
|
},
|
|
Data: map[string][]byte{"tls.crt": []byte("not-a-certificate")},
|
|
},
|
|
).Build()
|
|
|
|
registry := prometheus.NewRegistry()
|
|
recorder := metrics.NewRecorder(registry)
|
|
|
|
s := &CertificateLifecycle{
|
|
Deadline: 24 * time.Hour,
|
|
client: reader,
|
|
Metrics: recorder,
|
|
}
|
|
|
|
if err := s.refreshCertificatesMetrics(t.Context()); err != nil {
|
|
t.Fatalf("refreshCertificatesMetrics returned error: %v", err)
|
|
}
|
|
|
|
family := mustMetricFamilyFromGatherer(t, registry, "kamaji_certificates_current")
|
|
if got := gaugeValueByLabels(t, family, map[string]string{"tcp_namespace": "default", "tcp_name": "tcp-a", "status": metrics.CertificateStatusValid, "strategy": metrics.CertificateStrategyX509}); got != 1 {
|
|
t.Fatalf("expected valid/x509 certificates gauge to be 1, got %v", got)
|
|
}
|
|
if got := gaugeValueByLabels(t, family, map[string]string{"tcp_namespace": "default", "tcp_name": "tcp-a", "status": metrics.CertificateStatusExpiring, "strategy": metrics.CertificateStrategyX509}); got != 1 {
|
|
t.Fatalf("expected expiring/x509 certificates gauge to be 1, got %v", got)
|
|
}
|
|
if got := gaugeValueByLabels(t, family, map[string]string{"tcp_namespace": "default", "tcp_name": "tcp-a", "status": metrics.CertificateStatusInvalid, "strategy": metrics.CertificateStrategyX509}); got != 1 {
|
|
t.Fatalf("expected invalid/x509 certificates gauge to be 1, got %v", got)
|
|
}
|
|
if got := gaugeValueByLabels(t, family, map[string]string{"tcp_namespace": "default", "tcp_name": "tcp-a", "status": metrics.CertificateStatusValid, "strategy": metrics.CertificateStrategyKubeconfig}); got != 0 {
|
|
t.Fatalf("expected valid/kubeconfig certificates gauge to be 0, got %v", got)
|
|
}
|
|
}
|
|
|
|
func testCertificatePEM(notAfter time.Time) ([]byte, error) {
|
|
privateKey, err := rsa.GenerateKey(rand.Reader, 2048)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
template := &x509.Certificate{
|
|
SerialNumber: big.NewInt(1),
|
|
Subject: pkix.Name{
|
|
CommonName: "metrics-test",
|
|
},
|
|
NotBefore: time.Now().Add(-time.Minute),
|
|
NotAfter: notAfter,
|
|
KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageKeyEncipherment,
|
|
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
|
|
BasicConstraintsValid: true,
|
|
}
|
|
|
|
derBytes, err := x509.CreateCertificate(rand.Reader, template, template, &privateKey.PublicKey, privateKey)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: derBytes}), nil
|
|
}
|