Skip to content

Commit a82d40c

Browse files
committed
copy annotations too
1 parent 9935891 commit a82d40c

File tree

8 files changed

+156
-12
lines changed

8 files changed

+156
-12
lines changed

replicate/common/common.go

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
package common
22

33
import (
4+
"strings"
5+
46
v1 "k8s.io/api/core/v1"
57
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
6-
"strings"
78
)
89

910
type Replicator interface {
@@ -42,3 +43,25 @@ func BuildStrictRegex(regex string) string {
4243
func JSONPatchPathEscape(annotation string) string {
4344
return strings.ReplaceAll(annotation, "/", "~1")
4445
}
46+
47+
type Annotatable interface {
48+
GetAnnotations() map[string]string
49+
SetAnnotations(map[string]string)
50+
}
51+
52+
func CopyAnnotations[I, O Annotatable](input I, output O) {
53+
val := input.GetAnnotations()
54+
copy := make(map[string]string, len(val))
55+
56+
strip, ok := val[StripAnnotations]
57+
if !ok || strings.ToLower(strip) != "true" {
58+
for k, v := range val {
59+
if strings.HasPrefix(k, Prefix) {
60+
continue
61+
}
62+
copy[k] = v
63+
}
64+
65+
output.SetAnnotations(copy)
66+
}
67+
}

replicate/common/consts.go

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,19 @@ package common
22

33
// Annotations that are used to control this Controller's behaviour
44
const (
5-
ReplicateFromAnnotation = "replicator.v1.mittwald.de/replicate-from"
6-
ReplicatedAtAnnotation = "replicator.v1.mittwald.de/replicated-at"
7-
ReplicatedFromVersionAnnotation = "replicator.v1.mittwald.de/replicated-from-version"
8-
ReplicatedKeysAnnotation = "replicator.v1.mittwald.de/replicated-keys"
9-
ReplicationAllowed = "replicator.v1.mittwald.de/replication-allowed"
10-
ReplicationAllowedNamespaces = "replicator.v1.mittwald.de/replication-allowed-namespaces"
11-
ReplicateTo = "replicator.v1.mittwald.de/replicate-to"
12-
ReplicateToMatching = "replicator.v1.mittwald.de/replicate-to-matching"
13-
KeepOwnerReferences = "replicator.v1.mittwald.de/keep-owner-references"
14-
StripLabels = "replicator.v1.mittwald.de/strip-labels"
5+
Prefix = "replicator.v1.mittwald.de"
6+
)
7+
8+
var (
9+
ReplicateFromAnnotation = Prefix + "/replicate-from"
10+
ReplicatedAtAnnotation = Prefix + "/replicated-at"
11+
ReplicatedFromVersionAnnotation = Prefix + "/replicated-from-version"
12+
ReplicatedKeysAnnotation = Prefix + "/replicated-keys"
13+
ReplicationAllowed = Prefix + "/replication-allowed"
14+
ReplicationAllowedNamespaces = Prefix + "/replication-allowed-namespaces"
15+
ReplicateTo = Prefix + "/replicate-to"
16+
ReplicateToMatching = Prefix + "/replicate-to-matching"
17+
KeepOwnerReferences = Prefix + "/keep-owner-references"
18+
StripLabels = Prefix + "/strip-labels"
19+
StripAnnotations = Prefix + "/strip-annotations"
1520
)

replicate/configmap/configmaps.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ func (r *Replicator) ReplicateDataFrom(sourceObj interface{}, targetObj interfac
7171
}
7272

7373
targetCopy := target.DeepCopy()
74+
7475
if targetCopy.Data == nil {
7576
targetCopy.Data = make(map[string]string)
7677
}
@@ -107,6 +108,8 @@ func (r *Replicator) ReplicateDataFrom(sourceObj interface{}, targetObj interfac
107108

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

111+
common.CopyAnnotations(source, targetCopy)
112+
110113
targetCopy.Annotations[common.ReplicatedAtAnnotation] = time.Now().Format(time.RFC3339)
111114
targetCopy.Annotations[common.ReplicatedFromVersionAnnotation] = source.ResourceVersion
112115
targetCopy.Annotations[common.ReplicatedKeysAnnotation] = strings.Join(replicatedKeys, ",")
@@ -207,6 +210,7 @@ func (r *Replicator) ReplicateObjectTo(sourceObj interface{}, target *v1.Namespa
207210
sort.Strings(replicatedKeys)
208211
resourceCopy.Name = source.Name
209212
resourceCopy.Labels = labelsCopy
213+
common.CopyAnnotations(source, resourceCopy)
210214
resourceCopy.Annotations[common.ReplicatedAtAnnotation] = time.Now().Format(time.RFC3339)
211215
resourceCopy.Annotations[common.ReplicatedFromVersionAnnotation] = source.ResourceVersion
212216
resourceCopy.Annotations[common.ReplicatedKeysAnnotation] = strings.Join(replicatedKeys, ",")

replicate/role/roles.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,8 @@ func (r *Replicator) ReplicateDataFrom(sourceObj interface{}, targetObj interfac
7777

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

80+
common.CopyAnnotations(source, targetCopy)
81+
8082
targetCopy.Annotations[common.ReplicatedAtAnnotation] = time.Now().Format(time.RFC3339)
8183
targetCopy.Annotations[common.ReplicatedFromVersionAnnotation] = source.ResourceVersion
8284

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

replicate/rolebinding/rolebindings.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ func (r *Replicator) ReplicateDataFrom(sourceObj interface{}, targetObj interfac
7979

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

82+
common.CopyAnnotations(source, targetCopy)
8283
targetCopy.Annotations[common.ReplicatedAtAnnotation] = time.Now().Format(time.RFC3339)
8384
targetCopy.Annotations[common.ReplicatedFromVersionAnnotation] = source.ResourceVersion
8485

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

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

181-
//Checks if Role required for RoleBinding exists. Retries a few times before returning error to allow replication to catch up
183+
// Checks if Role required for RoleBinding exists. Retries a few times before returning error to allow replication to catch up
182184
func (r *Replicator) canReplicate(targetNameSpace string, roleRef string) (err error) {
183185
for i := 0; i < 5; i++ {
184186
_, err = r.Client.RbacV1().Roles(targetNameSpace).Get(context.TODO(), roleRef, metav1.GetOptions{})

replicate/secret/secrets.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,8 @@ func (r *Replicator) ReplicateDataFrom(sourceObj interface{}, targetObj interfac
102102

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

105+
common.CopyAnnotations(source, targetCopy)
106+
105107
targetCopy.Annotations[common.ReplicatedAtAnnotation] = time.Now().Format(time.RFC3339)
106108
targetCopy.Annotations[common.ReplicatedFromVersionAnnotation] = source.ResourceVersion
107109
targetCopy.Annotations[common.ReplicatedKeysAnnotation] = strings.Join(replicatedKeys, ",")
@@ -179,6 +181,7 @@ func (r *Replicator) ReplicateObjectTo(sourceObj interface{}, target *v1.Namespa
179181
resourceCopy.Name = source.Name
180182
resourceCopy.Labels = labelsCopy
181183
resourceCopy.Type = targetResourceType
184+
common.CopyAnnotations(source, resourceCopy)
182185
resourceCopy.Annotations[common.ReplicatedAtAnnotation] = time.Now().Format(time.RFC3339)
183186
resourceCopy.Annotations[common.ReplicatedFromVersionAnnotation] = source.ResourceVersion
184187
resourceCopy.Annotations[common.ReplicatedKeysAnnotation] = strings.Join(replicatedKeys, ",")

replicate/secret/secrets_test.go

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1275,6 +1275,108 @@ func TestSecretReplicator(t *testing.T) {
12751275

12761276
})
12771277

1278+
t.Run("replication copies annotations", func(t *testing.T) {
1279+
sourceLabels := map[string]string{
1280+
"foo": "bar",
1281+
"hello": "world",
1282+
}
1283+
source := corev1.Secret{
1284+
ObjectMeta: metav1.ObjectMeta{
1285+
Name: "annotation-push",
1286+
Namespace: ns.Name,
1287+
Annotations: map[string]string{
1288+
common.ReplicateTo: prefix + "test2",
1289+
"test-annotation": "bar",
1290+
},
1291+
Labels: sourceLabels,
1292+
},
1293+
Type: corev1.SecretTypeOpaque,
1294+
Data: map[string][]byte{
1295+
"foo": []byte("Hello Foo"),
1296+
"bar": []byte("Hello Bar"),
1297+
},
1298+
}
1299+
1300+
wg, stop := waitForSecrets(client, 2, EventHandlerFuncs{
1301+
AddFunc: func(wg *sync.WaitGroup, obj interface{}) {
1302+
secret := obj.(*corev1.Secret)
1303+
if secret.Namespace == source.Namespace && secret.Name == source.Name {
1304+
log.Debugf("AddFunc %+v", obj)
1305+
wg.Done()
1306+
} else if secret.Namespace == prefix+"test2" && secret.Name == source.Name {
1307+
log.Debugf("AddFunc %+v", obj)
1308+
wg.Done()
1309+
}
1310+
},
1311+
})
1312+
_, err := secrets.Create(context.TODO(), &source, metav1.CreateOptions{})
1313+
require.NoError(t, err)
1314+
1315+
waitWithTimeout(wg, MaxWaitTime)
1316+
close(stop)
1317+
1318+
secrets2 := client.CoreV1().Secrets(prefix + "test2")
1319+
updTarget, err := secrets2.Get(context.TODO(), source.Name, metav1.GetOptions{})
1320+
1321+
require.NoError(t, err)
1322+
require.Equal(t, []byte("Hello Foo"), updTarget.Data["foo"])
1323+
require.True(t, reflect.DeepEqual(sourceLabels, updTarget.Labels))
1324+
1325+
require.Equal(t, "bar", updTarget.Annotations["test-annotation"])
1326+
})
1327+
1328+
t.Run("replication copies annotations but honors strip-annotations", func(t *testing.T) {
1329+
sourceLabels := map[string]string{
1330+
"foo": "bar",
1331+
"hello": "world",
1332+
}
1333+
source := corev1.Secret{
1334+
ObjectMeta: metav1.ObjectMeta{
1335+
Name: "annotation-push-strip",
1336+
Namespace: ns.Name,
1337+
Annotations: map[string]string{
1338+
common.ReplicateTo: prefix + "test2",
1339+
common.StripAnnotations: "true",
1340+
"test-annotation": "bar",
1341+
},
1342+
Labels: sourceLabels,
1343+
},
1344+
Type: corev1.SecretTypeOpaque,
1345+
Data: map[string][]byte{
1346+
"foo": []byte("Hello Foo"),
1347+
"bar": []byte("Hello Bar"),
1348+
},
1349+
}
1350+
1351+
wg, stop := waitForSecrets(client, 2, EventHandlerFuncs{
1352+
AddFunc: func(wg *sync.WaitGroup, obj interface{}) {
1353+
secret := obj.(*corev1.Secret)
1354+
if secret.Namespace == source.Namespace && secret.Name == source.Name {
1355+
log.Debugf("AddFunc %+v", obj)
1356+
wg.Done()
1357+
} else if secret.Namespace == prefix+"test2" && secret.Name == source.Name {
1358+
log.Debugf("AddFunc %+v", obj)
1359+
wg.Done()
1360+
}
1361+
},
1362+
})
1363+
_, err := secrets.Create(context.TODO(), &source, metav1.CreateOptions{})
1364+
require.NoError(t, err)
1365+
1366+
waitWithTimeout(wg, MaxWaitTime)
1367+
close(stop)
1368+
1369+
secrets2 := client.CoreV1().Secrets(prefix + "test2")
1370+
updTarget, err := secrets2.Get(context.TODO(), source.Name, metav1.GetOptions{})
1371+
1372+
require.NoError(t, err)
1373+
require.Equal(t, []byte("Hello Foo"), updTarget.Data["foo"])
1374+
require.True(t, reflect.DeepEqual(sourceLabels, updTarget.Labels))
1375+
1376+
_, exists := updTarget.Annotations["test-annotation"]
1377+
require.False(t, exists)
1378+
})
1379+
12781380
}
12791381

12801382
func waitForNamespaces(client *kubernetes.Clientset, count int, eventHandlers EventHandlerFuncs) (wg *sync.WaitGroup, stop chan struct{}) {

replicate/serviceaccount/serviceaccounts.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ func (r *Replicator) ReplicateDataFrom(sourceObj interface{}, targetObj interfac
7676
targetCopy.ImagePullSecrets = source.ImagePullSecrets
7777

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

8081
targetCopy.Annotations[common.ReplicatedAtAnnotation] = time.Now().Format(time.RFC3339)
8182
targetCopy.Annotations[common.ReplicatedFromVersionAnnotation] = source.ResourceVersion
@@ -146,6 +147,7 @@ func (r *Replicator) ReplicateObjectTo(sourceObj interface{}, target *v1.Namespa
146147
targetCopy.Name = source.Name
147148
targetCopy.Labels = labelsCopy
148149
targetCopy.ImagePullSecrets = source.ImagePullSecrets
150+
common.CopyAnnotations(source, targetCopy)
149151
targetCopy.Annotations[common.ReplicatedAtAnnotation] = time.Now().Format(time.RFC3339)
150152
targetCopy.Annotations[common.ReplicatedFromVersionAnnotation] = source.ResourceVersion
151153

0 commit comments

Comments
 (0)