This is an automated email from the ASF dual-hosted git repository.

houston pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/solr-operator.git


The following commit(s) were added to refs/heads/main by this push:
     new 38d5ff3  Support custom Lifecycle for Solr & PrometheusExporter 
containers (#324)
38d5ff3 is described below

commit 38d5ff3ad85255fe4859cad9cf10179f9ca5129c
Author: Nick Vladiceanu <[email protected]>
AuthorDate: Thu Sep 23 22:09:51 2021 +0200

    Support custom Lifecycle for Solr & PrometheusExporter containers (#324)
    
    Co-authored-by: Nick Vladiceanu <[email protected]>
    Co-authored-by: Houston Putman <[email protected]>
---
 api/v1beta1/common_types.go                        |   4 +
 api/v1beta1/zz_generated.deepcopy.go               |   5 +
 config/crd/bases/solr.apache.org_solrclouds.yaml   | 134 +++++++++++
 .../solr.apache.org_solrprometheusexporters.yaml   | 134 +++++++++++
 controllers/controller_utils_test.go               |  19 +-
 .../solrcloud_controller_externaldns_test.go       |   3 +-
 controllers/solrcloud_controller_ingress_test.go   |   5 +-
 controllers/solrcloud_controller_test.go           |   8 +-
 controllers/solrcloud_controller_zk_test.go        |   3 +-
 .../solrprometheusexporter_controller_test.go      |  11 +-
 controllers/util/common.go                         |  13 +-
 controllers/util/prometheus_exporter_util.go       |   9 +-
 controllers/util/solr_util.go                      |  30 ++-
 helm/solr-operator/Chart.yaml                      |   9 +-
 helm/solr-operator/crds/crds.yaml                  | 268 +++++++++++++++++++++
 helm/solr/README.md                                |   1 +
 helm/solr/templates/_custom_option_helpers.tpl     |   4 +
 helm/solr/values.yaml                              |   3 +
 18 files changed, 630 insertions(+), 33 deletions(-)

diff --git a/api/v1beta1/common_types.go b/api/v1beta1/common_types.go
index 838b9f5..13984f4 100644
--- a/api/v1beta1/common_types.go
+++ b/api/v1beta1/common_types.go
@@ -110,6 +110,10 @@ type PodOptions struct {
        // +optional
        PriorityClassName string `json:"priorityClassName,omitempty"`
 
+       // Lifecycle for the main container
+       // +optional
+       Lifecycle *corev1.Lifecycle `json:"lifecycle,omitempty"`
+
        // Sidecar containers to run in the pod. These are in addition to the 
Solr Container
        // +optional
        SidecarContainers []corev1.Container 
`json:"sidecarContainers,omitempty"`
diff --git a/api/v1beta1/zz_generated.deepcopy.go 
b/api/v1beta1/zz_generated.deepcopy.go
index 6560597..9fb0fd9 100644
--- a/api/v1beta1/zz_generated.deepcopy.go
+++ b/api/v1beta1/zz_generated.deepcopy.go
@@ -465,6 +465,11 @@ func (in *PodOptions) DeepCopyInto(out *PodOptions) {
                *out = new(v1.Probe)
                (*in).DeepCopyInto(*out)
        }
+       if in.Lifecycle != nil {
+               in, out := &in.Lifecycle, &out.Lifecycle
+               *out = new(v1.Lifecycle)
+               (*in).DeepCopyInto(*out)
+       }
        if in.SidecarContainers != nil {
                in, out := &in.SidecarContainers, &out.SidecarContainers
                *out = make([]v1.Container, len(*in))
diff --git a/config/crd/bases/solr.apache.org_solrclouds.yaml 
b/config/crd/bases/solr.apache.org_solrclouds.yaml
index 8632db7..bdd7eab 100644
--- a/config/crd/bases/solr.apache.org_solrclouds.yaml
+++ b/config/crd/bases/solr.apache.org_solrclouds.yaml
@@ -1335,6 +1335,140 @@ spec:
                           type: string
                         description: Labels to be added for pods.
                         type: object
+                      lifecycle:
+                        description: Lifecycle for the main container
+                        properties:
+                          postStart:
+                            description: 'PostStart is called immediately 
after a container is created. If the handler fails, the container is terminated 
and restarted according to its restart policy. Other management of the 
container blocks until the hook completes. More info: 
https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/#container-hooks'
+                            properties:
+                              exec:
+                                description: One and only one of the following 
should be specified. Exec specifies the action to take.
+                                properties:
+                                  command:
+                                    description: Command is the command line 
to execute inside the container, the working directory for the command  is root 
('/') in the container's filesystem. The command is simply exec'd, it is not 
run inside a shell, so traditional shell instructions ('|', etc) won't work. To 
use a shell, you need to explicitly call out to that shell. Exit status of 0 is 
treated as live/healthy and non-zero is unhealthy.
+                                    items:
+                                      type: string
+                                    type: array
+                                type: object
+                              httpGet:
+                                description: HTTPGet specifies the http 
request to perform.
+                                properties:
+                                  host:
+                                    description: Host name to connect to, 
defaults to the pod IP. You probably want to set "Host" in httpHeaders instead.
+                                    type: string
+                                  httpHeaders:
+                                    description: Custom headers to set in the 
request. HTTP allows repeated headers.
+                                    items:
+                                      description: HTTPHeader describes a 
custom header to be used in HTTP probes
+                                      properties:
+                                        name:
+                                          description: The header field name
+                                          type: string
+                                        value:
+                                          description: The header field value
+                                          type: string
+                                      required:
+                                      - name
+                                      - value
+                                      type: object
+                                    type: array
+                                  path:
+                                    description: Path to access on the HTTP 
server.
+                                    type: string
+                                  port:
+                                    anyOf:
+                                    - type: integer
+                                    - type: string
+                                    description: Name or number of the port to 
access on the container. Number must be in the range 1 to 65535. Name must be 
an IANA_SVC_NAME.
+                                    x-kubernetes-int-or-string: true
+                                  scheme:
+                                    description: Scheme to use for connecting 
to the host. Defaults to HTTP.
+                                    type: string
+                                required:
+                                - port
+                                type: object
+                              tcpSocket:
+                                description: 'TCPSocket specifies an action 
involving a TCP port. TCP hooks not yet supported TODO: implement a realistic 
TCP lifecycle hook'
+                                properties:
+                                  host:
+                                    description: 'Optional: Host name to 
connect to, defaults to the pod IP.'
+                                    type: string
+                                  port:
+                                    anyOf:
+                                    - type: integer
+                                    - type: string
+                                    description: Number or name of the port to 
access on the container. Number must be in the range 1 to 65535. Name must be 
an IANA_SVC_NAME.
+                                    x-kubernetes-int-or-string: true
+                                required:
+                                - port
+                                type: object
+                            type: object
+                          preStop:
+                            description: 'PreStop is called immediately before 
a container is terminated due to an API request or management event such as 
liveness/startup probe failure, preemption, resource contention, etc. The 
handler is not called if the container crashes or exits. The reason for 
termination is passed to the handler. The Pod''s termination grace period 
countdown begins before the PreStop hooked is executed. Regardless of the 
outcome of the handler, the container will  [...]
+                            properties:
+                              exec:
+                                description: One and only one of the following 
should be specified. Exec specifies the action to take.
+                                properties:
+                                  command:
+                                    description: Command is the command line 
to execute inside the container, the working directory for the command  is root 
('/') in the container's filesystem. The command is simply exec'd, it is not 
run inside a shell, so traditional shell instructions ('|', etc) won't work. To 
use a shell, you need to explicitly call out to that shell. Exit status of 0 is 
treated as live/healthy and non-zero is unhealthy.
+                                    items:
+                                      type: string
+                                    type: array
+                                type: object
+                              httpGet:
+                                description: HTTPGet specifies the http 
request to perform.
+                                properties:
+                                  host:
+                                    description: Host name to connect to, 
defaults to the pod IP. You probably want to set "Host" in httpHeaders instead.
+                                    type: string
+                                  httpHeaders:
+                                    description: Custom headers to set in the 
request. HTTP allows repeated headers.
+                                    items:
+                                      description: HTTPHeader describes a 
custom header to be used in HTTP probes
+                                      properties:
+                                        name:
+                                          description: The header field name
+                                          type: string
+                                        value:
+                                          description: The header field value
+                                          type: string
+                                      required:
+                                      - name
+                                      - value
+                                      type: object
+                                    type: array
+                                  path:
+                                    description: Path to access on the HTTP 
server.
+                                    type: string
+                                  port:
+                                    anyOf:
+                                    - type: integer
+                                    - type: string
+                                    description: Name or number of the port to 
access on the container. Number must be in the range 1 to 65535. Name must be 
an IANA_SVC_NAME.
+                                    x-kubernetes-int-or-string: true
+                                  scheme:
+                                    description: Scheme to use for connecting 
to the host. Defaults to HTTP.
+                                    type: string
+                                required:
+                                - port
+                                type: object
+                              tcpSocket:
+                                description: 'TCPSocket specifies an action 
involving a TCP port. TCP hooks not yet supported TODO: implement a realistic 
TCP lifecycle hook'
+                                properties:
+                                  host:
+                                    description: 'Optional: Host name to 
connect to, defaults to the pod IP.'
+                                    type: string
+                                  port:
+                                    anyOf:
+                                    - type: integer
+                                    - type: string
+                                    description: Number or name of the port to 
access on the container. Number must be in the range 1 to 65535. Name must be 
an IANA_SVC_NAME.
+                                    x-kubernetes-int-or-string: true
+                                required:
+                                - port
+                                type: object
+                            type: object
+                        type: object
                       livenessProbe:
                         description: Liveness probe parameters
                         properties:
diff --git a/config/crd/bases/solr.apache.org_solrprometheusexporters.yaml 
b/config/crd/bases/solr.apache.org_solrprometheusexporters.yaml
index e8d9f9b..eb1a9e4 100644
--- a/config/crd/bases/solr.apache.org_solrprometheusexporters.yaml
+++ b/config/crd/bases/solr.apache.org_solrprometheusexporters.yaml
@@ -1277,6 +1277,140 @@ spec:
                           type: string
                         description: Labels to be added for pods.
                         type: object
+                      lifecycle:
+                        description: Lifecycle for the main container
+                        properties:
+                          postStart:
+                            description: 'PostStart is called immediately 
after a container is created. If the handler fails, the container is terminated 
and restarted according to its restart policy. Other management of the 
container blocks until the hook completes. More info: 
https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/#container-hooks'
+                            properties:
+                              exec:
+                                description: One and only one of the following 
should be specified. Exec specifies the action to take.
+                                properties:
+                                  command:
+                                    description: Command is the command line 
to execute inside the container, the working directory for the command  is root 
('/') in the container's filesystem. The command is simply exec'd, it is not 
run inside a shell, so traditional shell instructions ('|', etc) won't work. To 
use a shell, you need to explicitly call out to that shell. Exit status of 0 is 
treated as live/healthy and non-zero is unhealthy.
+                                    items:
+                                      type: string
+                                    type: array
+                                type: object
+                              httpGet:
+                                description: HTTPGet specifies the http 
request to perform.
+                                properties:
+                                  host:
+                                    description: Host name to connect to, 
defaults to the pod IP. You probably want to set "Host" in httpHeaders instead.
+                                    type: string
+                                  httpHeaders:
+                                    description: Custom headers to set in the 
request. HTTP allows repeated headers.
+                                    items:
+                                      description: HTTPHeader describes a 
custom header to be used in HTTP probes
+                                      properties:
+                                        name:
+                                          description: The header field name
+                                          type: string
+                                        value:
+                                          description: The header field value
+                                          type: string
+                                      required:
+                                      - name
+                                      - value
+                                      type: object
+                                    type: array
+                                  path:
+                                    description: Path to access on the HTTP 
server.
+                                    type: string
+                                  port:
+                                    anyOf:
+                                    - type: integer
+                                    - type: string
+                                    description: Name or number of the port to 
access on the container. Number must be in the range 1 to 65535. Name must be 
an IANA_SVC_NAME.
+                                    x-kubernetes-int-or-string: true
+                                  scheme:
+                                    description: Scheme to use for connecting 
to the host. Defaults to HTTP.
+                                    type: string
+                                required:
+                                - port
+                                type: object
+                              tcpSocket:
+                                description: 'TCPSocket specifies an action 
involving a TCP port. TCP hooks not yet supported TODO: implement a realistic 
TCP lifecycle hook'
+                                properties:
+                                  host:
+                                    description: 'Optional: Host name to 
connect to, defaults to the pod IP.'
+                                    type: string
+                                  port:
+                                    anyOf:
+                                    - type: integer
+                                    - type: string
+                                    description: Number or name of the port to 
access on the container. Number must be in the range 1 to 65535. Name must be 
an IANA_SVC_NAME.
+                                    x-kubernetes-int-or-string: true
+                                required:
+                                - port
+                                type: object
+                            type: object
+                          preStop:
+                            description: 'PreStop is called immediately before 
a container is terminated due to an API request or management event such as 
liveness/startup probe failure, preemption, resource contention, etc. The 
handler is not called if the container crashes or exits. The reason for 
termination is passed to the handler. The Pod''s termination grace period 
countdown begins before the PreStop hooked is executed. Regardless of the 
outcome of the handler, the container will  [...]
+                            properties:
+                              exec:
+                                description: One and only one of the following 
should be specified. Exec specifies the action to take.
+                                properties:
+                                  command:
+                                    description: Command is the command line 
to execute inside the container, the working directory for the command  is root 
('/') in the container's filesystem. The command is simply exec'd, it is not 
run inside a shell, so traditional shell instructions ('|', etc) won't work. To 
use a shell, you need to explicitly call out to that shell. Exit status of 0 is 
treated as live/healthy and non-zero is unhealthy.
+                                    items:
+                                      type: string
+                                    type: array
+                                type: object
+                              httpGet:
+                                description: HTTPGet specifies the http 
request to perform.
+                                properties:
+                                  host:
+                                    description: Host name to connect to, 
defaults to the pod IP. You probably want to set "Host" in httpHeaders instead.
+                                    type: string
+                                  httpHeaders:
+                                    description: Custom headers to set in the 
request. HTTP allows repeated headers.
+                                    items:
+                                      description: HTTPHeader describes a 
custom header to be used in HTTP probes
+                                      properties:
+                                        name:
+                                          description: The header field name
+                                          type: string
+                                        value:
+                                          description: The header field value
+                                          type: string
+                                      required:
+                                      - name
+                                      - value
+                                      type: object
+                                    type: array
+                                  path:
+                                    description: Path to access on the HTTP 
server.
+                                    type: string
+                                  port:
+                                    anyOf:
+                                    - type: integer
+                                    - type: string
+                                    description: Name or number of the port to 
access on the container. Number must be in the range 1 to 65535. Name must be 
an IANA_SVC_NAME.
+                                    x-kubernetes-int-or-string: true
+                                  scheme:
+                                    description: Scheme to use for connecting 
to the host. Defaults to HTTP.
+                                    type: string
+                                required:
+                                - port
+                                type: object
+                              tcpSocket:
+                                description: 'TCPSocket specifies an action 
involving a TCP port. TCP hooks not yet supported TODO: implement a realistic 
TCP lifecycle hook'
+                                properties:
+                                  host:
+                                    description: 'Optional: Host name to 
connect to, defaults to the pod IP.'
+                                    type: string
+                                  port:
+                                    anyOf:
+                                    - type: integer
+                                    - type: string
+                                    description: Number or name of the port to 
access on the container. Number must be in the range 1 to 65535. Name must be 
an IANA_SVC_NAME.
+                                    x-kubernetes-int-or-string: true
+                                required:
+                                - port
+                                type: object
+                            type: object
+                        type: object
                       livenessProbe:
                         description: Liveness probe parameters
                         properties:
diff --git a/controllers/controller_utils_test.go 
b/controllers/controller_utils_test.go
index a7279d6..db69fae 100644
--- a/controllers/controller_utils_test.go
+++ b/controllers/controller_utils_test.go
@@ -19,10 +19,11 @@ package controllers
 
 import (
        "fmt"
+       "testing"
+
        "github.com/apache/solr-operator/controllers/util"
        zkv1beta1 
"github.com/pravega/zookeeper-operator/pkg/apis/zookeeper/v1beta1"
        metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
-       "testing"
 
        solr "github.com/apache/solr-operator/api/v1beta1"
        "github.com/onsi/gomega"
@@ -276,6 +277,10 @@ func testPodProbe(t *testing.T, expectedProbe 
*corev1.Probe, foundProbe *corev1.
        assert.EqualValuesf(t, expectedProbe, foundProbe, "Incorrect default 
container %s probe", probeType)
 }
 
+func testPodLifecycle(t *testing.T, expectedLifecycle *corev1.Lifecycle, 
foundLifecycle *corev1.Lifecycle) {
+       assert.EqualValuesf(t, expectedLifecycle, foundLifecycle, "Expected 
Lifecycle and found Lifecyle don't match")
+}
+
 func testMapsEqual(t *testing.T, mapName string, expected map[string]string, 
found map[string]string) {
        assert.Equal(t, expected, found, "Expected and found %s are not the 
same", mapName)
 }
@@ -520,6 +525,18 @@ var (
                        },
                },
        }
+       testLifecycle = &corev1.Lifecycle{
+               PostStart: &corev1.Handler{
+                       Exec: &corev1.ExecAction{
+                               Command: []string{"/bin/sh", "-c", "echo Hello 
from the postStart handler"},
+                       },
+               },
+               PreStop: &corev1.Handler{
+                       Exec: &corev1.ExecAction{
+                               Command: []string{"/bin/sh", "-c", "echo Hello 
from the preStop handler"},
+                       },
+               },
+       }
        testTolerations = []corev1.Toleration{
                {
                        Effect:   "NoSchedule",
diff --git a/controllers/solrcloud_controller_externaldns_test.go 
b/controllers/solrcloud_controller_externaldns_test.go
index 3a68cd4..696c769 100644
--- a/controllers/solrcloud_controller_externaldns_test.go
+++ b/controllers/solrcloud_controller_externaldns_test.go
@@ -18,9 +18,10 @@
 package controllers
 
 import (
-       "k8s.io/apimachinery/pkg/types"
        "testing"
 
+       "k8s.io/apimachinery/pkg/types"
+
        "github.com/apache/solr-operator/controllers/util"
        "github.com/stretchr/testify/assert"
 
diff --git a/controllers/solrcloud_controller_ingress_test.go 
b/controllers/solrcloud_controller_ingress_test.go
index a86a5c1..fc6e6eb 100644
--- a/controllers/solrcloud_controller_ingress_test.go
+++ b/controllers/solrcloud_controller_ingress_test.go
@@ -18,11 +18,12 @@
 package controllers
 
 import (
-       extv1 "k8s.io/api/extensions/v1beta1"
-       "k8s.io/apimachinery/pkg/types"
        "strconv"
        "testing"
 
+       extv1 "k8s.io/api/extensions/v1beta1"
+       "k8s.io/apimachinery/pkg/types"
+
        "github.com/apache/solr-operator/controllers/util"
        "github.com/stretchr/testify/assert"
 
diff --git a/controllers/solrcloud_controller_test.go 
b/controllers/solrcloud_controller_test.go
index 5a9ecdb..353876d 100644
--- a/controllers/solrcloud_controller_test.go
+++ b/controllers/solrcloud_controller_test.go
@@ -23,6 +23,9 @@ import (
        "strconv"
        "time"
 
+       "strings"
+       "testing"
+
        solr "github.com/apache/solr-operator/api/v1beta1"
        "github.com/apache/solr-operator/controllers/util"
        "github.com/onsi/gomega"
@@ -36,8 +39,6 @@ import (
        ctrl "sigs.k8s.io/controller-runtime"
        "sigs.k8s.io/controller-runtime/pkg/manager"
        "sigs.k8s.io/controller-runtime/pkg/reconcile"
-       "strings"
-       "testing"
 )
 
 var _ reconcile.Reconciler = &SolrCloudReconciler{}
@@ -206,6 +207,7 @@ func TestCustomKubeOptionsCloudReconcile(t *testing.T) {
                                        LivenessProbe:                 
testProbeLivenessNonDefaults,
                                        ReadinessProbe:                
testProbeReadinessNonDefaults,
                                        StartupProbe:                  
testProbeStartup,
+                                       Lifecycle:                     
testLifecycle,
                                        PriorityClassName:             
testPriorityClass,
                                        ImagePullSecrets:              
testAdditionalImagePullSecrets,
                                        TerminationGracePeriodSeconds: 
&testTerminationGracePeriodSeconds,
@@ -297,7 +299,7 @@ func TestCustomKubeOptionsCloudReconcile(t *testing.T) {
        testPodProbe(t, testProbeLivenessNonDefaults, 
statefulSet.Spec.Template.Spec.Containers[0].LivenessProbe, "liveness")
        testPodProbe(t, testProbeReadinessNonDefaults, 
statefulSet.Spec.Template.Spec.Containers[0].ReadinessProbe, "readiness")
        testPodProbe(t, testProbeStartup, 
statefulSet.Spec.Template.Spec.Containers[0].StartupProbe, "startup")
-       assert.Equal(t, []string{"solr", "stop", "-p", "8983"}, 
statefulSet.Spec.Template.Spec.Containers[0].Lifecycle.PreStop.Exec.Command, 
"Incorrect pre-stop command")
+       testPodLifecycle(t, testLifecycle, 
statefulSet.Spec.Template.Spec.Containers[0].Lifecycle)
        testPodTolerations(t, testTolerations, 
statefulSet.Spec.Template.Spec.Tolerations)
        assert.EqualValues(t, testPriorityClass, 
statefulSet.Spec.Template.Spec.PriorityClassName, "Incorrect Priority class 
name for Pod Spec")
        assert.ElementsMatch(t, append(testAdditionalImagePullSecrets, 
corev1.LocalObjectReference{Name: testImagePullSecretName}), 
statefulSet.Spec.Template.Spec.ImagePullSecrets, "Incorrect imagePullSecrets")
diff --git a/controllers/solrcloud_controller_zk_test.go 
b/controllers/solrcloud_controller_zk_test.go
index 03aab7e..ff75e24 100644
--- a/controllers/solrcloud_controller_zk_test.go
+++ b/controllers/solrcloud_controller_zk_test.go
@@ -19,13 +19,14 @@ package controllers
 
 import (
        "fmt"
+       "testing"
+
        "github.com/apache/solr-operator/controllers/util"
        zkv1beta1 
"github.com/pravega/zookeeper-operator/pkg/apis/zookeeper/v1beta1"
        "github.com/pravega/zookeeper-operator/pkg/controller/zookeepercluster"
        appsv1 "k8s.io/api/apps/v1"
        corev1 "k8s.io/api/core/v1"
        "k8s.io/apimachinery/pkg/types"
-       "testing"
 
        "github.com/stretchr/testify/assert"
 
diff --git a/controllers/solrprometheusexporter_controller_test.go 
b/controllers/solrprometheusexporter_controller_test.go
index d4b3a8d..5432133 100644
--- a/controllers/solrprometheusexporter_controller_test.go
+++ b/controllers/solrprometheusexporter_controller_test.go
@@ -20,6 +20,10 @@ package controllers
 import (
        "crypto/md5"
        "fmt"
+       "strings"
+       "testing"
+       "time"
+
        solr "github.com/apache/solr-operator/api/v1beta1"
        "github.com/apache/solr-operator/controllers/util"
        "github.com/onsi/gomega"
@@ -34,9 +38,6 @@ import (
        "sigs.k8s.io/controller-runtime/pkg/client"
        "sigs.k8s.io/controller-runtime/pkg/manager"
        "sigs.k8s.io/controller-runtime/pkg/reconcile"
-       "strings"
-       "testing"
-       "time"
 )
 
 var _ reconcile.Reconciler = &SolrPrometheusExporterReconciler{}
@@ -68,6 +69,7 @@ func TestMetricsReconcileWithoutExporterConfig(t *testing.T) {
                                        TerminationGracePeriodSeconds: 
&testTerminationGracePeriodSeconds,
                                        LivenessProbe:                 
testProbeLivenessNonDefaults,
                                        ReadinessProbe:                
testProbeReadinessNonDefaults,
+                                       Lifecycle:                     
testLifecycle,
                                },
                        },
                        ExporterEntrypoint: "/test/entry-point",
@@ -137,6 +139,7 @@ func TestMetricsReconcileWithoutExporterConfig(t 
*testing.T) {
 
        testPodProbe(t, testProbeLivenessNonDefaults, 
deployment.Spec.Template.Spec.Containers[0].LivenessProbe, "liveness")
        testPodProbe(t, testProbeReadinessNonDefaults, 
deployment.Spec.Template.Spec.Containers[0].ReadinessProbe, "readiness")
+       testPodLifecycle(t, testLifecycle, 
deployment.Spec.Template.Spec.Containers[0].Lifecycle)
        assert.Nilf(t, 
deployment.Spec.Template.Spec.Containers[0].StartupProbe, "%s probe should be 
nil since it was not specified", "startup")
 
        // Check the Service
@@ -160,6 +163,7 @@ func TestMetricsReconcileWithExporterConfig(t *testing.T) {
                                        NodeSelector:      testNodeSelectors,
                                        PriorityClassName: testPriorityClass,
                                        StartupProbe:      testProbeStartup,
+                                       Lifecycle:         testLifecycle,
                                },
                                DeploymentOptions: &solr.DeploymentOptions{
                                        Annotations: testDeploymentAnnotations,
@@ -252,6 +256,7 @@ func TestMetricsReconcileWithExporterConfig(t *testing.T) {
                FailureThreshold:    3,
        }, deployment.Spec.Template.Spec.Containers[0].LivenessProbe, 
"liveness")
        testPodProbe(t, testProbeStartup, 
deployment.Spec.Template.Spec.Containers[0].StartupProbe, "startup")
+       testPodLifecycle(t, testLifecycle, 
deployment.Spec.Template.Spec.Containers[0].Lifecycle)
        assert.Nilf(t, 
deployment.Spec.Template.Spec.Containers[0].ReadinessProbe, "%s probe should be 
nil since it was not specified", "readiness")
 
        // Check the Service
diff --git a/controllers/util/common.go b/controllers/util/common.go
index 45074d4..1ef1ea6 100644
--- a/controllers/util/common.go
+++ b/controllers/util/common.go
@@ -18,6 +18,10 @@
 package util
 
 import (
+       "reflect"
+       "strconv"
+       "strings"
+
        "github.com/go-logr/logr"
        appsv1 "k8s.io/api/apps/v1"
        corev1 "k8s.io/api/core/v1"
@@ -25,10 +29,7 @@ import (
        metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
        "k8s.io/apimachinery/pkg/runtime"
        "k8s.io/utils/pointer"
-       "reflect"
        "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
-       "strconv"
-       "strings"
 )
 
 // CopyLabelsAndAnnotations copies the labels and annotations from one object 
to another.
@@ -559,6 +560,12 @@ func CopyPodContainers(fromPtr, toPtr *[]corev1.Container, 
basePath string, logg
                                to[i].StartupProbe = from[i].StartupProbe
                        }
 
+                       if !DeepEqualWithNils(to[i].Lifecycle, 
from[i].Lifecycle) {
+                               requireUpdate = true
+                               logger.Info("Update required because field 
changed", "field", containerBasePath+"Lifecycle", "from", to[i].Lifecycle, 
"to", from[i].Lifecycle)
+                               to[i].Lifecycle = from[i].Lifecycle
+                       }
+
                        if from[i].TerminationMessagePath != "" && 
!DeepEqualWithNils(to[i].TerminationMessagePath, 
from[i].TerminationMessagePath) {
                                requireUpdate = true
                                logger.Info("Update required because field 
changed", "field", containerBasePath+"TerminationMessagePath", "from", 
to[i].TerminationMessagePath, "to", from[i].TerminationMessagePath)
diff --git a/controllers/util/prometheus_exporter_util.go 
b/controllers/util/prometheus_exporter_util.go
index 99ee1d0..f5a122a 100644
--- a/controllers/util/prometheus_exporter_util.go
+++ b/controllers/util/prometheus_exporter_util.go
@@ -18,14 +18,15 @@
 package util
 
 import (
+       "strconv"
+       "strings"
+
        solr "github.com/apache/solr-operator/api/v1beta1"
        appsv1 "k8s.io/api/apps/v1"
        corev1 "k8s.io/api/core/v1"
        netv1 "k8s.io/api/networking/v1beta1"
        metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
        "k8s.io/apimachinery/pkg/util/intstr"
-       "strconv"
-       "strings"
 )
 
 const (
@@ -322,6 +323,10 @@ func 
GenerateSolrPrometheusExporterDeployment(solrPrometheusExporter *solr.SolrP
                if customPodOptions.LivenessProbe != nil {
                        metricsContainer.LivenessProbe = 
customizeProbe(metricsContainer.LivenessProbe, *customPodOptions.LivenessProbe)
                }
+
+               if customPodOptions.Lifecycle != nil {
+                       metricsContainer.Lifecycle = customPodOptions.Lifecycle
+               }
        }
 
        // Enrich the deployment definition to allow the exporter to make 
requests to TLS enabled Solr pods
diff --git a/controllers/util/solr_util.go b/controllers/util/solr_util.go
index d686e0b..5362123 100644
--- a/controllers/util/solr_util.go
+++ b/controllers/util/solr_util.go
@@ -22,18 +22,19 @@ import (
        b64 "encoding/base64"
        "encoding/json"
        "fmt"
-       solr "github.com/apache/solr-operator/api/v1beta1"
-       appsv1 "k8s.io/api/apps/v1"
-       corev1 "k8s.io/api/core/v1"
-       netv1 "k8s.io/api/networking/v1beta1"
-       metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
-       "k8s.io/apimachinery/pkg/util/intstr"
        "math/rand"
        "regexp"
        "sort"
        "strconv"
        "strings"
        "time"
+
+       solr "github.com/apache/solr-operator/api/v1beta1"
+       appsv1 "k8s.io/api/apps/v1"
+       corev1 "k8s.io/api/core/v1"
+       netv1 "k8s.io/api/networking/v1beta1"
+       metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+       "k8s.io/apimachinery/pkg/util/intstr"
 )
 
 const (
@@ -327,6 +328,13 @@ func GenerateStatefulSet(solrCloud *solr.SolrCloud, 
solrCloudStatus *solr.SolrCl
                }
        }
 
+       // Default preStop hook
+       preStop := &corev1.Handler{
+               Exec: &corev1.ExecAction{
+                       Command: []string{"solr", "stop", "-p", 
strconv.Itoa(solrPodPort)},
+               },
+       }
+
        // Add Custom EnvironmentVariables to the solr container
        if nil != customPodOptions {
                envVars = append(envVars, customPodOptions.EnvVariables...)
@@ -422,11 +430,7 @@ func GenerateStatefulSet(solrCloud *solr.SolrCloud, 
solrCloudStatus *solr.SolrCl
                        Env:          envVars,
                        Lifecycle: &corev1.Lifecycle{
                                PostStart: postStart,
-                               PreStop: &corev1.Handler{
-                                       Exec: &corev1.ExecAction{
-                                               Command: []string{"solr", 
"stop", "-p", strconv.Itoa(solrPodPort)},
-                                       },
-                               },
+                               PreStop:   preStop,
                        },
                },
        }
@@ -522,6 +526,10 @@ func GenerateStatefulSet(solrCloud *solr.SolrCloud, 
solrCloudStatus *solr.SolrCl
                        stateful.Spec.Template.Spec.SecurityContext = 
customPodOptions.PodSecurityContext
                }
 
+               if customPodOptions.Lifecycle != nil {
+                       solrContainer.Lifecycle = customPodOptions.Lifecycle
+               }
+
                if customPodOptions.Tolerations != nil {
                        stateful.Spec.Template.Spec.Tolerations = 
customPodOptions.Tolerations
                }
diff --git a/helm/solr-operator/Chart.yaml b/helm/solr-operator/Chart.yaml
index 6962c6a..2d15575 100644
--- a/helm/solr-operator/Chart.yaml
+++ b/helm/solr-operator/Chart.yaml
@@ -55,15 +55,12 @@ annotations:
   # Allowed syntax is described at: 
https://artifacthub.io/docs/topics/annotations/helm/#example
   artifacthub.io/changes: |
     - kind: added
-      description: Addition 1
+      description: Customize the Lifecycle for Solr and PrometheusExporter 
containers
       links:
         - name: Github Issue
-          url: https://github.com/issue-url
-    - kind: changed
-      description: Change 2
-      links:
+          url: https://github.com/apache/solr-operator/issues/322
         - name: Github PR
-          url: https://github.com/pr-url
+          url: https://github.com/apache/solr-operator/pull/324
   artifacthub.io/images: |
     - name: solr-operator
       image: apache/solr-operator:v0.5.0-prerelease
diff --git a/helm/solr-operator/crds/crds.yaml 
b/helm/solr-operator/crds/crds.yaml
index 0d53866..508bd40 100644
--- a/helm/solr-operator/crds/crds.yaml
+++ b/helm/solr-operator/crds/crds.yaml
@@ -2462,6 +2462,140 @@ spec:
                           type: string
                         description: Labels to be added for pods.
                         type: object
+                      lifecycle:
+                        description: Lifecycle for the main container
+                        properties:
+                          postStart:
+                            description: 'PostStart is called immediately 
after a container is created. If the handler fails, the container is terminated 
and restarted according to its restart policy. Other management of the 
container blocks until the hook completes. More info: 
https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/#container-hooks'
+                            properties:
+                              exec:
+                                description: One and only one of the following 
should be specified. Exec specifies the action to take.
+                                properties:
+                                  command:
+                                    description: Command is the command line 
to execute inside the container, the working directory for the command  is root 
('/') in the container's filesystem. The command is simply exec'd, it is not 
run inside a shell, so traditional shell instructions ('|', etc) won't work. To 
use a shell, you need to explicitly call out to that shell. Exit status of 0 is 
treated as live/healthy and non-zero is unhealthy.
+                                    items:
+                                      type: string
+                                    type: array
+                                type: object
+                              httpGet:
+                                description: HTTPGet specifies the http 
request to perform.
+                                properties:
+                                  host:
+                                    description: Host name to connect to, 
defaults to the pod IP. You probably want to set "Host" in httpHeaders instead.
+                                    type: string
+                                  httpHeaders:
+                                    description: Custom headers to set in the 
request. HTTP allows repeated headers.
+                                    items:
+                                      description: HTTPHeader describes a 
custom header to be used in HTTP probes
+                                      properties:
+                                        name:
+                                          description: The header field name
+                                          type: string
+                                        value:
+                                          description: The header field value
+                                          type: string
+                                      required:
+                                      - name
+                                      - value
+                                      type: object
+                                    type: array
+                                  path:
+                                    description: Path to access on the HTTP 
server.
+                                    type: string
+                                  port:
+                                    anyOf:
+                                    - type: integer
+                                    - type: string
+                                    description: Name or number of the port to 
access on the container. Number must be in the range 1 to 65535. Name must be 
an IANA_SVC_NAME.
+                                    x-kubernetes-int-or-string: true
+                                  scheme:
+                                    description: Scheme to use for connecting 
to the host. Defaults to HTTP.
+                                    type: string
+                                required:
+                                - port
+                                type: object
+                              tcpSocket:
+                                description: 'TCPSocket specifies an action 
involving a TCP port. TCP hooks not yet supported TODO: implement a realistic 
TCP lifecycle hook'
+                                properties:
+                                  host:
+                                    description: 'Optional: Host name to 
connect to, defaults to the pod IP.'
+                                    type: string
+                                  port:
+                                    anyOf:
+                                    - type: integer
+                                    - type: string
+                                    description: Number or name of the port to 
access on the container. Number must be in the range 1 to 65535. Name must be 
an IANA_SVC_NAME.
+                                    x-kubernetes-int-or-string: true
+                                required:
+                                - port
+                                type: object
+                            type: object
+                          preStop:
+                            description: 'PreStop is called immediately before 
a container is terminated due to an API request or management event such as 
liveness/startup probe failure, preemption, resource contention, etc. The 
handler is not called if the container crashes or exits. The reason for 
termination is passed to the handler. The Pod''s termination grace period 
countdown begins before the PreStop hooked is executed. Regardless of the 
outcome of the handler, the container will  [...]
+                            properties:
+                              exec:
+                                description: One and only one of the following 
should be specified. Exec specifies the action to take.
+                                properties:
+                                  command:
+                                    description: Command is the command line 
to execute inside the container, the working directory for the command  is root 
('/') in the container's filesystem. The command is simply exec'd, it is not 
run inside a shell, so traditional shell instructions ('|', etc) won't work. To 
use a shell, you need to explicitly call out to that shell. Exit status of 0 is 
treated as live/healthy and non-zero is unhealthy.
+                                    items:
+                                      type: string
+                                    type: array
+                                type: object
+                              httpGet:
+                                description: HTTPGet specifies the http 
request to perform.
+                                properties:
+                                  host:
+                                    description: Host name to connect to, 
defaults to the pod IP. You probably want to set "Host" in httpHeaders instead.
+                                    type: string
+                                  httpHeaders:
+                                    description: Custom headers to set in the 
request. HTTP allows repeated headers.
+                                    items:
+                                      description: HTTPHeader describes a 
custom header to be used in HTTP probes
+                                      properties:
+                                        name:
+                                          description: The header field name
+                                          type: string
+                                        value:
+                                          description: The header field value
+                                          type: string
+                                      required:
+                                      - name
+                                      - value
+                                      type: object
+                                    type: array
+                                  path:
+                                    description: Path to access on the HTTP 
server.
+                                    type: string
+                                  port:
+                                    anyOf:
+                                    - type: integer
+                                    - type: string
+                                    description: Name or number of the port to 
access on the container. Number must be in the range 1 to 65535. Name must be 
an IANA_SVC_NAME.
+                                    x-kubernetes-int-or-string: true
+                                  scheme:
+                                    description: Scheme to use for connecting 
to the host. Defaults to HTTP.
+                                    type: string
+                                required:
+                                - port
+                                type: object
+                              tcpSocket:
+                                description: 'TCPSocket specifies an action 
involving a TCP port. TCP hooks not yet supported TODO: implement a realistic 
TCP lifecycle hook'
+                                properties:
+                                  host:
+                                    description: 'Optional: Host name to 
connect to, defaults to the pod IP.'
+                                    type: string
+                                  port:
+                                    anyOf:
+                                    - type: integer
+                                    - type: string
+                                    description: Number or name of the port to 
access on the container. Number must be in the range 1 to 65535. Name must be 
an IANA_SVC_NAME.
+                                    x-kubernetes-int-or-string: true
+                                required:
+                                - port
+                                type: object
+                            type: object
+                        type: object
                       livenessProbe:
                         description: Liveness probe parameters
                         properties:
@@ -8093,6 +8227,140 @@ spec:
                           type: string
                         description: Labels to be added for pods.
                         type: object
+                      lifecycle:
+                        description: Lifecycle for the main container
+                        properties:
+                          postStart:
+                            description: 'PostStart is called immediately 
after a container is created. If the handler fails, the container is terminated 
and restarted according to its restart policy. Other management of the 
container blocks until the hook completes. More info: 
https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/#container-hooks'
+                            properties:
+                              exec:
+                                description: One and only one of the following 
should be specified. Exec specifies the action to take.
+                                properties:
+                                  command:
+                                    description: Command is the command line 
to execute inside the container, the working directory for the command  is root 
('/') in the container's filesystem. The command is simply exec'd, it is not 
run inside a shell, so traditional shell instructions ('|', etc) won't work. To 
use a shell, you need to explicitly call out to that shell. Exit status of 0 is 
treated as live/healthy and non-zero is unhealthy.
+                                    items:
+                                      type: string
+                                    type: array
+                                type: object
+                              httpGet:
+                                description: HTTPGet specifies the http 
request to perform.
+                                properties:
+                                  host:
+                                    description: Host name to connect to, 
defaults to the pod IP. You probably want to set "Host" in httpHeaders instead.
+                                    type: string
+                                  httpHeaders:
+                                    description: Custom headers to set in the 
request. HTTP allows repeated headers.
+                                    items:
+                                      description: HTTPHeader describes a 
custom header to be used in HTTP probes
+                                      properties:
+                                        name:
+                                          description: The header field name
+                                          type: string
+                                        value:
+                                          description: The header field value
+                                          type: string
+                                      required:
+                                      - name
+                                      - value
+                                      type: object
+                                    type: array
+                                  path:
+                                    description: Path to access on the HTTP 
server.
+                                    type: string
+                                  port:
+                                    anyOf:
+                                    - type: integer
+                                    - type: string
+                                    description: Name or number of the port to 
access on the container. Number must be in the range 1 to 65535. Name must be 
an IANA_SVC_NAME.
+                                    x-kubernetes-int-or-string: true
+                                  scheme:
+                                    description: Scheme to use for connecting 
to the host. Defaults to HTTP.
+                                    type: string
+                                required:
+                                - port
+                                type: object
+                              tcpSocket:
+                                description: 'TCPSocket specifies an action 
involving a TCP port. TCP hooks not yet supported TODO: implement a realistic 
TCP lifecycle hook'
+                                properties:
+                                  host:
+                                    description: 'Optional: Host name to 
connect to, defaults to the pod IP.'
+                                    type: string
+                                  port:
+                                    anyOf:
+                                    - type: integer
+                                    - type: string
+                                    description: Number or name of the port to 
access on the container. Number must be in the range 1 to 65535. Name must be 
an IANA_SVC_NAME.
+                                    x-kubernetes-int-or-string: true
+                                required:
+                                - port
+                                type: object
+                            type: object
+                          preStop:
+                            description: 'PreStop is called immediately before 
a container is terminated due to an API request or management event such as 
liveness/startup probe failure, preemption, resource contention, etc. The 
handler is not called if the container crashes or exits. The reason for 
termination is passed to the handler. The Pod''s termination grace period 
countdown begins before the PreStop hooked is executed. Regardless of the 
outcome of the handler, the container will  [...]
+                            properties:
+                              exec:
+                                description: One and only one of the following 
should be specified. Exec specifies the action to take.
+                                properties:
+                                  command:
+                                    description: Command is the command line 
to execute inside the container, the working directory for the command  is root 
('/') in the container's filesystem. The command is simply exec'd, it is not 
run inside a shell, so traditional shell instructions ('|', etc) won't work. To 
use a shell, you need to explicitly call out to that shell. Exit status of 0 is 
treated as live/healthy and non-zero is unhealthy.
+                                    items:
+                                      type: string
+                                    type: array
+                                type: object
+                              httpGet:
+                                description: HTTPGet specifies the http 
request to perform.
+                                properties:
+                                  host:
+                                    description: Host name to connect to, 
defaults to the pod IP. You probably want to set "Host" in httpHeaders instead.
+                                    type: string
+                                  httpHeaders:
+                                    description: Custom headers to set in the 
request. HTTP allows repeated headers.
+                                    items:
+                                      description: HTTPHeader describes a 
custom header to be used in HTTP probes
+                                      properties:
+                                        name:
+                                          description: The header field name
+                                          type: string
+                                        value:
+                                          description: The header field value
+                                          type: string
+                                      required:
+                                      - name
+                                      - value
+                                      type: object
+                                    type: array
+                                  path:
+                                    description: Path to access on the HTTP 
server.
+                                    type: string
+                                  port:
+                                    anyOf:
+                                    - type: integer
+                                    - type: string
+                                    description: Name or number of the port to 
access on the container. Number must be in the range 1 to 65535. Name must be 
an IANA_SVC_NAME.
+                                    x-kubernetes-int-or-string: true
+                                  scheme:
+                                    description: Scheme to use for connecting 
to the host. Defaults to HTTP.
+                                    type: string
+                                required:
+                                - port
+                                type: object
+                              tcpSocket:
+                                description: 'TCPSocket specifies an action 
involving a TCP port. TCP hooks not yet supported TODO: implement a realistic 
TCP lifecycle hook'
+                                properties:
+                                  host:
+                                    description: 'Optional: Host name to 
connect to, defaults to the pod IP.'
+                                    type: string
+                                  port:
+                                    anyOf:
+                                    - type: integer
+                                    - type: string
+                                    description: Number or name of the port to 
access on the container. Number must be in the range 1 to 65535. Name must be 
an IANA_SVC_NAME.
+                                    x-kubernetes-int-or-string: true
+                                required:
+                                - port
+                                type: object
+                            type: object
+                        type: object
                       livenessProbe:
                         description: Liveness probe parameters
                         properties:
diff --git a/helm/solr/README.md b/helm/solr/README.md
index 4ca49ea..10b15cc 100644
--- a/helm/solr/README.md
+++ b/helm/solr/README.md
@@ -255,6 +255,7 @@ Configure Solr to use a separate TLS certificate for client 
auth.
 | podOptions.livenessProbe | object |  | Custom liveness probe for the Solr 
container |
 | podOptions.readinessProbe | object |  | Custom readiness probe for the Solr 
container |
 | podOptions.startupProbe | object |  | Custom startup probe for the Solr 
container |
+| podOptions.lifecycle | object |  | Custom lifecycle for the Solr container |
 | podOptions.imagePullSecrets | []object |  | List of image pull secrets to 
inject into the Solr pod, in addition to `global.imagePullSecrets` |
 | podOptions.volumes | []object |  | List of additional volumes to attach to 
the Solr pod, and optionally how to mount them to the Solr container |
 | statefulSetOptions.annotations | map[string]string |  | Custom annotations 
to add to the Solr statefulSet |
diff --git a/helm/solr/templates/_custom_option_helpers.tpl 
b/helm/solr/templates/_custom_option_helpers.tpl
index b4d21ce..0e02556 100644
--- a/helm/solr/templates/_custom_option_helpers.tpl
+++ b/helm/solr/templates/_custom_option_helpers.tpl
@@ -82,6 +82,10 @@ readinessProbe:
 startupProbe:
   {{- toYaml .Values.podOptions.startupProbe | nindent 2 }}
 {{ end }}
+{{- if .Values.podOptions.lifecycle -}}
+lifecycle:
+  {{- toYaml .Values.podOptions.lifecycle | nindent 2 }}
+{{ end }}
 {{- if .Values.podOptions.sidecarContainers -}}
 sidecarContainers:
   {{- toYaml .Values.podOptions.sidecarContainers | nindent 2 }}
diff --git a/helm/solr/values.yaml b/helm/solr/values.yaml
index 0473421..0ef711b 100644
--- a/helm/solr/values.yaml
+++ b/helm/solr/values.yaml
@@ -255,6 +255,9 @@ podOptions:
   livenessProbe: {}
   readinessProbe: {}
   startupProbe: {}
+  
+  # Lifecycle for the Solr container
+  lifecycle: {}
 
   imagePullSecrets: []
 

Reply via email to