secret reconciler: allow for propagation to multiple secrets (#92)
Signed-off-by: hasheddan <georgedanielmangum@gmail.com>
This commit is contained in:
parent
efd6c68c68
commit
d5c9dedd2a
|
@ -18,6 +18,7 @@ package resource
|
|||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
|
@ -134,9 +135,7 @@ func (a *APIManagedConnectionPropagator) PropagateConnection(ctx context.Context
|
|||
}
|
||||
|
||||
meta.AddAnnotations(mgcs, map[string]string{
|
||||
AnnotationKeyPropagateToNamespace: cmcs.GetNamespace(),
|
||||
AnnotationKeyPropagateToName: cmcs.GetName(),
|
||||
AnnotationKeyPropagateToUID: string(cmcs.GetUID()),
|
||||
strings.Join([]string{AnnotationKeyPropagateToPrefix, string(cmcs.GetUID())}, SlashDelimeter): strings.Join([]string{cmcs.GetNamespace(), cmcs.GetName()}, SlashDelimeter),
|
||||
})
|
||||
|
||||
return errors.Wrap(a.client.Update(ctx, mgcs), errUpdateSecret)
|
||||
|
|
|
@ -18,6 +18,7 @@ package resource
|
|||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/google/go-cmp/cmp"
|
||||
|
@ -404,9 +405,84 @@ func TestPropagateConnection(t *testing.T) {
|
|||
case mgcsname:
|
||||
want.SetName(mgcsname)
|
||||
want.SetAnnotations(map[string]string{
|
||||
AnnotationKeyPropagateToNamespace: namespace,
|
||||
AnnotationKeyPropagateToName: cmcsname,
|
||||
AnnotationKeyPropagateToUID: string(uid),
|
||||
strings.Join([]string{AnnotationKeyPropagateToPrefix, string(uid)}, SlashDelimeter): strings.Join([]string{namespace, cmcsname}, SlashDelimeter),
|
||||
})
|
||||
if diff := cmp.Diff(want, got); diff != "" {
|
||||
t.Errorf("-want, +got:\n%s", diff)
|
||||
}
|
||||
default:
|
||||
return errors.New("unexpected secret name")
|
||||
}
|
||||
return nil
|
||||
}),
|
||||
},
|
||||
typer: fake.SchemeWith(&fake.Claim{}, &fake.Managed{}),
|
||||
},
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
cm: &fake.Claim{
|
||||
ObjectMeta: metav1.ObjectMeta{Namespace: namespace, Name: cmname, UID: uid},
|
||||
LocalConnectionSecretWriterTo: fake.LocalConnectionSecretWriterTo{
|
||||
Ref: &v1alpha1.LocalSecretReference{Name: cmcsname},
|
||||
},
|
||||
},
|
||||
mg: &fake.Managed{
|
||||
ObjectMeta: metav1.ObjectMeta{Name: mgname, UID: uid},
|
||||
ConnectionSecretWriterTo: fake.ConnectionSecretWriterTo{
|
||||
Ref: &v1alpha1.SecretReference{Namespace: mgcsnamespace, Name: mgcsname},
|
||||
},
|
||||
},
|
||||
},
|
||||
want: nil,
|
||||
},
|
||||
"SuccessfulWithExisting": {
|
||||
fields: fields{
|
||||
client: &test.MockClient{
|
||||
MockGet: func(_ context.Context, n types.NamespacedName, o runtime.Object) error {
|
||||
s := corev1.Secret{}
|
||||
s.SetNamespace(namespace)
|
||||
s.SetUID(uid)
|
||||
s.SetOwnerReferences([]metav1.OwnerReference{{UID: uid, Controller: &controller}})
|
||||
|
||||
switch n.Name {
|
||||
case mgcsname:
|
||||
s.SetName(mgcsname)
|
||||
meta.AddAnnotations(&s, map[string]string{
|
||||
strings.Join([]string{AnnotationKeyPropagateToPrefix, "existing-uid"}, SlashDelimeter): "existing-namespace/existing-name",
|
||||
})
|
||||
s.Data = mgcsdata
|
||||
*o.(*corev1.Secret) = s
|
||||
case cmcsname:
|
||||
s.SetName(cmcsname)
|
||||
*o.(*corev1.Secret) = s
|
||||
default:
|
||||
return errors.New("unexpected secret name")
|
||||
}
|
||||
return nil
|
||||
},
|
||||
MockUpdate: test.NewMockUpdateFn(nil, func(got runtime.Object) error {
|
||||
want := &corev1.Secret{}
|
||||
want.SetNamespace(namespace)
|
||||
want.SetUID(uid)
|
||||
want.SetOwnerReferences([]metav1.OwnerReference{{UID: uid, Controller: &controller}})
|
||||
want.Data = mgcsdata
|
||||
|
||||
switch got.(metav1.Object).GetName() {
|
||||
case cmcsname:
|
||||
want.SetName(cmcsname)
|
||||
want.SetAnnotations(map[string]string{
|
||||
AnnotationKeyPropagateFromNamespace: namespace,
|
||||
AnnotationKeyPropagateFromName: mgcsname,
|
||||
AnnotationKeyPropagateFromUID: string(uid),
|
||||
})
|
||||
if diff := cmp.Diff(want, got); diff != "" {
|
||||
t.Errorf("-want, +got:\n%s", diff)
|
||||
}
|
||||
case mgcsname:
|
||||
want.SetName(mgcsname)
|
||||
want.SetAnnotations(map[string]string{
|
||||
strings.Join([]string{AnnotationKeyPropagateToPrefix, "existing-uid"}, SlashDelimeter): "existing-namespace/existing-name",
|
||||
strings.Join([]string{AnnotationKeyPropagateToPrefix, string(uid)}, SlashDelimeter): strings.Join([]string{namespace, cmcsname}, SlashDelimeter),
|
||||
})
|
||||
if diff := cmp.Diff(want, got); diff != "" {
|
||||
t.Errorf("-want, +got:\n%s", diff)
|
||||
|
@ -490,7 +566,7 @@ func TestBind(t *testing.T) {
|
|||
err: errors.Wrap(errBoom, errUpdateManaged),
|
||||
cm: &fake.Claim{BindingStatus: v1alpha1.BindingStatus{Phase: v1alpha1.BindingPhaseBound}},
|
||||
mg: &fake.Managed{
|
||||
ClaimReferencer: fake.ClaimReferencer{meta.ReferenceTo(&fake.Claim{}, fake.GVK(&fake.Claim{}))},
|
||||
ClaimReferencer: fake.ClaimReferencer{Ref: meta.ReferenceTo(&fake.Claim{}, fake.GVK(&fake.Claim{}))},
|
||||
BindingStatus: v1alpha1.BindingStatus{Phase: v1alpha1.BindingPhaseBound},
|
||||
},
|
||||
},
|
||||
|
@ -522,7 +598,7 @@ func TestBind(t *testing.T) {
|
|||
},
|
||||
mg: &fake.Managed{
|
||||
ObjectMeta: metav1.ObjectMeta{Annotations: map[string]string{meta.ExternalNameAnnotationKey: externalName}},
|
||||
ClaimReferencer: fake.ClaimReferencer{meta.ReferenceTo(&fake.Claim{}, fake.GVK(&fake.Claim{}))},
|
||||
ClaimReferencer: fake.ClaimReferencer{Ref: meta.ReferenceTo(&fake.Claim{}, fake.GVK(&fake.Claim{}))},
|
||||
BindingStatus: v1alpha1.BindingStatus{Phase: v1alpha1.BindingPhaseBound},
|
||||
},
|
||||
},
|
||||
|
@ -539,7 +615,7 @@ func TestBind(t *testing.T) {
|
|||
err: nil,
|
||||
cm: &fake.Claim{BindingStatus: v1alpha1.BindingStatus{Phase: v1alpha1.BindingPhaseBound}},
|
||||
mg: &fake.Managed{
|
||||
ClaimReferencer: fake.ClaimReferencer{meta.ReferenceTo(&fake.Claim{}, fake.GVK(&fake.Claim{}))},
|
||||
ClaimReferencer: fake.ClaimReferencer{Ref: meta.ReferenceTo(&fake.Claim{}, fake.GVK(&fake.Claim{}))},
|
||||
BindingStatus: v1alpha1.BindingStatus{Phase: v1alpha1.BindingPhaseBound},
|
||||
},
|
||||
},
|
||||
|
@ -561,7 +637,7 @@ func TestBind(t *testing.T) {
|
|||
BindingStatus: v1alpha1.BindingStatus{Phase: v1alpha1.BindingPhaseBound}},
|
||||
mg: &fake.Managed{
|
||||
ObjectMeta: metav1.ObjectMeta{Annotations: map[string]string{meta.ExternalNameAnnotationKey: externalName}},
|
||||
ClaimReferencer: fake.ClaimReferencer{meta.ReferenceTo(&fake.Claim{}, fake.GVK(&fake.Claim{}))},
|
||||
ClaimReferencer: fake.ClaimReferencer{Ref: meta.ReferenceTo(&fake.Claim{}, fake.GVK(&fake.Claim{}))},
|
||||
BindingStatus: v1alpha1.BindingStatus{Phase: v1alpha1.BindingPhaseBound},
|
||||
},
|
||||
},
|
||||
|
@ -626,7 +702,7 @@ func TestStatusBind(t *testing.T) {
|
|||
err: errors.Wrap(errBoom, errUpdateManaged),
|
||||
cm: &fake.Claim{BindingStatus: v1alpha1.BindingStatus{Phase: v1alpha1.BindingPhaseBound}},
|
||||
mg: &fake.Managed{
|
||||
ClaimReferencer: fake.ClaimReferencer{meta.ReferenceTo(&fake.Claim{}, fake.GVK(&fake.Claim{}))},
|
||||
ClaimReferencer: fake.ClaimReferencer{Ref: meta.ReferenceTo(&fake.Claim{}, fake.GVK(&fake.Claim{}))},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -645,7 +721,7 @@ func TestStatusBind(t *testing.T) {
|
|||
err: errors.Wrap(errBoom, errUpdateManagedStatus),
|
||||
cm: &fake.Claim{BindingStatus: v1alpha1.BindingStatus{Phase: v1alpha1.BindingPhaseBound}},
|
||||
mg: &fake.Managed{
|
||||
ClaimReferencer: fake.ClaimReferencer{meta.ReferenceTo(&fake.Claim{}, fake.GVK(&fake.Claim{}))},
|
||||
ClaimReferencer: fake.ClaimReferencer{Ref: meta.ReferenceTo(&fake.Claim{}, fake.GVK(&fake.Claim{}))},
|
||||
BindingStatus: v1alpha1.BindingStatus{Phase: v1alpha1.BindingPhaseBound},
|
||||
},
|
||||
},
|
||||
|
@ -680,7 +756,7 @@ func TestStatusBind(t *testing.T) {
|
|||
},
|
||||
mg: &fake.Managed{
|
||||
ObjectMeta: metav1.ObjectMeta{Annotations: map[string]string{meta.ExternalNameAnnotationKey: externalName}},
|
||||
ClaimReferencer: fake.ClaimReferencer{meta.ReferenceTo(&fake.Claim{}, fake.GVK(&fake.Claim{}))},
|
||||
ClaimReferencer: fake.ClaimReferencer{Ref: meta.ReferenceTo(&fake.Claim{}, fake.GVK(&fake.Claim{}))},
|
||||
BindingStatus: v1alpha1.BindingStatus{Phase: v1alpha1.BindingPhaseBound},
|
||||
},
|
||||
},
|
||||
|
@ -700,7 +776,7 @@ func TestStatusBind(t *testing.T) {
|
|||
err: nil,
|
||||
cm: &fake.Claim{BindingStatus: v1alpha1.BindingStatus{Phase: v1alpha1.BindingPhaseBound}},
|
||||
mg: &fake.Managed{
|
||||
ClaimReferencer: fake.ClaimReferencer{meta.ReferenceTo(&fake.Claim{}, fake.GVK(&fake.Claim{}))},
|
||||
ClaimReferencer: fake.ClaimReferencer{Ref: meta.ReferenceTo(&fake.Claim{}, fake.GVK(&fake.Claim{}))},
|
||||
BindingStatus: v1alpha1.BindingStatus{Phase: v1alpha1.BindingPhaseBound},
|
||||
},
|
||||
},
|
||||
|
@ -726,7 +802,7 @@ func TestStatusBind(t *testing.T) {
|
|||
},
|
||||
mg: &fake.Managed{
|
||||
ObjectMeta: metav1.ObjectMeta{Annotations: map[string]string{meta.ExternalNameAnnotationKey: externalName}},
|
||||
ClaimReferencer: fake.ClaimReferencer{meta.ReferenceTo(&fake.Claim{}, fake.GVK(&fake.Claim{}))},
|
||||
ClaimReferencer: fake.ClaimReferencer{Ref: meta.ReferenceTo(&fake.Claim{}, fake.GVK(&fake.Claim{}))},
|
||||
BindingStatus: v1alpha1.BindingStatus{Phase: v1alpha1.BindingPhaseBound},
|
||||
},
|
||||
},
|
||||
|
|
|
@ -17,6 +17,8 @@ limitations under the License.
|
|||
package resource
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"k8s.io/client-go/util/workqueue"
|
||||
|
@ -65,52 +67,62 @@ func addClaim(obj runtime.Object, queue adder) {
|
|||
}
|
||||
}
|
||||
|
||||
// EnqueueRequestForPropagator enqueues a reconcile.Request for the
|
||||
// EnqueueRequestForPropagated enqueues a reconcile.Request for the
|
||||
// NamespacedName of a propagated object, i.e. an object with propagation
|
||||
// metadata annotations.
|
||||
type EnqueueRequestForPropagator struct{}
|
||||
type EnqueueRequestForPropagated struct{}
|
||||
|
||||
// Create adds a NamespacedName for the supplied CreateEvent if its Object is
|
||||
// propagated.
|
||||
func (e *EnqueueRequestForPropagator) Create(evt event.CreateEvent, q workqueue.RateLimitingInterface) {
|
||||
addPropagator(evt.Object, q)
|
||||
func (e *EnqueueRequestForPropagated) Create(evt event.CreateEvent, q workqueue.RateLimitingInterface) {
|
||||
addPropagated(evt.Object, q)
|
||||
}
|
||||
|
||||
// Update adds a NamespacedName for the supplied UpdateEvent if its Objects are
|
||||
// propagated.
|
||||
func (e *EnqueueRequestForPropagator) Update(evt event.UpdateEvent, q workqueue.RateLimitingInterface) {
|
||||
addPropagator(evt.ObjectOld, q)
|
||||
addPropagator(evt.ObjectNew, q)
|
||||
func (e *EnqueueRequestForPropagated) Update(evt event.UpdateEvent, q workqueue.RateLimitingInterface) {
|
||||
addPropagated(evt.ObjectOld, q)
|
||||
addPropagated(evt.ObjectNew, q)
|
||||
}
|
||||
|
||||
// Delete adds a NamespacedName for the supplied DeleteEvent if its Object is
|
||||
// propagated.
|
||||
func (e *EnqueueRequestForPropagator) Delete(evt event.DeleteEvent, q workqueue.RateLimitingInterface) {
|
||||
addPropagator(evt.Object, q)
|
||||
func (e *EnqueueRequestForPropagated) Delete(evt event.DeleteEvent, q workqueue.RateLimitingInterface) {
|
||||
addPropagated(evt.Object, q)
|
||||
}
|
||||
|
||||
// Generic adds a NamespacedName for the supplied GenericEvent if its Object is
|
||||
// propagated.
|
||||
func (e *EnqueueRequestForPropagator) Generic(evt event.GenericEvent, q workqueue.RateLimitingInterface) {
|
||||
addPropagator(evt.Object, q)
|
||||
func (e *EnqueueRequestForPropagated) Generic(evt event.GenericEvent, q workqueue.RateLimitingInterface) {
|
||||
addPropagated(evt.Object, q)
|
||||
}
|
||||
|
||||
func addPropagator(obj runtime.Object, queue adder) {
|
||||
func addPropagated(obj runtime.Object, queue adder) {
|
||||
ao, ok := obj.(annotated)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
a := ao.GetAnnotations()
|
||||
switch {
|
||||
case a[AnnotationKeyPropagateFromNamespace] == "":
|
||||
return
|
||||
case a[AnnotationKeyPropagateFromName] == "":
|
||||
return
|
||||
default:
|
||||
queue.Add(reconcile.Request{NamespacedName: types.NamespacedName{
|
||||
Namespace: a[AnnotationKeyPropagateFromNamespace],
|
||||
Name: a[AnnotationKeyPropagateFromName],
|
||||
}})
|
||||
|
||||
for key, val := range a {
|
||||
if !strings.HasPrefix(key, AnnotationKeyPropagateToPrefix) {
|
||||
continue
|
||||
}
|
||||
t := strings.Split(val, SlashDelimeter)
|
||||
if len(t) != 2 {
|
||||
continue
|
||||
}
|
||||
switch {
|
||||
case t[0] == "":
|
||||
continue
|
||||
case t[1] == "":
|
||||
continue
|
||||
default:
|
||||
queue.Add(reconcile.Request{NamespacedName: types.NamespacedName{
|
||||
Namespace: t[0],
|
||||
Name: t[1],
|
||||
}})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@ limitations under the License.
|
|||
package resource
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/google/go-cmp/cmp"
|
||||
|
@ -74,9 +75,10 @@ func TestAddClaim(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestAddPropagator(t *testing.T) {
|
||||
func TestAddPropagated(t *testing.T) {
|
||||
ns := "coolns"
|
||||
name := "coolname"
|
||||
uid := "a-cool-uid"
|
||||
|
||||
cases := map[string]struct {
|
||||
obj runtime.Object
|
||||
|
@ -85,22 +87,15 @@ func TestAddPropagator(t *testing.T) {
|
|||
"ObjectIsNotAnnotated": {
|
||||
queue: addFn(func(_ interface{}) { t.Errorf("queue.Add() called unexpectedly") }),
|
||||
},
|
||||
"ObjectMissing" + AnnotationKeyPropagateFromNamespace: {
|
||||
"ObjectMissing" + AnnotationKeyPropagateToPrefix: {
|
||||
obj: &fake.Managed{ObjectMeta: metav1.ObjectMeta{Annotations: map[string]string{
|
||||
AnnotationKeyPropagateFromName: name,
|
||||
"some.annotation": "some-value",
|
||||
}}},
|
||||
queue: addFn(func(_ interface{}) { t.Errorf("queue.Add() called unexpectedly") }),
|
||||
},
|
||||
"ObjectMissing" + AnnotationKeyPropagateFromName: {
|
||||
"IsPropagatorObject": {
|
||||
obj: &fake.Managed{ObjectMeta: metav1.ObjectMeta{Annotations: map[string]string{
|
||||
AnnotationKeyPropagateFromNamespace: ns,
|
||||
}}},
|
||||
queue: addFn(func(_ interface{}) { t.Errorf("queue.Add() called unexpectedly") }),
|
||||
},
|
||||
"IsPropagatedObject": {
|
||||
obj: &fake.Managed{ObjectMeta: metav1.ObjectMeta{Annotations: map[string]string{
|
||||
AnnotationKeyPropagateFromNamespace: ns,
|
||||
AnnotationKeyPropagateFromName: name,
|
||||
strings.Join([]string{AnnotationKeyPropagateToPrefix, uid}, SlashDelimeter): strings.Join([]string{ns, name}, SlashDelimeter),
|
||||
}}},
|
||||
queue: addFn(func(got interface{}) {
|
||||
want := reconcile.Request{NamespacedName: types.NamespacedName{Namespace: ns, Name: name}}
|
||||
|
@ -112,6 +107,6 @@ func TestAddPropagator(t *testing.T) {
|
|||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
addPropagator(tc.obj, tc.queue)
|
||||
addPropagated(tc.obj, tc.queue)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,6 +17,8 @@ limitations under the License.
|
|||
package resource
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
|
@ -134,17 +136,13 @@ func IsPropagator() PredicateFn {
|
|||
return false
|
||||
}
|
||||
|
||||
a := ao.GetAnnotations()
|
||||
switch {
|
||||
case a[AnnotationKeyPropagateToNamespace] == "":
|
||||
return false
|
||||
case a[AnnotationKeyPropagateToName] == "":
|
||||
return false
|
||||
case a[AnnotationKeyPropagateToUID] == "":
|
||||
return false
|
||||
default:
|
||||
return true
|
||||
for key := range ao.GetAnnotations() {
|
||||
if strings.HasPrefix(key, AnnotationKeyPropagateToPrefix) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -283,32 +283,22 @@ func TestIsPropagator(t *testing.T) {
|
|||
"NotAnAnnotator": {
|
||||
want: false,
|
||||
},
|
||||
"Missing" + AnnotationKeyPropagateToNamespace: {
|
||||
"NotAPropagator": {
|
||||
obj: &corev1.Secret{ObjectMeta: v1.ObjectMeta{Annotations: map[string]string{
|
||||
AnnotationKeyPropagateToName: name,
|
||||
AnnotationKeyPropagateToUID: string(uid),
|
||||
}}},
|
||||
want: false,
|
||||
},
|
||||
"Missing" + AnnotationKeyPropagateToName: {
|
||||
obj: &corev1.Secret{ObjectMeta: v1.ObjectMeta{Annotations: map[string]string{
|
||||
AnnotationKeyPropagateToNamespace: namespace,
|
||||
AnnotationKeyPropagateToUID: string(uid),
|
||||
}}},
|
||||
want: false,
|
||||
},
|
||||
"Missing" + AnnotationKeyPropagateToUID: {
|
||||
obj: &corev1.Secret{ObjectMeta: v1.ObjectMeta{Annotations: map[string]string{
|
||||
AnnotationKeyPropagateToNamespace: namespace,
|
||||
AnnotationKeyPropagateToName: name,
|
||||
"some.annotation": "someValue",
|
||||
}}},
|
||||
want: false,
|
||||
},
|
||||
"IsPropagator": {
|
||||
obj: &corev1.Secret{ObjectMeta: v1.ObjectMeta{Annotations: map[string]string{
|
||||
AnnotationKeyPropagateToNamespace: namespace,
|
||||
AnnotationKeyPropagateToName: name,
|
||||
AnnotationKeyPropagateToUID: string(uid),
|
||||
AnnotationKeyPropagateToPrefix + "cool-uid": "cool-namespace/cool-name",
|
||||
}}},
|
||||
want: true,
|
||||
},
|
||||
"IsMultiPropagator": {
|
||||
obj: &corev1.Secret{ObjectMeta: v1.ObjectMeta{Annotations: map[string]string{
|
||||
AnnotationKeyPropagateToPrefix + "cool-uid": "cool-namespace/cool-name",
|
||||
AnnotationKeyPropagateToPrefix + "cool-uid-two": "cool-namespace/cool-name-2",
|
||||
}}},
|
||||
want: true,
|
||||
},
|
||||
|
@ -332,24 +322,9 @@ func TestIsPropagated(t *testing.T) {
|
|||
"NotAnAnnotator": {
|
||||
want: false,
|
||||
},
|
||||
"Missing" + AnnotationKeyPropagateFromNamespace: {
|
||||
"NotPropagated": {
|
||||
obj: &corev1.Secret{ObjectMeta: v1.ObjectMeta{Annotations: map[string]string{
|
||||
AnnotationKeyPropagateFromName: name,
|
||||
AnnotationKeyPropagateFromUID: string(uid),
|
||||
}}},
|
||||
want: false,
|
||||
},
|
||||
"Missing" + AnnotationKeyPropagateFromName: {
|
||||
obj: &corev1.Secret{ObjectMeta: v1.ObjectMeta{Annotations: map[string]string{
|
||||
AnnotationKeyPropagateFromNamespace: namespace,
|
||||
AnnotationKeyPropagateFromUID: string(uid),
|
||||
}}},
|
||||
want: false,
|
||||
},
|
||||
"Missing" + AnnotationKeyPropagateFromUID: {
|
||||
obj: &corev1.Secret{ObjectMeta: v1.ObjectMeta{Annotations: map[string]string{
|
||||
AnnotationKeyPropagateFromNamespace: namespace,
|
||||
AnnotationKeyPropagateFromName: name,
|
||||
"some.annotation": "someValue",
|
||||
}}},
|
||||
want: false,
|
||||
},
|
||||
|
|
|
@ -18,6 +18,7 @@ package resource
|
|||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
@ -33,17 +34,12 @@ import (
|
|||
// propagated to the named resource of the same kind, assuming it exists and
|
||||
// consents to propagation.
|
||||
const (
|
||||
AnnotationKeyPropagateToNamespace = "crossplane.io/propagate-to-namespace"
|
||||
AnnotationKeyPropagateToName = "crossplane.io/propagate-to-name"
|
||||
AnnotationKeyPropagateToUID = "crossplane.io/propagate-to-uid"
|
||||
)
|
||||
AnnotationKeyPropagateToPrefix = "to.propagate.crossplane.io"
|
||||
SlashDelimeter = "/"
|
||||
|
||||
// Supported resources with all of these annotations consent to be fully or
|
||||
// partially propagated from the named resource of the same kind.
|
||||
const (
|
||||
AnnotationKeyPropagateFromNamespace = "crossplane.io/propagate-from-namespace"
|
||||
AnnotationKeyPropagateFromName = "crossplane.io/propagate-from-name"
|
||||
AnnotationKeyPropagateFromUID = "crossplane.io/propagate-from-uid"
|
||||
AnnotationKeyPropagateFromNamespace = "from.propagate.crossplane.io/namespace"
|
||||
AnnotationKeyPropagateFromName = "from.propagate.crossplane.io/name"
|
||||
AnnotationKeyPropagateFromUID = "from.propagate.crossplane.io/uid"
|
||||
)
|
||||
|
||||
type annotated interface {
|
||||
|
@ -53,6 +49,8 @@ type annotated interface {
|
|||
const (
|
||||
secretControllerName = "secretpropagator.crossplane.io"
|
||||
secretReconcileTimeout = 1 * time.Minute
|
||||
errUnexpectedFromUID = "unexpected propagate from uid on propagated secret"
|
||||
errUnexpectedToUID = "unexpected propagate to uid on propagator secret"
|
||||
)
|
||||
|
||||
// NewSecretPropagatingReconciler returns a Reconciler that reconciles secrets
|
||||
|
@ -68,9 +66,26 @@ func NewSecretPropagatingReconciler(m manager.Manager) reconcile.Reconciler {
|
|||
ctx, cancel := context.WithTimeout(context.Background(), secretReconcileTimeout)
|
||||
defer cancel()
|
||||
|
||||
// The 'to' secret is also known as the 'propagated' secret. We guard
|
||||
// against abusers of the propagation process by requiring that both
|
||||
// secrets consent to propagation by specifying each other's UID. We
|
||||
// cannot know the UID of a secret that doesn't exist, so the propagated
|
||||
// secret must be created outside of the propagation process.
|
||||
to := &corev1.Secret{}
|
||||
if err := client.Get(ctx, req.NamespacedName, to); err != nil {
|
||||
// There's no propagation to be done if the secret we propagate to
|
||||
// does not exist. We assume we have a watch on that secret and will
|
||||
// be queued if/when it is created. Otherwise we'll be requeued
|
||||
// implicitly because we return an error.
|
||||
return reconcile.Result{}, errors.Wrap(IgnoreNotFound(err), errGetSecret)
|
||||
}
|
||||
// The 'from' secret is also know as the 'propagating' secret.
|
||||
from := &corev1.Secret{}
|
||||
if err := client.Get(ctx, req.NamespacedName, from); err != nil {
|
||||
n := types.NamespacedName{
|
||||
Namespace: to.GetAnnotations()[AnnotationKeyPropagateFromNamespace],
|
||||
Name: to.GetAnnotations()[AnnotationKeyPropagateFromName],
|
||||
}
|
||||
if err := client.Get(ctx, n, from); err != nil {
|
||||
// There's no propagation to be done if the secret we're propagating
|
||||
// from does not exist. We assume we have a watch on that secret and
|
||||
// will be queued if/when it is created. Otherwise we'll be requeued
|
||||
|
@ -78,43 +93,24 @@ func NewSecretPropagatingReconciler(m manager.Manager) reconcile.Reconciler {
|
|||
return reconcile.Result{}, errors.Wrap(IgnoreNotFound(err), errGetSecret)
|
||||
}
|
||||
|
||||
// The 'to' secret is also known as the 'propagated' secret. We guard
|
||||
// against abusers of the propagation process by requiring that both
|
||||
// secrets consent to propagation by specifying each other's UID. We
|
||||
// cannot know the UID of a secret that doesn't exist, so the propagated
|
||||
// secret must be created outside of the propagation process.
|
||||
to := &corev1.Secret{}
|
||||
n := types.NamespacedName{
|
||||
Namespace: from.GetAnnotations()[AnnotationKeyPropagateToNamespace],
|
||||
Name: from.GetAnnotations()[AnnotationKeyPropagateToName],
|
||||
}
|
||||
if err := client.Get(ctx, n, to); err != nil {
|
||||
// There's no propagation to be done if the secret we propagate to
|
||||
// does not exist. We assume we have a watch on that secret and will
|
||||
// be queued if/when it is created. Otherwise we'll be requeued
|
||||
// implicitly because we return an error.
|
||||
return reconcile.Result{}, errors.Wrap(IgnoreNotFound(err), errGetSecret)
|
||||
}
|
||||
|
||||
if from.GetAnnotations()[AnnotationKeyPropagateToUID] != string(to.GetUID()) {
|
||||
// The propagating secret expected a different propagated secret. We
|
||||
// assume we have a watch on both secrets, and will be requeued if
|
||||
// and when this situation is remedied.
|
||||
return reconcile.Result{}, nil
|
||||
}
|
||||
|
||||
if to.GetAnnotations()[AnnotationKeyPropagateFromUID] != string(from.GetUID()) {
|
||||
// The propagated secret expected a different propagating secret. We
|
||||
// assume we have a watch on both secrets, and will be requeued if
|
||||
// and when this situation is remedied.
|
||||
return reconcile.Result{}, nil
|
||||
return reconcile.Result{}, errors.New(errUnexpectedFromUID)
|
||||
}
|
||||
|
||||
if _, ok := from.GetAnnotations()[strings.Join([]string{AnnotationKeyPropagateToPrefix, string(to.GetUID())}, SlashDelimeter)]; !ok {
|
||||
// The propagating secret expected a different propagated secret. We
|
||||
// assume we have a watch on both secrets, and will be requeued if
|
||||
// and when this situation is remedied.
|
||||
return reconcile.Result{}, errors.New(errUnexpectedToUID)
|
||||
}
|
||||
|
||||
to.Data = from.Data
|
||||
|
||||
// If our update was successful there's nothing else to do. We assume we
|
||||
// have a watch on both secrets and will be queued if either changes.
|
||||
// Otherwise we'll be requeued implicitly because we return an error.
|
||||
// If our update was unsuccessful. Keep trying to update
|
||||
// additional secrets but implicitly requeue when finished.
|
||||
return reconcile.Result{Requeue: false}, errors.Wrap(client.Update(ctx, to), errUpdateSecret)
|
||||
})
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@ package resource
|
|||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/google/go-cmp/cmp"
|
||||
|
@ -60,71 +61,17 @@ func TestSecretPropagatingReconciler(t *testing.T) {
|
|||
args args
|
||||
want want
|
||||
}{
|
||||
"FromNotFound": {
|
||||
args: args{
|
||||
m: &fake.Manager{
|
||||
Client: &test.MockClient{
|
||||
MockGet: func(_ context.Context, n types.NamespacedName, o runtime.Object) error {
|
||||
switch n.Name {
|
||||
case fromName:
|
||||
return kerrors.NewNotFound(schema.GroupResource{}, "")
|
||||
default:
|
||||
return errors.New("unexpected secret name")
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
want: want{
|
||||
result: reconcile.Result{},
|
||||
},
|
||||
},
|
||||
"GetFromError": {
|
||||
args: args{
|
||||
m: &fake.Manager{
|
||||
Client: &test.MockClient{
|
||||
MockGet: func(_ context.Context, n types.NamespacedName, o runtime.Object) error {
|
||||
switch n.Name {
|
||||
case fromName:
|
||||
return errBoom
|
||||
default:
|
||||
return errors.New("unexpected secret name")
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
want: want{
|
||||
err: errors.Wrap(errBoom, errGetSecret),
|
||||
},
|
||||
},
|
||||
"ToNotFound": {
|
||||
args: args{
|
||||
m: &fake.Manager{
|
||||
Client: &test.MockClient{
|
||||
MockGet: func(_ context.Context, n types.NamespacedName, o runtime.Object) error {
|
||||
s := o.(*corev1.Secret)
|
||||
switch n.Name {
|
||||
case fromName:
|
||||
*s = corev1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: ns,
|
||||
Name: fromName,
|
||||
UID: fromUID,
|
||||
Annotations: map[string]string{
|
||||
AnnotationKeyPropagateToNamespace: ns,
|
||||
AnnotationKeyPropagateToName: toName,
|
||||
AnnotationKeyPropagateToUID: string(toUID),
|
||||
},
|
||||
},
|
||||
Data: fromData,
|
||||
}
|
||||
case toName:
|
||||
return kerrors.NewNotFound(schema.GroupResource{}, "")
|
||||
default:
|
||||
return errors.New("unexpected secret name")
|
||||
}
|
||||
return nil
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -134,27 +81,79 @@ func TestSecretPropagatingReconciler(t *testing.T) {
|
|||
},
|
||||
},
|
||||
"GetToError": {
|
||||
args: args{
|
||||
m: &fake.Manager{
|
||||
Client: &test.MockClient{
|
||||
MockGet: func(_ context.Context, n types.NamespacedName, o runtime.Object) error {
|
||||
switch n.Name {
|
||||
case toName:
|
||||
return errBoom
|
||||
default:
|
||||
return errors.New("unexpected secret name")
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
want: want{
|
||||
err: errors.Wrap(errBoom, errGetSecret),
|
||||
},
|
||||
},
|
||||
"FromNotFound": {
|
||||
args: args{
|
||||
m: &fake.Manager{
|
||||
Client: &test.MockClient{
|
||||
MockGet: func(_ context.Context, n types.NamespacedName, o runtime.Object) error {
|
||||
s := o.(*corev1.Secret)
|
||||
switch n.Name {
|
||||
case fromName:
|
||||
case toName:
|
||||
*s = corev1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: ns,
|
||||
Name: fromName,
|
||||
UID: fromUID,
|
||||
Name: toName,
|
||||
UID: toUID,
|
||||
Annotations: map[string]string{
|
||||
AnnotationKeyPropagateToNamespace: ns,
|
||||
AnnotationKeyPropagateToName: toName,
|
||||
AnnotationKeyPropagateToUID: string(toUID),
|
||||
AnnotationKeyPropagateFromName: fromName,
|
||||
AnnotationKeyPropagateFromNamespace: ns,
|
||||
AnnotationKeyPropagateFromUID: string(fromUID),
|
||||
},
|
||||
},
|
||||
Data: fromData,
|
||||
}
|
||||
case fromName:
|
||||
return kerrors.NewNotFound(schema.GroupResource{}, fromName)
|
||||
default:
|
||||
return errors.New("unexpected secret name")
|
||||
}
|
||||
return nil
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
want: want{
|
||||
result: reconcile.Result{},
|
||||
},
|
||||
},
|
||||
"GetFromError": {
|
||||
args: args{
|
||||
m: &fake.Manager{
|
||||
Client: &test.MockClient{
|
||||
MockGet: func(_ context.Context, n types.NamespacedName, o runtime.Object) error {
|
||||
s := o.(*corev1.Secret)
|
||||
switch n.Name {
|
||||
case toName:
|
||||
*s = corev1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: ns,
|
||||
Name: toName,
|
||||
UID: toUID,
|
||||
Annotations: map[string]string{
|
||||
AnnotationKeyPropagateFromName: fromName,
|
||||
AnnotationKeyPropagateFromNamespace: ns,
|
||||
AnnotationKeyPropagateFromUID: string(fromUID),
|
||||
},
|
||||
},
|
||||
}
|
||||
case fromName:
|
||||
return errBoom
|
||||
default:
|
||||
return errors.New("unexpected secret name")
|
||||
|
@ -168,56 +167,6 @@ func TestSecretPropagatingReconciler(t *testing.T) {
|
|||
err: errors.Wrap(errBoom, errGetSecret),
|
||||
},
|
||||
},
|
||||
"UnexpectedToUID": {
|
||||
args: args{
|
||||
m: &fake.Manager{
|
||||
Client: &test.MockClient{
|
||||
MockGet: func(_ context.Context, n types.NamespacedName, o runtime.Object) error {
|
||||
s := o.(*corev1.Secret)
|
||||
|
||||
switch n.Name {
|
||||
case fromName:
|
||||
*s = corev1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: ns,
|
||||
Name: fromName,
|
||||
UID: fromUID,
|
||||
Annotations: map[string]string{
|
||||
AnnotationKeyPropagateToNamespace: ns,
|
||||
AnnotationKeyPropagateToName: toName,
|
||||
AnnotationKeyPropagateToUID: "some-other-uuid",
|
||||
},
|
||||
},
|
||||
Data: fromData,
|
||||
}
|
||||
case toName:
|
||||
*s = corev1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: ns,
|
||||
Name: toName,
|
||||
UID: toUID,
|
||||
Annotations: map[string]string{
|
||||
AnnotationKeyPropagateFromNamespace: ns,
|
||||
AnnotationKeyPropagateFromName: fromName,
|
||||
AnnotationKeyPropagateFromUID: string(fromUID),
|
||||
},
|
||||
},
|
||||
}
|
||||
default:
|
||||
return errors.New("unexpected secret name")
|
||||
}
|
||||
return nil
|
||||
},
|
||||
MockUpdate: test.NewMockUpdateFn(nil, func(got runtime.Object) error {
|
||||
return errors.New("called unexpectedly")
|
||||
}),
|
||||
},
|
||||
},
|
||||
},
|
||||
want: want{
|
||||
result: reconcile.Result{},
|
||||
},
|
||||
},
|
||||
"UnexpectedFromUID": {
|
||||
args: args{
|
||||
m: &fake.Manager{
|
||||
|
@ -226,20 +175,6 @@ func TestSecretPropagatingReconciler(t *testing.T) {
|
|||
s := o.(*corev1.Secret)
|
||||
|
||||
switch n.Name {
|
||||
case fromName:
|
||||
*s = corev1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: ns,
|
||||
Name: fromName,
|
||||
UID: fromUID,
|
||||
Annotations: map[string]string{
|
||||
AnnotationKeyPropagateToNamespace: ns,
|
||||
AnnotationKeyPropagateToName: toName,
|
||||
AnnotationKeyPropagateToUID: string(toUID),
|
||||
},
|
||||
},
|
||||
Data: fromData,
|
||||
}
|
||||
case toName:
|
||||
*s = corev1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
|
@ -247,11 +182,24 @@ func TestSecretPropagatingReconciler(t *testing.T) {
|
|||
Name: toName,
|
||||
UID: toUID,
|
||||
Annotations: map[string]string{
|
||||
AnnotationKeyPropagateFromNamespace: ns,
|
||||
AnnotationKeyPropagateFromName: fromName,
|
||||
AnnotationKeyPropagateFromUID: "some-other-uuid",
|
||||
AnnotationKeyPropagateFromNamespace: ns,
|
||||
AnnotationKeyPropagateFromUID: "some-other-UID",
|
||||
},
|
||||
},
|
||||
Data: fromData,
|
||||
}
|
||||
case fromName:
|
||||
*s = corev1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: ns,
|
||||
Name: fromName,
|
||||
UID: fromUID,
|
||||
Annotations: map[string]string{
|
||||
strings.Join([]string{AnnotationKeyPropagateToPrefix, string(toUID)}, SlashDelimeter): strings.Join([]string{ns, toName}, SlashDelimeter),
|
||||
},
|
||||
},
|
||||
Data: fromData,
|
||||
}
|
||||
default:
|
||||
return errors.New("unexpected secret name")
|
||||
|
@ -266,6 +214,57 @@ func TestSecretPropagatingReconciler(t *testing.T) {
|
|||
},
|
||||
want: want{
|
||||
result: reconcile.Result{},
|
||||
err: errors.New(errUnexpectedFromUID),
|
||||
},
|
||||
},
|
||||
"UnexpectedToUID": {
|
||||
args: args{
|
||||
m: &fake.Manager{
|
||||
Client: &test.MockClient{
|
||||
MockGet: func(_ context.Context, n types.NamespacedName, o runtime.Object) error {
|
||||
s := o.(*corev1.Secret)
|
||||
|
||||
switch n.Name {
|
||||
case toName:
|
||||
*s = corev1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: ns,
|
||||
Name: toName,
|
||||
UID: toUID,
|
||||
Annotations: map[string]string{
|
||||
AnnotationKeyPropagateFromName: fromName,
|
||||
AnnotationKeyPropagateFromNamespace: ns,
|
||||
AnnotationKeyPropagateFromUID: string(fromUID),
|
||||
},
|
||||
},
|
||||
Data: fromData,
|
||||
}
|
||||
case fromName:
|
||||
*s = corev1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: ns,
|
||||
Name: fromName,
|
||||
UID: fromUID,
|
||||
Annotations: map[string]string{
|
||||
strings.Join([]string{AnnotationKeyPropagateToPrefix, "some-other-uid"}, SlashDelimeter): strings.Join([]string{ns, toName}, SlashDelimeter),
|
||||
},
|
||||
},
|
||||
Data: fromData,
|
||||
}
|
||||
default:
|
||||
return errors.New("unexpected secret name")
|
||||
}
|
||||
return nil
|
||||
},
|
||||
MockUpdate: test.NewMockUpdateFn(nil, func(got runtime.Object) error {
|
||||
return errors.New("called unexpectedly")
|
||||
}),
|
||||
},
|
||||
},
|
||||
},
|
||||
want: want{
|
||||
result: reconcile.Result{},
|
||||
err: errors.New(errUnexpectedToUID),
|
||||
},
|
||||
},
|
||||
"UpdateToError": {
|
||||
|
@ -276,20 +275,6 @@ func TestSecretPropagatingReconciler(t *testing.T) {
|
|||
s := o.(*corev1.Secret)
|
||||
|
||||
switch n.Name {
|
||||
case fromName:
|
||||
*s = corev1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: ns,
|
||||
Name: fromName,
|
||||
UID: fromUID,
|
||||
Annotations: map[string]string{
|
||||
AnnotationKeyPropagateToNamespace: ns,
|
||||
AnnotationKeyPropagateToName: toName,
|
||||
AnnotationKeyPropagateToUID: string(toUID),
|
||||
},
|
||||
},
|
||||
Data: fromData,
|
||||
}
|
||||
case toName:
|
||||
*s = corev1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
|
@ -297,11 +282,24 @@ func TestSecretPropagatingReconciler(t *testing.T) {
|
|||
Name: toName,
|
||||
UID: toUID,
|
||||
Annotations: map[string]string{
|
||||
AnnotationKeyPropagateFromNamespace: ns,
|
||||
AnnotationKeyPropagateFromName: fromName,
|
||||
AnnotationKeyPropagateFromNamespace: ns,
|
||||
AnnotationKeyPropagateFromUID: string(fromUID),
|
||||
},
|
||||
},
|
||||
Data: fromData,
|
||||
}
|
||||
case fromName:
|
||||
*s = corev1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: ns,
|
||||
Name: fromName,
|
||||
UID: fromUID,
|
||||
Annotations: map[string]string{
|
||||
strings.Join([]string{AnnotationKeyPropagateToPrefix, string(toUID)}, SlashDelimeter): strings.Join([]string{ns, toName}, SlashDelimeter),
|
||||
},
|
||||
},
|
||||
Data: fromData,
|
||||
}
|
||||
default:
|
||||
return errors.New("unexpected secret name")
|
||||
|
@ -318,7 +316,7 @@ func TestSecretPropagatingReconciler(t *testing.T) {
|
|||
err: errors.Wrap(errBoom, errUpdateSecret),
|
||||
},
|
||||
},
|
||||
"Successful": {
|
||||
"SuccessfulSingle": {
|
||||
args: args{
|
||||
m: &fake.Manager{
|
||||
Client: &test.MockClient{
|
||||
|
@ -326,20 +324,6 @@ func TestSecretPropagatingReconciler(t *testing.T) {
|
|||
s := o.(*corev1.Secret)
|
||||
|
||||
switch n.Name {
|
||||
case fromName:
|
||||
*s = corev1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: ns,
|
||||
Name: fromName,
|
||||
UID: fromUID,
|
||||
Annotations: map[string]string{
|
||||
AnnotationKeyPropagateToNamespace: ns,
|
||||
AnnotationKeyPropagateToName: toName,
|
||||
AnnotationKeyPropagateToUID: string(toUID),
|
||||
},
|
||||
},
|
||||
Data: fromData,
|
||||
}
|
||||
case toName:
|
||||
*s = corev1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
|
@ -347,11 +331,24 @@ func TestSecretPropagatingReconciler(t *testing.T) {
|
|||
Name: toName,
|
||||
UID: toUID,
|
||||
Annotations: map[string]string{
|
||||
AnnotationKeyPropagateFromNamespace: ns,
|
||||
AnnotationKeyPropagateFromName: fromName,
|
||||
AnnotationKeyPropagateFromNamespace: ns,
|
||||
AnnotationKeyPropagateFromUID: string(fromUID),
|
||||
},
|
||||
},
|
||||
Data: fromData,
|
||||
}
|
||||
case fromName:
|
||||
*s = corev1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: ns,
|
||||
Name: fromName,
|
||||
UID: fromUID,
|
||||
Annotations: map[string]string{
|
||||
strings.Join([]string{AnnotationKeyPropagateToPrefix, string(toUID)}, SlashDelimeter): strings.Join([]string{ns, toName}, SlashDelimeter),
|
||||
},
|
||||
},
|
||||
Data: fromData,
|
||||
}
|
||||
default:
|
||||
return errors.New("unexpected secret name")
|
||||
|
@ -365,8 +362,75 @@ func TestSecretPropagatingReconciler(t *testing.T) {
|
|||
Name: toName,
|
||||
UID: toUID,
|
||||
Annotations: map[string]string{
|
||||
AnnotationKeyPropagateFromNamespace: ns,
|
||||
AnnotationKeyPropagateFromName: fromName,
|
||||
AnnotationKeyPropagateFromNamespace: ns,
|
||||
AnnotationKeyPropagateFromUID: string(fromUID),
|
||||
},
|
||||
},
|
||||
Data: fromData,
|
||||
}
|
||||
if diff := cmp.Diff(want, got); diff != "" {
|
||||
t.Errorf("-want, +got:\n%s", diff)
|
||||
}
|
||||
return nil
|
||||
}),
|
||||
},
|
||||
},
|
||||
},
|
||||
want: want{
|
||||
result: reconcile.Result{},
|
||||
},
|
||||
},
|
||||
"SuccessfulMultiple": {
|
||||
args: args{
|
||||
m: &fake.Manager{
|
||||
Client: &test.MockClient{
|
||||
MockGet: func(_ context.Context, n types.NamespacedName, o runtime.Object) error {
|
||||
s := o.(*corev1.Secret)
|
||||
|
||||
switch n.Name {
|
||||
case toName:
|
||||
*s = corev1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: ns,
|
||||
Name: toName,
|
||||
UID: toUID,
|
||||
Annotations: map[string]string{
|
||||
AnnotationKeyPropagateFromName: fromName,
|
||||
AnnotationKeyPropagateFromNamespace: ns,
|
||||
AnnotationKeyPropagateFromUID: string(fromUID),
|
||||
},
|
||||
},
|
||||
Data: fromData,
|
||||
}
|
||||
case fromName:
|
||||
*s = corev1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: ns,
|
||||
Name: fromName,
|
||||
UID: fromUID,
|
||||
Annotations: map[string]string{
|
||||
strings.Join([]string{AnnotationKeyPropagateToPrefix, string(toUID)}, SlashDelimeter): strings.Join([]string{ns, toName}, SlashDelimeter),
|
||||
strings.Join([]string{AnnotationKeyPropagateToPrefix, "some-uid"}, SlashDelimeter): strings.Join([]string{ns, toName}, SlashDelimeter),
|
||||
strings.Join([]string{AnnotationKeyPropagateToPrefix, "some-other-uid"}, SlashDelimeter): strings.Join([]string{ns, toName}, SlashDelimeter),
|
||||
},
|
||||
},
|
||||
Data: fromData,
|
||||
}
|
||||
default:
|
||||
return errors.New("unexpected secret name")
|
||||
}
|
||||
return nil
|
||||
},
|
||||
MockUpdate: test.NewMockUpdateFn(nil, func(got runtime.Object) error {
|
||||
want := &corev1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: ns,
|
||||
Name: toName,
|
||||
UID: toUID,
|
||||
Annotations: map[string]string{
|
||||
AnnotationKeyPropagateFromName: fromName,
|
||||
AnnotationKeyPropagateFromNamespace: ns,
|
||||
AnnotationKeyPropagateFromUID: string(fromUID),
|
||||
},
|
||||
},
|
||||
|
@ -389,7 +453,7 @@ func TestSecretPropagatingReconciler(t *testing.T) {
|
|||
for name, tc := range cases {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
r := NewSecretPropagatingReconciler(tc.args.m)
|
||||
got, err := r.Reconcile(reconcile.Request{NamespacedName: types.NamespacedName{Namespace: ns, Name: fromName}})
|
||||
got, err := r.Reconcile(reconcile.Request{NamespacedName: types.NamespacedName{Namespace: ns, Name: toName}})
|
||||
|
||||
if diff := cmp.Diff(tc.want.err, err, test.EquateErrors()); diff != "" {
|
||||
t.Errorf("r.Reconcile(...): -want error, +got error:\n%s", diff)
|
||||
|
|
Loading…
Reference in New Issue