Use string instead if interface for KVSecret data

Signed-off-by: Hasan Turken <turkenh@gmail.com>
This commit is contained in:
Hasan Turken 2022-03-12 23:25:29 +03:00
parent 80debfade8
commit 6f9579f9bd
No known key found for this signature in database
GPG Key ID: D7AA042F8F8B488E
5 changed files with 103 additions and 124 deletions

View File

@ -75,6 +75,14 @@ func (s *Secret) GetOwner() string {
return s.Metadata.GetOwnerUID()
}
// GetLabels returns the labels of the secret.
func (s *Secret) GetLabels() map[string]string {
if s.Metadata == nil {
return nil
}
return s.Metadata.Labels
}
// A WriteOption is called before writing the desired secret over the
// current object.
type WriteOption func(ctx context.Context, current, desired *Secret) error

View File

@ -64,23 +64,31 @@ func AllowUpdateIf(fn func(current, desired *KVSecret) bool) ApplyOption {
// KVSecret is a KVAdditiveClient Engine secret.
type KVSecret struct {
CustomMeta map[string]interface{}
Data map[string]interface{}
CustomMeta map[string]string
Data map[string]string
version json.Number
}
// NewKVSecret returns a new KVSecret.
func NewKVSecret(data map[string]string, meta map[string]string) *KVSecret {
return &KVSecret{
Data: data,
CustomMeta: meta,
}
}
// AddData adds supplied key value as data.
func (kv *KVSecret) AddData(key string, val interface{}) {
func (kv *KVSecret) AddData(key string, val string) {
if kv.Data == nil {
kv.Data = map[string]interface{}{}
kv.Data = map[string]string{}
}
kv.Data[key] = val
}
// AddMetadata adds supplied key value as metadata.
func (kv *KVSecret) AddMetadata(key string, val interface{}) {
func (kv *KVSecret) AddMetadata(key string, val string) {
if kv.CustomMeta == nil {
kv.CustomMeta = map[string]interface{}{}
kv.CustomMeta = map[string]string{}
}
kv.CustomMeta[key] = val
}
@ -204,7 +212,7 @@ func (k *KVAdditiveClient) Delete(path string) error {
}
func dataPayloadV2(existing, new *KVSecret) (map[string]interface{}, bool) {
data := make(map[string]interface{}, len(existing.Data)+len(new.Data))
data := make(map[string]string, len(existing.Data)+len(new.Data))
for k, v := range existing.Data {
data[k] = v
}
@ -227,7 +235,7 @@ func dataPayloadV2(existing, new *KVSecret) (map[string]interface{}, bool) {
}, changed
}
func metadataPayload(existing, new map[string]interface{}) (map[string]interface{}, bool) {
func metadataPayload(existing, new map[string]string) (map[string]interface{}, bool) {
payload := map[string]interface{}{
"custom_metadata": new,
}
@ -268,14 +276,16 @@ func payloadV1(existing, new *KVSecret) (map[string]interface{}, bool) {
return payload, changed
}
func (k *KVAdditiveClient) parseAsKVSecret(s *api.Secret, kv *KVSecret) error {
func (k *KVAdditiveClient) parseAsKVSecret(s *api.Secret, kv *KVSecret) error { // nolint: gocyclo
if k.version == v1.VaultKVVersionV1 {
for key, val := range s.Data {
if strings.HasPrefix(key, metadataPrefix) {
kv.AddMetadata(strings.TrimPrefix(key, metadataPrefix), val)
continue
if sVal, ok := val.(string); ok {
if strings.HasPrefix(key, metadataPrefix) {
kv.AddMetadata(strings.TrimPrefix(key, metadataPrefix), sVal)
continue
}
kv.AddData(key, sVal)
}
kv.AddData(key, val)
}
return nil
}
@ -286,12 +296,22 @@ func (k *KVAdditiveClient) parseAsKVSecret(s *api.Secret, kv *KVSecret) error {
// block inside the top level generic "Data" field.
// https://www.vaultproject.io/api/secret/kv/kv-v2#sample-response-1
if sData, ok := s.Data["data"].(map[string]interface{}); ok && sData != nil {
kv.Data = sData
kv.Data = make(map[string]string, len(sData))
for key, val := range sData {
if sVal, ok := val.(string); ok {
kv.Data[key] = sVal
}
}
}
if sMeta, ok := s.Data["metadata"].(map[string]interface{}); ok && sMeta != nil {
kv.version, _ = sMeta["version"].(json.Number)
if cMeta, ok := sMeta["custom_metadata"].(map[string]interface{}); ok && cMeta != nil {
kv.CustomMeta = cMeta
kv.CustomMeta = make(map[string]string, len(cMeta))
for key, val := range cMeta {
if sVal, ok := val.(string); ok {
kv.CustomMeta[key] = sVal
}
}
}
}
return nil

View File

@ -115,10 +115,10 @@ func TestKVClientGet(t *testing.T) {
},
want: want{
out: &KVSecret{
Data: map[string]interface{}{
Data: map[string]string{
"foo": "bar",
},
CustomMeta: map[string]interface{}{
CustomMeta: map[string]string{
"owner": "jdoe",
"mission_critical": "false",
},
@ -159,10 +159,10 @@ func TestKVClientGet(t *testing.T) {
},
want: want{
out: &KVSecret{
Data: map[string]interface{}{
Data: map[string]string{
"foo": "bar",
},
CustomMeta: map[string]interface{}{
CustomMeta: map[string]string{
"owner": "jdoe",
"mission_critical": "false",
},
@ -236,7 +236,7 @@ func TestKVClientApply(t *testing.T) {
version: &kvv1,
path: secretName,
in: &KVSecret{
Data: map[string]interface{}{
Data: map[string]string{
"key1": "val1updated",
"key3": "val3",
},
@ -253,7 +253,7 @@ func TestKVClientApply(t *testing.T) {
ReadFn: func(path string) (*api.Secret, error) {
return &api.Secret{
Data: map[string]interface{}{
"data": map[string]interface{}{
"data": map[string]string{
"key1": "val1",
"key2": "val2",
},
@ -274,11 +274,11 @@ func TestKVClientApply(t *testing.T) {
version: &kvv2,
path: secretName,
in: &KVSecret{
Data: map[string]interface{}{
Data: map[string]string{
"key1": "val1updated",
"key3": "val3",
},
CustomMeta: map[string]interface{}{
CustomMeta: map[string]string{
"foo": "bar",
"baz": "qux",
},
@ -295,7 +295,7 @@ func TestKVClientApply(t *testing.T) {
ReadFn: func(path string) (*api.Secret, error) {
return &api.Secret{
Data: map[string]interface{}{
"data": map[string]interface{}{
"data": map[string]string{
"key1": "val1",
"key2": "val2",
},
@ -315,11 +315,11 @@ func TestKVClientApply(t *testing.T) {
version: &kvv2,
path: secretName,
in: &KVSecret{
Data: map[string]interface{}{
Data: map[string]string{
"key1": "val1",
"key2": "val2",
},
CustomMeta: map[string]interface{}{
CustomMeta: map[string]string{
"foo": "baz",
},
},
@ -348,10 +348,10 @@ func TestKVClientApply(t *testing.T) {
version: &kvv1,
path: secretName,
in: &KVSecret{
Data: map[string]interface{}{
Data: map[string]string{
"foo": "bar",
},
CustomMeta: map[string]interface{}{
CustomMeta: map[string]string{
"owner": "jdoe",
"mission_critical": "false",
},
@ -393,11 +393,11 @@ func TestKVClientApply(t *testing.T) {
version: &kvv2,
path: secretName,
in: &KVSecret{
CustomMeta: map[string]interface{}{
CustomMeta: map[string]string{
"owner": "jdoe",
"mission_critical": "false",
},
Data: map[string]interface{}{
Data: map[string]string{
"foo": "bar",
},
},
@ -431,7 +431,7 @@ func TestKVClientApply(t *testing.T) {
version: &kvv1,
path: secretName,
in: &KVSecret{
Data: map[string]interface{}{
Data: map[string]string{
"key1": "val1",
"key2": "val2",
},
@ -455,7 +455,7 @@ func TestKVClientApply(t *testing.T) {
t.Errorf("r: -want, +got:\n%s", diff)
}
if diff := cmp.Diff(map[string]interface{}{
"data": map[string]interface{}{
"data": map[string]string{
"key1": "val1",
"key2": "val2",
},
@ -471,7 +471,7 @@ func TestKVClientApply(t *testing.T) {
version: &kvv2,
path: secretName,
in: &KVSecret{
Data: map[string]interface{}{
Data: map[string]string{
"key1": "val1",
"key2": "val2",
},
@ -510,7 +510,7 @@ func TestKVClientApply(t *testing.T) {
version: &kvv1,
path: secretName,
in: &KVSecret{
Data: map[string]interface{}{
Data: map[string]string{
"key1": "val1updated",
"key3": "val3",
},
@ -546,7 +546,7 @@ func TestKVClientApply(t *testing.T) {
t.Errorf("r: -want, +got:\n%s", diff)
}
if diff := cmp.Diff(map[string]interface{}{
"data": map[string]interface{}{
"data": map[string]string{
"key1": "val1updated",
"key2": "val2",
"key3": "val3",
@ -563,11 +563,11 @@ func TestKVClientApply(t *testing.T) {
version: &kvv2,
path: secretName,
in: &KVSecret{
Data: map[string]interface{}{
Data: map[string]string{
"key1": "val1updated",
"key3": "val3",
},
CustomMeta: map[string]interface{}{
CustomMeta: map[string]string{
"foo": "bar",
"baz": "qux",
},
@ -607,11 +607,11 @@ func TestKVClientApply(t *testing.T) {
version: &kvv1,
path: secretName,
in: &KVSecret{
Data: map[string]interface{}{
Data: map[string]string{
"key1": "val1",
"key2": "val2",
},
CustomMeta: map[string]interface{}{
CustomMeta: map[string]string{
"foo": "bar",
"baz": "qux",
},
@ -652,11 +652,11 @@ func TestKVClientApply(t *testing.T) {
version: &kvv1,
path: secretName,
in: &KVSecret{
Data: map[string]interface{}{
Data: map[string]string{
"key1": "val1",
"key2": "val2",
},
CustomMeta: map[string]interface{}{
CustomMeta: map[string]string{
"old": "meta",
"foo": "bar",
},
@ -688,7 +688,7 @@ func TestKVClientApply(t *testing.T) {
t.Errorf("r: -want, +got:\n%s", diff)
}
if diff := cmp.Diff(map[string]interface{}{
"custom_metadata": map[string]interface{}{
"custom_metadata": map[string]string{
"foo": "bar",
"baz": "qux",
},
@ -701,11 +701,11 @@ func TestKVClientApply(t *testing.T) {
version: &kvv2,
path: secretName,
in: &KVSecret{
Data: map[string]interface{}{
Data: map[string]string{
"key1": "val1",
"key2": "val2",
},
CustomMeta: map[string]interface{}{
CustomMeta: map[string]string{
"foo": "bar",
"baz": "qux",
},
@ -740,7 +740,7 @@ func TestKVClientApply(t *testing.T) {
t.Errorf("r: -want, +got:\n%s", diff)
}
if diff := cmp.Diff(map[string]interface{}{
"custom_metadata": map[string]interface{}{
"custom_metadata": map[string]string{
"foo": "bar",
"baz": "qux",
},
@ -753,11 +753,11 @@ func TestKVClientApply(t *testing.T) {
version: &kvv2,
path: secretName,
in: &KVSecret{
Data: map[string]interface{}{
Data: map[string]string{
"key1": "val1",
"key2": "val2",
},
CustomMeta: map[string]interface{}{
CustomMeta: map[string]string{
"foo": "bar",
"baz": "qux",
},

View File

@ -114,20 +114,11 @@ func (ss *SecretStore) ReadKeyValues(_ context.Context, n store.ScopedName, s *s
return errors.Wrap(err, errGet)
}
kv := make(store.KeyValues, len(kvs.Data))
for k, v := range kvs.Data {
kv[k] = []byte(v.(string))
}
s.ScopedName = n
s.Data = kv
s.Data = keyValuesFromData(kvs.Data)
if len(kvs.CustomMeta) > 0 {
s.Metadata = &v1.ConnectionSecretMetadata{
Labels: make(map[string]string, len(kvs.CustomMeta)),
}
}
for k, v := range kvs.CustomMeta {
if val, ok := v.(string); ok {
s.Metadata.Labels[k] = val
Labels: kvs.CustomMeta,
}
}
return nil
@ -135,26 +126,12 @@ func (ss *SecretStore) ReadKeyValues(_ context.Context, n store.ScopedName, s *s
// WriteKeyValues writes key value pairs to a given Vault Secret.
func (ss *SecretStore) WriteKeyValues(_ context.Context, s *store.Secret, wo ...store.WriteOption) (changed bool, err error) {
data := make(map[string]interface{}, len(s.Data))
for k, v := range s.Data {
data[k] = string(v)
}
kvSecret := &kvclient.KVSecret{}
kvSecret.Data = data
if s.Metadata != nil && len(s.Metadata.Labels) > 0 {
kvSecret.CustomMeta = make(map[string]interface{}, len(s.Metadata.Labels))
for k, v := range s.Metadata.Labels {
kvSecret.CustomMeta[k] = v
}
}
ao := applyOptions(wo...)
ao = append(ao, kvclient.AllowUpdateIf(func(current, desired *kvclient.KVSecret) bool {
return !cmp.Equal(current, desired, cmpopts.EquateEmpty(), cmpopts.IgnoreUnexported(kvclient.KVSecret{}))
}))
err = ss.client.Apply(ss.path(s.ScopedName), kvSecret, ao...)
err = ss.client.Apply(ss.path(s.ScopedName), kvclient.NewKVSecret(dataFromKeyValues(s.Data), s.GetLabels()), ao...)
if resource.IsNotAllowed(err) {
// The update was not allowed because it was a no-op.
return false, nil
@ -213,20 +190,20 @@ func applyOptions(wo ...store.WriteOption) []kvclient.ApplyOption {
ao[i] = func(current, desired *kvclient.KVSecret) error {
cs := &store.Secret{
Metadata: &v1.ConnectionSecretMetadata{
Labels: labelsFromCustomMetadata(current.CustomMeta),
Labels: current.CustomMeta,
},
Data: keyValuesFromData(current.Data),
}
ds := &store.Secret{
Metadata: &v1.ConnectionSecretMetadata{
Labels: labelsFromCustomMetadata(desired.CustomMeta),
Labels: desired.CustomMeta,
},
Data: keyValuesFromData(desired.Data),
}
if err := o(context.Background(), cs, ds); err != nil {
return err
}
desired.CustomMeta = customMetaFromLabels(ds.Metadata.Labels)
desired.CustomMeta = ds.GetLabels()
desired.Data = dataFromKeyValues(ds.Data)
return nil
}
@ -234,48 +211,22 @@ func applyOptions(wo ...store.WriteOption) []kvclient.ApplyOption {
return ao
}
func labelsFromCustomMetadata(meta map[string]interface{}) map[string]string {
if len(meta) == 0 {
return nil
}
l := make(map[string]string, len(meta))
for k := range meta {
if val, ok := meta[k].(string); ok {
l[k] = val
}
}
return l
}
func keyValuesFromData(data map[string]interface{}) store.KeyValues {
func keyValuesFromData(data map[string]string) store.KeyValues {
if len(data) == 0 {
return nil
}
kv := make(store.KeyValues, len(data))
for k := range data {
if val, ok := data[k].(string); ok {
kv[k] = []byte(val)
}
for k, v := range data {
kv[k] = []byte(v)
}
return kv
}
func customMetaFromLabels(labels map[string]string) map[string]interface{} {
if len(labels) == 0 {
return nil
}
meta := make(map[string]interface{}, len(labels))
for k, v := range labels {
meta[k] = v
}
return meta
}
func dataFromKeyValues(kv store.KeyValues) map[string]interface{} {
func dataFromKeyValues(kv store.KeyValues) map[string]string {
if len(kv) == 0 {
return nil
}
data := make(map[string]interface{}, len(kv))
data := make(map[string]string, len(kv))
for k, v := range kv {
// NOTE(turkenh): vault stores values as strings. So we convert []byte
// to string before writing to Vault.

View File

@ -86,7 +86,7 @@ func TestSecretStoreReadKeyValues(t *testing.T) {
if diff := cmp.Diff(filepath.Join(parentPathDefault, secretName), path); diff != "" {
t.Errorf("r: -want, +got:\n%s", diff)
}
secret.Data = map[string]interface{}{
secret.Data = map[string]string{
"key1": "val1",
"key2": "val2",
}
@ -119,7 +119,7 @@ func TestSecretStoreReadKeyValues(t *testing.T) {
if diff := cmp.Diff(filepath.Join("another-scope", secretName), path); diff != "" {
t.Errorf("r: -want, +got:\n%s", diff)
}
secret.Data = map[string]interface{}{
secret.Data = map[string]string{
"key1": "val1",
"key2": "val2",
}
@ -154,11 +154,11 @@ func TestSecretStoreReadKeyValues(t *testing.T) {
if diff := cmp.Diff(filepath.Join(parentPathDefault, secretName), path); diff != "" {
t.Errorf("r: -want, +got:\n%s", diff)
}
secret.Data = map[string]interface{}{
secret.Data = map[string]string{
"key1": "val1",
"key2": "val2",
}
secret.CustomMeta = map[string]interface{}{
secret.CustomMeta = map[string]string{
"foo": "bar",
}
return nil
@ -289,11 +289,11 @@ func TestSecretStoreWriteKeyValues(t *testing.T) {
ApplyFn: func(path string, secret *kvclient.KVSecret, ao ...kvclient.ApplyOption) error {
for _, o := range ao {
if err := o(&kvclient.KVSecret{
Data: map[string]interface{}{
Data: map[string]string{
"key1": "val1",
"key2": "val2",
},
CustomMeta: map[string]interface{}{
CustomMeta: map[string]string{
"foo": "bar",
},
}, secret); err != nil {
@ -336,7 +336,7 @@ func TestSecretStoreWriteKeyValues(t *testing.T) {
ApplyFn: func(path string, secret *kvclient.KVSecret, ao ...kvclient.ApplyOption) error {
for _, o := range ao {
if err := o(&kvclient.KVSecret{
Data: map[string]interface{}{
Data: map[string]string{
"key1": "val1",
"key2": "val2",
},
@ -371,7 +371,7 @@ func TestSecretStoreWriteKeyValues(t *testing.T) {
if diff := cmp.Diff(filepath.Join(parentPathDefault, secretName), path); diff != "" {
t.Errorf("r: -want, +got:\n%s", diff)
}
if diff := cmp.Diff(map[string]interface{}{
if diff := cmp.Diff(map[string]string{
"key1": "val1",
"key2": "val2",
}, secret.Data); diff != "" {
@ -403,13 +403,13 @@ func TestSecretStoreWriteKeyValues(t *testing.T) {
if diff := cmp.Diff(filepath.Join(parentPathDefault, secretName), path); diff != "" {
t.Errorf("r: -want, +got:\n%s", diff)
}
if diff := cmp.Diff(map[string]interface{}{
if diff := cmp.Diff(map[string]string{
"key1": "val1",
"key2": "val2",
}, secret.Data); diff != "" {
t.Errorf("r: -want, +got:\n%s", diff)
}
if diff := cmp.Diff(map[string]interface{}{
if diff := cmp.Diff(map[string]string{
"foo": "bar",
}, secret.CustomMeta); diff != "" {
t.Errorf("r: -want, +got:\n%s", diff)
@ -512,7 +512,7 @@ func TestSecretStoreDeleteKeyValues(t *testing.T) {
args: args{
client: &fake.KVClient{
GetFn: func(path string, secret *kvclient.KVSecret) error {
secret.Data = map[string]interface{}{
secret.Data = map[string]string{
"key1": "val1",
"key2": "val2",
"key3": "val3",
@ -538,7 +538,7 @@ func TestSecretStoreDeleteKeyValues(t *testing.T) {
args: args{
client: &fake.KVClient{
GetFn: func(path string, secret *kvclient.KVSecret) error {
secret.Data = map[string]interface{}{
secret.Data = map[string]string{
"key1": "val1",
"key2": "val2",
"key3": "val3",
@ -571,7 +571,7 @@ func TestSecretStoreDeleteKeyValues(t *testing.T) {
args: args{
client: &fake.KVClient{
GetFn: func(path string, secret *kvclient.KVSecret) error {
secret.Data = map[string]interface{}{
secret.Data = map[string]string{
"key1": "val1",
"key2": "val2",
"key3": "val3",
@ -579,7 +579,7 @@ func TestSecretStoreDeleteKeyValues(t *testing.T) {
return nil
},
ApplyFn: func(path string, secret *kvclient.KVSecret, ao ...kvclient.ApplyOption) error {
if diff := cmp.Diff(map[string]interface{}{
if diff := cmp.Diff(map[string]string{
"key3": "val3",
}, secret.Data); diff != "" {
t.Errorf("r: -want, +got:\n%s", diff)
@ -609,7 +609,7 @@ func TestSecretStoreDeleteKeyValues(t *testing.T) {
args: args{
client: &fake.KVClient{
GetFn: func(path string, secret *kvclient.KVSecret) error {
secret.Data = map[string]interface{}{
secret.Data = map[string]string{
"key1": "val1",
"key2": "val2",
"key3": "val3",
@ -640,7 +640,7 @@ func TestSecretStoreDeleteKeyValues(t *testing.T) {
args: args{
client: &fake.KVClient{
GetFn: func(path string, secret *kvclient.KVSecret) error {
secret.Data = map[string]interface{}{
secret.Data = map[string]string{
"key1": "val1",
}
return nil
@ -669,7 +669,7 @@ func TestSecretStoreDeleteKeyValues(t *testing.T) {
args: args{
client: &fake.KVClient{
GetFn: func(path string, secret *kvclient.KVSecret) error {
secret.Data = map[string]interface{}{
secret.Data = map[string]string{
"key1": "val1",
"key2": "val2",
"key3": "val3",