1
0
Fork 0
mirror of https://github.com/external-secrets/external-secrets.git synced 2024-12-14 11:57:59 +00:00

Merge pull request #110 from external-secrets/metrics-first-iteration

Add first iteration of custom metrics
This commit is contained in:
Jonatas Baldin 2021-04-22 18:35:35 +02:00 committed by GitHub
commit b8fda4387d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 223 additions and 31 deletions

5
docs/guides-metrics.md Normal file
View file

@ -0,0 +1,5 @@
# Metrics
The External Secrets Operator exposes its Prometheus metrics in the `/metrics` path. To enable it, set the `prometheus.enabled` Helm flag to `true`.
The Operator has the metrics inherited from Kubebuilder plus some custom metrics with the `external_secret` prefix.

5
go.mod
View file

@ -53,14 +53,13 @@ require (
github.com/onsi/ginkgo v1.16.1
github.com/onsi/gomega v1.11.0
github.com/pierrec/lz4 v2.5.2+incompatible // indirect
github.com/prometheus/client_golang v1.9.0 // indirect
github.com/prometheus/procfs v0.4.0 // indirect
github.com/prometheus/client_golang v1.10.0
github.com/prometheus/client_model v0.2.0
github.com/stretchr/testify v1.6.1
github.com/tidwall/gjson v1.7.4
golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad // indirect
golang.org/x/net v0.0.0-20210119194325-5f4716e94777 // indirect
golang.org/x/oauth2 v0.0.0-20210201163806-010130855d6c // indirect
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c // indirect
golang.org/x/term v0.0.0-20201210144234-2321bbc49cbf // indirect
golang.org/x/text v0.3.5 // indirect
golang.org/x/time v0.0.0-20201208040808-7e3f01d25324 // indirect

19
go.sum
View file

@ -497,8 +497,8 @@ github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDf
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
github.com/prometheus/client_golang v1.3.0/go.mod h1:hJaj2vgQTGQmVCsAACORcieXFeDPbaTKGT+JTgUa3og=
github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M=
github.com/prometheus/client_golang v1.9.0 h1:Rrch9mh17XcxvEu9D9DEpb4isxjGBtcevQjKvxPRQIU=
github.com/prometheus/client_golang v1.9.0/go.mod h1:FqZLKOZnGdFAhOK4nqGHa7D66IdsO+O441Eve7ptJDU=
github.com/prometheus/client_golang v1.10.0 h1:/o0BDeWzLWXNZ+4q5gXltUvaMpJqckTa+jTNoB+z4cg=
github.com/prometheus/client_golang v1.10.0/go.mod h1:WJM3cc3yu7XKBKa/I8WeZm+V3eltZnBwfENSU7mdogU=
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
@ -513,8 +513,8 @@ github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y8
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA=
github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo=
github.com/prometheus/common v0.15.0 h1:4fgOnadei3EZvgRwxJ7RMpG1k1pOZth5Pc13tyspaKM=
github.com/prometheus/common v0.15.0/go.mod h1:U+gB1OBLb1lF3O42bTCL+FK18tX9Oar16Clt/msog/s=
github.com/prometheus/common v0.18.0 h1:WCVKW7aL6LEe1uryfI9dnEc2ZqNB1Fn0ok930v0iL1Y=
github.com/prometheus/common v0.18.0/go.mod h1:U+gB1OBLb1lF3O42bTCL+FK18tX9Oar16Clt/msog/s=
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.0-20181204211112-1dc9a6cbc91a/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
@ -523,13 +523,15 @@ github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsT
github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A=
github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
github.com/prometheus/procfs v0.2.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
github.com/prometheus/procfs v0.4.0 h1:2XVTOS3f4uP3n077heNHPNQ0a9LHAO7uPZgDFZP77sg=
github.com/prometheus/procfs v0.4.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
github.com/prometheus/procfs v0.6.0 h1:mxy4L2jP6qMonqmq+aTtOx1ifVWUgG/TAmntgbh3xv4=
github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/russross/blackfriday v1.5.2 h1:HyvC0ARfnZBqnXwABFeSZHpKvJHJJfPz81GNueLj0oo=
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q=
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
@ -537,6 +539,7 @@ github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkB
github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc=
github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E=
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo=
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
@ -727,6 +730,7 @@ golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@ -779,10 +783,11 @@ golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201112073958-5cba982894dd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201214210602-f9fddec55a1e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c h1:VwygUrnw9jn88c4u8GD3rZQbqrP/tgas88tPUbBxQrk=
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210309074719-68d13333faf2 h1:46ULzRKLh1CwgRq2dC5SlBzEqqNCi8rreOZnNrbqcIY=
golang.org/x/sys v0.0.0-20210309074719-68d13333faf2/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20201210144234-2321bbc49cbf h1:MZ2shdL+ZM/XzY3ZGOnh4Nlpnxz5GSOhOmtHo3iPU6M=

View file

@ -28,6 +28,7 @@ nav:
- Getting started: guides-getting-started.md
- Advanced Templating: guides-templating.md
- Multi Tenancy: guides-multi-tenancy.md
- Metrics: guides-metrics.md
- Provider:
- AWS:
- Secrets Manager: provider-aws-secrets-manager.md

View file

@ -20,6 +20,7 @@ import (
"time"
"github.com/go-logr/logr"
"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"
@ -52,11 +53,14 @@ type Reconciler struct {
func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
log := r.Log.WithValues("ExternalSecret", req.NamespacedName)
syncCallsMetricLabels := prometheus.Labels{"name": req.Name, "namespace": req.Namespace}
var externalSecret esv1alpha1.ExternalSecret
err := r.Get(ctx, req.NamespacedName, &externalSecret)
if err != nil {
log.Error(err, "could not get ExternalSecret")
syncCallsError.With(syncCallsMetricLabels).Inc()
return ctrl.Result{}, client.IgnoreNotFound(err)
}
@ -71,8 +75,10 @@ func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Resu
if err != nil {
log.Error(err, "could not get store reference")
conditionSynced := NewExternalSecretCondition(esv1alpha1.ExternalSecretReady, corev1.ConditionFalse, esv1alpha1.ConditionReasonSecretSyncedError, err.Error())
SetExternalSecretCondition(&externalSecret.Status, *conditionSynced)
SetExternalSecretCondition(&externalSecret, *conditionSynced)
err = r.Status().Update(ctx, &externalSecret)
syncCallsError.With(syncCallsMetricLabels).Inc()
return ctrl.Result{RequeueAfter: requeueAfter}, nil
}
@ -87,6 +93,7 @@ func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Resu
storeProvider, err := schema.GetProvider(store)
if err != nil {
log.Error(err, "could not get store provider")
syncCallsError.With(syncCallsMetricLabels).Inc()
return ctrl.Result{RequeueAfter: requeueAfter}, nil
}
@ -94,8 +101,9 @@ func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Resu
if err != nil {
log.Error(err, "could not get provider client")
conditionSynced := NewExternalSecretCondition(esv1alpha1.ExternalSecretReady, corev1.ConditionFalse, esv1alpha1.ConditionReasonSecretSyncedError, err.Error())
SetExternalSecretCondition(&externalSecret.Status, *conditionSynced)
SetExternalSecretCondition(&externalSecret, *conditionSynced)
err = r.Status().Update(ctx, &externalSecret)
syncCallsError.With(syncCallsMetricLabels).Inc()
return ctrl.Result{RequeueAfter: requeueAfter}, nil
}
@ -119,11 +127,12 @@ func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Resu
if err != nil {
log.Error(err, "could not reconcile ExternalSecret")
conditionSynced := NewExternalSecretCondition(esv1alpha1.ExternalSecretReady, corev1.ConditionFalse, esv1alpha1.ConditionReasonSecretSyncedError, err.Error())
SetExternalSecretCondition(&externalSecret.Status, *conditionSynced)
SetExternalSecretCondition(&externalSecret, *conditionSynced)
err = r.Status().Update(ctx, &externalSecret)
if err != nil {
log.Error(err, "unable to update status")
}
syncCallsError.With(syncCallsMetricLabels).Inc()
return ctrl.Result{RequeueAfter: requeueAfter}, nil
}
@ -133,13 +142,15 @@ func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Resu
}
conditionSynced := NewExternalSecretCondition(esv1alpha1.ExternalSecretReady, corev1.ConditionTrue, esv1alpha1.ConditionReasonSecretSynced, "Secret was synced")
SetExternalSecretCondition(&externalSecret.Status, *conditionSynced)
SetExternalSecretCondition(&externalSecret, *conditionSynced)
externalSecret.Status.RefreshTime = metav1.NewTime(time.Now())
err = r.Status().Update(ctx, &externalSecret)
if err != nil {
log.Error(err, "unable to update status")
}
syncCallsTotal.With(syncCallsMetricLabels).Inc()
return ctrl.Result{
RequeueAfter: dur,
}, nil

View file

@ -20,6 +20,7 @@ import (
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
dto "github.com/prometheus/client_model/go"
v1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
@ -32,15 +33,18 @@ import (
"github.com/external-secrets/external-secrets/pkg/provider/schema"
)
var fakeProvider *fake.Client
var (
fakeProvider *fake.Client
metric dto.Metric
timeout = time.Second * 5
interval = time.Millisecond * 250
)
var _ = Describe("ExternalSecret controller", func() {
const (
ExternalSecretName = "test-es"
ExternalSecretStore = "test-store"
ExternalSecretTargetSecretName = "test-secret"
timeout = time.Second * 5
interval = time.Millisecond * 250
)
var ExternalSecretNamespace string
@ -63,7 +67,12 @@ var _ = Describe("ExternalSecret controller", func() {
},
})).To(Succeed())
metric.Reset()
syncCallsTotal.Reset()
syncCallsError.Reset()
externalSecretCondition.Reset()
})
AfterEach(func() {
Expect(k8sClient.Delete(context.Background(), &v1.Namespace{
ObjectMeta: metav1.ObjectMeta{
@ -78,9 +87,8 @@ var _ = Describe("ExternalSecret controller", func() {
}, client.PropagationPolicy(metav1.DeletePropagationBackground)), client.GracePeriodSeconds(0)).To(Succeed())
})
Context("When updating ExternalSecret Status", func() {
Context("When creating an ExternalSecret", func() {
It("should set the condition eventually", func() {
By("creating an ExternalSecret")
ctx := context.Background()
es := &esv1alpha1.ExternalSecret{
ObjectMeta: metav1.ObjectMeta{
@ -110,13 +118,66 @@ var _ = Describe("ExternalSecret controller", func() {
}
return true
}, timeout, interval).Should(BeTrue())
Expect(externalSecretConditionShouldBe(ExternalSecretName, ExternalSecretNamespace, esv1alpha1.ExternalSecretReady, v1.ConditionFalse, 0.0)).To(BeTrue())
Expect(externalSecretConditionShouldBe(ExternalSecretName, ExternalSecretNamespace, esv1alpha1.ExternalSecretReady, v1.ConditionTrue, 1.0)).To(BeTrue())
Eventually(func() float64 {
Expect(syncCallsTotal.WithLabelValues(ExternalSecretName, ExternalSecretNamespace).Write(&metric)).To(Succeed())
return metric.GetCounter().GetValue()
}, timeout, interval).Should(Equal(2.0))
})
})
Context("When updating an ExternalSecret", func() {
It("should increment the syncCallsTotal metric", func() {
ctx := context.Background()
es := &esv1alpha1.ExternalSecret{
ObjectMeta: metav1.ObjectMeta{
Name: ExternalSecretName,
Namespace: ExternalSecretNamespace,
},
Spec: esv1alpha1.ExternalSecretSpec{
SecretStoreRef: esv1alpha1.SecretStoreRef{
Name: ExternalSecretStore,
},
Target: esv1alpha1.ExternalSecretTarget{
Name: ExternalSecretTargetSecretName,
},
},
}
Expect(k8sClient.Create(ctx, es)).Should(Succeed())
createdES := &esv1alpha1.ExternalSecret{}
Eventually(func() error {
esLookupKey := types.NamespacedName{Name: ExternalSecretName, Namespace: ExternalSecretNamespace}
err := k8sClient.Get(ctx, esLookupKey, createdES)
if err != nil {
return err
}
createdES.Spec.RefreshInterval = &metav1.Duration{Duration: 10 * time.Second}
err = k8sClient.Update(ctx, createdES)
if err != nil {
return err
}
return nil
}, timeout, interval).Should(Succeed())
Eventually(func() float64 {
Expect(syncCallsTotal.WithLabelValues(ExternalSecretName, ExternalSecretNamespace).Write(&metric)).To(Succeed())
return metric.GetCounter().GetValue()
}, timeout, interval).Should(Equal(3.0))
})
})
Context("When syncing ExternalSecret value", func() {
It("should set the secret value and sync labels/annotations", func() {
By("creating an ExternalSecret")
ctx := context.Background()
const targetProp = "targetProperty"
const secretVal = "someValue"
@ -171,7 +232,6 @@ var _ = Describe("ExternalSecret controller", func() {
})
It("should refresh secret value", func() {
By("creating an ExternalSecret")
ctx := context.Background()
const targetProp = "targetProperty"
const secretVal = "someValue"
@ -227,7 +287,6 @@ var _ = Describe("ExternalSecret controller", func() {
})
It("should fetch secrets using dataFrom", func() {
By("creating an ExternalSecret")
ctx := context.Background()
const secretVal = "someValue"
es := &esv1alpha1.ExternalSecret{
@ -272,7 +331,6 @@ var _ = Describe("ExternalSecret controller", func() {
})
It("should set an error condition when provider errors", func() {
By("creating an ExternalSecret")
ctx := context.Background()
const targetProp = "targetProperty"
es := &esv1alpha1.ExternalSecret{
@ -317,10 +375,17 @@ var _ = Describe("ExternalSecret controller", func() {
}
return true
}, timeout, interval).Should(BeTrue())
Eventually(func() float64 {
Expect(syncCallsError.WithLabelValues(ExternalSecretName, ExternalSecretNamespace).Write(&metric)).To(Succeed())
return metric.GetCounter().GetValue()
}, timeout, interval).Should(Equal(2.0))
Expect(externalSecretConditionShouldBe(ExternalSecretName, ExternalSecretNamespace, esv1alpha1.ExternalSecretReady, v1.ConditionFalse, 1.0)).To(BeTrue())
Expect(externalSecretConditionShouldBe(ExternalSecretName, ExternalSecretNamespace, esv1alpha1.ExternalSecretReady, v1.ConditionTrue, 0.0)).To(BeTrue())
})
It("should set an error condition when store does not exist", func() {
By("creating an ExternalSecret")
ctx := context.Background()
const targetProp = "targetProperty"
es := &esv1alpha1.ExternalSecret{
@ -364,10 +429,17 @@ var _ = Describe("ExternalSecret controller", func() {
}
return true
}, timeout, interval).Should(BeTrue())
Eventually(func() float64 {
Expect(syncCallsError.WithLabelValues(ExternalSecretName, ExternalSecretNamespace).Write(&metric)).To(Succeed())
return metric.GetCounter().GetValue()
}, timeout, interval).Should(Equal(2.0))
Expect(externalSecretConditionShouldBe(ExternalSecretName, ExternalSecretNamespace, esv1alpha1.ExternalSecretReady, v1.ConditionFalse, 1.0)).To(BeTrue())
Expect(externalSecretConditionShouldBe(ExternalSecretName, ExternalSecretNamespace, esv1alpha1.ExternalSecretReady, v1.ConditionTrue, 0.0)).To(BeTrue())
})
It("should set an error condition when store provider constructor fails", func() {
By("creating an ExternalSecret")
ctx := context.Background()
const targetProp = "targetProperty"
es := &esv1alpha1.ExternalSecret{
@ -415,10 +487,17 @@ var _ = Describe("ExternalSecret controller", func() {
}
return true
}, timeout, interval).Should(BeTrue())
Eventually(func() float64 {
Expect(syncCallsError.WithLabelValues(ExternalSecretName, ExternalSecretNamespace).Write(&metric)).To(Succeed())
return metric.GetCounter().GetValue()
}, timeout, interval).Should(Equal(2.0))
Expect(externalSecretConditionShouldBe(ExternalSecretName, ExternalSecretNamespace, esv1alpha1.ExternalSecretReady, v1.ConditionFalse, 1.0)).To(BeTrue())
Expect(externalSecretConditionShouldBe(ExternalSecretName, ExternalSecretNamespace, esv1alpha1.ExternalSecretReady, v1.ConditionTrue, 0.0)).To(BeTrue())
})
It("should not process stores with mismatching controller field", func() {
By("creating an ExternalSecret")
ctx := context.Background()
storeName := "example-ts-foo"
Expect(k8sClient.Create(context.Background(), &esv1alpha1.SecretStore{
@ -483,8 +562,21 @@ var _ = Describe("ExternalSecret controller", func() {
cond := GetExternalSecretCondition(createdES.Status, esv1alpha1.ExternalSecretReady)
return cond == nil
}, timeout, interval).Should(BeTrue())
})
// Condition True and False should be 0, since the Condition was not created
Eventually(func() float64 {
Expect(externalSecretCondition.WithLabelValues(ExternalSecretName, ExternalSecretNamespace, string(esv1alpha1.ExternalSecretReady), string(v1.ConditionTrue)).Write(&metric)).To(Succeed())
return metric.GetGauge().GetValue()
}, timeout, interval).Should(Equal(0.0))
Eventually(func() float64 {
Expect(externalSecretCondition.WithLabelValues(ExternalSecretName, ExternalSecretNamespace, string(esv1alpha1.ExternalSecretReady), string(v1.ConditionFalse)).Write(&metric)).To(Succeed())
return metric.GetGauge().GetValue()
}, timeout, interval).Should(Equal(0.0))
Expect(externalSecretConditionShouldBe(ExternalSecretName, ExternalSecretNamespace, esv1alpha1.ExternalSecretReady, v1.ConditionFalse, 0.0)).To(BeTrue())
Expect(externalSecretConditionShouldBe(ExternalSecretName, ExternalSecretNamespace, esv1alpha1.ExternalSecretReady, v1.ConditionTrue, 0.0)).To(BeTrue())
})
})
})
@ -510,6 +602,13 @@ func CreateNamespace(baseName string, c client.Client) (string, error) {
return ns.Name, nil
}
func externalSecretConditionShouldBe(name, ns string, ct esv1alpha1.ExternalSecretConditionType, cs v1.ConditionStatus, v float64) bool {
return Eventually(func() float64 {
Expect(externalSecretCondition.WithLabelValues(name, ns, string(ct), string(cs)).Write(&metric)).To(Succeed())
return metric.GetGauge().GetValue()
}, timeout, interval).Should(Equal(v))
}
func init() {
fakeProvider = fake.New()
schema.ForceRegister(fakeProvider, &esv1alpha1.SecretStoreProvider{

View file

@ -0,0 +1,62 @@
/*
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package externalsecret
import (
"github.com/prometheus/client_golang/prometheus"
"sigs.k8s.io/controller-runtime/pkg/metrics"
esv1alpha1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1alpha1"
)
const (
ExternalSecretSubsystem = "externalsecret"
SyncCallsKey = "sync_calls_total"
SyncCallsErrorKey = "sync_calls_error"
externalSecretStatusConditionKey = "status_condition"
)
var (
syncCallsTotal = prometheus.NewCounterVec(prometheus.CounterOpts{
Subsystem: ExternalSecretSubsystem,
Name: SyncCallsKey,
Help: "Total number of the External Secret sync calls",
}, []string{"name", "namespace"})
syncCallsError = prometheus.NewCounterVec(prometheus.CounterOpts{
Subsystem: ExternalSecretSubsystem,
Name: SyncCallsErrorKey,
Help: "Total number of the External Secret sync errors",
}, []string{"name", "namespace"})
externalSecretCondition = prometheus.NewGaugeVec(prometheus.GaugeOpts{
Subsystem: ExternalSecretSubsystem,
Name: externalSecretStatusConditionKey,
Help: "The status condition of a specific External Secret",
}, []string{"name", "namespace", "condition", "status"})
)
func updateExternalSecretCondition(es *esv1alpha1.ExternalSecret, condition *esv1alpha1.ExternalSecretStatusCondition, value float64) {
externalSecretCondition.With(prometheus.Labels{
"name": es.Name,
"namespace": es.Namespace,
"condition": string(condition.Type),
"status": string(condition.Status),
}).Set(value)
}
func init() {
metrics.Registry.MustRegister(syncCallsTotal, syncCallsError, externalSecretCondition)
}

View file

@ -43,16 +43,26 @@ func GetExternalSecretCondition(status esv1alpha1.ExternalSecretStatus, condType
// SetExternalSecretCondition updates the external secret to include the provided
// condition.
func SetExternalSecretCondition(status *esv1alpha1.ExternalSecretStatus, condition esv1alpha1.ExternalSecretStatusCondition) {
currentCond := GetExternalSecretCondition(*status, condition.Type)
func SetExternalSecretCondition(es *esv1alpha1.ExternalSecret, condition esv1alpha1.ExternalSecretStatusCondition) {
currentCond := GetExternalSecretCondition(es.Status, condition.Type)
if currentCond != nil && currentCond.Status == condition.Status && currentCond.Reason == condition.Reason {
updateExternalSecretCondition(es, &condition, 1.0)
return
}
// Do not update lastTransitionTime if the status of the condition doesn't change.
if currentCond != nil && currentCond.Status == condition.Status {
condition.LastTransitionTime = currentCond.LastTransitionTime
}
status.Conditions = append(filterOutCondition(status.Conditions, condition.Type), condition)
es.Status.Conditions = append(filterOutCondition(es.Status.Conditions, condition.Type), condition)
if currentCond != nil {
updateExternalSecretCondition(es, currentCond, 0.0)
}
updateExternalSecretCondition(es, &condition, 1.0)
}
func filterOutCondition(conditions []esv1alpha1.ExternalSecretStatusCondition, condType esv1alpha1.ExternalSecretConditionType) []esv1alpha1.ExternalSecretStatusCondition {