Define scheme for connection secret metadata
Signed-off-by: Hasan Turken <turkenh@gmail.com>
This commit is contained in:
parent
15cf494997
commit
06c155d60b
|
@ -16,19 +16,17 @@ limitations under the License.
|
|||
|
||||
package v1
|
||||
|
||||
import "k8s.io/apimachinery/pkg/runtime"
|
||||
import (
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
)
|
||||
|
||||
// PublishConnectionDetailsTo represents configuration of a connection secret.
|
||||
type PublishConnectionDetailsTo struct {
|
||||
// Name is the name of the connection secret
|
||||
// Name is the name of the connection secret.
|
||||
Name string `json:"name"`
|
||||
|
||||
// Metadata is secret store specific key/value pairs to be used as metadata
|
||||
// Please note, expected keys will differ for each store type. For example,
|
||||
// it could be "labels" and "annotations" in case of "Kubernetes", but it
|
||||
// would be "tags" for "AWS Secret Manager".
|
||||
// +kubebuilder:pruning:PreserveUnknownFields
|
||||
Metadata runtime.RawExtension `json:"metadata,omitempty"`
|
||||
// Metadata is the metadata for connection secret.
|
||||
Metadata ConnectionSecretMetadata `json:"metadata,omitempty"`
|
||||
|
||||
// SecretStoreConfigRef specifies which secret store config should be used
|
||||
// for this ConnectionSecret.
|
||||
|
@ -37,6 +35,21 @@ type PublishConnectionDetailsTo struct {
|
|||
SecretStoreConfigRef *Reference `json:"configRef,omitempty"`
|
||||
}
|
||||
|
||||
// ConnectionSecretMetadata represents metadata of a connection secret.
|
||||
type ConnectionSecretMetadata struct {
|
||||
// Labels are the labels/tags to be added to connection secret.
|
||||
// - For Kubernetes secrets, this will be used as "metadata.labels".
|
||||
// - It is up to Secret Store implementation for others store types.
|
||||
Labels map[string]string `json:"labels"`
|
||||
// Annotations are the annotations to be added to connection secret.
|
||||
// - For Kubernetes secrets, this will be used as "metadata.annotations".
|
||||
// - It is up to Secret Store implementation for others store types.
|
||||
Annotations map[string]string `json:"annotations"`
|
||||
// Type is the SecretType for the connection secret.
|
||||
// - Only valid for Kubernetes Secret Stores.
|
||||
Type corev1.SecretType `json:"type"`
|
||||
}
|
||||
|
||||
// SecretStoreType represents a secret store type.
|
||||
type SecretStoreType string
|
||||
|
||||
|
|
|
@ -93,6 +93,35 @@ func (in *ConditionedStatus) DeepCopy() *ConditionedStatus {
|
|||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *ConnectionSecretMetadata) DeepCopyInto(out *ConnectionSecretMetadata) {
|
||||
*out = *in
|
||||
if in.Labels != nil {
|
||||
in, out := &in.Labels, &out.Labels
|
||||
*out = make(map[string]string, len(*in))
|
||||
for key, val := range *in {
|
||||
(*out)[key] = val
|
||||
}
|
||||
}
|
||||
if in.Annotations != nil {
|
||||
in, out := &in.Annotations, &out.Annotations
|
||||
*out = make(map[string]string, len(*in))
|
||||
for key, val := range *in {
|
||||
(*out)[key] = val
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ConnectionSecretMetadata.
|
||||
func (in *ConnectionSecretMetadata) DeepCopy() *ConnectionSecretMetadata {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(ConnectionSecretMetadata)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *EnvSelector) DeepCopyInto(out *EnvSelector) {
|
||||
*out = *in
|
||||
|
|
|
@ -106,7 +106,8 @@ func (m *DetailsManager) PublishConnection(ctx context.Context, mg resource.Mana
|
|||
|
||||
// UnpublishConnection deletes connection details secret from the configured
|
||||
// connection Store.
|
||||
// TODO(turkenh): Refactor this method once existing interface methods refactored.
|
||||
// TODO(turkenh): Refactor this method once the `managed.ConnectionPublisher`
|
||||
// interface methods refactored per new types: SecretOwner and KeyValues
|
||||
func (m *DetailsManager) UnpublishConnection(ctx context.Context, mg resource.Managed, c managed.ConnectionDetails) error {
|
||||
return m.unpublishConnection(ctx, mg.(SecretOwner), store.KeyValues(c))
|
||||
}
|
||||
|
@ -135,7 +136,7 @@ func (m *DetailsManager) publishConnection(ctx context.Context, so SecretOwner,
|
|||
return errors.Wrap(ss.WriteKeyValues(ctx, store.Secret{
|
||||
Name: p.Name,
|
||||
Scope: so.GetNamespace(),
|
||||
Metadata: p.Metadata.Raw,
|
||||
Metadata: p.Metadata,
|
||||
}, kv), errWriteStore)
|
||||
}
|
||||
|
||||
|
@ -154,6 +155,6 @@ func (m *DetailsManager) unpublishConnection(ctx context.Context, so SecretOwner
|
|||
return errors.Wrap(ss.DeleteKeyValues(ctx, store.Secret{
|
||||
Name: p.Name,
|
||||
Scope: so.GetNamespace(),
|
||||
Metadata: p.Metadata.Raw,
|
||||
Metadata: p.Metadata,
|
||||
}, kv), errDeleteFromStore)
|
||||
}
|
||||
|
|
|
@ -18,7 +18,6 @@ package kubernetes
|
|||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
kerrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
|
@ -35,23 +34,16 @@ import (
|
|||
|
||||
// Error strings.
|
||||
const (
|
||||
errGetSecret = "cannot get secret"
|
||||
errDeleteSecret = "cannot delete secret"
|
||||
errUpdateSecret = "cannot update secret"
|
||||
errApplySecret = "cannot apply secret"
|
||||
errParseMetadata = "cannot parse metadata"
|
||||
errGetSecret = "cannot get secret"
|
||||
errDeleteSecret = "cannot delete secret"
|
||||
errUpdateSecret = "cannot update secret"
|
||||
errApplySecret = "cannot apply secret"
|
||||
|
||||
errExtractKubernetesAuthCreds = "cannot extract kubernetes auth credentials"
|
||||
errBuildRestConfig = "cannot build rest config kubeconfig"
|
||||
errBuildClient = "cannot build Kubernetes client"
|
||||
)
|
||||
|
||||
type secretMetadata struct {
|
||||
Labels map[string]string `json:"labels"`
|
||||
Annotations map[string]string `json:"annotations"`
|
||||
Type corev1.SecretType `json:"type"`
|
||||
}
|
||||
|
||||
// SecretStore is a Kubernetes Secret Store.
|
||||
type SecretStore struct {
|
||||
client resource.ClientApplicator
|
||||
|
@ -101,24 +93,17 @@ func (ss *SecretStore) ReadKeyValues(ctx context.Context, i store.Secret) (store
|
|||
|
||||
// WriteKeyValues writes key value pairs to a given Kubernetes Secret.
|
||||
func (ss *SecretStore) WriteKeyValues(ctx context.Context, i store.Secret, kv store.KeyValues) error {
|
||||
meta := secretMetadata{}
|
||||
if len(i.Metadata) > 0 {
|
||||
if err := json.Unmarshal(i.Metadata, &meta); err != nil {
|
||||
return errors.Wrap(err, errParseMetadata)
|
||||
}
|
||||
}
|
||||
|
||||
t := resource.SecretTypeConnection
|
||||
if meta.Type != "" {
|
||||
t = meta.Type
|
||||
if i.Metadata.Type != "" {
|
||||
t = i.Metadata.Type
|
||||
}
|
||||
|
||||
s := &corev1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: i.Name,
|
||||
Namespace: ss.namespaceForSecret(i),
|
||||
Labels: meta.Labels,
|
||||
Annotations: meta.Annotations,
|
||||
Labels: i.Metadata.Labels,
|
||||
Annotations: i.Metadata.Annotations,
|
||||
},
|
||||
Type: t,
|
||||
Data: kv,
|
||||
|
|
|
@ -151,17 +151,6 @@ func TestSecretStoreWriteKeyValues(t *testing.T) {
|
|||
args
|
||||
want
|
||||
}{
|
||||
"CannotParseMetadata": {
|
||||
reason: "Should return a proper error when metadata cannot be parsed.",
|
||||
args: args{
|
||||
secret: store.Secret{
|
||||
Metadata: []byte("malformed-json"),
|
||||
},
|
||||
},
|
||||
want: want{
|
||||
err: errors.Wrap(errors.New("invalid character 'm' looking for beginning of value"), errParseMetadata),
|
||||
},
|
||||
},
|
||||
"ApplyFailed": {
|
||||
reason: "Should return a proper error when cannot apply.",
|
||||
args: args{
|
||||
|
@ -288,9 +277,18 @@ func TestSecretStoreWriteKeyValues(t *testing.T) {
|
|||
}),
|
||||
},
|
||||
secret: store.Secret{
|
||||
Name: fakeSecretName,
|
||||
Scope: fakeSecretNamespace,
|
||||
Metadata: []byte(`{ "labels":{ "environment": "unit-test","reason": "testing"},"annotations":{"some-annotation-key": "some-annotation-value"},"type": "Opaque"}`),
|
||||
Name: fakeSecretName,
|
||||
Scope: fakeSecretNamespace,
|
||||
Metadata: v1.ConnectionSecretMetadata{
|
||||
Labels: map[string]string{
|
||||
"environment": "unit-test",
|
||||
"reason": "testing",
|
||||
},
|
||||
Annotations: map[string]string{
|
||||
"some-annotation-key": "some-annotation-value",
|
||||
},
|
||||
Type: "Opaque",
|
||||
},
|
||||
},
|
||||
kv: store.KeyValues(fakeKV),
|
||||
},
|
||||
|
|
|
@ -16,6 +16,10 @@
|
|||
|
||||
package store
|
||||
|
||||
import (
|
||||
v1 "github.com/crossplane/crossplane-runtime/apis/common/v1"
|
||||
)
|
||||
|
||||
// KeyValues is a map with sensitive values.
|
||||
type KeyValues map[string][]byte
|
||||
|
||||
|
@ -23,5 +27,5 @@ type KeyValues map[string][]byte
|
|||
type Secret struct {
|
||||
Name string
|
||||
Scope string
|
||||
Metadata []byte
|
||||
Metadata v1.ConnectionSecretMetadata
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue