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: []