SecretsManager: Refactor and clean metrics (#108908)
This commit is contained in:
@@ -27,7 +27,7 @@ type DecryptAuthorizer interface {
|
||||
Authorize(ctx context.Context, secureValueName string, secureValueDecrypters []string) (identity string, allowed bool)
|
||||
}
|
||||
|
||||
// DecryptService is the inferface for the decrypt service.
|
||||
// DecryptService is the interface for the decrypt service.
|
||||
type DecryptService interface {
|
||||
Decrypt(ctx context.Context, namespace string, names ...string) (map[string]DecryptResult, error)
|
||||
Close() error
|
||||
|
||||
@@ -0,0 +1,128 @@
|
||||
package metrics
|
||||
|
||||
import (
|
||||
"sync"
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
)
|
||||
|
||||
const (
|
||||
namespace = "grafana_secrets_manager"
|
||||
subsystem = "service"
|
||||
)
|
||||
|
||||
// SecureValueServiceMetrics is a struct that contains all the metrics for SecureValue.
|
||||
type SecureValueServiceMetrics struct {
|
||||
SecureValueCreateDuration *prometheus.HistogramVec
|
||||
SecureValueCreateCount *prometheus.CounterVec
|
||||
SecureValueUpdateDuration *prometheus.HistogramVec
|
||||
SecureValueUpdateCount *prometheus.CounterVec
|
||||
SecureValueReadDuration *prometheus.HistogramVec
|
||||
SecureValueReadCount *prometheus.CounterVec
|
||||
SecureValueListDuration *prometheus.HistogramVec
|
||||
SecureValueListCount *prometheus.CounterVec
|
||||
SecureValueDeleteDuration *prometheus.HistogramVec
|
||||
SecureValueDeleteCount *prometheus.CounterVec
|
||||
}
|
||||
|
||||
func newSecureValueServiceMetrics() *SecureValueServiceMetrics {
|
||||
return &SecureValueServiceMetrics{
|
||||
SecureValueCreateDuration: prometheus.NewHistogramVec(prometheus.HistogramOpts{
|
||||
Namespace: namespace,
|
||||
Subsystem: subsystem,
|
||||
Name: "secure_value_create_duration_seconds",
|
||||
Help: "Duration of Secure Value create operations",
|
||||
Buckets: prometheus.DefBuckets,
|
||||
}, []string{"success"}),
|
||||
SecureValueCreateCount: prometheus.NewCounterVec(prometheus.CounterOpts{
|
||||
Namespace: namespace,
|
||||
Subsystem: subsystem,
|
||||
Name: "secure_value_create_count",
|
||||
Help: "Count of Secure Value create operations",
|
||||
}, []string{"success"}),
|
||||
SecureValueReadDuration: prometheus.NewHistogramVec(prometheus.HistogramOpts{
|
||||
Namespace: namespace,
|
||||
Subsystem: subsystem,
|
||||
Name: "secure_value_read_duration_seconds",
|
||||
Help: "Duration of Secure Value read operations",
|
||||
Buckets: prometheus.DefBuckets,
|
||||
}, []string{"success"}),
|
||||
SecureValueReadCount: prometheus.NewCounterVec(prometheus.CounterOpts{
|
||||
Namespace: namespace,
|
||||
Subsystem: subsystem,
|
||||
Name: "secure_value_read_count",
|
||||
Help: "Count of Secure Value read operations",
|
||||
}, []string{"success"}),
|
||||
SecureValueUpdateDuration: prometheus.NewHistogramVec(prometheus.HistogramOpts{
|
||||
Namespace: namespace,
|
||||
Subsystem: subsystem,
|
||||
Name: "secure_value_update_duration_seconds",
|
||||
Help: "Duration of Secure Value update operations",
|
||||
Buckets: prometheus.DefBuckets,
|
||||
}, []string{"success"}),
|
||||
SecureValueUpdateCount: prometheus.NewCounterVec(prometheus.CounterOpts{
|
||||
Namespace: namespace,
|
||||
Subsystem: subsystem,
|
||||
Name: "secure_value_update_count",
|
||||
Help: "Count of Secure Value update operations",
|
||||
}, []string{"success"}),
|
||||
SecureValueListDuration: prometheus.NewHistogramVec(prometheus.HistogramOpts{
|
||||
Namespace: namespace,
|
||||
Subsystem: subsystem,
|
||||
Name: "secure_value_list_duration_seconds",
|
||||
Help: "Duration of Secure Value list operations",
|
||||
Buckets: prometheus.DefBuckets,
|
||||
}, []string{"success"}),
|
||||
SecureValueListCount: prometheus.NewCounterVec(prometheus.CounterOpts{
|
||||
Namespace: namespace,
|
||||
Subsystem: subsystem,
|
||||
Name: "secure_value_list_count",
|
||||
Help: "Count of Secure Value list operations",
|
||||
}, []string{"success"}),
|
||||
SecureValueDeleteDuration: prometheus.NewHistogramVec(prometheus.HistogramOpts{
|
||||
Namespace: namespace,
|
||||
Subsystem: subsystem,
|
||||
Name: "secure_value_delete_duration_seconds",
|
||||
Help: "Duration of Secure Value delete operations",
|
||||
Buckets: prometheus.DefBuckets,
|
||||
}, []string{"success"}),
|
||||
SecureValueDeleteCount: prometheus.NewCounterVec(prometheus.CounterOpts{
|
||||
Namespace: namespace,
|
||||
Subsystem: subsystem,
|
||||
Name: "secure_value_delete_count",
|
||||
Help: "Count of Secure Value delete operations",
|
||||
}, []string{"success"}),
|
||||
}
|
||||
}
|
||||
|
||||
var (
|
||||
initOnce sync.Once
|
||||
metricsInstance *SecureValueServiceMetrics
|
||||
)
|
||||
|
||||
func NewSecureValueServiceMetrics(reg prometheus.Registerer) *SecureValueServiceMetrics {
|
||||
initOnce.Do(func() {
|
||||
m := newSecureValueServiceMetrics()
|
||||
|
||||
if reg != nil {
|
||||
reg.MustRegister(
|
||||
m.SecureValueCreateDuration,
|
||||
m.SecureValueCreateCount,
|
||||
m.SecureValueReadDuration,
|
||||
m.SecureValueReadCount,
|
||||
m.SecureValueUpdateDuration,
|
||||
m.SecureValueUpdateCount,
|
||||
m.SecureValueListDuration,
|
||||
m.SecureValueListCount,
|
||||
m.SecureValueDeleteDuration,
|
||||
m.SecureValueDeleteCount,
|
||||
)
|
||||
}
|
||||
metricsInstance = m
|
||||
})
|
||||
return metricsInstance
|
||||
}
|
||||
|
||||
func NewTestMetrics() *SecureValueServiceMetrics {
|
||||
return newSecureValueServiceMetrics()
|
||||
}
|
||||
@@ -3,6 +3,8 @@ package service
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
claims "github.com/grafana/authlib/types"
|
||||
"go.opentelemetry.io/otel/attribute"
|
||||
@@ -12,9 +14,14 @@ import (
|
||||
secretv1beta1 "github.com/grafana/grafana/apps/secret/pkg/apis/secret/v1beta1"
|
||||
"github.com/grafana/grafana/pkg/apimachinery/utils"
|
||||
"github.com/grafana/grafana/pkg/registry/apis/secret/contracts"
|
||||
"github.com/grafana/grafana/pkg/registry/apis/secret/service/metrics"
|
||||
"github.com/grafana/grafana/pkg/registry/apis/secret/xkube"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"go.opentelemetry.io/otel/codes"
|
||||
)
|
||||
|
||||
var _ contracts.SecureValueService = (*SecureValueService)(nil)
|
||||
|
||||
type SecureValueService struct {
|
||||
tracer trace.Tracer
|
||||
accessClient claims.AccessClient
|
||||
@@ -22,6 +29,7 @@ type SecureValueService struct {
|
||||
secureValueMetadataStorage contracts.SecureValueMetadataStorage
|
||||
keeperMetadataStorage contracts.KeeperMetadataStorage
|
||||
keeperService contracts.KeeperService
|
||||
metrics *metrics.SecureValueServiceMetrics
|
||||
}
|
||||
|
||||
func ProvideSecureValueService(
|
||||
@@ -31,6 +39,7 @@ func ProvideSecureValueService(
|
||||
secureValueMetadataStorage contracts.SecureValueMetadataStorage,
|
||||
keeperMetadataStorage contracts.KeeperMetadataStorage,
|
||||
keeperService contracts.KeeperService,
|
||||
reg prometheus.Registerer,
|
||||
) contracts.SecureValueService {
|
||||
return &SecureValueService{
|
||||
tracer: tracer,
|
||||
@@ -39,27 +48,77 @@ func ProvideSecureValueService(
|
||||
secureValueMetadataStorage: secureValueMetadataStorage,
|
||||
keeperMetadataStorage: keeperMetadataStorage,
|
||||
keeperService: keeperService,
|
||||
metrics: metrics.NewSecureValueServiceMetrics(reg),
|
||||
}
|
||||
}
|
||||
|
||||
func (s *SecureValueService) Create(ctx context.Context, sv *secretv1beta1.SecureValue, actorUID string) (*secretv1beta1.SecureValue, error) {
|
||||
func (s *SecureValueService) Create(ctx context.Context, sv *secretv1beta1.SecureValue, actorUID string) (_ *secretv1beta1.SecureValue, createErr error) {
|
||||
start := time.Now()
|
||||
name, namespace := sv.GetName(), sv.GetNamespace()
|
||||
ctx, span := s.tracer.Start(ctx, "SecureValueService.Create", trace.WithAttributes(
|
||||
attribute.String("name", sv.GetName()),
|
||||
attribute.String("namespace", sv.GetNamespace()),
|
||||
attribute.String("name", name),
|
||||
attribute.String("namespace", namespace),
|
||||
attribute.String("actor", actorUID),
|
||||
))
|
||||
defer span.End()
|
||||
|
||||
defer func() {
|
||||
args := []any{
|
||||
"name", name,
|
||||
"namespace", namespace,
|
||||
"actorUID", actorUID,
|
||||
}
|
||||
|
||||
success := createErr == nil
|
||||
args = append(args, "success", success)
|
||||
if !success {
|
||||
span.SetStatus(codes.Error, "SecureValueService.Create failed")
|
||||
span.RecordError(createErr)
|
||||
args = append(args, "error", createErr)
|
||||
}
|
||||
|
||||
logging.FromContext(ctx).Info("SecureValueService.Create finished", args...)
|
||||
|
||||
s.metrics.SecureValueCreateDuration.WithLabelValues(strconv.FormatBool(success)).Observe(time.Since(start).Seconds())
|
||||
s.metrics.SecureValueCreateCount.WithLabelValues(strconv.FormatBool(success)).Inc()
|
||||
}()
|
||||
|
||||
return s.createNewVersion(ctx, sv, actorUID)
|
||||
}
|
||||
|
||||
func (s *SecureValueService) Update(ctx context.Context, newSecureValue *secretv1beta1.SecureValue, actorUID string) (*secretv1beta1.SecureValue, bool, error) {
|
||||
func (s *SecureValueService) Update(ctx context.Context, newSecureValue *secretv1beta1.SecureValue, actorUID string) (_ *secretv1beta1.SecureValue, sync bool, updateErr error) {
|
||||
start := time.Now()
|
||||
name, namespace := newSecureValue.GetName(), newSecureValue.GetNamespace()
|
||||
|
||||
ctx, span := s.tracer.Start(ctx, "SecureValueService.Update", trace.WithAttributes(
|
||||
attribute.String("name", newSecureValue.GetName()),
|
||||
attribute.String("namespace", newSecureValue.GetNamespace()),
|
||||
attribute.String("name", name),
|
||||
attribute.String("namespace", namespace),
|
||||
attribute.String("actor", actorUID),
|
||||
))
|
||||
defer span.End()
|
||||
|
||||
defer func() {
|
||||
args := []any{
|
||||
"name", name,
|
||||
"namespace", namespace,
|
||||
"actorUID", actorUID,
|
||||
"sync", sync,
|
||||
}
|
||||
|
||||
success := updateErr == nil
|
||||
args = append(args, "success", success)
|
||||
if !success {
|
||||
span.SetStatus(codes.Error, "SecureValueService.Update failed")
|
||||
span.RecordError(updateErr)
|
||||
args = append(args, "error", updateErr)
|
||||
}
|
||||
|
||||
logging.FromContext(ctx).Info("SecureValueService.Update finished", args...)
|
||||
|
||||
s.metrics.SecureValueUpdateDuration.WithLabelValues(strconv.FormatBool(success)).Observe(time.Since(start).Seconds())
|
||||
s.metrics.SecureValueUpdateCount.WithLabelValues(strconv.FormatBool(success)).Inc()
|
||||
}()
|
||||
|
||||
if newSecureValue.Spec.Value == nil {
|
||||
currentVersion, err := s.secureValueMetadataStorage.Read(ctx, xkube.Namespace(newSecureValue.Namespace), newSecureValue.Name, contracts.ReadOpts{})
|
||||
if err != nil {
|
||||
@@ -136,22 +195,66 @@ func (s *SecureValueService) createNewVersion(ctx context.Context, sv *secretv1b
|
||||
return createdSv, nil
|
||||
}
|
||||
|
||||
func (s *SecureValueService) Read(ctx context.Context, namespace xkube.Namespace, name string) (*secretv1beta1.SecureValue, error) {
|
||||
func (s *SecureValueService) Read(ctx context.Context, namespace xkube.Namespace, name string) (_ *secretv1beta1.SecureValue, readErr error) {
|
||||
start := time.Now()
|
||||
|
||||
ctx, span := s.tracer.Start(ctx, "SecureValueService.Read", trace.WithAttributes(
|
||||
attribute.String("name", name),
|
||||
attribute.String("namespace", namespace.String()),
|
||||
))
|
||||
|
||||
defer func() {
|
||||
args := []any{
|
||||
"name", name,
|
||||
"namespace", namespace,
|
||||
}
|
||||
|
||||
success := readErr == nil
|
||||
args = append(args, "success", success)
|
||||
if !success {
|
||||
span.SetStatus(codes.Error, "SecureValueService.Read failed")
|
||||
span.RecordError(readErr)
|
||||
args = append(args, "error", readErr)
|
||||
}
|
||||
|
||||
logging.FromContext(ctx).Info("SecureValueService.Read finished", args...)
|
||||
|
||||
s.metrics.SecureValueReadDuration.WithLabelValues(strconv.FormatBool(success)).Observe(time.Since(start).Seconds())
|
||||
s.metrics.SecureValueReadCount.WithLabelValues(strconv.FormatBool(success)).Inc()
|
||||
}()
|
||||
|
||||
defer span.End()
|
||||
|
||||
return s.secureValueMetadataStorage.Read(ctx, namespace, name, contracts.ReadOpts{ForUpdate: false})
|
||||
}
|
||||
|
||||
func (s *SecureValueService) List(ctx context.Context, namespace xkube.Namespace) (*secretv1beta1.SecureValueList, error) {
|
||||
func (s *SecureValueService) List(ctx context.Context, namespace xkube.Namespace) (_ *secretv1beta1.SecureValueList, listErr error) {
|
||||
start := time.Now()
|
||||
|
||||
ctx, span := s.tracer.Start(ctx, "SecureValueService.List", trace.WithAttributes(
|
||||
attribute.String("namespace", namespace.String()),
|
||||
))
|
||||
defer span.End()
|
||||
|
||||
defer func() {
|
||||
args := []any{
|
||||
"namespace", namespace,
|
||||
}
|
||||
|
||||
success := listErr == nil
|
||||
args = append(args, "success", success)
|
||||
if !success {
|
||||
span.SetStatus(codes.Error, "SecureValueService.List failed")
|
||||
span.RecordError(listErr)
|
||||
args = append(args, "error", listErr)
|
||||
}
|
||||
|
||||
logging.FromContext(ctx).Info("SecureValueService.List finished", args...)
|
||||
|
||||
s.metrics.SecureValueListDuration.WithLabelValues(strconv.FormatBool(success)).Observe(time.Since(start).Seconds())
|
||||
s.metrics.SecureValueListCount.WithLabelValues(strconv.FormatBool(success)).Inc()
|
||||
}()
|
||||
|
||||
user, ok := claims.AuthInfoFrom(ctx)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("missing auth info in context")
|
||||
@@ -188,13 +291,35 @@ func (s *SecureValueService) List(ctx context.Context, namespace xkube.Namespace
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *SecureValueService) Delete(ctx context.Context, namespace xkube.Namespace, name string) (*secretv1beta1.SecureValue, error) {
|
||||
func (s *SecureValueService) Delete(ctx context.Context, namespace xkube.Namespace, name string) (_ *secretv1beta1.SecureValue, deleteErr error) {
|
||||
start := time.Now()
|
||||
|
||||
ctx, span := s.tracer.Start(ctx, "SecureValueService.Delete", trace.WithAttributes(
|
||||
attribute.String("name", name),
|
||||
attribute.String("namespace", namespace.String()),
|
||||
))
|
||||
defer span.End()
|
||||
|
||||
defer func() {
|
||||
args := []any{
|
||||
"name", name,
|
||||
"namespace", namespace,
|
||||
}
|
||||
|
||||
success := deleteErr == nil
|
||||
args = append(args, "success", success)
|
||||
if !success {
|
||||
span.SetStatus(codes.Error, "SecureValueService.Delete failed")
|
||||
span.RecordError(deleteErr)
|
||||
args = append(args, "error", deleteErr)
|
||||
}
|
||||
|
||||
logging.FromContext(ctx).Info("SecureValueService.Delete finished", args...)
|
||||
|
||||
s.metrics.SecureValueDeleteDuration.WithLabelValues(strconv.FormatBool(success)).Observe(time.Since(start).Seconds())
|
||||
s.metrics.SecureValueDeleteCount.WithLabelValues(strconv.FormatBool(success)).Inc()
|
||||
}()
|
||||
|
||||
// TODO: does this need to be for update?
|
||||
sv, err := s.secureValueMetadataStorage.Read(ctx, namespace, name, contracts.ReadOpts{ForUpdate: true})
|
||||
if err != nil {
|
||||
|
||||
@@ -120,7 +120,7 @@ func Setup(t *testing.T, opts ...func(*SetupConfig)) Sut {
|
||||
keeperService = setupCfg.KeeperService
|
||||
}
|
||||
|
||||
secureValueService := service.ProvideSecureValueService(tracer, accessClient, database, secureValueMetadataStorage, keeperMetadataStorage, keeperService)
|
||||
secureValueService := service.ProvideSecureValueService(tracer, accessClient, database, secureValueMetadataStorage, keeperMetadataStorage, keeperService, nil)
|
||||
|
||||
decryptAuthorizer := decrypt.ProvideDecryptAuthorizer(tracer)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user