From 35af7529af7939e26fa75ee3483979aeab56925d Mon Sep 17 00:00:00 2001 From: Jaime Bohorquez Date: Fri, 23 Feb 2024 02:48:02 +0000 Subject: [PATCH] Add native sidecar compatibility with istio --- pkg/webhook/mutatingwebhook.go | 45 ++++++++++++++++++++--- pkg/webhook/mutatingwebhook_test.go | 57 +++++++++++++++++++++++++++++ 2 files changed, 97 insertions(+), 5 deletions(-) diff --git a/pkg/webhook/mutatingwebhook.go b/pkg/webhook/mutatingwebhook.go index 152155be..0dccdf7d 100644 --- a/pkg/webhook/mutatingwebhook.go +++ b/pkg/webhook/mutatingwebhook.go @@ -110,11 +110,7 @@ func (si *SidecarInjector) Handle(_ context.Context, req admission.Request) admi } // Inject container. - if supportsNativeSidecar { - pod.Spec.InitContainers = append([]corev1.Container{GetNativeSidecarContainerSpec(config)}, pod.Spec.InitContainers...) - } else { - pod.Spec.Containers = append([]corev1.Container{GetSidecarContainerSpec(config)}, pod.Spec.Containers...) - } + injectSidecarContainer(pod, config, supportsNativeSidecar) pod.Spec.Volumes = append(GetSidecarContainerVolumeSpec(pod.Spec.Volumes), pod.Spec.Volumes...) marshaledPod, err := json.Marshal(pod) @@ -242,3 +238,42 @@ func getRelease(version string) (string, error) { return k8sBreakadown[0] + "." + k8sBreakadown[1], nil } + +func injectSidecarContainer(pod *corev1.Pod, config *Config, supportsNativeSidecar bool) { + if supportsNativeSidecar { + sidecarSpec := GetNativeSidecarContainerSpec(config) + if istioSidecarPresent(pod.Spec.InitContainers) { + index := 1 + newSlice := append(pod.Spec.InitContainers, corev1.Container{}) + copy(newSlice[index+1:], pod.Spec.InitContainers[index:]) + newSlice[index] = sidecarSpec + pod.Spec.InitContainers = newSlice + } else { + pod.Spec.InitContainers = append([]corev1.Container{sidecarSpec}, pod.Spec.InitContainers...) + } + } else { + sidecarSpec := GetSidecarContainerSpec(config) + if istioSidecarPresent(pod.Spec.Containers) { + index := 1 + newSlice := append(pod.Spec.Containers, corev1.Container{}) + copy(newSlice[index+1:], pod.Spec.Containers[index:]) + newSlice[index] = sidecarSpec + pod.Spec.Containers = newSlice + } else { + pod.Spec.Containers = append([]corev1.Container{sidecarSpec}, pod.Spec.Containers...) + } + } +} + +// Checks the first index of the container array for the istio container sidecar. +func istioSidecarPresent(containers []corev1.Container) bool { + if len(containers) == 0 { + return false + } + + if containers[0].Name == "istio-proxy" { + return true + } + + return false +} diff --git a/pkg/webhook/mutatingwebhook_test.go b/pkg/webhook/mutatingwebhook_test.go index 9a937c28..8f6aea99 100644 --- a/pkg/webhook/mutatingwebhook_test.go +++ b/pkg/webhook/mutatingwebhook_test.go @@ -39,6 +39,10 @@ import ( "sigs.k8s.io/controller-runtime/pkg/webhook/admission" ) +var istioContainer = corev1.Container{ + Name: "istio-proxy", +} + func TestPrepareConfig(t *testing.T) { t.Parallel() @@ -342,6 +346,20 @@ func TestValidateMutatingWebhookResponse(t *testing.T) { wantResponse: wantResponse(t, true, true), nodes: nativeSupportNodes(), }, + { + name: "regular container injection with istio present success test.", + operation: v1.Create, + inputPod: validInputPodWithIstio(false, false), + wantResponse: wantResponseWithIstio(t, false, false), + nodes: skewVersionNodes(), + }, + { + name: "Injection with custom sidecar container image successful test.", + operation: v1.Create, + inputPod: validInputPodWithIstio(true, true), + wantResponse: wantResponseWithIstio(t, true, true), + nodes: nativeSupportNodes(), + }, } for _, tc := range testCases { @@ -589,6 +607,18 @@ func validInputPod(customImage bool) *corev1.Pod { return pod } +func validInputPodWithIstio(customImage, nativeIstio bool) *corev1.Pod { + pod := validInputPod(customImage) + + if nativeIstio { + pod.Spec.InitContainers = append([]corev1.Container{istioContainer}, pod.Spec.InitContainers...) + } else { + pod.Spec.Containers = append([]corev1.Container{istioContainer}, pod.Spec.Containers...) + } + + return pod +} + func wantResponse(t *testing.T, customImage bool, native bool) admission.Response { t.Helper() newPod := validInputPod(customImage) @@ -608,6 +638,33 @@ func wantResponse(t *testing.T, customImage bool, native bool) admission.Respons return admission.PatchResponseFromRaw(serialize(t, validInputPod(customImage)), serialize(t, newPod)) } +func wantResponseWithIstio(t *testing.T, customImage bool, native bool) admission.Response { + t.Helper() + + originalPod := validInputPod(customImage) + if native { + originalPod.Spec.InitContainers = append([]corev1.Container{istioContainer}, originalPod.Spec.InitContainers...) + } else { + originalPod.Spec.Containers = append([]corev1.Container{istioContainer}, originalPod.Spec.Containers...) + } + + newPod := validInputPod(customImage) + config := FakeConfig() + if customImage { + config.ContainerImage = newPod.Spec.Containers[len(newPod.Spec.Containers)-1].Image + newPod.Spec.Containers = newPod.Spec.Containers[:len(newPod.Spec.Containers)-1] + } + + if native { + newPod.Spec.InitContainers = append([]corev1.Container{istioContainer, GetNativeSidecarContainerSpec(config)}, newPod.Spec.InitContainers...) + } else { + newPod.Spec.Containers = append([]corev1.Container{istioContainer, GetSidecarContainerSpec(config)}, newPod.Spec.Containers...) + } + newPod.Spec.Volumes = append(GetSidecarContainerVolumeSpec(newPod.Spec.Volumes), newPod.Spec.Volumes...) + + return admission.PatchResponseFromRaw(serialize(t, originalPod), serialize(t, newPod)) +} + func nativeSupportNodes() []corev1.Node { return []corev1.Node{ {