Skip to content

Commit

Permalink
add_enhanced_livenessProbe_webhook
Browse files Browse the repository at this point in the history
  • Loading branch information
BH4AWS committed Dec 12, 2023
1 parent fa9a9a0 commit 0b69996
Show file tree
Hide file tree
Showing 4 changed files with 301 additions and 8 deletions.
16 changes: 11 additions & 5 deletions pkg/features/kruise_features.go
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,9 @@ const (

// DeletionProtectionForCRDCascadingGate enable deletionProtection for crd Cascading
DeletionProtectionForCRDCascadingGate featuregate.Feature = "DeletionProtectionForCRDCascadingGate"

// Enables a enhanced livenessProbe solution
EnhancedLivenessProbe featuregate.Feature = "EnhancedLivenessProbe"
)

var defaultFeatureGates = map[featuregate.Feature]featuregate.FeatureSpec{
Expand All @@ -135,11 +138,14 @@ var defaultFeatureGates = map[featuregate.Feature]featuregate.FeatureSpec{
SidecarTerminator: {Default: false, PreRelease: featuregate.Alpha},
PodProbeMarkerGate: {Default: true, PreRelease: featuregate.Alpha},
PreDownloadImageForDaemonSetUpdate: {Default: false, PreRelease: featuregate.Alpha},
CloneSetEventHandlerOptimization: {Default: false, PreRelease: featuregate.Alpha},
PreparingUpdateAsUpdate: {Default: false, PreRelease: featuregate.Alpha},
ImagePullJobGate: {Default: false, PreRelease: featuregate.Alpha},
ResourceDistributionGate: {Default: false, PreRelease: featuregate.Alpha},
DeletionProtectionForCRDCascadingGate: {Default: false, PreRelease: featuregate.Alpha},

CloneSetEventHandlerOptimization: {Default: false, PreRelease: featuregate.Alpha},
PreparingUpdateAsUpdate: {Default: false, PreRelease: featuregate.Alpha},
ImagePullJobGate: {Default: false, PreRelease: featuregate.Alpha},
ResourceDistributionGate: {Default: false, PreRelease: featuregate.Alpha},
DeletionProtectionForCRDCascadingGate: {Default: false, PreRelease: featuregate.Alpha},

EnhancedLivenessProbe: {Default: false, PreRelease: featuregate.Alpha},
}

func init() {
Expand Down
89 changes: 89 additions & 0 deletions pkg/webhook/pod/mutating/enhancedlivenessprobe_handler.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
package mutating

import (
"encoding/json"
"fmt"

admissionv1 "k8s.io/api/admission/v1"
v1 "k8s.io/api/core/v1"
"k8s.io/klog/v2"
"sigs.k8s.io/controller-runtime/pkg/webhook/admission"

"github.com/openkruise/kruise/pkg/features"
"github.com/openkruise/kruise/pkg/util"
utilfeature "github.com/openkruise/kruise/pkg/util/feature"
)

const (
AnnotationUsingEnhancedLiveness = "apps.kruise.io/using-enhanced-liveness"
AnnotationNativeLivenessContext = "apps.kruise.io/livenessprobe-context"
)

type containerLivenessProbe struct {
Name string `json:"name"`
LivenessProbe v1.Probe `json:"livenessProbe"`
}

func (h *PodCreateHandler) enhancedLivenessProbeWhenPodCreate(req admission.Request, pod *v1.Pod) (skip bool, err error) {

if len(req.AdmissionRequest.SubResource) > 0 ||
req.AdmissionRequest.Operation != admissionv1.Create ||
req.AdmissionRequest.Resource.Resource != "pods" {
return true, nil
}

if !util.IsPodOwnedByKruise(pod) && !utilfeature.DefaultFeatureGate.Enabled(features.EnhancedLivenessProbe) {
return true, nil
}

if !usingEnhancedLivenessProbe(pod) {
return true, nil
}

context, err := removeAndBackUpPodContainerLivenessProbe(pod)
if err != nil {
klog.Errorf("Remove pod (%v/%v) container livenessProbe config and backup error: %v", pod.Namespace, pod.Name, err)
return false, err
}
klog.V(3).Infof("Mutating add pod(%s/%s) annotation[%s]=%s", pod.Namespace, pod.Name, AnnotationNativeLivenessContext, context)
return false, nil
}

func removeAndBackUpPodContainerLivenessProbe(pod *v1.Pod) (string, error) {
if len(pod.Spec.Containers) == 0 {
return "", nil
}

containersLivenessProbe := []containerLivenessProbe{}
for index, _ := range pod.Spec.Containers {

Check failure on line 58 in pkg/webhook/pod/mutating/enhancedlivenessprobe_handler.go

View workflow job for this annotation

GitHub Actions / golangci-lint

File is not `gofmt`-ed with `-s` (gofmt)
getContainer := &pod.Spec.Containers[index]
if getContainer.LivenessProbe == nil {
continue
}
containersLivenessProbe = append(containersLivenessProbe, containerLivenessProbe{
Name: getContainer.Name,
LivenessProbe: *getContainer.LivenessProbe,
})
getContainer.LivenessProbe = nil
}

if len(containersLivenessProbe) == 0 {
return "", nil
}
containersLivenessProbeRaw, err := json.Marshal(containersLivenessProbe)
if err != nil {
klog.Errorf("Failed to json marshal %v for pod: %v/%v, err: %v",
containersLivenessProbe, pod.Namespace, pod.Name, err)
return "", fmt.Errorf("Failed to json marshal %v for pod: %v/%v, err: %v",
containersLivenessProbe, pod.Namespace, pod.Name, err)
}
if pod.Annotations == nil {
pod.Annotations = map[string]string{}
}
pod.Annotations[AnnotationNativeLivenessContext] = string(containersLivenessProbeRaw)
return pod.Annotations[AnnotationNativeLivenessContext], nil
}

func usingEnhancedLivenessProbe(pod *v1.Pod) bool {
return pod.Annotations[AnnotationUsingEnhancedLiveness] == "true"
}
188 changes: 188 additions & 0 deletions pkg/webhook/pod/mutating/enhancedlivenessprobe_handler_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,188 @@
package mutating

import (
"reflect"
"testing"

corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/intstr"
)

func TestRemoveAndBackUpPodContainerLivenessProbe(t *testing.T) {

testCases := []struct {
name string
pod *corev1.Pod
expectResult string
}{
{
name: "livenessProbe configuration for standard container",
pod: &corev1.Pod{
ObjectMeta: metav1.ObjectMeta{
Name: "pod1",
Namespace: "namespace1",
},
Spec: corev1.PodSpec{
Containers: []corev1.Container{
{
Name: "c1",
LivenessProbe: &corev1.Probe{
FailureThreshold: 3,
InitialDelaySeconds: 3000,
PeriodSeconds: 100,
SuccessThreshold: 1,
TimeoutSeconds: 5,
ProbeHandler: corev1.ProbeHandler{
HTTPGet: &corev1.HTTPGetAction{
Path: "/health",
Port: intstr.IntOrString{
Type: intstr.Int,
IntVal: 7001,
},
Scheme: corev1.URISchemeHTTP,
},
},
},
},
},
},
},
expectResult: `[{"name":"c1","livenessProbe":{"httpGet":{"path":"/health","port":7001,"scheme":"HTTP"},"initialDelaySeconds":3000,"timeoutSeconds":5,"periodSeconds":100,"successThreshold":1,"failureThreshold":3}}]`,
},
{
name: "livenessProbe configuration for multi-standard containers",
pod: &corev1.Pod{
ObjectMeta: metav1.ObjectMeta{
Name: "pod2",
Namespace: "sp1",
},
Spec: corev1.PodSpec{
Containers: []corev1.Container{
{
Name: "c1",
LivenessProbe: &corev1.Probe{
FailureThreshold: 3,
InitialDelaySeconds: 3000,
PeriodSeconds: 100,
SuccessThreshold: 1,
TimeoutSeconds: 5,
ProbeHandler: corev1.ProbeHandler{
HTTPGet: &corev1.HTTPGetAction{
Path: "/health",
Port: intstr.IntOrString{
Type: intstr.Int,
IntVal: 7001,
},
Scheme: corev1.URISchemeHTTP,
},
},
},
},
{
Name: "c2",
LivenessProbe: &corev1.Probe{
FailureThreshold: 3,
InitialDelaySeconds: 3000,
PeriodSeconds: 100,
SuccessThreshold: 1,
TimeoutSeconds: 5,
ProbeHandler: corev1.ProbeHandler{
Exec: &corev1.ExecAction{
Command: []string{
"/home/admin/liveness.sh",
},
},
},
},
},
},
},
},
expectResult: `[{"name":"c1","livenessProbe":{"httpGet":{"path":"/health","port":7001,"scheme":"HTTP"},"initialDelaySeconds":3000,"timeoutSeconds":5,"periodSeconds":100,"successThreshold":1,"failureThreshold":3}},{"name":"c2","livenessProbe":{"exec":{"command":["/home/admin/liveness.sh"]},"initialDelaySeconds":3000,"timeoutSeconds":5,"periodSeconds":100,"successThreshold":1,"failureThreshold":3}}]`,
},
{
name: "different livenssProbe configuration for multi-standard containers",
pod: &corev1.Pod{
ObjectMeta: metav1.ObjectMeta{
Name: "pod3",
Namespace: "sp1",
},
Spec: corev1.PodSpec{
Containers: []corev1.Container{
{
Name: "c1",
LivenessProbe: &corev1.Probe{
FailureThreshold: 3,
InitialDelaySeconds: 3000,
PeriodSeconds: 100,
SuccessThreshold: 1,
TimeoutSeconds: 5,
ProbeHandler: corev1.ProbeHandler{
HTTPGet: &corev1.HTTPGetAction{
Path: "/health",
Port: intstr.IntOrString{
Type: intstr.Int,
IntVal: 7001,
},
Scheme: corev1.URISchemeHTTP,
},
},
},
},
{
Name: "c2",
LivenessProbe: &corev1.Probe{
FailureThreshold: 3,
InitialDelaySeconds: 3000,
PeriodSeconds: 100,
SuccessThreshold: 1,
TimeoutSeconds: 5,
ProbeHandler: corev1.ProbeHandler{
Exec: &corev1.ExecAction{
Command: []string{
"/home/admin/liveness.sh",
},
},
},
},
},
{
Name: "c3",
},
},
},
},
expectResult: `[{"name":"c1","livenessProbe":{"httpGet":{"path":"/health","port":7001,"scheme":"HTTP"},"initialDelaySeconds":3000,"timeoutSeconds":5,"periodSeconds":100,"successThreshold":1,"failureThreshold":3}},{"name":"c2","livenessProbe":{"exec":{"command":["/home/admin/liveness.sh"]},"initialDelaySeconds":3000,"timeoutSeconds":5,"periodSeconds":100,"successThreshold":1,"failureThreshold":3}}]`,
},
{
name: "no livenessProbe configuration for standard container",
pod: &corev1.Pod{
ObjectMeta: metav1.ObjectMeta{
Name: "pod3",
Namespace: "sp1",
},
Spec: corev1.PodSpec{
Containers: []corev1.Container{
{
Name: "c1",
},
},
},
},
},
}

for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
get, err := removeAndBackUpPodContainerLivenessProbe(tc.pod)
if err != nil {
t.Errorf("Test case: %v failed, err: %v", tc.name, err)
}
if !reflect.DeepEqual(get, tc.expectResult) {
t.Errorf("Test case: %v failed, expect: %v, but: %v",
tc.name, tc.expectResult, get)
}
})
}
}
16 changes: 13 additions & 3 deletions pkg/webhook/pod/mutating/pod_create_update_handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,14 @@ import (
"encoding/json"
"net/http"

"github.com/openkruise/kruise/pkg/features"
"github.com/openkruise/kruise/pkg/util/controllerfinder"
utilfeature "github.com/openkruise/kruise/pkg/util/feature"
corev1 "k8s.io/api/core/v1"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/runtime/inject"
"sigs.k8s.io/controller-runtime/pkg/webhook/admission"

"github.com/openkruise/kruise/pkg/features"
"github.com/openkruise/kruise/pkg/util/controllerfinder"
utilfeature "github.com/openkruise/kruise/pkg/util/feature"
)

// PodCreateHandler handles Pod
Expand Down Expand Up @@ -103,6 +104,15 @@ func (h *PodCreateHandler) Handle(ctx context.Context, req admission.Request) ad
changed = true
}

// EnhancedLivenessProbe enabled
if utilfeature.DefaultFeatureGate.Enabled(features.EnhancedLivenessProbe) {
if skip, err := h.enhancedLivenessProbeWhenPodCreate(req, obj); err != nil {
return admission.Errored(http.StatusInternalServerError, err)
} else if !skip {
changed = true
}
}

if !changed {
return admission.Allowed("")
}
Expand Down

0 comments on commit 0b69996

Please sign in to comment.