Add Readiness and Liveness probes
This commit is contained in:
parent
7f106df949
commit
2c9f630926
|
|
@ -5,6 +5,26 @@ metadata:
|
||||||
spec:
|
spec:
|
||||||
master:
|
master:
|
||||||
image: jenkins/jenkins:lts
|
image: jenkins/jenkins:lts
|
||||||
|
readinessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: /login
|
||||||
|
port: 8080
|
||||||
|
scheme: HTTP
|
||||||
|
failureThreshold: 12
|
||||||
|
initialDelaySeconds: 20
|
||||||
|
periodSeconds: 10
|
||||||
|
successThreshold: 1
|
||||||
|
timeoutSeconds: 5
|
||||||
|
livenessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: /login
|
||||||
|
port: 8080
|
||||||
|
scheme: HTTP
|
||||||
|
initialDelaySeconds: 20
|
||||||
|
failureThreshold: 12
|
||||||
|
periodSeconds: 10
|
||||||
|
successThreshold: 1
|
||||||
|
timeoutSeconds: 5
|
||||||
seedJobs:
|
seedJobs:
|
||||||
- id: jenkins-operator
|
- id: jenkins-operator
|
||||||
targets: "cicd/jobs/*.jenkins"
|
targets: "cicd/jobs/*.jenkins"
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,8 @@ type JenkinsMaster struct {
|
||||||
Annotations map[string]string `json:"masterAnnotations,omitempty"`
|
Annotations map[string]string `json:"masterAnnotations,omitempty"`
|
||||||
Resources corev1.ResourceRequirements `json:"resources,omitempty"`
|
Resources corev1.ResourceRequirements `json:"resources,omitempty"`
|
||||||
Env []corev1.EnvVar `json:"env,omitempty"`
|
Env []corev1.EnvVar `json:"env,omitempty"`
|
||||||
|
LivenessProbe *corev1.Probe `json:"livenessProbe,omitempty"`
|
||||||
|
ReadinessProbe *corev1.Probe `json:"readinessProbe,omitempty"`
|
||||||
// OperatorPlugins contains plugins required by operator
|
// OperatorPlugins contains plugins required by operator
|
||||||
OperatorPlugins map[string][]string `json:"basePlugins,omitempty"`
|
OperatorPlugins map[string][]string `json:"basePlugins,omitempty"`
|
||||||
// Plugins contains plugins required by user
|
// Plugins contains plugins required by user
|
||||||
|
|
|
||||||
|
|
@ -135,6 +135,16 @@ func (in *JenkinsMaster) DeepCopyInto(out *JenkinsMaster) {
|
||||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if in.LivenessProbe != nil {
|
||||||
|
in, out := &in.LivenessProbe, &out.LivenessProbe
|
||||||
|
*out = new(v1.Probe)
|
||||||
|
(*in).DeepCopyInto(*out)
|
||||||
|
}
|
||||||
|
if in.ReadinessProbe != nil {
|
||||||
|
in, out := &in.ReadinessProbe, &out.ReadinessProbe
|
||||||
|
*out = new(v1.Probe)
|
||||||
|
(*in).DeepCopyInto(*out)
|
||||||
|
}
|
||||||
if in.OperatorPlugins != nil {
|
if in.OperatorPlugins != nil {
|
||||||
in, out := &in.OperatorPlugins, &out.OperatorPlugins
|
in, out := &in.OperatorPlugins, &out.OperatorPlugins
|
||||||
*out = make(map[string][]string, len(*in))
|
*out = make(map[string][]string, len(*in))
|
||||||
|
|
|
||||||
|
|
@ -407,6 +407,18 @@ func (r *ReconcileJenkinsBaseConfiguration) isRecreatePodNeeded(currentJenkinsMa
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !reflect.DeepEqual(r.jenkins.Spec.Master.ReadinessProbe, currentJenkinsMasterPod.Spec.Containers[0].ReadinessProbe) {
|
||||||
|
r.logger.Info(fmt.Sprintf("Jenkins pod readinessProbe have changed, actual '%+v' required '%+v' - recreating pod",
|
||||||
|
currentJenkinsMasterPod.Spec.Containers[0].ReadinessProbe, r.jenkins.Spec.Master.ReadinessProbe))
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
if !reflect.DeepEqual(r.jenkins.Spec.Master.LivenessProbe, currentJenkinsMasterPod.Spec.Containers[0].LivenessProbe) {
|
||||||
|
r.logger.Info(fmt.Sprintf("Jenkins pod livenessProbe have changed, actual '%+v' required '%+v' - recreating pod",
|
||||||
|
currentJenkinsMasterPod.Spec.Containers[0].LivenessProbe, r.jenkins.Spec.Master.LivenessProbe))
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
if !reflect.DeepEqual(r.jenkins.Spec.Master.NodeSelector, currentJenkinsMasterPod.Spec.NodeSelector) {
|
if !reflect.DeepEqual(r.jenkins.Spec.Master.NodeSelector, currentJenkinsMasterPod.Spec.NodeSelector) {
|
||||||
r.logger.Info(fmt.Sprintf("Jenkins pod node selector has changed, actual '%+v' required '%+v' - recreating pod",
|
r.logger.Info(fmt.Sprintf("Jenkins pod node selector has changed, actual '%+v' required '%+v' - recreating pod",
|
||||||
currentJenkinsMasterPod.Spec.NodeSelector, r.jenkins.Spec.Master.NodeSelector))
|
currentJenkinsMasterPod.Spec.NodeSelector, r.jenkins.Spec.Master.NodeSelector))
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,6 @@ import (
|
||||||
|
|
||||||
corev1 "k8s.io/api/core/v1"
|
corev1 "k8s.io/api/core/v1"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/apimachinery/pkg/util/intstr"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|
@ -75,9 +74,6 @@ func GetJenkinsMasterPodBaseEnvs() []corev1.EnvVar {
|
||||||
|
|
||||||
// NewJenkinsMasterPod builds Jenkins Master Kubernetes Pod resource
|
// NewJenkinsMasterPod builds Jenkins Master Kubernetes Pod resource
|
||||||
func NewJenkinsMasterPod(objectMeta metav1.ObjectMeta, jenkins *v1alpha1.Jenkins) *corev1.Pod {
|
func NewJenkinsMasterPod(objectMeta metav1.ObjectMeta, jenkins *v1alpha1.Jenkins) *corev1.Pod {
|
||||||
initialDelaySeconds := int32(30)
|
|
||||||
timeoutSeconds := int32(5)
|
|
||||||
failureThreshold := int32(12)
|
|
||||||
runAsUser := jenkinsUserUID
|
runAsUser := jenkinsUserUID
|
||||||
|
|
||||||
objectMeta.Annotations = jenkins.Spec.Master.Annotations
|
objectMeta.Annotations = jenkins.Spec.Master.Annotations
|
||||||
|
|
@ -104,28 +100,8 @@ func NewJenkinsMasterPod(objectMeta metav1.ObjectMeta, jenkins *v1alpha1.Jenkins
|
||||||
"bash",
|
"bash",
|
||||||
fmt.Sprintf("%s/%s", jenkinsScriptsVolumePath, initScriptName),
|
fmt.Sprintf("%s/%s", jenkinsScriptsVolumePath, initScriptName),
|
||||||
},
|
},
|
||||||
LivenessProbe: &corev1.Probe{
|
LivenessProbe: jenkins.Spec.Master.LivenessProbe,
|
||||||
Handler: corev1.Handler{
|
ReadinessProbe: jenkins.Spec.Master.ReadinessProbe,
|
||||||
HTTPGet: &corev1.HTTPGetAction{
|
|
||||||
Path: "/login",
|
|
||||||
Port: intstr.FromString(httpPortName),
|
|
||||||
Scheme: corev1.URISchemeHTTP,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
InitialDelaySeconds: initialDelaySeconds,
|
|
||||||
TimeoutSeconds: timeoutSeconds,
|
|
||||||
FailureThreshold: failureThreshold,
|
|
||||||
},
|
|
||||||
ReadinessProbe: &corev1.Probe{
|
|
||||||
Handler: corev1.Handler{
|
|
||||||
HTTPGet: &corev1.HTTPGetAction{
|
|
||||||
Path: "/login",
|
|
||||||
Port: intstr.FromString(httpPortName),
|
|
||||||
Scheme: corev1.URISchemeHTTP,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
InitialDelaySeconds: initialDelaySeconds,
|
|
||||||
},
|
|
||||||
Ports: []corev1.ContainerPort{
|
Ports: []corev1.ContainerPort{
|
||||||
{
|
{
|
||||||
Name: httpPortName,
|
Name: httpPortName,
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ package jenkins
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"k8s.io/apimachinery/pkg/util/intstr"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
|
||||||
"github.com/jenkinsci/kubernetes-operator/pkg/apis/jenkinsio/v1alpha1"
|
"github.com/jenkinsci/kubernetes-operator/pkg/apis/jenkinsio/v1alpha1"
|
||||||
|
|
@ -136,7 +137,6 @@ func (r *ReconcileJenkins) reconcile(request reconcile.Request, logger logr.Logg
|
||||||
// Error reading the object - requeue the request.
|
// Error reading the object - requeue the request.
|
||||||
return reconcile.Result{}, errors.WithStack(err)
|
return reconcile.Result{}, errors.WithStack(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = r.setDefaults(jenkins, logger)
|
err = r.setDefaults(jenkins, logger)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return reconcile.Result{}, err
|
return reconcile.Result{}, err
|
||||||
|
|
@ -227,6 +227,36 @@ func (r *ReconcileJenkins) setDefaults(jenkins *v1alpha1.Jenkins, logger logr.Lo
|
||||||
changed = true
|
changed = true
|
||||||
jenkins.Spec.Master.ImagePullPolicy = corev1.PullAlways
|
jenkins.Spec.Master.ImagePullPolicy = corev1.PullAlways
|
||||||
}
|
}
|
||||||
|
if jenkins.Spec.Master.ReadinessProbe == nil {
|
||||||
|
logger.Info("Setting default Jenkins readinessProbe")
|
||||||
|
changed = true
|
||||||
|
jenkins.Spec.Master.ReadinessProbe = &corev1.Probe{
|
||||||
|
Handler: corev1.Handler{
|
||||||
|
HTTPGet: &corev1.HTTPGetAction{
|
||||||
|
Path: "/login",
|
||||||
|
Port: intstr.FromString("http"),
|
||||||
|
Scheme: corev1.URISchemeHTTP,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
InitialDelaySeconds: int32(30),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if jenkins.Spec.Master.LivenessProbe == nil {
|
||||||
|
logger.Info("Setting default Jenkins livenessProbe")
|
||||||
|
changed = true
|
||||||
|
jenkins.Spec.Master.LivenessProbe = &corev1.Probe{
|
||||||
|
Handler: corev1.Handler{
|
||||||
|
HTTPGet: &corev1.HTTPGetAction{
|
||||||
|
Path: "/login",
|
||||||
|
Port: intstr.FromString("http"),
|
||||||
|
Scheme: corev1.URISchemeHTTP,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
InitialDelaySeconds: int32(30),
|
||||||
|
TimeoutSeconds: int32(5),
|
||||||
|
FailureThreshold: int32(12),
|
||||||
|
}
|
||||||
|
}
|
||||||
if len(jenkins.Spec.Master.OperatorPlugins) == 0 {
|
if len(jenkins.Spec.Master.OperatorPlugins) == 0 {
|
||||||
logger.Info("Setting default operator plugins")
|
logger.Info("Setting default operator plugins")
|
||||||
changed = true
|
changed = true
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,7 @@ func TestConfiguration(t *testing.T) {
|
||||||
// Deletes test namespace
|
// Deletes test namespace
|
||||||
defer ctx.Cleanup()
|
defer ctx.Cleanup()
|
||||||
|
|
||||||
|
t.Logf("BASE")
|
||||||
jenkinsCRName := "e2e"
|
jenkinsCRName := "e2e"
|
||||||
numberOfExecutors := 6
|
numberOfExecutors := 6
|
||||||
systemMessage := "Configuration as Code integration works!!!"
|
systemMessage := "Configuration as Code integration works!!!"
|
||||||
|
|
@ -42,6 +43,7 @@ func TestConfiguration(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// base
|
// base
|
||||||
|
|
||||||
createUserConfigurationSecret(t, jenkinsCRName, namespace, systemMessageEnvName, systemMessage)
|
createUserConfigurationSecret(t, jenkinsCRName, namespace, systemMessageEnvName, systemMessage)
|
||||||
createUserConfigurationConfigMap(t, jenkinsCRName, namespace, numberOfExecutors, fmt.Sprintf("${%s}", systemMessageEnvName))
|
createUserConfigurationConfigMap(t, jenkinsCRName, namespace, numberOfExecutors, fmt.Sprintf("${%s}", systemMessageEnvName))
|
||||||
jenkins := createJenkinsCR(t, jenkinsCRName, namespace, &[]v1alpha1.SeedJob{mySeedJob.SeedJob})
|
jenkins := createJenkinsCR(t, jenkinsCRName, namespace, &[]v1alpha1.SeedJob{mySeedJob.SeedJob})
|
||||||
|
|
@ -151,6 +153,14 @@ func verifyJenkinsMasterPodAttributes(t *testing.T, jenkins *v1alpha1.Jenkins) {
|
||||||
t.Fatalf("Invalid jenkins pod node selector expected '%+v', actual '%+v'", jenkins.Spec.Master.NodeSelector, jenkinsPod.Spec.NodeSelector)
|
t.Fatalf("Invalid jenkins pod node selector expected '%+v', actual '%+v'", jenkins.Spec.Master.NodeSelector, jenkinsPod.Spec.NodeSelector)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !reflect.DeepEqual(jenkinsPod.Spec.Containers[0].ReadinessProbe, jenkins.Spec.Master.ReadinessProbe) {
|
||||||
|
t.Fatalf("Invalid jenkins pod readinessProbe. Expected '%+v', actual '%+v'", jenkins.Spec.Master.NodeSelector, jenkinsPod.Spec.NodeSelector)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !reflect.DeepEqual(jenkinsPod.Spec.Containers[0].LivenessProbe, jenkins.Spec.Master.LivenessProbe) {
|
||||||
|
t.Fatalf("Invalid jenkins pod livenessProbe. Expected '%+v', actual '%+v'", jenkins.Spec.Master.NodeSelector, jenkinsPod.Spec.NodeSelector)
|
||||||
|
}
|
||||||
|
|
||||||
requiredEnvs := resources.GetJenkinsMasterPodBaseEnvs()
|
requiredEnvs := resources.GetJenkinsMasterPodBaseEnvs()
|
||||||
requiredEnvs = append(requiredEnvs, jenkins.Spec.Master.Env...)
|
requiredEnvs = append(requiredEnvs, jenkins.Spec.Master.Env...)
|
||||||
if !reflect.DeepEqual(jenkinsPod.Spec.Containers[0].Env, requiredEnvs) {
|
if !reflect.DeepEqual(jenkinsPod.Spec.Containers[0].Env, requiredEnvs) {
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ package e2e
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"k8s.io/apimachinery/pkg/util/intstr"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/jenkinsci/kubernetes-operator/pkg/apis/jenkinsio/v1alpha1"
|
"github.com/jenkinsci/kubernetes-operator/pkg/apis/jenkinsio/v1alpha1"
|
||||||
|
|
@ -10,6 +11,7 @@ import (
|
||||||
|
|
||||||
framework "github.com/operator-framework/operator-sdk/pkg/test"
|
framework "github.com/operator-framework/operator-sdk/pkg/test"
|
||||||
"k8s.io/api/core/v1"
|
"k8s.io/api/core/v1"
|
||||||
|
corev1 "k8s.io/api/core/v1"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/apimachinery/pkg/labels"
|
"k8s.io/apimachinery/pkg/labels"
|
||||||
"k8s.io/apimachinery/pkg/types"
|
"k8s.io/apimachinery/pkg/types"
|
||||||
|
|
@ -84,6 +86,28 @@ func createJenkinsCR(t *testing.T, name, namespace string, seedJob *[]v1alpha1.S
|
||||||
Value: "test_env_value",
|
Value: "test_env_value",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
ReadinessProbe: &corev1.Probe{
|
||||||
|
Handler: corev1.Handler{
|
||||||
|
HTTPGet: &corev1.HTTPGetAction{
|
||||||
|
Path: "/login",
|
||||||
|
Port: intstr.FromString("http"),
|
||||||
|
Scheme: corev1.URISchemeHTTP,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
InitialDelaySeconds: int32(50),
|
||||||
|
},
|
||||||
|
LivenessProbe: &corev1.Probe{
|
||||||
|
Handler: corev1.Handler{
|
||||||
|
HTTPGet: &corev1.HTTPGetAction{
|
||||||
|
Path: "/login",
|
||||||
|
Port: intstr.FromString("http"),
|
||||||
|
Scheme: corev1.URISchemeHTTP,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
InitialDelaySeconds: int32(40),
|
||||||
|
TimeoutSeconds: int32(8),
|
||||||
|
FailureThreshold: int32(15),
|
||||||
|
},
|
||||||
},
|
},
|
||||||
SeedJobs: seedJobs,
|
SeedJobs: seedJobs,
|
||||||
},
|
},
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue