From 81f8e5eafbeb26e615a8cb6977c34998944a5e04 Mon Sep 17 00:00:00 2001 From: Yevhen Ivantsov Date: Mon, 11 Dec 2023 19:58:31 +1100 Subject: [PATCH] Add optional postStart hook --- src/main/charts/bamboo/README.md | 1 + .../charts/bamboo/templates/statefulset.yaml | 5 ++ src/main/charts/bamboo/values.yaml | 7 +++ src/main/charts/bitbucket/README.md | 1 + .../bitbucket/templates/statefulset.yaml | 5 ++ src/main/charts/bitbucket/values.yaml | 7 +++ src/main/charts/confluence/README.md | 1 + .../confluence/templates/statefulset.yaml | 5 ++ src/main/charts/confluence/values.yaml | 7 +++ src/main/charts/crowd/README.md | 1 + .../charts/crowd/templates/statefulset.yaml | 5 ++ src/main/charts/crowd/values.yaml | 7 +++ src/main/charts/jira/README.md | 1 + .../charts/jira/templates/statefulset.yaml | 5 ++ src/main/charts/jira/values.yaml | 7 +++ src/test/java/test/LifecycleHooksTest.java | 56 +++++++++++++++++++ .../expected_helm_output/bamboo/output.yaml | 2 + .../bitbucket/output.yaml | 2 + .../confluence/output.yaml | 2 + .../expected_helm_output/crowd/output.yaml | 2 + .../expected_helm_output/jira/output.yaml | 2 + 21 files changed, 131 insertions(+) create mode 100644 src/test/java/test/LifecycleHooksTest.java diff --git a/src/main/charts/bamboo/README.md b/src/main/charts/bamboo/README.md index 878200648..046e7e6d3 100644 --- a/src/main/charts/bamboo/README.md +++ b/src/main/charts/bamboo/README.md @@ -64,6 +64,7 @@ Kubernetes: `>=1.21.x-0` | bamboo.livenessProbe.timeoutSeconds | int | `1` | Number of seconds after which the probe times out | | bamboo.ports.http | int | `8085` | The port on which the Bamboo container listens for HTTP traffic | | bamboo.ports.jms | int | `54663` | JMS port | +| bamboo.postStart | object | `{"command":null}` | PostStart is executed immediately after a container is created. However, there is no guarantee that the hook will execute before the container ENTRYPOINT. See: https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/#container-hooks | | bamboo.readinessProbe.customProbe | object | `{}` | Custom ReadinessProbe to override the default /status httpGet | | bamboo.readinessProbe.enabled | bool | `true` | Whether to apply the readinessProbe check to pod. | | bamboo.readinessProbe.failureThreshold | int | `30` | The number of consecutive failures of the Bamboo container readiness probe before the pod fails readiness checks. | diff --git a/src/main/charts/bamboo/templates/statefulset.yaml b/src/main/charts/bamboo/templates/statefulset.yaml index 89cac651a..078523657 100644 --- a/src/main/charts/bamboo/templates/statefulset.yaml +++ b/src/main/charts/bamboo/templates/statefulset.yaml @@ -246,6 +246,11 @@ spec: {{ end }} {{- end }} lifecycle: + {{- if .Values.bamboo.postStart.command }} + postStart: + exec: + command: ["/bin/sh", "-c", {{- .Values.bamboo.postStart.command | quote }}] + {{- end }} preStop: exec: command: ["sh", "-c", {{ .Values.bamboo.shutdown.command | quote }}] diff --git a/src/main/charts/bamboo/values.yaml b/src/main/charts/bamboo/values.yaml index 8997affc5..21b415d45 100644 --- a/src/main/charts/bamboo/values.yaml +++ b/src/main/charts/bamboo/values.yaml @@ -726,6 +726,13 @@ bamboo: # command: "/shutdown-wait.sh" + # -- PostStart is executed immediately after a container is created. + # However, there is no guarantee that the hook will execute before the container ENTRYPOINT. + # See: https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/#container-hooks + # + postStart: + command: + # Pod resource requests # resources: diff --git a/src/main/charts/bitbucket/README.md b/src/main/charts/bitbucket/README.md index cb7e9cfdb..afa8d51ac 100644 --- a/src/main/charts/bitbucket/README.md +++ b/src/main/charts/bitbucket/README.md @@ -99,6 +99,7 @@ Kubernetes: `>=1.21.x-0` | bitbucket.ports.hazelcast | int | `5701` | The port on which the Hazelcast listens for client traffic | | bitbucket.ports.http | int | `7990` | The port on which the Bitbucket container listens for HTTP traffic | | bitbucket.ports.ssh | int | `7999` | The port on which the Bitbucket SSH service will listen on. Must be within 1024-65535 range | +| bitbucket.postStart | object | `{"command":null}` | PostStart is executed immediately after a container is created. However, there is no guarantee that the hook will execute before the container ENTRYPOINT. See: https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/#container-hooks | | bitbucket.readinessProbe.customProbe | object | `{}` | Custom readinessProbe to override the default /status httpGet | | bitbucket.readinessProbe.enabled | bool | `true` | Whether to apply the readinessProbe check to pod. | | bitbucket.readinessProbe.failureThreshold | int | `60` | The number of consecutive failures of the Bitbucket container readiness probe before the pod fails readiness checks. | diff --git a/src/main/charts/bitbucket/templates/statefulset.yaml b/src/main/charts/bitbucket/templates/statefulset.yaml index 1259d7ecc..b0770a682 100644 --- a/src/main/charts/bitbucket/templates/statefulset.yaml +++ b/src/main/charts/bitbucket/templates/statefulset.yaml @@ -266,6 +266,11 @@ spec: {{ end }} {{- include "bitbucket.additionalEnvironmentVariables" . | nindent 12 }} lifecycle: + {{- if .Values.bitbucket.postStart.command }} + postStart: + exec: + command: ["/bin/sh", "-c", {{- .Values.bitbucket.postStart.command | quote }}] + {{- end }} preStop: exec: command: ["sh", "-c", {{ .Values.bitbucket.shutdown.command | quote }}] diff --git a/src/main/charts/bitbucket/values.yaml b/src/main/charts/bitbucket/values.yaml index 463cbf658..72824c0a7 100644 --- a/src/main/charts/bitbucket/values.yaml +++ b/src/main/charts/bitbucket/values.yaml @@ -831,6 +831,13 @@ bitbucket: # command: "/shutdown-wait.sh" + # -- PostStart is executed immediately after a container is created. + # However, there is no guarantee that the hook will execute before the container ENTRYPOINT. + # See: https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/#container-hooks + # + postStart: + command: + # -- Pod management strategy. Bitbucket Data Center requires the "OrderedReady" value but for Bitbucket Mirrors you # can use the "Parallel" option. # To learn more, visit https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/#pod-management-policies diff --git a/src/main/charts/confluence/README.md b/src/main/charts/confluence/README.md index 32cc68d1c..eebe4b2d3 100644 --- a/src/main/charts/confluence/README.md +++ b/src/main/charts/confluence/README.md @@ -62,6 +62,7 @@ Kubernetes: `>=1.21.x-0` | confluence.livenessProbe.timeoutSeconds | int | `1` | Number of seconds after which the probe times out | | confluence.ports.hazelcast | int | `5701` | The port on which the Confluence container listens for Hazelcast traffic | | confluence.ports.http | int | `8090` | The port on which the Confluence container listens for HTTP traffic | +| confluence.postStart | object | `{"command":null}` | PostStart is executed immediately after a container is created. However, there is no guarantee that the hook will execute before the container ENTRYPOINT. See: https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/#container-hooks | | confluence.readinessProbe.customProbe | object | `{}` | Custom readinessProbe to override the default /status httpGet | | confluence.readinessProbe.enabled | bool | `true` | Whether to apply the readinessProbe check to pod. | | confluence.readinessProbe.failureThreshold | int | `6` | The number of consecutive failures of the Confluence container readiness probe before the pod fails readiness checks. | diff --git a/src/main/charts/confluence/templates/statefulset.yaml b/src/main/charts/confluence/templates/statefulset.yaml index a55942349..d8bca6a62 100644 --- a/src/main/charts/confluence/templates/statefulset.yaml +++ b/src/main/charts/confluence/templates/statefulset.yaml @@ -214,6 +214,11 @@ spec: name: {{ include "common.names.fullname" . }}-jvm-config {{- include "confluence.additionalEnvironmentVariables" . | nindent 12 }} lifecycle: + {{- if .Values.confluence.postStart.command }} + postStart: + exec: + command: ["/bin/sh", "-c", {{- .Values.confluence.postStart.command | quote }}] + {{- end }} preStop: exec: command: ["sh", "-c", {{ .Values.confluence.shutdown.command | quote }}] diff --git a/src/main/charts/confluence/values.yaml b/src/main/charts/confluence/values.yaml index 9db75b8be..b30231b6d 100644 --- a/src/main/charts/confluence/values.yaml +++ b/src/main/charts/confluence/values.yaml @@ -827,6 +827,13 @@ confluence: # command: "/shutdown-wait.sh" + # -- PostStart is executed immediately after a container is created. + # However, there is no guarantee that the hook will execute before the container ENTRYPOINT. + # See: https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/#container-hooks + # + postStart: + command: + # -- The Docker entrypoint.py generates application configuration on # first start; not all of these files are regenerated on subsequent starts. # By default, confluence.cfg.xml is generated only once. Set `forceConfigUpdate` to true diff --git a/src/main/charts/crowd/README.md b/src/main/charts/crowd/README.md index 1817b1d61..baa0ec204 100644 --- a/src/main/charts/crowd/README.md +++ b/src/main/charts/crowd/README.md @@ -51,6 +51,7 @@ Kubernetes: `>=1.21.x-0` | crowd.livenessProbe.periodSeconds | int | `5` | How often (in seconds) the Crowd container liveness probe will run | | crowd.livenessProbe.timeoutSeconds | int | `1` | Number of seconds after which the probe times out | | crowd.ports.http | int | `8095` | The port on which the Crowd container listens for HTTP traffic | +| crowd.postStart | object | `{"command":null}` | PostStart is executed immediately after a container is created. However, there is no guarantee that the hook will execute before the container ENTRYPOINT. See: https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/#container-hooks | | crowd.readinessProbe.customProbe | object | `{}` | Custom readinessProbe to override the default /status httpGet | | crowd.readinessProbe.enabled | bool | `true` | Whether to apply the readinessProbe check to pod. | | crowd.readinessProbe.failureThreshold | int | `10` | The number of consecutive failures of the Crowd container readiness probe before the pod fails readiness checks. | diff --git a/src/main/charts/crowd/templates/statefulset.yaml b/src/main/charts/crowd/templates/statefulset.yaml index da4dd338b..ed19ad762 100644 --- a/src/main/charts/crowd/templates/statefulset.yaml +++ b/src/main/charts/crowd/templates/statefulset.yaml @@ -197,6 +197,11 @@ spec: name: {{ include "common.names.fullname" . }}-jvm-config {{- include "crowd.additionalEnvironmentVariables" . | nindent 12 }} lifecycle: + {{- if .Values.crowd.postStart.command }} + postStart: + exec: + command: ["/bin/sh", "-c", {{- .Values.crowd.postStart.command | quote }}] + {{- end }} preStop: exec: command: ["sh", "-c", {{ .Values.crowd.shutdown.command | quote }}] diff --git a/src/main/charts/crowd/values.yaml b/src/main/charts/crowd/values.yaml index a1dda0a00..2a14dd013 100644 --- a/src/main/charts/crowd/values.yaml +++ b/src/main/charts/crowd/values.yaml @@ -284,6 +284,13 @@ crowd: # command: "/shutdown-wait.sh" + # -- PostStart is executed immediately after a container is created. + # However, there is no guarantee that the hook will execute before the container ENTRYPOINT. + # See: https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/#container-hooks + # + postStart: + command: + # Crowd Pod resource requests # resources: diff --git a/src/main/charts/jira/README.md b/src/main/charts/jira/README.md index 68adaab74..fc86b3dd8 100644 --- a/src/main/charts/jira/README.md +++ b/src/main/charts/jira/README.md @@ -87,6 +87,7 @@ Kubernetes: `>=1.21.x-0` | jira.ports.ehcache | int | `40001` | Ehcache port | | jira.ports.ehcacheobject | int | `40011` | Ehcache object port | | jira.ports.http | int | `8080` | The port on which the Jira container listens for HTTP traffic | +| jira.postStart | object | `{"command":null}` | PostStart is executed immediately after a container is created. However, there is no guarantee that the hook will execute before the container ENTRYPOINT. See: https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/#container-hooks | | jira.readinessProbe.customProbe | object | `{}` | Custom readinessProbe to override the default /status httpGet | | jira.readinessProbe.enabled | bool | `true` | Whether to apply the readinessProbe check to pod. | | jira.readinessProbe.failureThreshold | int | `10` | The number of consecutive failures of the Jira container readiness probe before the pod fails readiness checks. | diff --git a/src/main/charts/jira/templates/statefulset.yaml b/src/main/charts/jira/templates/statefulset.yaml index f9c7b0f0f..92968ae64 100644 --- a/src/main/charts/jira/templates/statefulset.yaml +++ b/src/main/charts/jira/templates/statefulset.yaml @@ -207,6 +207,11 @@ spec: {{ end }} {{- end }} lifecycle: + {{- if .Values.jira.postStart.command }} + postStart: + exec: + command: ["/bin/sh", "-c", {{- .Values.jira.postStart.command | quote }}] + {{- end }} preStop: exec: command: ["sh", "-c", {{ .Values.jira.shutdown.command | quote }}] diff --git a/src/main/charts/jira/values.yaml b/src/main/charts/jira/values.yaml index 977ff4f17..0b0b53084 100644 --- a/src/main/charts/jira/values.yaml +++ b/src/main/charts/jira/values.yaml @@ -640,6 +640,13 @@ jira: # command: "/shutdown-wait.sh" + # -- PostStart is executed immediately after a container is created. + # However, there is no guarantee that the hook will execute before the container ENTRYPOINT. + # See: https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/#container-hooks + # + postStart: + command: + # Pod resource requests # resources: diff --git a/src/test/java/test/LifecycleHooksTest.java b/src/test/java/test/LifecycleHooksTest.java new file mode 100644 index 000000000..e7eba8d83 --- /dev/null +++ b/src/test/java/test/LifecycleHooksTest.java @@ -0,0 +1,56 @@ +package test; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.TestInfo; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.EnumSource; +import test.helm.Helm; +import test.model.Product; + +import java.util.Map; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class LifecycleHooksTest { + + private Helm helm; + + @BeforeEach + void initHelm(TestInfo testInfo) { + helm = new Helm(testInfo); + } + + @ParameterizedTest + @EnumSource(value = Product.class, names = {"bamboo_agent"}, mode = EnumSource.Mode.EXCLUDE) + void default_pre_stop_hook(Product product) throws Exception { + final var resources = helm.captureKubeResourcesFromHelmChart(product, Map.of()); + final var statefulSet = resources.getStatefulSet(product.getHelmReleaseName()); + assertEquals("sh", statefulSet.getContainer().get("lifecycle").get("preStop").get("exec").get("command").get(0).asText()); + assertEquals("-c", statefulSet.getContainer().get("lifecycle").get("preStop").get("exec").get("command").get(1).asText()); + assertEquals("/shutdown-wait.sh", statefulSet.getContainer().get("lifecycle").get("preStop").get("exec").get("command").get(2).asText()); + } + + @ParameterizedTest + @EnumSource(value = Product.class, names = {"bamboo_agent"}, mode = EnumSource.Mode.EXCLUDE) + void custom_pre_stop_hook(Product product) throws Exception { + final var resources = helm.captureKubeResourcesFromHelmChart(product, Map.of( + product.name() + ".shutdown.command", "echo hello" + )); + final var statefulSet = resources.getStatefulSet(product.getHelmReleaseName()); + assertEquals("sh", statefulSet.getContainer().get("lifecycle").get("preStop").get("exec").get("command").get(0).asText()); + assertEquals("-c", statefulSet.getContainer().get("lifecycle").get("preStop").get("exec").get("command").get(1).asText()); + assertEquals("echo hello", statefulSet.getContainer().get("lifecycle").get("preStop").get("exec").get("command").get(2).asText()); + } + + @ParameterizedTest + @EnumSource(value = Product.class, names = {"bamboo_agent"}, mode = EnumSource.Mode.EXCLUDE) + void custom_post_start_hook(Product product) throws Exception { + final var resources = helm.captureKubeResourcesFromHelmChart(product, Map.of( + product.name() + ".postStart.command", "echo hello" + )); + final var statefulSet = resources.getStatefulSet(product.getHelmReleaseName()); + assertEquals("/bin/sh", statefulSet.getContainer().get("lifecycle").get("postStart").get("exec").get("command").get(0).asText()); + assertEquals("-c", statefulSet.getContainer().get("lifecycle").get("postStart").get("exec").get("command").get(1).asText()); + assertEquals("echo hello", statefulSet.getContainer().get("lifecycle").get("postStart").get("exec").get("command").get(2).asText()); + } +} diff --git a/src/test/resources/expected_helm_output/bamboo/output.yaml b/src/test/resources/expected_helm_output/bamboo/output.yaml index 0e3113d28..6ba07c36c 100644 --- a/src/test/resources/expected_helm_output/bamboo/output.yaml +++ b/src/test/resources/expected_helm_output/bamboo/output.yaml @@ -127,6 +127,8 @@ data: ports: http: 8085 jms: 54663 + postStart: + command: null readinessProbe: customProbe: {} enabled: true diff --git a/src/test/resources/expected_helm_output/bitbucket/output.yaml b/src/test/resources/expected_helm_output/bitbucket/output.yaml index 7ffe5a999..071404888 100644 --- a/src/test/resources/expected_helm_output/bitbucket/output.yaml +++ b/src/test/resources/expected_helm_output/bitbucket/output.yaml @@ -196,6 +196,8 @@ data: hazelcast: 5701 http: 7990 ssh: 7999 + postStart: + command: null readinessProbe: customProbe: {} enabled: true diff --git a/src/test/resources/expected_helm_output/confluence/output.yaml b/src/test/resources/expected_helm_output/confluence/output.yaml index 9817a352f..57a54ccdc 100644 --- a/src/test/resources/expected_helm_output/confluence/output.yaml +++ b/src/test/resources/expected_helm_output/confluence/output.yaml @@ -127,6 +127,8 @@ data: ports: hazelcast: 5701 http: 8090 + postStart: + command: null readinessProbe: customProbe: {} enabled: true diff --git a/src/test/resources/expected_helm_output/crowd/output.yaml b/src/test/resources/expected_helm_output/crowd/output.yaml index adfa7e781..c5cb6c620 100644 --- a/src/test/resources/expected_helm_output/crowd/output.yaml +++ b/src/test/resources/expected_helm_output/crowd/output.yaml @@ -115,6 +115,8 @@ data: timeoutSeconds: 1 ports: http: 8095 + postStart: + command: null readinessProbe: customProbe: {} enabled: true diff --git a/src/test/resources/expected_helm_output/jira/output.yaml b/src/test/resources/expected_helm_output/jira/output.yaml index 814d3b1a5..f265e1b2e 100644 --- a/src/test/resources/expected_helm_output/jira/output.yaml +++ b/src/test/resources/expected_helm_output/jira/output.yaml @@ -156,6 +156,8 @@ data: ehcache: 40001 ehcacheobject: 40011 http: 8080 + postStart: + command: null readinessProbe: customProbe: {} enabled: true