Skip to content

Commit

Permalink
add extra annotations for cms and secrets
Browse files Browse the repository at this point in the history
  • Loading branch information
jabdoa2 authored and toelke committed May 3, 2024
1 parent 5b3b521 commit 7f0e1b0
Show file tree
Hide file tree
Showing 5 changed files with 80 additions and 5 deletions.
19 changes: 19 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,25 @@ spec:
From now on, when a mounted ConfigMap or Secret is updated, Wave will update
this `config-hash` annotation and cause a Rolling Update to occur.

### Advanced Features

If your Pod is reading some ConfigMap or Secret using the API and you want it
to be restarted on change you can tell Wave in an annotation:

```
apiVersion: apps/v1
kind: Deployment
metadata:
annotations:
wave.pusher.com/update-on-config-change: "true"
wave.pusher.com/extra-configmaps: "some-namespace/my-configmap,configmap-in-same-namespace"
wave.pusher.com/extra-secrets: "some-namespace/my-secret,some-other-namespace/foo"
...
```

Wave will watch those ConfigMap or Secret and behave just like if they were
mounted.

## Project Concepts

This section outlines some of the underlying concepts that enable this
Expand Down
24 changes: 24 additions & 0 deletions pkg/core/children.go
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,30 @@ func getChildNamesByType(obj podController) (configMetadataMap, configMetadataMa
}
}
}

// Parse deployment annotations for cms/secrets used inside the pod
if annotations := obj.GetAnnotations(); annotations != nil {
if configMapString, ok := annotations[ExtraConfigMapsAnnotation]; ok {
for _, cm := range strings.Split(configMapString, ",") {
parts := strings.Split(cm, "/")
if len(parts) == 1 {
configMaps[GetNamespacedName(parts[0], obj.GetNamespace())] = configMetadata{required: false, allKeys: true}
} else if len(parts) == 2 {
configMaps[GetNamespacedName(parts[1], parts[0])] = configMetadata{required: false, allKeys: true}
}
}
}
if secretString, ok := annotations[ExtraSecretsAnnotation]; ok {
for _, secret := range strings.Split(secretString, ",") {
parts := strings.Split(secret, "/")
if len(parts) == 1 {
secrets[GetNamespacedName(parts[0], obj.GetNamespace())] = configMetadata{required: false, allKeys: true}
} else if len(parts) == 2 {
secrets[GetNamespacedName(parts[1], parts[0])] = configMetadata{required: false, allKeys: true}
}
}
}
}
}

// Range through all Containers and their respective EnvFrom,
Expand Down
22 changes: 20 additions & 2 deletions pkg/core/children_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,24 @@ var _ = Describe("Wave children Suite", func() {
configMaps, secrets = getChildNamesByType(podControllerDeployment)
})

It("returns ConfigMaps referenced in extra-configmaps annotations", func() {
Expect(configMaps).To(HaveKeyWithValue(GetNamespacedName("test-cm1", "ns1"),
configMetadata{required: false, allKeys: true}))
Expect(configMaps).To(HaveKeyWithValue(GetNamespacedName("test-cm2", "ns2"),
configMetadata{required: false, allKeys: true}))
Expect(configMaps).To(HaveKeyWithValue(GetNamespacedName("local-cm1", podControllerDeployment.GetNamespace()),
configMetadata{required: false, allKeys: true}))
})

It("returns Secrets referenced in extra-secrets annotations", func() {
Expect(secrets).To(HaveKeyWithValue(GetNamespacedName("test-secret1", "ns1"),
configMetadata{required: false, allKeys: true}))
Expect(secrets).To(HaveKeyWithValue(GetNamespacedName("test-secret2", "ns2"),
configMetadata{required: false, allKeys: true}))
Expect(secrets).To(HaveKeyWithValue(GetNamespacedName("local-secret1", podControllerDeployment.GetNamespace()),
configMetadata{required: false, allKeys: true}))
})

It("returns ConfigMaps referenced in Volumes", func() {
Expect(configMaps).To(HaveKeyWithValue(GetNamespacedName(cm1.GetName(), podControllerDeployment.GetNamespace()),
configMetadata{required: true, allKeys: true}))
Expand Down Expand Up @@ -364,8 +382,8 @@ var _ = Describe("Wave children Suite", func() {
})

It("does not return extra children", func() {
Expect(configMaps).To(HaveLen(9))
Expect(secrets).To(HaveLen(9))
Expect(configMaps).To(HaveLen(12))
Expect(secrets).To(HaveLen(12))
})
})

Expand Down
8 changes: 8 additions & 0 deletions pkg/core/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,14 @@ const (
// SchedulingDisabledSchedulerName is the dummy scheduler to disable scheduling of pods
SchedulingDisabledSchedulerName = "wave.pusher.com/invalid"

// ExtraConfigMapsAnnotation is the key of the annotation that contains additional
// ConfigMaps which Wave should watch
ExtraConfigMapsAnnotation = "wave.pusher.com/extra-configmaps"

// ExtraSecretsAnnotation is the key of the annotation that contains additional
// Secrets which Wave should watch
ExtraSecretsAnnotation = "wave.pusher.com/extra-secrets"

// RequiredAnnotation is the key of the annotation on the Deployment that Wave
// checks for before processing the deployment
RequiredAnnotation = "wave.pusher.com/update-on-config-change"
Expand Down
12 changes: 9 additions & 3 deletions test/utils/test_objects.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,20 @@ var labels = map[string]string{
"app": "example",
}

var annotations = map[string]string{
"wave.pusher.com/extra-configmaps": "ns1/test-cm1,ns2/test-cm2,local-cm1",
"wave.pusher.com/extra-secrets": "ns1/test-secret1,ns2/test-secret2,local-secret1",
}

var trueValue = true

// ExampleDeployment is an example Deployment object for use within test suites
var ExampleDeployment = &appsv1.Deployment{
ObjectMeta: metav1.ObjectMeta{
Name: "example",
Namespace: "default",
Labels: labels,
Name: "example",
Namespace: "default",
Labels: labels,
Annotations: annotations,
},
Spec: appsv1.DeploymentSpec{
Selector: &metav1.LabelSelector{
Expand Down

0 comments on commit 7f0e1b0

Please sign in to comment.