mirror of
https://github.com/external-secrets/external-secrets.git
synced 2024-12-14 11:57:59 +00:00
Ignore ExternalSecret processing if the store is not usuable (e.g.
NotReady).
This commit is contained in:
parent
84af221762
commit
4820cc9165
31 changed files with 169 additions and 83 deletions
|
@ -273,6 +273,7 @@ const (
|
|||
ConditionReasonSecretDeleted = "SecretDeleted"
|
||||
|
||||
ReasonInvalidStoreRef = "InvalidStoreRef"
|
||||
ReasonUnavailableStore = "UnavailableStore"
|
||||
ReasonProviderClientConfig = "InvalidProviderClientConfig"
|
||||
ReasonUpdateFailed = "UpdateFailed"
|
||||
ReasonUpdated = "Updated"
|
||||
|
|
|
@ -20,6 +20,18 @@ import (
|
|||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
)
|
||||
|
||||
const (
|
||||
ValidationResultReady ValidationResult = iota
|
||||
ValidationResultUnknown
|
||||
ValidationResultError
|
||||
)
|
||||
|
||||
type ValidationResult uint8
|
||||
|
||||
func (v ValidationResult) String() string {
|
||||
return [...]string{"Ready", "Unknown", "Error"}[v]
|
||||
}
|
||||
|
||||
// +kubebuilder:object:root=false
|
||||
// +kubebuilder:object:generate:false
|
||||
// +k8s:deepcopy-gen:interfaces=nil
|
||||
|
@ -47,8 +59,9 @@ type SecretsClient interface {
|
|||
GetSecret(ctx context.Context, ref ExternalSecretDataRemoteRef) ([]byte, error)
|
||||
|
||||
// Validate checks if the client is configured correctly
|
||||
// and is able to retrieve secrets from the provider
|
||||
Validate() error
|
||||
// and is able to retrieve secrets from the provider.
|
||||
// If the validation result is unknown it will be ignored.
|
||||
Validate() (ValidationResult, error)
|
||||
|
||||
// GetSecretMap returns multiple k/v pairs from the provider
|
||||
GetSecretMap(ctx context.Context, ref ExternalSecretDataRemoteRef) (map[string][]byte, error)
|
||||
|
|
|
@ -50,8 +50,8 @@ func (p *PP) Close(ctx context.Context) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (p *PP) Validate() error {
|
||||
return nil
|
||||
func (p *PP) Validate() (ValidationResult, error) {
|
||||
return ValidationResultReady, nil
|
||||
}
|
||||
|
||||
func (p *PP) ValidateStore(store GenericStore) error {
|
||||
|
|
|
@ -32,6 +32,10 @@ type SecretStoreSpec struct {
|
|||
// Used to configure http retries if failed
|
||||
// +optional
|
||||
RetrySettings *SecretStoreRetrySettings `json:"retrySettings,omitempty"`
|
||||
|
||||
// Used to configure store refresh interval in seconds. Empty or 0 will default to the controller config.
|
||||
// +optional
|
||||
RefreshInterval int `json:"refreshInterval"`
|
||||
}
|
||||
|
||||
// SecretStoreProvider contains the provider-specific configration.
|
||||
|
|
|
@ -55,6 +55,7 @@ var (
|
|||
namespace string
|
||||
enableClusterStoreReconciler bool
|
||||
enableClusterExternalSecretReconciler bool
|
||||
enableFloodGate bool
|
||||
storeRequeueInterval time.Duration
|
||||
serviceName, serviceNamespace string
|
||||
secretName, secretNamespace string
|
||||
|
@ -138,6 +139,7 @@ var rootCmd = &cobra.Command{
|
|||
ControllerClass: controllerClass,
|
||||
RequeueInterval: time.Hour,
|
||||
ClusterSecretStoreEnabled: enableClusterStoreReconciler,
|
||||
EnableFloodGate: enableFloodGate,
|
||||
}).SetupWithManager(mgr, controller.Options{
|
||||
MaxConcurrentReconciles: concurrent,
|
||||
}); err != nil {
|
||||
|
@ -181,5 +183,6 @@ func init() {
|
|||
rootCmd.Flags().StringVar(&namespace, "namespace", "", "watch external secrets scoped in the provided namespace only. ClusterSecretStore can be used but only work if it doesn't reference resources from other namespaces")
|
||||
rootCmd.Flags().BoolVar(&enableClusterStoreReconciler, "enable-cluster-store-reconciler", true, "Enable cluster store reconciler.")
|
||||
rootCmd.Flags().BoolVar(&enableClusterExternalSecretReconciler, "enable-cluster-external-secret-reconciler", true, "Enable cluster external secret reconciler.")
|
||||
rootCmd.Flags().DurationVar(&storeRequeueInterval, "store-requeue-interval", time.Minute*5, "Time duration between reconciling (Cluster)SecretStores")
|
||||
rootCmd.Flags().DurationVar(&storeRequeueInterval, "store-requeue-interval", time.Minute*5, "Default Time duration between reconciling (Cluster)SecretStores")
|
||||
rootCmd.Flags().BoolVar(&enableFloodGate, "enable-flood-gate", true, "Enable flood gate. External secret will be reconciled only if the ClusterStore or Store have an healthy or unknown state.")
|
||||
}
|
||||
|
|
|
@ -2704,6 +2704,10 @@ spec:
|
|||
- auth
|
||||
type: object
|
||||
type: object
|
||||
refreshInterval:
|
||||
description: Used to configure store refresh interval in seconds.
|
||||
Empty or 0 will default to the controller config.
|
||||
type: integer
|
||||
retrySettings:
|
||||
description: Used to configure http retries if failed
|
||||
properties:
|
||||
|
|
|
@ -2707,6 +2707,10 @@ spec:
|
|||
- auth
|
||||
type: object
|
||||
type: object
|
||||
refreshInterval:
|
||||
description: Used to configure store refresh interval in seconds.
|
||||
Empty or 0 will default to the controller config.
|
||||
type: integer
|
||||
retrySettings:
|
||||
description: Used to configure http retries if failed
|
||||
properties:
|
||||
|
|
|
@ -2316,6 +2316,9 @@ spec:
|
|||
- auth
|
||||
type: object
|
||||
type: object
|
||||
refreshInterval:
|
||||
description: Used to configure store refresh interval in seconds. Empty or 0 will default to the controller config.
|
||||
type: integer
|
||||
retrySettings:
|
||||
description: Used to configure http retries if failed
|
||||
properties:
|
||||
|
@ -4870,6 +4873,9 @@ spec:
|
|||
- auth
|
||||
type: object
|
||||
type: object
|
||||
refreshInterval:
|
||||
description: Used to configure store refresh interval in seconds. Empty or 0 will default to the controller config.
|
||||
type: integer
|
||||
retrySettings:
|
||||
description: Used to configure http retries if failed
|
||||
properties:
|
||||
|
|
|
@ -18,8 +18,6 @@ import (
|
|||
|
||||
// nolint
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
// nolint
|
||||
. "github.com/onsi/ginkgo/v2/extensions/table"
|
||||
|
||||
"github.com/external-secrets/external-secrets/e2e/framework"
|
||||
"github.com/external-secrets/external-secrets/e2e/suite/common"
|
||||
|
|
|
@ -18,8 +18,6 @@ import (
|
|||
|
||||
// nolint
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
// nolint
|
||||
. "github.com/onsi/ginkgo/v2/extensions/table"
|
||||
|
||||
"github.com/external-secrets/external-secrets/e2e/framework"
|
||||
"github.com/external-secrets/external-secrets/e2e/suite/common"
|
||||
|
|
|
@ -21,8 +21,6 @@ import (
|
|||
|
||||
// nolint
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
// nolint
|
||||
. "github.com/onsi/ginkgo/v2/extensions/table"
|
||||
|
||||
"github.com/external-secrets/external-secrets/e2e/framework"
|
||||
"github.com/external-secrets/external-secrets/e2e/suite/common"
|
||||
|
|
|
@ -16,8 +16,6 @@ import (
|
|||
|
||||
// nolint
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
// nolint
|
||||
. "github.com/onsi/ginkgo/v2/extensions/table"
|
||||
|
||||
"github.com/external-secrets/external-secrets/e2e/framework"
|
||||
"github.com/external-secrets/external-secrets/e2e/suite/common"
|
||||
|
|
|
@ -53,8 +53,10 @@ const (
|
|||
errUpdateSecret = "could not update Secret"
|
||||
errPatchStatus = "unable to patch status"
|
||||
errGetSecretStore = "could not get SecretStore %q, %w"
|
||||
errSecretStoreNotReady = "the desired SecretStore %s is not ready"
|
||||
errGetClusterSecretStore = "could not get ClusterSecretStore %q, %w"
|
||||
errStoreRef = "could not get store reference"
|
||||
errStoreUsability = "could not use store reference"
|
||||
errStoreProvider = "could not get store provider"
|
||||
errStoreClient = "could not get provider client"
|
||||
errGetExistingSecret = "could not get existing secret: %w"
|
||||
|
@ -82,6 +84,7 @@ type Reconciler struct {
|
|||
ControllerClass string
|
||||
RequeueInterval time.Duration
|
||||
ClusterSecretStoreEnabled bool
|
||||
EnableFloodGate bool
|
||||
recorder record.EventRecorder
|
||||
}
|
||||
|
||||
|
@ -133,7 +136,7 @@ func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Resu
|
|||
conditionSynced := NewExternalSecretCondition(esv1beta1.ExternalSecretReady, v1.ConditionFalse, esv1beta1.ConditionReasonSecretSyncedError, errStoreRef)
|
||||
SetExternalSecretCondition(&externalSecret, *conditionSynced)
|
||||
syncCallsError.With(syncCallsMetricLabels).Inc()
|
||||
return ctrl.Result{RequeueAfter: requeueAfter}, nil
|
||||
return ctrl.Result{}, err
|
||||
}
|
||||
|
||||
log = log.WithValues("SecretStore", store.GetNamespacedName())
|
||||
|
@ -144,6 +147,17 @@ func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Resu
|
|||
return ctrl.Result{}, nil
|
||||
}
|
||||
|
||||
if r.EnableFloodGate {
|
||||
if err = assertStoreIsUsable(store); err != nil {
|
||||
log.Error(err, errStoreUsability)
|
||||
r.recorder.Event(&externalSecret, v1.EventTypeWarning, esv1beta1.ReasonUnavailableStore, err.Error())
|
||||
conditionSynced := NewExternalSecretCondition(esv1beta1.ExternalSecretReady, v1.ConditionFalse, esv1beta1.ConditionReasonSecretSyncedError, errStoreUsability)
|
||||
SetExternalSecretCondition(&externalSecret, *conditionSynced)
|
||||
syncCallsError.With(syncCallsMetricLabels).Inc()
|
||||
return ctrl.Result{}, err
|
||||
}
|
||||
}
|
||||
|
||||
storeProvider, err := esv1beta1.GetProvider(store)
|
||||
if err != nil {
|
||||
log.Error(err, errStoreProvider)
|
||||
|
@ -158,7 +172,7 @@ func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Resu
|
|||
SetExternalSecretCondition(&externalSecret, *conditionSynced)
|
||||
r.recorder.Event(&externalSecret, v1.EventTypeWarning, esv1beta1.ReasonProviderClientConfig, err.Error())
|
||||
syncCallsError.With(syncCallsMetricLabels).Inc()
|
||||
return ctrl.Result{RequeueAfter: requeueAfter}, nil
|
||||
return ctrl.Result{}, err
|
||||
}
|
||||
|
||||
defer func() {
|
||||
|
@ -467,7 +481,14 @@ func isSecretValid(existingSecret v1.Secret) bool {
|
|||
return true
|
||||
}
|
||||
|
||||
// getStore returns the store with the provided ExternalSecret.
|
||||
// assertStoreIsUsable assert that the store is ready to use.
|
||||
func assertStoreIsUsable(store esv1beta1.GenericStore) error {
|
||||
if secretstore.GetSecretStoreCondition(store.GetStatus(), esv1beta1.SecretStoreReady).Status != v1.ConditionTrue {
|
||||
return fmt.Errorf(errSecretStoreNotReady, store.GetName())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *Reconciler) getStore(ctx context.Context, externalSecret *esv1beta1.ExternalSecret) (esv1beta1.GenericStore, error) {
|
||||
ref := types.NamespacedName{
|
||||
Name: externalSecret.Spec.SecretStoreRef.Name,
|
||||
|
@ -479,7 +500,6 @@ func (r *Reconciler) getStore(ctx context.Context, externalSecret *esv1beta1.Ext
|
|||
if err != nil {
|
||||
return nil, fmt.Errorf(errGetClusterSecretStore, ref.Name, err)
|
||||
}
|
||||
|
||||
return &store, nil
|
||||
}
|
||||
|
||||
|
@ -490,6 +510,7 @@ func (r *Reconciler) getStore(ctx context.Context, externalSecret *esv1beta1.Ext
|
|||
if err != nil {
|
||||
return nil, fmt.Errorf(errGetSecretStore, ref.Name, err)
|
||||
}
|
||||
|
||||
return &store, nil
|
||||
}
|
||||
|
||||
|
|
|
@ -46,6 +46,10 @@ func reconcile(ctx context.Context, req ctrl.Request, ss esapi.GenericStore, cl
|
|||
return ctrl.Result{}, nil
|
||||
}
|
||||
|
||||
if ss.GetSpec().RefreshInterval != 0 {
|
||||
requeueInterval = time.Second * time.Duration(ss.GetSpec().RefreshInterval)
|
||||
}
|
||||
|
||||
// patch status when done processing
|
||||
p := client.MergeFrom(ss.Copy())
|
||||
defer func() {
|
||||
|
@ -93,8 +97,8 @@ func validateStore(ctx context.Context, namespace string, store esapi.GenericSto
|
|||
}
|
||||
defer cl.Close(ctx)
|
||||
|
||||
err = cl.Validate()
|
||||
if err != nil {
|
||||
validationResult, err := cl.Validate()
|
||||
if err != nil && validationResult != esapi.ValidationResultUnknown {
|
||||
cond := NewSecretStoreCondition(esapi.SecretStoreReady, v1.ConditionFalse, esapi.ReasonValidationFailed, errUnableValidateStore)
|
||||
SetExternalSecretCondition(store, *cond)
|
||||
recorder.Event(store, v1.EventTypeWarning, esapi.ReasonValidationFailed, err.Error())
|
||||
|
|
|
@ -111,11 +111,15 @@ func (a *Akeyless) Close(ctx context.Context) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (a *Akeyless) Validate() error {
|
||||
func (a *Akeyless) Validate() (esv1beta1.ValidationResult, error) {
|
||||
timeout := 15 * time.Second
|
||||
url := a.url
|
||||
|
||||
return utils.NetworkValidate(url, timeout)
|
||||
if err := utils.NetworkValidate(url, timeout); err != nil {
|
||||
return esv1beta1.ValidationResultError, err
|
||||
}
|
||||
|
||||
return esv1beta1.ValidationResultReady, nil
|
||||
}
|
||||
|
||||
// Implements store.Client.GetSecret Interface.
|
||||
|
|
|
@ -197,11 +197,14 @@ func (kms *KeyManagementService) Close(ctx context.Context) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (kms *KeyManagementService) Validate() error {
|
||||
func (kms *KeyManagementService) Validate() (esv1beta1.ValidationResult, error) {
|
||||
timeout := 15 * time.Second
|
||||
url := kms.url
|
||||
|
||||
return utils.NetworkValidate(url, timeout)
|
||||
if err := utils.NetworkValidate(url, timeout); err != nil {
|
||||
return esv1beta1.ValidationResultError, err
|
||||
}
|
||||
return esv1beta1.ValidationResultReady, nil
|
||||
}
|
||||
|
||||
func (kms *KeyManagementService) ValidateStore(store esv1beta1.GenericStore) error {
|
||||
|
|
|
@ -225,7 +225,10 @@ func (pm *ParameterStore) Close(ctx context.Context) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (pm *ParameterStore) Validate() error {
|
||||
func (pm *ParameterStore) Validate() (esv1beta1.ValidationResult, error) {
|
||||
_, err := pm.sess.Config.Credentials.Get()
|
||||
return err
|
||||
if err != nil {
|
||||
return esv1beta1.ValidationResultError, err
|
||||
}
|
||||
return esv1beta1.ValidationResultReady, nil
|
||||
}
|
||||
|
|
|
@ -287,7 +287,10 @@ func (sm *SecretsManager) Close(ctx context.Context) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (sm *SecretsManager) Validate() error {
|
||||
func (sm *SecretsManager) Validate() (esv1beta1.ValidationResult, error) {
|
||||
_, err := sm.sess.Config.Credentials.Get()
|
||||
return err
|
||||
if err != nil {
|
||||
return esv1beta1.ValidationResultError, err
|
||||
}
|
||||
return esv1beta1.ValidationResultReady, nil
|
||||
}
|
||||
|
|
|
@ -480,8 +480,8 @@ func (a *Azure) Close(ctx context.Context) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (a *Azure) Validate() error {
|
||||
return nil
|
||||
func (a *Azure) Validate() (esv1beta1.ValidationResult, error) {
|
||||
return esv1beta1.ValidationResultReady, nil
|
||||
}
|
||||
|
||||
func getObjType(ref esv1beta1.ExternalSecretDataRemoteRef) (string, string) {
|
||||
|
|
|
@ -94,8 +94,8 @@ func (p *Provider) Close(ctx context.Context) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (p *Provider) Validate() error {
|
||||
return nil
|
||||
func (p *Provider) Validate() (esv1beta1.ValidationResult, error) {
|
||||
return esv1beta1.ValidationResultReady, nil
|
||||
}
|
||||
|
||||
func (p *Provider) ValidateStore(store esv1beta1.GenericStore) error {
|
||||
|
|
|
@ -423,8 +423,8 @@ func (sm *ProviderGCP) Close(ctx context.Context) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (sm *ProviderGCP) Validate() error {
|
||||
return nil
|
||||
func (sm *ProviderGCP) Validate() (esv1beta1.ValidationResult, error) {
|
||||
return esv1beta1.ValidationResultReady, nil
|
||||
}
|
||||
|
||||
func (sm *ProviderGCP) ValidateStore(store esv1beta1.GenericStore) error {
|
||||
|
|
|
@ -226,14 +226,14 @@ func (g *Gitlab) Close(ctx context.Context) error {
|
|||
}
|
||||
|
||||
// Validate will use the gitlab client to validate the gitlab provider using the ListVariable call to ensure get permissions without needing a specific key.
|
||||
func (g *Gitlab) Validate() error {
|
||||
func (g *Gitlab) Validate() (esv1beta1.ValidationResult, error) {
|
||||
_, resp, err := g.client.ListVariables(g.projectID, nil)
|
||||
if err != nil {
|
||||
return fmt.Errorf(errList, err)
|
||||
return esv1beta1.ValidationResultError, fmt.Errorf(errList, err)
|
||||
} else if resp == nil || resp.StatusCode != http.StatusOK {
|
||||
return fmt.Errorf(errAuth)
|
||||
return esv1beta1.ValidationResultError, fmt.Errorf(errAuth)
|
||||
}
|
||||
return nil
|
||||
return esv1beta1.ValidationResultReady, nil
|
||||
}
|
||||
|
||||
func (g *Gitlab) ValidateStore(store esv1beta1.GenericStore) error {
|
||||
|
|
|
@ -28,33 +28,35 @@ import (
|
|||
)
|
||||
|
||||
type secretManagerTestCase struct {
|
||||
mockClient *fakegitlab.GitlabMockClient
|
||||
apiInputProjectID string
|
||||
apiInputKey string
|
||||
apiOutput *gitlab.ProjectVariable
|
||||
apiResponse *gitlab.Response
|
||||
ref *esv1beta1.ExternalSecretDataRemoteRef
|
||||
projectID *string
|
||||
apiErr error
|
||||
expectError string
|
||||
expectedSecret string
|
||||
mockClient *fakegitlab.GitlabMockClient
|
||||
apiInputProjectID string
|
||||
apiInputKey string
|
||||
apiOutput *gitlab.ProjectVariable
|
||||
apiResponse *gitlab.Response
|
||||
ref *esv1beta1.ExternalSecretDataRemoteRef
|
||||
projectID *string
|
||||
apiErr error
|
||||
expectError string
|
||||
expectedSecret string
|
||||
expectedValidationResult esv1beta1.ValidationResult
|
||||
// for testing secretmap
|
||||
expectedData map[string][]byte
|
||||
}
|
||||
|
||||
func makeValidSecretManagerTestCase() *secretManagerTestCase {
|
||||
smtc := secretManagerTestCase{
|
||||
mockClient: &fakegitlab.GitlabMockClient{},
|
||||
apiInputProjectID: makeValidAPIInputProjectID(),
|
||||
apiInputKey: makeValidAPIInputKey(),
|
||||
ref: makeValidRef(),
|
||||
projectID: nil,
|
||||
apiOutput: makeValidAPIOutput(),
|
||||
apiResponse: makeValidAPIResponse(),
|
||||
apiErr: nil,
|
||||
expectError: "",
|
||||
expectedSecret: "",
|
||||
expectedData: map[string][]byte{},
|
||||
mockClient: &fakegitlab.GitlabMockClient{},
|
||||
apiInputProjectID: makeValidAPIInputProjectID(),
|
||||
apiInputKey: makeValidAPIInputKey(),
|
||||
ref: makeValidRef(),
|
||||
projectID: nil,
|
||||
apiOutput: makeValidAPIOutput(),
|
||||
apiResponse: makeValidAPIResponse(),
|
||||
apiErr: nil,
|
||||
expectError: "",
|
||||
expectedSecret: "",
|
||||
expectedValidationResult: esv1beta1.ValidationResultReady,
|
||||
expectedData: map[string][]byte{},
|
||||
}
|
||||
smtc.mockClient.WithValue(smtc.apiInputProjectID, smtc.apiInputKey, smtc.apiOutput, smtc.apiResponse, smtc.apiErr)
|
||||
return &smtc
|
||||
|
@ -104,22 +106,26 @@ func makeValidSecretManagerTestCaseCustom(tweaks ...func(smtc *secretManagerTest
|
|||
var setAPIErr = func(smtc *secretManagerTestCase) {
|
||||
smtc.apiErr = fmt.Errorf("oh no")
|
||||
smtc.expectError = "oh no"
|
||||
smtc.expectedValidationResult = esv1beta1.ValidationResultError
|
||||
}
|
||||
|
||||
var setListAPIErr = func(smtc *secretManagerTestCase) {
|
||||
err := fmt.Errorf("oh no")
|
||||
smtc.apiErr = err
|
||||
smtc.expectError = fmt.Errorf(errList, err).Error()
|
||||
smtc.expectedValidationResult = esv1beta1.ValidationResultError
|
||||
}
|
||||
|
||||
var setListAPIRespNil = func(smtc *secretManagerTestCase) {
|
||||
smtc.apiResponse = nil
|
||||
smtc.expectError = errAuth
|
||||
smtc.expectedValidationResult = esv1beta1.ValidationResultError
|
||||
}
|
||||
|
||||
var setListAPIRespBadCode = func(smtc *secretManagerTestCase) {
|
||||
smtc.apiResponse.StatusCode = http.StatusUnauthorized
|
||||
smtc.expectError = errAuth
|
||||
smtc.expectedValidationResult = esv1beta1.ValidationResultError
|
||||
}
|
||||
|
||||
var setNilMockClient = func(smtc *secretManagerTestCase) {
|
||||
|
@ -172,10 +178,13 @@ func TestValidate(t *testing.T) {
|
|||
for k, v := range successCases {
|
||||
sm.client = v.mockClient
|
||||
t.Logf("%+v", v)
|
||||
err := sm.Validate()
|
||||
validationResult, err := sm.Validate()
|
||||
if !ErrorContains(err, v.expectError) {
|
||||
t.Errorf("[%d], unexpected error: %s, expected: '%s'", k, err.Error(), v.expectError)
|
||||
}
|
||||
if validationResult != v.expectedValidationResult {
|
||||
t.Errorf("[%d], unexpected validationResult: %s, expected: '%s'", k, validationResult, v.expectedValidationResult)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -496,8 +496,8 @@ func (ibm *providerIBM) Close(ctx context.Context) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (ibm *providerIBM) Validate() error {
|
||||
return nil
|
||||
func (ibm *providerIBM) Validate() (esv1beta1.ValidationResult, error) {
|
||||
return esv1beta1.ValidationResultReady, nil
|
||||
}
|
||||
|
||||
func (ibm *providerIBM) ValidateStore(store esv1beta1.GenericStore) error {
|
||||
|
|
|
@ -241,7 +241,7 @@ func (k *BaseClient) fetchSecretKey(ctx context.Context, key esmeta.SecretKeySel
|
|||
return val, nil
|
||||
}
|
||||
|
||||
func (k *ProviderKubernetes) Validate() error {
|
||||
func (k *ProviderKubernetes) Validate() (esv1beta1.ValidationResult, error) {
|
||||
ctx := context.Background()
|
||||
|
||||
authReview, err := k.ReviewClient.Create(ctx, &authv1.SelfSubjectAccessReview{
|
||||
|
@ -255,14 +255,14 @@ func (k *ProviderKubernetes) Validate() error {
|
|||
}, metav1.CreateOptions{})
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not verify if client is valid: %w", err)
|
||||
return esv1beta1.ValidationResultUnknown, fmt.Errorf("could not verify if client is valid: %w", err)
|
||||
}
|
||||
|
||||
if !authReview.Status.Allowed {
|
||||
return fmt.Errorf("client is not allowed to get secrets")
|
||||
return esv1beta1.ValidationResultError, fmt.Errorf("client is not allowed to get secrets")
|
||||
}
|
||||
|
||||
return nil
|
||||
return esv1beta1.ValidationResultReady, nil
|
||||
}
|
||||
|
||||
func (k *ProviderKubernetes) ValidateStore(store esv1beta1.GenericStore) error {
|
||||
|
|
|
@ -373,10 +373,14 @@ func TestValidate(t *testing.T) {
|
|||
}
|
||||
fakeClient := fakeReviewClient{authReview: &authReview}
|
||||
k := ProviderKubernetes{ReviewClient: fakeClient}
|
||||
err := k.Validate()
|
||||
validationResult, err := k.Validate()
|
||||
if err != nil {
|
||||
t.Errorf("Test Failed! %v", err)
|
||||
}
|
||||
if validationResult != esv1beta1.ValidationResultReady {
|
||||
t.Errorf("Test Failed! Wanted could not indicate validationResult is %s, got: %s", esv1beta1.ValidationResultReady, validationResult)
|
||||
}
|
||||
|
||||
authReview = authv1.SelfSubjectAccessReview{
|
||||
Status: authv1.SubjectAccessReviewStatus{
|
||||
Allowed: false,
|
||||
|
@ -384,15 +388,21 @@ func TestValidate(t *testing.T) {
|
|||
}
|
||||
fakeClient = fakeReviewClient{authReview: &authReview}
|
||||
k = ProviderKubernetes{ReviewClient: fakeClient}
|
||||
err = k.Validate()
|
||||
validationResult, err = k.Validate()
|
||||
if err.Error() != "client is not allowed to get secrets" {
|
||||
t.Errorf("Test Failed! Wanted client is not allowed to get secrets got: %v", err)
|
||||
}
|
||||
if validationResult != esv1beta1.ValidationResultError {
|
||||
t.Errorf("Test Failed! Wanted could not indicate validationResult is %s, got: %s", esv1beta1.ValidationResultError, validationResult)
|
||||
}
|
||||
|
||||
fakeClient = fakeReviewClient{}
|
||||
k = ProviderKubernetes{ReviewClient: fakeClient}
|
||||
err = k.Validate()
|
||||
validationResult, err = k.Validate()
|
||||
if err.Error() != "could not verify if client is valid: Something went wrong" {
|
||||
t.Errorf("Test Failed! Wanted could not verify if client is valid: Something went wrong got: %v", err)
|
||||
}
|
||||
if validationResult != esv1beta1.ValidationResultUnknown {
|
||||
t.Errorf("Test Failed! Wanted could not indicate validationResult is %s, got: %s", esv1beta1.ValidationResultUnknown, validationResult)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -223,8 +223,8 @@ func (vms *VaultManagementService) Close(ctx context.Context) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (vms *VaultManagementService) Validate() error {
|
||||
return nil
|
||||
func (vms *VaultManagementService) Validate() (esv1beta1.ValidationResult, error) {
|
||||
return esv1beta1.ValidationResultReady, nil
|
||||
}
|
||||
|
||||
func (vms *VaultManagementService) ValidateStore(store esv1beta1.GenericStore) error {
|
||||
|
|
|
@ -26,8 +26,7 @@ var _ esv1beta1.Provider = &Client{}
|
|||
|
||||
// Client is a fake client for testing.
|
||||
type Client struct {
|
||||
NewFn func(context.Context, esv1beta1.GenericStore, client.Client,
|
||||
string) (esv1beta1.SecretsClient, error)
|
||||
NewFn func(context.Context, esv1beta1.GenericStore, client.Client, string) (esv1beta1.SecretsClient, error)
|
||||
GetSecretFn func(context.Context, esv1beta1.ExternalSecretDataRemoteRef) ([]byte, error)
|
||||
GetSecretMapFn func(context.Context, esv1beta1.ExternalSecretDataRemoteRef) (map[string][]byte, error)
|
||||
GetAllSecretsFn func(context.Context, esv1beta1.ExternalSecretFind) (map[string][]byte, error)
|
||||
|
@ -59,7 +58,7 @@ func (v *Client) RegisterAs(provider *esv1beta1.SecretStoreProvider) {
|
|||
esv1beta1.ForceRegister(v, provider)
|
||||
}
|
||||
|
||||
// GetSecret implements the provider.Provider interface.
|
||||
// GetAllSecrets implements the provider.Provider interface.
|
||||
func (v *Client) GetAllSecrets(ctx context.Context, ref esv1beta1.ExternalSecretFind) (map[string][]byte, error) {
|
||||
return v.GetAllSecretsFn(ctx, ref)
|
||||
}
|
||||
|
@ -77,7 +76,7 @@ func (v *Client) WithGetSecret(secData []byte, err error) *Client {
|
|||
return v
|
||||
}
|
||||
|
||||
// GetSecretMap imeplements the provider.Provider interface.
|
||||
// GetSecretMap implements the provider.Provider interface.
|
||||
func (v *Client) GetSecretMap(ctx context.Context, ref esv1beta1.ExternalSecretDataRemoteRef) (map[string][]byte, error) {
|
||||
return v.GetSecretMapFn(ctx, ref)
|
||||
}
|
||||
|
@ -86,8 +85,8 @@ func (v *Client) Close(ctx context.Context) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (v *Client) Validate() error {
|
||||
return nil
|
||||
func (v *Client) Validate() (esv1beta1.ValidationResult, error) {
|
||||
return esv1beta1.ValidationResultReady, nil
|
||||
}
|
||||
|
||||
func (v *Client) ValidateStore(store esv1beta1.GenericStore) error {
|
||||
|
|
|
@ -576,12 +576,12 @@ func (v *client) Close(ctx context.Context) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (v *client) Validate() error {
|
||||
func (v *client) Validate() (esv1beta1.ValidationResult, error) {
|
||||
_, err := checkToken(context.Background(), v)
|
||||
if err != nil {
|
||||
return fmt.Errorf(errInvalidCredentials, err)
|
||||
return esv1beta1.ValidationResultError, fmt.Errorf(errInvalidCredentials, err)
|
||||
}
|
||||
return nil
|
||||
return esv1beta1.ValidationResultReady, nil
|
||||
}
|
||||
|
||||
func (v *client) buildMetadataPath(path string) (string, error) {
|
||||
|
|
|
@ -394,11 +394,14 @@ func (w *WebHook) Close(ctx context.Context) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (w *WebHook) Validate() error {
|
||||
func (w *WebHook) Validate() (esv1beta1.ValidationResult, error) {
|
||||
timeout := 15 * time.Second
|
||||
url := w.url
|
||||
|
||||
return utils.NetworkValidate(url, timeout)
|
||||
if err := utils.NetworkValidate(url, timeout); err != nil {
|
||||
return esv1beta1.ValidationResultError, err
|
||||
}
|
||||
return esv1beta1.ValidationResultReady, nil
|
||||
}
|
||||
|
||||
func executeTemplateString(tmpl string, data map[string]map[string]string) (string, error) {
|
||||
|
|
|
@ -288,8 +288,8 @@ func (c *lockboxSecretsClient) Close(ctx context.Context) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (c *lockboxSecretsClient) Validate() error {
|
||||
return nil
|
||||
func (c *lockboxSecretsClient) Validate() (esv1beta1.ValidationResult, error) {
|
||||
return esv1beta1.ValidationResultReady, nil
|
||||
}
|
||||
|
||||
func getValueAsIs(entry *lockbox.Payload_Entry) (interface{}, error) {
|
||||
|
|
Loading…
Reference in a new issue