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

Support GetAllSecrets for the fake provider (#2844)

* Support GetAllSecrets for the fake provider

Signed-off-by: shuheiktgw <s-kitagawa@mercari.com>

* Stop reassigning map keys

Signed-off-by: shuheiktgw <s-kitagawa@mercari.com>

* Use a single loop to construct the dataMap

Signed-off-by: shuheiktgw <s-kitagawa@mercari.com>

---------

Signed-off-by: shuheiktgw <s-kitagawa@mercari.com>
This commit is contained in:
Shuhei Kitagawa 2023-11-07 09:48:49 +09:00 committed by GitHub
parent a15b146165
commit e0c1d93f9b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 198 additions and 11 deletions

View file

@ -308,6 +308,7 @@ type ExternalSecretFind struct {
// A root path to start the find operations.
// +optional
Path *string `json:"path,omitempty"`
// Finds secrets based on the name.
// +optional
Name *FindName `json:"name,omitempty"`

View file

@ -17,6 +17,7 @@ package fake
import (
"context"
"fmt"
"strings"
"github.com/tidwall/gjson"
corev1 "k8s.io/api/core/v1"
@ -24,6 +25,8 @@ import (
"sigs.k8s.io/controller-runtime/pkg/client"
esv1beta1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1beta1"
"github.com/external-secrets/external-secrets/pkg/find"
"github.com/external-secrets/external-secrets/pkg/utils"
)
var (
@ -77,14 +80,14 @@ func (p *Provider) NewClient(_ context.Context, store esv1beta1.GenericStore, _
}
}
for _, data := range c.Data {
mapKey := fmt.Sprintf("%v%v", data.Key, data.Version)
cfg[mapKey] = &Data{
key := mapKey(data.Key, data.Version)
cfg[key] = &Data{
Value: data.Value,
Version: data.Version,
Origin: FakeSecretStore,
}
if data.ValueMap != nil {
cfg[mapKey].ValueMap = data.ValueMap
cfg[key].ValueMap = data.ValueMap
}
}
p.database[store.GetName()] = cfg
@ -124,16 +127,44 @@ func (p *Provider) PushSecret(_ context.Context, value []byte, _ corev1.SecretTy
return nil
}
// Empty GetAllSecrets.
func (p *Provider) GetAllSecrets(_ context.Context, _ esv1beta1.ExternalSecretFind) (map[string][]byte, error) {
// TO be implemented
return nil, fmt.Errorf("GetAllSecrets not implemented")
// GetAllSecrets returns multiple secrets from the given ExternalSecretFind
// Currently, only the Name operator is supported.
func (p *Provider) GetAllSecrets(_ context.Context, ref esv1beta1.ExternalSecretFind) (map[string][]byte, error) {
if ref.Name != nil {
matcher, err := find.New(*ref.Name)
if err != nil {
return nil, err
}
latestVersionMap := make(map[string]string)
dataMap := make(map[string][]byte)
for key, data := range p.config {
// Reconstruct the original key without the version suffix
// See the mapKey function to know how the provider generates keys
originalKey := strings.TrimSuffix(key, data.Version)
if !matcher.MatchName(originalKey) {
continue
}
if version, ok := latestVersionMap[originalKey]; ok {
// Need to get only the latest version
if version < data.Version {
latestVersionMap[originalKey] = data.Version
dataMap[originalKey] = []byte(data.Value)
}
} else {
latestVersionMap[originalKey] = data.Version
dataMap[originalKey] = []byte(data.Value)
}
}
return utils.ConvertKeys(ref.ConversionStrategy, dataMap)
}
return nil, fmt.Errorf("unsupported find operator: %#v", ref)
}
// GetSecret returns a single secret from the provider.
func (p *Provider) GetSecret(_ context.Context, ref esv1beta1.ExternalSecretDataRemoteRef) ([]byte, error) {
mapKey := fmt.Sprintf("%v%v", ref.Key, ref.Version)
data, ok := p.config[mapKey]
data, ok := p.config[mapKey(ref.Key, ref.Version)]
if !ok || data.Version != ref.Version {
return nil, esv1beta1.NoSecretErr
}
@ -152,8 +183,7 @@ func (p *Provider) GetSecret(_ context.Context, ref esv1beta1.ExternalSecretData
// GetSecretMap returns multiple k/v pairs from the provider.
func (p *Provider) GetSecretMap(_ context.Context, ref esv1beta1.ExternalSecretDataRemoteRef) (map[string][]byte, error) {
mapKey := fmt.Sprintf("%v%v", ref.Key, ref.Version)
data, ok := p.config[mapKey]
data, ok := p.config[mapKey(ref.Key, ref.Version)]
if !ok || data.Version != ref.Version || data.ValueMap == nil {
return nil, esv1beta1.NoSecretErr
}
@ -192,6 +222,11 @@ func (p *Provider) ValidateStore(store esv1beta1.GenericStore) error {
return nil
}
func mapKey(key, version string) string {
// Add the version suffix to preserve entries with the old versions as well.
return fmt.Sprintf("%v%v", key, version)
}
func init() {
esv1beta1.Register(&Provider{}, &esv1beta1.SecretStoreProvider{
Fake: &esv1beta1.FakeProvider{},

View file

@ -17,10 +17,13 @@ import (
"context"
"errors"
"fmt"
"strings"
"testing"
"github.com/google/go-cmp/cmp"
"github.com/onsi/gomega"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/utils/ptr"
esv1alpha1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1alpha1"
esv1beta1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1beta1"
@ -87,6 +90,154 @@ type testCase struct {
expErr string
}
func TestGetAllSecrets(t *testing.T) {
cases := []struct {
desc string
data []esv1beta1.FakeProviderData
ref esv1beta1.ExternalSecretFind
expected map[string][]byte
expectedErr string
}{
{
desc: "no matches",
data: []esv1beta1.FakeProviderData{},
ref: esv1beta1.ExternalSecretFind{
Name: &esv1beta1.FindName{
RegExp: "some-key",
},
},
expected: map[string][]byte{},
},
{
desc: "matches",
data: []esv1beta1.FakeProviderData{
{
Key: "some-key1",
Value: "some-value1",
},
{
Key: "some-key2",
Value: "some-value2",
},
{
Key: "another-key1",
Value: "another-value1",
},
},
ref: esv1beta1.ExternalSecretFind{
Name: &esv1beta1.FindName{
RegExp: "some-key.*",
},
},
expected: map[string][]byte{
"some-key1": []byte("some-value1"),
"some-key2": []byte("some-value2"),
},
},
{
desc: "matches with version",
data: []esv1beta1.FakeProviderData{
{
Key: "some-key1",
Value: "some-value1-version1",
Version: "1",
},
{
Key: "some-key1",
Value: "some-value1-version2",
Version: "2",
},
{
Key: "some-key2",
Value: "some-value2-version1",
Version: "1",
},
{
Key: "some-key2",
Value: "some-value2-version2",
Version: "2",
},
{
Key: "some-key2",
Value: "some-value2-version3",
Version: "3",
},
{
Key: "another-key1",
Value: "another-value1-version1",
Version: "1",
},
{
Key: "another-key1",
Value: "another-value1-version2",
Version: "2",
},
},
ref: esv1beta1.ExternalSecretFind{
Name: &esv1beta1.FindName{
RegExp: "some-key.*",
},
},
expected: map[string][]byte{
"some-key1": []byte("some-value1-version2"),
"some-key2": []byte("some-value2-version3"),
},
},
{
desc: "unsupported operator",
data: []esv1beta1.FakeProviderData{},
ref: esv1beta1.ExternalSecretFind{
Path: ptr.To("some-path"),
},
expectedErr: "unsupported find operator",
},
}
for i, tc := range cases {
t.Run(tc.desc, func(t *testing.T) {
ctx := context.Background()
p := Provider{}
client, err := p.NewClient(ctx, &esv1beta1.SecretStore{
ObjectMeta: metav1.ObjectMeta{
Name: fmt.Sprintf("secret-store-%v", i),
},
Spec: esv1beta1.SecretStoreSpec{
Provider: &esv1beta1.SecretStoreProvider{
Fake: &esv1beta1.FakeProvider{
Data: tc.data,
},
},
},
}, nil, "")
if err != nil {
t.Fatalf("failed to create a client: %v", err)
}
got, err := client.GetAllSecrets(ctx, tc.ref)
if err != nil {
if tc.expectedErr == "" {
t.Fatalf("failed to call GetAllSecrets: %v", err)
}
if !strings.Contains(err.Error(), tc.expectedErr) {
t.Fatalf("%q expected to contain substring %q", err.Error(), tc.expectedErr)
}
return
}
if tc.expectedErr != "" {
t.Fatal("expected to receive an error but got nil")
}
if diff := cmp.Diff(tc.expected, got); diff != "" {
t.Fatalf("(-got, +want)\n%s", diff)
}
})
}
}
func TestGetSecret(t *testing.T) {
gomega.RegisterTestingT(t)
p := &Provider{}