From 1ae3c6a1ad91080d49ec0c45d2960effea63e12d Mon Sep 17 00:00:00 2001 From: Ryan Richard Date: Wed, 12 May 2021 14:00:39 -0700 Subject: [PATCH] Split package upstreamwatchers into four packages --- cmd/pinniped-supervisor/main.go | 7 +- .../conditionsutil/conditions_util.go.go | 68 ++++++++++++++ .../ldap_upstream_watcher.go | 27 +++--- .../ldap_upstream_watcher_test.go | 6 +- .../oidc_upstream_watcher.go | 91 ++++--------------- .../oidc_upstream_watcher_test.go | 6 +- .../upstreamwatchers/upstream_watchers.go | 16 ++++ 7 files changed, 126 insertions(+), 95 deletions(-) create mode 100644 internal/controller/conditionsutil/conditions_util.go.go rename internal/controller/supervisorconfig/{upstreamwatcher => ldapupstreamwatcher}/ldap_upstream_watcher.go (93%) rename internal/controller/supervisorconfig/{upstreamwatcher => ldapupstreamwatcher}/ldap_upstream_watcher_test.go (99%) rename internal/controller/supervisorconfig/{upstreamwatcher => oidcupstreamwatcher}/oidc_upstream_watcher.go (82%) rename internal/controller/supervisorconfig/{upstreamwatcher => oidcupstreamwatcher}/oidc_upstream_watcher_test.go (99%) create mode 100644 internal/controller/supervisorconfig/upstreamwatchers/upstream_watchers.go diff --git a/cmd/pinniped-supervisor/main.go b/cmd/pinniped-supervisor/main.go index 7d196333..0cf897ae 100644 --- a/cmd/pinniped-supervisor/main.go +++ b/cmd/pinniped-supervisor/main.go @@ -32,7 +32,8 @@ import ( "go.pinniped.dev/internal/config/supervisor" "go.pinniped.dev/internal/controller/supervisorconfig" "go.pinniped.dev/internal/controller/supervisorconfig/generator" - "go.pinniped.dev/internal/controller/supervisorconfig/upstreamwatcher" + "go.pinniped.dev/internal/controller/supervisorconfig/ldapupstreamwatcher" + "go.pinniped.dev/internal/controller/supervisorconfig/oidcupstreamwatcher" "go.pinniped.dev/internal/controller/supervisorstorage" "go.pinniped.dev/internal/controllerlib" "go.pinniped.dev/internal/deploymentref" @@ -233,7 +234,7 @@ func startControllers( singletonWorker, ). WithController( - upstreamwatcher.NewOIDCUpstreamWatcherController( + oidcupstreamwatcher.New( dynamicUpstreamIDPProvider, pinnipedClient, pinnipedInformers.IDP().V1alpha1().OIDCIdentityProviders(), @@ -243,7 +244,7 @@ func startControllers( ), singletonWorker). WithController( - upstreamwatcher.NewLDAPUpstreamWatcherController( + ldapupstreamwatcher.New( dynamicUpstreamIDPProvider, pinnipedClient, pinnipedInformers.IDP().V1alpha1().LDAPIdentityProviders(), diff --git a/internal/controller/conditionsutil/conditions_util.go.go b/internal/controller/conditionsutil/conditions_util.go.go new file mode 100644 index 00000000..67f13b03 --- /dev/null +++ b/internal/controller/conditionsutil/conditions_util.go.go @@ -0,0 +1,68 @@ +// Copyright 2021 the Pinniped contributors. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +package conditionsutil + +import ( + "sort" + + "github.com/go-logr/logr" + "k8s.io/apimachinery/pkg/api/equality" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + "go.pinniped.dev/generated/latest/apis/supervisor/idp/v1alpha1" +) + +// Merge merges conditions into conditionsToUpdate. If returns true if it merged any error conditions. +func Merge(conditions []*v1alpha1.Condition, observedGeneration int64, conditionsToUpdate *[]v1alpha1.Condition, log logr.Logger) bool { + hadErrorCondition := false + for i := range conditions { + cond := conditions[i].DeepCopy() + cond.LastTransitionTime = v1.Now() + cond.ObservedGeneration = observedGeneration + if mergeCondition(conditionsToUpdate, cond) { + log.Info("updated condition", "type", cond.Type, "status", cond.Status, "reason", cond.Reason, "message", cond.Message) + } + if cond.Status == v1alpha1.ConditionFalse { + hadErrorCondition = true + } + } + sort.SliceStable(*conditionsToUpdate, func(i, j int) bool { + return (*conditionsToUpdate)[i].Type < (*conditionsToUpdate)[j].Type + }) + return hadErrorCondition +} + +// mergeCondition merges a new v1alpha1.Condition into a slice of existing conditions. It returns true +// if the condition has meaningfully changed. +func mergeCondition(existing *[]v1alpha1.Condition, new *v1alpha1.Condition) bool { + // Find any existing condition with a matching type. + var old *v1alpha1.Condition + for i := range *existing { + if (*existing)[i].Type == new.Type { + old = &(*existing)[i] + continue + } + } + + // If there is no existing condition of this type, append this one and we're done. + if old == nil { + *existing = append(*existing, *new) + return true + } + + // Set the LastTransitionTime depending on whether the status has changed. + new = new.DeepCopy() + if old.Status == new.Status { + new.LastTransitionTime = old.LastTransitionTime + } + + // If anything has actually changed, update the entry and return true. + if !equality.Semantic.DeepEqual(old, new) { + *old = *new + return true + } + + // Otherwise the entry is already up to date. + return false +} diff --git a/internal/controller/supervisorconfig/upstreamwatcher/ldap_upstream_watcher.go b/internal/controller/supervisorconfig/ldapupstreamwatcher/ldap_upstream_watcher.go similarity index 93% rename from internal/controller/supervisorconfig/upstreamwatcher/ldap_upstream_watcher.go rename to internal/controller/supervisorconfig/ldapupstreamwatcher/ldap_upstream_watcher.go index 274cccd4..6c70c0ec 100644 --- a/internal/controller/supervisorconfig/upstreamwatcher/ldap_upstream_watcher.go +++ b/internal/controller/supervisorconfig/ldapupstreamwatcher/ldap_upstream_watcher.go @@ -1,7 +1,8 @@ // Copyright 2021 the Pinniped contributors. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 -package upstreamwatcher +// Package ldapupstreamwatcher implements a controller which watches LDAPIdentityProviders. +package ldapupstreamwatcher import ( "context" @@ -22,6 +23,8 @@ import ( pinnipedclientset "go.pinniped.dev/generated/latest/client/supervisor/clientset/versioned" idpinformers "go.pinniped.dev/generated/latest/client/supervisor/informers/externalversions/idp/v1alpha1" pinnipedcontroller "go.pinniped.dev/internal/controller" + "go.pinniped.dev/internal/controller/conditionsutil" + "go.pinniped.dev/internal/controller/supervisorconfig/upstreamwatchers" "go.pinniped.dev/internal/controllerlib" "go.pinniped.dev/internal/oidc/provider" "go.pinniped.dev/internal/upstreamldap" @@ -58,8 +61,8 @@ type ldapWatcherController struct { secretInformer corev1informers.SecretInformer } -// NewLDAPUpstreamWatcherController instantiates a new controllerlib.Controller which will populate the provided UpstreamLDAPIdentityProviderICache. -func NewLDAPUpstreamWatcherController( +// New instantiates a new controllerlib.Controller which will populate the provided UpstreamLDAPIdentityProviderICache. +func New( idpCache UpstreamLDAPIdentityProviderICache, client pinnipedclientset.Interface, ldapIdentityProviderInformer idpinformers.LDAPIdentityProviderInformer, @@ -178,7 +181,7 @@ func (c *ldapWatcherController) validateTLSConfig(upstream *v1alpha1.LDAPIdentit ca := x509.NewCertPool() ok := ca.AppendCertsFromPEM(bundle) if !ok { - return c.invalidTLSCondition(fmt.Sprintf("certificateAuthorityData is invalid: %s", errNoCertificates)) + return c.invalidTLSCondition(fmt.Sprintf("certificateAuthorityData is invalid: %s", upstreamwatchers.ErrNoCertificates)) } config.CABundle = bundle @@ -219,7 +222,7 @@ func (c *ldapWatcherController) testConnection( return &v1alpha1.Condition{ Type: typeLDAPConnectionValid, Status: v1alpha1.ConditionTrue, - Reason: reasonSuccess, + Reason: upstreamwatchers.ReasonSuccess, Message: fmt.Sprintf(`successfully able to connect to "%s" and bind as user "%s" [validated with Secret "%s" at version "%s"]`, config.Host, config.BindUsername, upstream.Spec.Bind.SecretName, currentSecretVersion), } @@ -248,7 +251,7 @@ func (c *ldapWatcherController) validTLSCondition(message string) *v1alpha1.Cond return &v1alpha1.Condition{ Type: typeTLSConfigurationValid, Status: v1alpha1.ConditionTrue, - Reason: reasonSuccess, + Reason: upstreamwatchers.ReasonSuccess, Message: message, } } @@ -257,7 +260,7 @@ func (c *ldapWatcherController) invalidTLSCondition(message string) *v1alpha1.Co return &v1alpha1.Condition{ Type: typeTLSConfigurationValid, Status: v1alpha1.ConditionFalse, - Reason: reasonInvalidTLSConfig, + Reason: upstreamwatchers.ReasonInvalidTLSConfig, Message: message, } } @@ -270,7 +273,7 @@ func (c *ldapWatcherController) validateSecret(upstream *v1alpha1.LDAPIdentityPr return &v1alpha1.Condition{ Type: typeBindSecretValid, Status: v1alpha1.ConditionFalse, - Reason: reasonNotFound, + Reason: upstreamwatchers.ReasonNotFound, Message: err.Error(), }, "" } @@ -279,7 +282,7 @@ func (c *ldapWatcherController) validateSecret(upstream *v1alpha1.LDAPIdentityPr return &v1alpha1.Condition{ Type: typeBindSecretValid, Status: v1alpha1.ConditionFalse, - Reason: reasonWrongType, + Reason: upstreamwatchers.ReasonWrongType, Message: fmt.Sprintf("referenced Secret %q has wrong type %q (should be %q)", secretName, secret.Type, corev1.SecretTypeBasicAuth), }, secret.ResourceVersion @@ -291,7 +294,7 @@ func (c *ldapWatcherController) validateSecret(upstream *v1alpha1.LDAPIdentityPr return &v1alpha1.Condition{ Type: typeBindSecretValid, Status: v1alpha1.ConditionFalse, - Reason: reasonMissingKeys, + Reason: upstreamwatchers.ReasonMissingKeys, Message: fmt.Sprintf("referenced Secret %q is missing required keys %q", secretName, []string{corev1.BasicAuthUsernameKey, corev1.BasicAuthPasswordKey}), }, secret.ResourceVersion @@ -300,7 +303,7 @@ func (c *ldapWatcherController) validateSecret(upstream *v1alpha1.LDAPIdentityPr return &v1alpha1.Condition{ Type: typeBindSecretValid, Status: v1alpha1.ConditionTrue, - Reason: reasonSuccess, + Reason: upstreamwatchers.ReasonSuccess, Message: "loaded bind secret", }, secret.ResourceVersion } @@ -309,7 +312,7 @@ func (c *ldapWatcherController) updateStatus(ctx context.Context, upstream *v1al log := klogr.New().WithValues("namespace", upstream.Namespace, "name", upstream.Name) updated := upstream.DeepCopy() - hadErrorCondition := mergeConditions(conditions, upstream.Generation, &updated.Status.Conditions, log) + hadErrorCondition := conditionsutil.Merge(conditions, upstream.Generation, &updated.Status.Conditions, log) updated.Status.Phase = v1alpha1.LDAPPhaseReady if hadErrorCondition { diff --git a/internal/controller/supervisorconfig/upstreamwatcher/ldap_upstream_watcher_test.go b/internal/controller/supervisorconfig/ldapupstreamwatcher/ldap_upstream_watcher_test.go similarity index 99% rename from internal/controller/supervisorconfig/upstreamwatcher/ldap_upstream_watcher_test.go rename to internal/controller/supervisorconfig/ldapupstreamwatcher/ldap_upstream_watcher_test.go index 9e90cdd1..1875e7e2 100644 --- a/internal/controller/supervisorconfig/upstreamwatcher/ldap_upstream_watcher_test.go +++ b/internal/controller/supervisorconfig/ldapupstreamwatcher/ldap_upstream_watcher_test.go @@ -1,7 +1,7 @@ // Copyright 2020-2021 the Pinniped contributors. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 -package upstreamwatcher +package ldapupstreamwatcher import ( "context" @@ -78,7 +78,7 @@ func TestLDAPUpstreamWatcherControllerFilterSecrets(t *testing.T) { secretInformer := kubeInformers.Core().V1().Secrets() withInformer := testutil.NewObservableWithInformerOption() - NewLDAPUpstreamWatcherController(nil, nil, ldapIDPInformer, secretInformer, withInformer.WithInformer) + New(nil, nil, ldapIDPInformer, secretInformer, withInformer.WithInformer) unrelated := corev1.Secret{} filter := withInformer.GetFilterForInformer(secretInformer) @@ -123,7 +123,7 @@ func TestLDAPUpstreamWatcherControllerFilterLDAPIdentityProviders(t *testing.T) secretInformer := kubeInformers.Core().V1().Secrets() withInformer := testutil.NewObservableWithInformerOption() - NewLDAPUpstreamWatcherController(nil, nil, ldapIDPInformer, secretInformer, withInformer.WithInformer) + New(nil, nil, ldapIDPInformer, secretInformer, withInformer.WithInformer) unrelated := corev1.Secret{} filter := withInformer.GetFilterForInformer(ldapIDPInformer) diff --git a/internal/controller/supervisorconfig/upstreamwatcher/oidc_upstream_watcher.go b/internal/controller/supervisorconfig/oidcupstreamwatcher/oidc_upstream_watcher.go similarity index 82% rename from internal/controller/supervisorconfig/upstreamwatcher/oidc_upstream_watcher.go rename to internal/controller/supervisorconfig/oidcupstreamwatcher/oidc_upstream_watcher.go index 609e1679..d1b3cb78 100644 --- a/internal/controller/supervisorconfig/upstreamwatcher/oidc_upstream_watcher.go +++ b/internal/controller/supervisorconfig/oidcupstreamwatcher/oidc_upstream_watcher.go @@ -1,8 +1,8 @@ // Copyright 2020-2021 the Pinniped contributors. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 -// Package upstreamwatcher implements controllers that watch the idp.supervisor.pinniped.dev API group's objects. -package upstreamwatcher +// Package oidcupstreamwatcher implements a controller which watches OIDCIdentityProviders. +package oidcupstreamwatcher import ( "context" @@ -31,6 +31,8 @@ import ( idpinformers "go.pinniped.dev/generated/latest/client/supervisor/informers/externalversions/idp/v1alpha1" "go.pinniped.dev/internal/constable" pinnipedcontroller "go.pinniped.dev/internal/controller" + "go.pinniped.dev/internal/controller/conditionsutil" + "go.pinniped.dev/internal/controller/supervisorconfig/upstreamwatchers" "go.pinniped.dev/internal/controllerlib" "go.pinniped.dev/internal/oidc/provider" "go.pinniped.dev/internal/upstreamoidc" @@ -52,17 +54,12 @@ const ( // Constants related to conditions. typeClientCredentialsValid = "ClientCredentialsValid" typeOIDCDiscoverySucceeded = "OIDCDiscoverySucceeded" - reasonNotFound = "SecretNotFound" - reasonWrongType = "SecretWrongType" - reasonMissingKeys = "SecretMissingKeys" - reasonSuccess = "Success" - reasonUnreachable = "Unreachable" - reasonInvalidTLSConfig = "InvalidTLSConfig" - reasonInvalidResponse = "InvalidResponse" + + reasonUnreachable = "Unreachable" + reasonInvalidResponse = "InvalidResponse" // Errors that are generated by our reconcile process. errOIDCFailureStatus = constable.Error("OIDCIdentityProvider has a failing condition") - errNoCertificates = constable.Error("no certificates found") ) // UpstreamOIDCIdentityProviderICache is a thread safe cache that holds a list of validated upstream OIDC IDP configurations. @@ -111,8 +108,8 @@ type oidcWatcherController struct { } } -// NewOIDCUpstreamWatcherController instantiates a new controllerlib.Controller which will populate the provided UpstreamOIDCIdentityProviderICache. -func NewOIDCUpstreamWatcherController( +// New instantiates a new controllerlib.Controller which will populate the provided UpstreamOIDCIdentityProviderICache. +func New( idpCache UpstreamOIDCIdentityProviderICache, client pinnipedclientset.Interface, oidcIdentityProviderInformer idpinformers.OIDCIdentityProviderInformer, @@ -212,7 +209,7 @@ func (c *oidcWatcherController) validateSecret(upstream *v1alpha1.OIDCIdentityPr return &v1alpha1.Condition{ Type: typeClientCredentialsValid, Status: v1alpha1.ConditionFalse, - Reason: reasonNotFound, + Reason: upstreamwatchers.ReasonNotFound, Message: err.Error(), } } @@ -222,7 +219,7 @@ func (c *oidcWatcherController) validateSecret(upstream *v1alpha1.OIDCIdentityPr return &v1alpha1.Condition{ Type: typeClientCredentialsValid, Status: v1alpha1.ConditionFalse, - Reason: reasonWrongType, + Reason: upstreamwatchers.ReasonWrongType, Message: fmt.Sprintf("referenced Secret %q has wrong type %q (should be %q)", secretName, secret.Type, oidcClientSecretType), } } @@ -234,7 +231,7 @@ func (c *oidcWatcherController) validateSecret(upstream *v1alpha1.OIDCIdentityPr return &v1alpha1.Condition{ Type: typeClientCredentialsValid, Status: v1alpha1.ConditionFalse, - Reason: reasonMissingKeys, + Reason: upstreamwatchers.ReasonMissingKeys, Message: fmt.Sprintf("referenced Secret %q is missing required keys %q", secretName, []string{clientIDDataKey, clientSecretDataKey}), } } @@ -245,7 +242,7 @@ func (c *oidcWatcherController) validateSecret(upstream *v1alpha1.OIDCIdentityPr return &v1alpha1.Condition{ Type: typeClientCredentialsValid, Status: v1alpha1.ConditionTrue, - Reason: reasonSuccess, + Reason: upstreamwatchers.ReasonSuccess, Message: "loaded client credentials", } } @@ -262,7 +259,7 @@ func (c *oidcWatcherController) validateIssuer(ctx context.Context, upstream *v1 return &v1alpha1.Condition{ Type: typeOIDCDiscoverySucceeded, Status: v1alpha1.ConditionFalse, - Reason: reasonInvalidTLSConfig, + Reason: upstreamwatchers.ReasonInvalidTLSConfig, Message: err.Error(), } } @@ -314,7 +311,7 @@ func (c *oidcWatcherController) validateIssuer(ctx context.Context, upstream *v1 return &v1alpha1.Condition{ Type: typeOIDCDiscoverySucceeded, Status: v1alpha1.ConditionTrue, - Reason: reasonSuccess, + Reason: upstreamwatchers.ReasonSuccess, Message: "discovered issuer configuration", } } @@ -335,7 +332,7 @@ func (*oidcWatcherController) getTLSConfig(upstream *v1alpha1.OIDCIdentityProvid result.RootCAs = x509.NewCertPool() if !result.RootCAs.AppendCertsFromPEM(bundle) { - return nil, fmt.Errorf("spec.certificateAuthorityData is invalid: %w", errNoCertificates) + return nil, fmt.Errorf("spec.certificateAuthorityData is invalid: %w", upstreamwatchers.ErrNoCertificates) } return &result, nil @@ -345,7 +342,7 @@ func (c *oidcWatcherController) updateStatus(ctx context.Context, upstream *v1al log := c.log.WithValues("namespace", upstream.Namespace, "name", upstream.Name) updated := upstream.DeepCopy() - hadErrorCondition := mergeConditions(conditions, upstream.Generation, &updated.Status.Conditions, log) + hadErrorCondition := conditionsutil.Merge(conditions, upstream.Generation, &updated.Status.Conditions, log) updated.Status.Phase = v1alpha1.PhaseReady if hadErrorCondition { @@ -365,60 +362,6 @@ func (c *oidcWatcherController) updateStatus(ctx context.Context, upstream *v1al } } -// mergeConditions merges conditions into conditionsToUpdate. If returns true if it merged any error conditions. -func mergeConditions(conditions []*v1alpha1.Condition, observedGeneration int64, conditionsToUpdate *[]v1alpha1.Condition, log logr.Logger) bool { - hadErrorCondition := false - for i := range conditions { - cond := conditions[i].DeepCopy() - cond.LastTransitionTime = metav1.Now() - cond.ObservedGeneration = observedGeneration - if mergeCondition(conditionsToUpdate, cond) { - log.Info("updated condition", "type", cond.Type, "status", cond.Status, "reason", cond.Reason, "message", cond.Message) - } - if cond.Status == v1alpha1.ConditionFalse { - hadErrorCondition = true - } - } - sort.SliceStable(*conditionsToUpdate, func(i, j int) bool { - return (*conditionsToUpdate)[i].Type < (*conditionsToUpdate)[j].Type - }) - return hadErrorCondition -} - -// mergeCondition merges a new v1alpha1.Condition into a slice of existing conditions. It returns true -// if the condition has meaningfully changed. -func mergeCondition(existing *[]v1alpha1.Condition, new *v1alpha1.Condition) bool { - // Find any existing condition with a matching type. - var old *v1alpha1.Condition - for i := range *existing { - if (*existing)[i].Type == new.Type { - old = &(*existing)[i] - continue - } - } - - // If there is no existing condition of this type, append this one and we're done. - if old == nil { - *existing = append(*existing, *new) - return true - } - - // Set the LastTransitionTime depending on whether the status has changed. - new = new.DeepCopy() - if old.Status == new.Status { - new.LastTransitionTime = old.LastTransitionTime - } - - // If anything has actually changed, update the entry and return true. - if !equality.Semantic.DeepEqual(old, new) { - *old = *new - return true - } - - // Otherwise the entry is already up to date. - return false -} - func (*oidcWatcherController) computeScopes(additionalScopes []string) []string { // First compute the unique set of scopes, including "openid" (de-duplicate). set := make(map[string]bool, len(additionalScopes)+1) diff --git a/internal/controller/supervisorconfig/upstreamwatcher/oidc_upstream_watcher_test.go b/internal/controller/supervisorconfig/oidcupstreamwatcher/oidc_upstream_watcher_test.go similarity index 99% rename from internal/controller/supervisorconfig/upstreamwatcher/oidc_upstream_watcher_test.go rename to internal/controller/supervisorconfig/oidcupstreamwatcher/oidc_upstream_watcher_test.go index 06b82c02..9370aad3 100644 --- a/internal/controller/supervisorconfig/upstreamwatcher/oidc_upstream_watcher_test.go +++ b/internal/controller/supervisorconfig/oidcupstreamwatcher/oidc_upstream_watcher_test.go @@ -1,7 +1,7 @@ // Copyright 2020-2021 the Pinniped contributors. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 -package upstreamwatcher +package oidcupstreamwatcher import ( "context" @@ -82,7 +82,7 @@ func TestOIDCUpstreamWatcherControllerFilterSecret(t *testing.T) { secretInformer := kubeInformers.Core().V1().Secrets() withInformer := testutil.NewObservableWithInformerOption() - NewOIDCUpstreamWatcherController( + New( cache, nil, pinnipedInformers.IDP().V1alpha1().OIDCIdentityProviders(), @@ -762,7 +762,7 @@ oidc: issuer did not match the issuer returned by provider, expected "` + testIs &upstreamoidc.ProviderConfig{Name: "initial-entry"}, }) - controller := NewOIDCUpstreamWatcherController( + controller := New( cache, fakePinnipedClient, pinnipedInformers.IDP().V1alpha1().OIDCIdentityProviders(), diff --git a/internal/controller/supervisorconfig/upstreamwatchers/upstream_watchers.go b/internal/controller/supervisorconfig/upstreamwatchers/upstream_watchers.go new file mode 100644 index 00000000..36bd37c8 --- /dev/null +++ b/internal/controller/supervisorconfig/upstreamwatchers/upstream_watchers.go @@ -0,0 +1,16 @@ +// Copyright 2021 the Pinniped contributors. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +package upstreamwatchers + +import "go.pinniped.dev/internal/constable" + +const ( + ReasonNotFound = "SecretNotFound" + ReasonWrongType = "SecretWrongType" + ReasonMissingKeys = "SecretMissingKeys" + ReasonSuccess = "Success" + ReasonInvalidTLSConfig = "InvalidTLSConfig" + + ErrNoCertificates = constable.Error("no certificates found") +)