You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@solr.apache.org by ho...@apache.org on 2021/09/23 20:09:57 UTC
[solr-operator] branch main updated: Support custom Lifecycle for
Solr & PrometheusExporter containers (#324)
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 <vl...@gmail.com>
AuthorDate: Thu Sep 23 22:09:51 2021 +0200
Support custom Lifecycle for Solr & PrometheusExporter containers (#324)
Co-authored-by: Nick Vladiceanu <ni...@olx.com>
Co-authored-by: Houston Putman <ho...@apache.org>
---
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: []