From 375d942fa19250cb2ba0476d5008c177398403bf Mon Sep 17 00:00:00 2001 From: hime Date: Tue, 17 Sep 2024 21:07:40 +0000 Subject: [PATCH] Add annotation to manually enable/disable native sidecar injection. --- pkg/webhook/injection.go | 11 +++++++- pkg/webhook/mutatingwebhook.go | 30 +++++++++++---------- pkg/webhook/mutatingwebhook_test.go | 42 +++++++++++++++++++++++++++++ pkg/webhook/parsers.go | 11 ++++++++ 4 files changed, 79 insertions(+), 15 deletions(-) diff --git a/pkg/webhook/injection.go b/pkg/webhook/injection.go index 70a2636e1..443377f21 100644 --- a/pkg/webhook/injection.go +++ b/pkg/webhook/injection.go @@ -64,7 +64,16 @@ func (si *SidecarInjector) supportsNativeSidecar() (bool, error) { } func injectSidecarContainer(pod *corev1.Pod, config *Config, supportsNativeSidecar bool) { - if supportsNativeSidecar { + nativeSidecarEnabled := true + if enable, ok := pod.Annotations[GcsFuseNativeSidecarEnableAnnotation]; ok { + parsedAnnotation, err := ParseBool(enable) + if err != nil { + klog.Errorf("failed to parse enableNativeSidecar annotation... ignoring annotation: %v", err) + } else { + nativeSidecarEnabled = parsedAnnotation + } + } + if supportsNativeSidecar && nativeSidecarEnabled { pod.Spec.InitContainers = insert(pod.Spec.InitContainers, GetNativeSidecarContainerSpec(config), getInjectIndex(pod.Spec.InitContainers)) } else { pod.Spec.Containers = insert(pod.Spec.Containers, GetSidecarContainerSpec(config), getInjectIndex(pod.Spec.Containers)) diff --git a/pkg/webhook/mutatingwebhook.go b/pkg/webhook/mutatingwebhook.go index b003a7107..d8ad71cb9 100644 --- a/pkg/webhook/mutatingwebhook.go +++ b/pkg/webhook/mutatingwebhook.go @@ -22,7 +22,6 @@ import ( "encoding/json" "fmt" "net/http" - "strings" admissionv1 "k8s.io/api/admission/v1" corev1 "k8s.io/api/core/v1" @@ -34,13 +33,14 @@ import ( ) const ( - GcsFuseVolumeEnableAnnotation = "gke-gcsfuse/volumes" - cpuLimitAnnotation = "gke-gcsfuse/cpu-limit" - cpuRequestAnnotation = "gke-gcsfuse/cpu-request" - memoryLimitAnnotation = "gke-gcsfuse/memory-limit" - memoryRequestAnnotation = "gke-gcsfuse/memory-request" - ephemeralStorageLimitAnnotation = "gke-gcsfuse/ephemeral-storage-limit" - ephemeralStorageRequestAnnotation = "gke-gcsfuse/ephemeral-storage-request" + GcsFuseVolumeEnableAnnotation = "gke-gcsfuse/volumes" + GcsFuseNativeSidecarEnableAnnotation = "gke-gcsfuse/enable-native-sidecar" + cpuLimitAnnotation = "gke-gcsfuse/cpu-limit" + cpuRequestAnnotation = "gke-gcsfuse/cpu-request" + memoryLimitAnnotation = "gke-gcsfuse/memory-limit" + memoryRequestAnnotation = "gke-gcsfuse/memory-request" + ephemeralStorageLimitAnnotation = "gke-gcsfuse/ephemeral-storage-limit" + ephemeralStorageRequestAnnotation = "gke-gcsfuse/ephemeral-storage-request" ) type SidecarInjector struct { @@ -71,15 +71,17 @@ func (si *SidecarInjector) Handle(_ context.Context, req admission.Request) admi return admission.Allowed(fmt.Sprintf("The annotation key %q is not found, no injection required.", GcsFuseVolumeEnableAnnotation)) } - switch strings.ToLower(enableGcsfuseVolumes) { - case "false": - return admission.Allowed(fmt.Sprintf("found annotation '%v: false' for Pod: Name %q, GenerateName %q, Namespace %q, no injection required.", GcsFuseVolumeEnableAnnotation, pod.Name, pod.GenerateName, pod.Namespace)) - case "true": - klog.Infof("found annotation '%v: true' for Pod: Name %q, GenerateName %q, Namespace %q, start to inject the sidecar container.", GcsFuseVolumeEnableAnnotation, pod.Name, pod.GenerateName, pod.Namespace) - default: + shouldInjectSidecar, err := ParseBool(enableGcsfuseVolumes) + if err != nil { return admission.Errored(http.StatusBadRequest, fmt.Errorf("the acceptable values for %q are 'True', 'true', 'false' or 'False'", GcsFuseVolumeEnableAnnotation)) } + if shouldInjectSidecar { + klog.Infof("found annotation '%v: true' for Pod: Name %q, GenerateName %q, Namespace %q, start to inject the sidecar container.", GcsFuseVolumeEnableAnnotation, pod.Name, pod.GenerateName, pod.Namespace) + } else { + return admission.Allowed(fmt.Sprintf("found annotation '%v: false' for Pod: Name %q, GenerateName %q, Namespace %q, no injection required.", GcsFuseVolumeEnableAnnotation, pod.Name, pod.GenerateName, pod.Namespace)) + } + sidecarInjected, _ := ValidatePodHasSidecarContainerInjected(pod) if sidecarInjected { return admission.Allowed("The sidecar container was injected, no injection required.") diff --git a/pkg/webhook/mutatingwebhook_test.go b/pkg/webhook/mutatingwebhook_test.go index 410948f5b..dfa021b58 100644 --- a/pkg/webhook/mutatingwebhook_test.go +++ b/pkg/webhook/mutatingwebhook_test.go @@ -364,6 +364,41 @@ func TestValidateMutatingWebhookResponse(t *testing.T) { wantResponse: wantResponse(t, false, false), nodes: skewVersionNodes(), }, + { + name: "native container set via annotation injection successful test.", + operation: admissionv1.Create, + inputPod: validInputPodWithNativeAnnotation(false, "true"), + wantResponse: wantResponse(t, false, true), + nodes: nativeSupportNodes(), + }, + { + name: "native container set via annotation injection successful with custom image test.", + operation: admissionv1.Create, + inputPod: validInputPodWithNativeAnnotation(true, "true"), + wantResponse: wantResponse(t, true, true), + nodes: nativeSupportNodes(), + }, + { + name: "regular container set via annotation injection successful test.", + operation: admissionv1.Create, + inputPod: validInputPodWithNativeAnnotation(false, "false"), + wantResponse: wantResponse(t, false, false), + nodes: nativeSupportNodes(), + }, + { + name: "native container set via invalid annotation injection successful test.", + operation: admissionv1.Create, + inputPod: validInputPodWithNativeAnnotation(false, "maybe"), + wantResponse: wantResponse(t, false, true), + nodes: nativeSupportNodes(), + }, + { + name: "native container set via annotation injection unsupported test.", + operation: admissionv1.Create, + inputPod: validInputPodWithNativeAnnotation(false, "true"), + wantResponse: wantResponse(t, false, false), + nodes: skewVersionNodes(), + }, { name: "Injection with custom sidecar container image successful test.", operation: admissionv1.Create, @@ -527,6 +562,13 @@ func getDuplicateDeclarationPodSpecResponse() *corev1.Pod { return result } +func validInputPodWithNativeAnnotation(customImage bool, enableNativeSidecarAnnotation string) *corev1.Pod { + pod := validInputPod(customImage) + pod.ObjectMeta.Annotations[GcsFuseNativeSidecarEnableAnnotation] = enableNativeSidecarAnnotation + + return pod +} + func validInputPod(customImage bool) *corev1.Pod { pod := &corev1.Pod{ Spec: corev1.PodSpec{ diff --git a/pkg/webhook/parsers.go b/pkg/webhook/parsers.go index 45aa1d1aa..b3cf06ab0 100644 --- a/pkg/webhook/parsers.go +++ b/pkg/webhook/parsers.go @@ -27,6 +27,17 @@ import ( var minimumSupportedVersion = version.MustParseGeneric("1.29.0") +func ParseBool(str string) (bool, error) { + switch str { + case "True", "true": + return true, nil + case "False", "false": + return false, nil + default: + return false, fmt.Errorf("could not parse string to bool: the acceptable values for %q are 'True', 'true', 'false' or 'False'", str) + } +} + // parseSidecarContainerImage supports our Privately Hosted Sidecar Image option // by iterating the container list and finding a container named "gke-gcsfuse-sidecar" // If we find "gke-gcsfuse-sidecar":