Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,13 @@ All notable changes to this project will be documented in this file.

## [Unreleased]

### Added

- Support the `restarter.stackable.tech/ignore` annotation on ConfigMaps and Secrets to exclude
them from the restarter controller ([#410]).

[#410]: https://github.com/stackabletech/commons-operator/pull/410

## [26.3.0] - 2026-03-16

## [26.3.0-rc1] - 2026-03-16
Expand Down
18 changes: 9 additions & 9 deletions Cargo.nix

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

18 changes: 9 additions & 9 deletions crate-hashes.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

42 changes: 42 additions & 0 deletions docs/modules/commons-operator/pages/restarter.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,45 @@ Label:: `restarter.stackable.tech/enabled`

The operator can restart StatefulSets when any referenced configuration object (ConfigMap or Secret) changes.
To enable this, set the `restarter.stackable.tech/enabled` label on the StatefulSet to `true`.

Annotation:: `restarter.stackable.tech/ignore`

If a resource is only used for initialization or is hot-reloaded and should not trigger a restart, add the annotation `restarter.stackable.tech/ignore: "true"` to the corresponding ConfigMap or Secret:

[source,yaml]
----
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: statefulset-with-enabled-restarter
labels:
restarter.stackable.tech/enabled: "true"
spec:
template:
spec:
volumes:
- name: hot-reloaded-configmap
configMap:
name: hot-reloaded-configmap
- name: hot-reloaded-secret
secret:
secretName: hot-reloaded-secret
...
---
apiVersion: v1
kind: ConfigMap
metadata:
name: hot-reloaded-configmap
annotations:
restarter.stackable.tech/ignore: "true"
...
---
apiVersion: v1
kind: Secret
metadata:
name: hot-reloaded-secret
annotations:
restarter.stackable.tech/ignore: "true"
...
----
22 changes: 17 additions & 5 deletions rust/operator-binary/src/restart_controller/statefulset.rs
Original file line number Diff line number Diff line change
Expand Up @@ -278,7 +278,13 @@ pub async fn get_updated_restarter_annotations(
format!(
"{}/{}",
cm.metadata.uid.as_ref()?,
cm.metadata.resource_version.as_ref()?
if cm.annotations().get("restarter.stackable.tech/ignore")
== Some(&"true".to_owned())
{
"any"
} else {
cm.metadata.resource_version.as_ref()?
}
),
))
}));
Expand Down Expand Up @@ -308,16 +314,22 @@ pub async fn get_updated_restarter_annotations(
annotations.extend(
secret_refs
.flat_map(|secret_ref| secrets.get(&secret_ref))
.flat_map(|cm| {
.flat_map(|secret| {
Some((
format!(
"secret.restarter.stackable.tech/{}",
cm.metadata.name.as_ref()?
secret.metadata.name.as_ref()?
),
format!(
"{}/{}",
cm.metadata.uid.as_ref()?,
cm.metadata.resource_version.as_ref()?
secret.metadata.uid.as_ref()?,
if secret.annotations().get("restarter.stackable.tech/ignore")
== Some(&"true".to_owned())
{
"any"
} else {
secret.metadata.resource_version.as_ref()?
}
),
))
}),
Expand Down
4 changes: 2 additions & 2 deletions tests/templates/kuttl/restarter/10-assert.yaml
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
---
apiVersion: kuttl.dev/v1beta1
kind: TestAssert
timeout: 30
timeout: 120
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: sleep
name: test
status:
readyReplicas: 1
replicas: 1
93 changes: 93 additions & 0 deletions tests/templates/kuttl/restarter/10-create-test-resources.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
---
apiVersion: v1
kind: ConfigMap
metadata:
name: configmap-not-ignored
data:
revision: "1"
---
apiVersion: v1
kind: Secret
metadata:
name: secret-not-ignored
stringData:
revision: "1"
---
apiVersion: v1
kind: ConfigMap
metadata:
name: configmap-ignored
annotations:
restarter.stackable.tech/ignore: "true"
data:
revision: "1"
---
apiVersion: v1
kind: Secret
metadata:
name: secret-ignored
annotations:
restarter.stackable.tech/ignore: "true"
stringData:
revision: "1"
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: test
labels:
restarter.stackable.tech/enabled: "true"
spec:
selector:
matchLabels:
app: test
serviceName: test
replicas: 1
template:
metadata:
labels:
app: test
spec:
serviceAccount: integration-tests-sa
volumes:
- name: configmap-not-ignored
configMap:
name: configmap-not-ignored
- name: secret-not-ignored
secret:
secretName: secret-not-ignored
- name: configmap-ignored
configMap:
name: configmap-ignored
- name: secret-ignored
secret:
secretName: secret-ignored
containers:
- name: test
image: alpine
command:
- sleep
args:
- infinity
volumeMounts:
- mountPath: /config/configmap-not-ignored-subpath/revision
name: configmap-not-ignored
# Use a subPath, so that changes are only visible after a restart.
subPath: revision
- mountPath: /config/secret-not-ignored-subpath/revision
name: secret-not-ignored
# Use a subPath, so that changes are only visible after a restart.
subPath: revision
- mountPath: /config/configmap-ignored
name: configmap-ignored
- mountPath: /config/secret-ignored
name: secret-ignored
- mountPath: /config/configmap-ignored-subpath/revision
name: configmap-ignored
# Use a subPath, so that changes are only visible after a restart.
subPath: revision
- mountPath: /config/secret-ignored-subpath/revision
name: secret-ignored
# Use a subPath, so that changes are only visible after a restart.
subPath: revision
terminationGracePeriodSeconds: 5
44 changes: 0 additions & 44 deletions tests/templates/kuttl/restarter/10-sleep.yaml

This file was deleted.

14 changes: 13 additions & 1 deletion tests/templates/kuttl/restarter/20-assert.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,16 @@ apiVersion: kuttl.dev/v1beta1
kind: TestAssert
timeout: 180
commands:
- script: test "restarted" = $(kubectl exec sleep-0 -c sleep -n $NAMESPACE -- cat /config/property)
- script: |
. ../../../../templates/kuttl/restarter/test-script.sh

# Resources mounted via subPath are not hot-reloaded by Kubernetes.
# It is expected, that the restart controller ignored the annotated resources and that only
# the resources not mounted via subPath were updated.

assert_revision 1 configmap-not-ignored-subpath
assert_revision 1 secret-not-ignored-subpath
assert_revision 1 configmap-ignored-subpath
assert_revision 1 secret-ignored-subpath
assert_revision 2 configmap-ignored
assert_revision 2 secret-ignored
14 changes: 14 additions & 0 deletions tests/templates/kuttl/restarter/20-hot-reload.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
---
apiVersion: v1
kind: ConfigMap
metadata:
name: configmap-ignored
data:
revision: "2"
---
apiVersion: v1
kind: Secret
metadata:
name: secret-ignored
stringData:
revision: "2"
Loading
Loading