Skip to content

Commit

Permalink
copy annotations too
Browse files Browse the repository at this point in the history
  • Loading branch information
fiksn committed Nov 14, 2023
1 parent 9935891 commit 98ba366
Show file tree
Hide file tree
Showing 8 changed files with 156 additions and 12 deletions.
25 changes: 24 additions & 1 deletion replicate/common/common.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
package common

import (
"strings"

v1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"strings"
)

type Replicator interface {
Expand Down Expand Up @@ -42,3 +43,25 @@ func BuildStrictRegex(regex string) string {
func JSONPatchPathEscape(annotation string) string {
return strings.ReplaceAll(annotation, "/", "~1")
}

type Annotatable interface {
GetAnnotations() map[string]string
SetAnnotations(map[string]string)
}

func CopyAnnotations[I, O Annotatable](input I, output O) {
val := input.GetAnnotations()
copy := make(map[string]string, len(val))

strip, ok := val[StripAnnotations]
if !ok && strip != "true" {
for k, v := range val {
if strings.HasPrefix(k, Prefix) {
continue
}
copy[k] = v
}

output.SetAnnotations(copy)
}
}
25 changes: 15 additions & 10 deletions replicate/common/consts.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,19 @@ package common

// Annotations that are used to control this Controller's behaviour
const (
ReplicateFromAnnotation = "replicator.v1.mittwald.de/replicate-from"
ReplicatedAtAnnotation = "replicator.v1.mittwald.de/replicated-at"
ReplicatedFromVersionAnnotation = "replicator.v1.mittwald.de/replicated-from-version"
ReplicatedKeysAnnotation = "replicator.v1.mittwald.de/replicated-keys"
ReplicationAllowed = "replicator.v1.mittwald.de/replication-allowed"
ReplicationAllowedNamespaces = "replicator.v1.mittwald.de/replication-allowed-namespaces"
ReplicateTo = "replicator.v1.mittwald.de/replicate-to"
ReplicateToMatching = "replicator.v1.mittwald.de/replicate-to-matching"
KeepOwnerReferences = "replicator.v1.mittwald.de/keep-owner-references"
StripLabels = "replicator.v1.mittwald.de/strip-labels"
Prefix = "replicator.v1.mittwald.de"
)

var (
ReplicateFromAnnotation = Prefix + "/replicate-from"
ReplicatedAtAnnotation = Prefix + "/replicated-at"
ReplicatedFromVersionAnnotation = Prefix + "/replicated-from-version"
ReplicatedKeysAnnotation = Prefix + "/replicated-keys"
ReplicationAllowed = Prefix + "/replication-allowed"
ReplicationAllowedNamespaces = Prefix + "/replication-allowed-namespaces"
ReplicateTo = Prefix + "/replicate-to"
ReplicateToMatching = Prefix + "/replicate-to-matching"
KeepOwnerReferences = Prefix + "/keep-owner-references"
StripLabels = Prefix + "/strip-labels"
StripAnnotations = Prefix + "/strip-annotations"
)
4 changes: 4 additions & 0 deletions replicate/configmap/configmaps.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ func (r *Replicator) ReplicateDataFrom(sourceObj interface{}, targetObj interfac
}

targetCopy := target.DeepCopy()

if targetCopy.Data == nil {
targetCopy.Data = make(map[string]string)
}
Expand Down Expand Up @@ -107,6 +108,8 @@ func (r *Replicator) ReplicateDataFrom(sourceObj interface{}, targetObj interfac

logger.Infof("updating config map %s/%s", target.Namespace, target.Name)

common.CopyAnnotations(source, targetCopy)

targetCopy.Annotations[common.ReplicatedAtAnnotation] = time.Now().Format(time.RFC3339)
targetCopy.Annotations[common.ReplicatedFromVersionAnnotation] = source.ResourceVersion
targetCopy.Annotations[common.ReplicatedKeysAnnotation] = strings.Join(replicatedKeys, ",")
Expand Down Expand Up @@ -207,6 +210,7 @@ func (r *Replicator) ReplicateObjectTo(sourceObj interface{}, target *v1.Namespa
sort.Strings(replicatedKeys)
resourceCopy.Name = source.Name
resourceCopy.Labels = labelsCopy
common.CopyAnnotations(source, resourceCopy)
resourceCopy.Annotations[common.ReplicatedAtAnnotation] = time.Now().Format(time.RFC3339)
resourceCopy.Annotations[common.ReplicatedFromVersionAnnotation] = source.ResourceVersion
resourceCopy.Annotations[common.ReplicatedKeysAnnotation] = strings.Join(replicatedKeys, ",")
Expand Down
3 changes: 3 additions & 0 deletions replicate/role/roles.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,8 @@ func (r *Replicator) ReplicateDataFrom(sourceObj interface{}, targetObj interfac

logger.Infof("updating target %s/%s", target.Namespace, target.Name)

common.CopyAnnotations(source, targetCopy)

targetCopy.Annotations[common.ReplicatedAtAnnotation] = time.Now().Format(time.RFC3339)
targetCopy.Annotations[common.ReplicatedFromVersionAnnotation] = source.ResourceVersion

Expand Down Expand Up @@ -148,6 +150,7 @@ func (r *Replicator) ReplicateObjectTo(sourceObj interface{}, target *v1.Namespa
targetCopy.Name = source.Name
targetCopy.Labels = labelsCopy
targetCopy.Rules = source.Rules
common.CopyAnnotations(source, targetCopy)
targetCopy.Annotations[common.ReplicatedAtAnnotation] = time.Now().Format(time.RFC3339)
targetCopy.Annotations[common.ReplicatedFromVersionAnnotation] = source.ResourceVersion

Expand Down
4 changes: 3 additions & 1 deletion replicate/rolebinding/rolebindings.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ func (r *Replicator) ReplicateDataFrom(sourceObj interface{}, targetObj interfac

log.Infof("updating target %s/%s", target.Namespace, target.Name)

common.CopyAnnotations(source, targetCopy)
targetCopy.Annotations[common.ReplicatedAtAnnotation] = time.Now().Format(time.RFC3339)
targetCopy.Annotations[common.ReplicatedFromVersionAnnotation] = source.ResourceVersion

Expand Down Expand Up @@ -149,6 +150,7 @@ func (r *Replicator) ReplicateObjectTo(sourceObj interface{}, target *v1.Namespa
targetCopy.Labels = labelsCopy
targetCopy.Subjects = source.Subjects
targetCopy.RoleRef = source.RoleRef
common.CopyAnnotations(source, targetCopy)
targetCopy.Annotations[common.ReplicatedAtAnnotation] = time.Now().Format(time.RFC3339)
targetCopy.Annotations[common.ReplicatedFromVersionAnnotation] = source.ResourceVersion

Expand Down Expand Up @@ -178,7 +180,7 @@ func (r *Replicator) ReplicateObjectTo(sourceObj interface{}, target *v1.Namespa
return nil
}

//Checks if Role required for RoleBinding exists. Retries a few times before returning error to allow replication to catch up
// Checks if Role required for RoleBinding exists. Retries a few times before returning error to allow replication to catch up
func (r *Replicator) canReplicate(targetNameSpace string, roleRef string) (err error) {
for i := 0; i < 5; i++ {
_, err = r.Client.RbacV1().Roles(targetNameSpace).Get(context.TODO(), roleRef, metav1.GetOptions{})
Expand Down
3 changes: 3 additions & 0 deletions replicate/secret/secrets.go
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,8 @@ func (r *Replicator) ReplicateDataFrom(sourceObj interface{}, targetObj interfac

logger.Infof("updating target %s", common.MustGetKey(target))

common.CopyAnnotations(source, targetCopy)

targetCopy.Annotations[common.ReplicatedAtAnnotation] = time.Now().Format(time.RFC3339)
targetCopy.Annotations[common.ReplicatedFromVersionAnnotation] = source.ResourceVersion
targetCopy.Annotations[common.ReplicatedKeysAnnotation] = strings.Join(replicatedKeys, ",")
Expand Down Expand Up @@ -179,6 +181,7 @@ func (r *Replicator) ReplicateObjectTo(sourceObj interface{}, target *v1.Namespa
resourceCopy.Name = source.Name
resourceCopy.Labels = labelsCopy
resourceCopy.Type = targetResourceType
common.CopyAnnotations(source, resourceCopy)
resourceCopy.Annotations[common.ReplicatedAtAnnotation] = time.Now().Format(time.RFC3339)
resourceCopy.Annotations[common.ReplicatedFromVersionAnnotation] = source.ResourceVersion
resourceCopy.Annotations[common.ReplicatedKeysAnnotation] = strings.Join(replicatedKeys, ",")
Expand Down
102 changes: 102 additions & 0 deletions replicate/secret/secrets_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1275,6 +1275,108 @@ func TestSecretReplicator(t *testing.T) {

})

t.Run("replication copies annotations", func(t *testing.T) {
sourceLabels := map[string]string{
"foo": "bar",
"hello": "world",
}
source := corev1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: "annotation-push",
Namespace: ns.Name,
Annotations: map[string]string{
common.ReplicateTo: prefix + "test2",
"test-annotation": "bar",
},
Labels: sourceLabels,
},
Type: corev1.SecretTypeOpaque,
Data: map[string][]byte{
"foo": []byte("Hello Foo"),
"bar": []byte("Hello Bar"),
},
}

wg, stop := waitForSecrets(client, 2, EventHandlerFuncs{
AddFunc: func(wg *sync.WaitGroup, obj interface{}) {
secret := obj.(*corev1.Secret)
if secret.Namespace == source.Namespace && secret.Name == source.Name {
log.Debugf("AddFunc %+v", obj)
wg.Done()
} else if secret.Namespace == prefix+"test2" && secret.Name == source.Name {
log.Debugf("AddFunc %+v", obj)
wg.Done()
}
},
})
_, err := secrets.Create(context.TODO(), &source, metav1.CreateOptions{})
require.NoError(t, err)

waitWithTimeout(wg, MaxWaitTime)
close(stop)

secrets2 := client.CoreV1().Secrets(prefix + "test2")
updTarget, err := secrets2.Get(context.TODO(), source.Name, metav1.GetOptions{})

require.NoError(t, err)
require.Equal(t, []byte("Hello Foo"), updTarget.Data["foo"])
require.True(t, reflect.DeepEqual(sourceLabels, updTarget.Labels))

require.Equal(t, "bar", updTarget.Annotations["test-annotation"])
})

t.Run("replication copies annotations but honors strip-annotations", func(t *testing.T) {
sourceLabels := map[string]string{
"foo": "bar",
"hello": "world",
}
source := corev1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: "annotation-push-strip",
Namespace: ns.Name,
Annotations: map[string]string{
common.ReplicateTo: prefix + "test2",
common.StripAnnotations: "true",
"test-annotation": "bar",
},
Labels: sourceLabels,
},
Type: corev1.SecretTypeOpaque,
Data: map[string][]byte{
"foo": []byte("Hello Foo"),
"bar": []byte("Hello Bar"),
},
}

wg, stop := waitForSecrets(client, 2, EventHandlerFuncs{
AddFunc: func(wg *sync.WaitGroup, obj interface{}) {
secret := obj.(*corev1.Secret)
if secret.Namespace == source.Namespace && secret.Name == source.Name {
log.Debugf("AddFunc %+v", obj)
wg.Done()
} else if secret.Namespace == prefix+"test2" && secret.Name == source.Name {
log.Debugf("AddFunc %+v", obj)
wg.Done()
}
},
})
_, err := secrets.Create(context.TODO(), &source, metav1.CreateOptions{})
require.NoError(t, err)

waitWithTimeout(wg, MaxWaitTime)
close(stop)

secrets2 := client.CoreV1().Secrets(prefix + "test2")
updTarget, err := secrets2.Get(context.TODO(), source.Name, metav1.GetOptions{})

require.NoError(t, err)
require.Equal(t, []byte("Hello Foo"), updTarget.Data["foo"])
require.True(t, reflect.DeepEqual(sourceLabels, updTarget.Labels))

_, exists := updTarget.Annotations["test-annotation"]
require.False(t, exists)
})

}

func waitForNamespaces(client *kubernetes.Clientset, count int, eventHandlers EventHandlerFuncs) (wg *sync.WaitGroup, stop chan struct{}) {
Expand Down
2 changes: 2 additions & 0 deletions replicate/serviceaccount/serviceaccounts.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ func (r *Replicator) ReplicateDataFrom(sourceObj interface{}, targetObj interfac
targetCopy.ImagePullSecrets = source.ImagePullSecrets

log.Infof("updating target %s/%s", target.Namespace, target.Name)
common.CopyAnnotations(source, target)

targetCopy.Annotations[common.ReplicatedAtAnnotation] = time.Now().Format(time.RFC3339)
targetCopy.Annotations[common.ReplicatedFromVersionAnnotation] = source.ResourceVersion
Expand Down Expand Up @@ -146,6 +147,7 @@ func (r *Replicator) ReplicateObjectTo(sourceObj interface{}, target *v1.Namespa
targetCopy.Name = source.Name
targetCopy.Labels = labelsCopy
targetCopy.ImagePullSecrets = source.ImagePullSecrets
common.CopyAnnotations(source, targetCopy)
targetCopy.Annotations[common.ReplicatedAtAnnotation] = time.Now().Format(time.RFC3339)
targetCopy.Annotations[common.ReplicatedFromVersionAnnotation] = source.ResourceVersion

Expand Down

0 comments on commit 98ba366

Please sign in to comment.