From 71b3bbdea2a591776fca2bfa0a29eaa6f5a01715 Mon Sep 17 00:00:00 2001 From: Rob Best Date: Tue, 27 Jul 2021 14:54:26 +0100 Subject: [PATCH] Add prependInitContainers option There are situations where init containers may depend on the actions of an injected container running beforehand. --- docs/sidecar-configuration-format.md | 3 ++ internal/pkg/config/config.go | 25 ++++++------ internal/pkg/config/config_test.go | 12 ++++++ internal/pkg/testing/config.go | 23 +++++------ pkg/server/webhook.go | 7 +++- pkg/server/webhook_test.go | 3 ++ .../patch/prepend-init-containers.json | 38 +++++++++++++++++++ .../request/prepend-init-containers.yaml | 9 +++++ test/fixtures/k8s/object9.yaml | 4 ++ .../sidecars/prepend-init-containers.yaml | 12 ++++++ 10 files changed, 112 insertions(+), 24 deletions(-) create mode 100644 test/fixtures/k8s/admissioncontrol/patch/prepend-init-containers.json create mode 100644 test/fixtures/k8s/admissioncontrol/request/prepend-init-containers.yaml create mode 100644 test/fixtures/k8s/object9.yaml create mode 100644 test/fixtures/sidecars/prepend-init-containers.yaml diff --git a/docs/sidecar-configuration-format.md b/docs/sidecar-configuration-format.md index 7cb5e27..2509003 100644 --- a/docs/sidecar-configuration-format.md +++ b/docs/sidecar-configuration-format.md @@ -44,6 +44,9 @@ inherits: "some-sidecar.yaml" # https://medium.com/@marko.luksa/delaying-application-start-until-sidecar-is-ready-2ec2d21a7b74 prependContainers: false +# prependInitContainers is the same as above, but for initContainers +prependInitContainers: false + containers: # we inject a nginx container - name: sidecar-nginx diff --git a/internal/pkg/config/config.go b/internal/pkg/config/config.go index 2fa243d..2db3a3e 100644 --- a/internal/pkg/config/config.go +++ b/internal/pkg/config/config.go @@ -32,18 +32,19 @@ var ( // InjectionConfig is a specific instance of a injected config, for a given annotation type InjectionConfig struct { - Name string `json:"name"` - Inherits string `json:"inherits"` - Containers []corev1.Container `json:"containers"` - Volumes []corev1.Volume `json:"volumes"` - Environment []corev1.EnvVar `json:"env"` - VolumeMounts []corev1.VolumeMount `json:"volumeMounts"` - HostAliases []corev1.HostAlias `json:"hostAliases"` - HostNetwork bool `json:"hostNetwork"` - HostPID bool `json:"hostPID"` - InitContainers []corev1.Container `json:"initContainers"` - ServiceAccountName string `json:"serviceAccountName"` - PrependContainers bool `json:"prependContainers"` + Name string `json:"name"` + Inherits string `json:"inherits"` + Containers []corev1.Container `json:"containers"` + Volumes []corev1.Volume `json:"volumes"` + Environment []corev1.EnvVar `json:"env"` + VolumeMounts []corev1.VolumeMount `json:"volumeMounts"` + HostAliases []corev1.HostAlias `json:"hostAliases"` + HostNetwork bool `json:"hostNetwork"` + HostPID bool `json:"hostPID"` + InitContainers []corev1.Container `json:"initContainers"` + ServiceAccountName string `json:"serviceAccountName"` + PrependContainers bool `json:"prependContainers"` + PrependInitContainers bool `json:"prependInitContainers"` version string } diff --git a/internal/pkg/config/config_test.go b/internal/pkg/config/config_test.go index 70a487b..b9b5721 100644 --- a/internal/pkg/config/config_test.go +++ b/internal/pkg/config/config_test.go @@ -206,6 +206,18 @@ var ( InitContainerCount: 0, PrependContainers: true, }, + "prepend-init-containers": testhelper.ConfigExpectation{ + Name: "prepend-init-containers", + Version: "latest", + Path: fixtureSidecarsDir + "/prepend-init-containers.yaml", + EnvCount: 0, + ContainerCount: 0, + VolumeCount: 0, + VolumeMountCount: 0, + HostAliasCount: 0, + InitContainerCount: 2, + PrependInitContainers: true, + }, } ) diff --git a/internal/pkg/testing/config.go b/internal/pkg/testing/config.go index fefa78f..c01f9b3 100644 --- a/internal/pkg/testing/config.go +++ b/internal/pkg/testing/config.go @@ -12,17 +12,18 @@ type ConfigExpectation struct { // version is the parsed version string, or "latest" if omitted Version string // Path is the path to the YAML to load the sidecar yaml from - Path string - EnvCount int - ContainerCount int - VolumeCount int - VolumeMountCount int - HostAliasCount int - HostNetwork bool - HostPID bool - InitContainerCount int - ServiceAccount string - PrependContainers bool + Path string + EnvCount int + ContainerCount int + VolumeCount int + VolumeMountCount int + HostAliasCount int + HostNetwork bool + HostPID bool + InitContainerCount int + ServiceAccount string + PrependContainers bool + PrependInitContainers bool // LoadError is an error, if any, that is expected during load LoadError error diff --git a/pkg/server/webhook.go b/pkg/server/webhook.go index f532974..bcb1ac1 100644 --- a/pkg/server/webhook.go +++ b/pkg/server/webhook.go @@ -470,7 +470,12 @@ func createPatch(pod *corev1.Pod, inj *config.InjectionConfig, annotations map[s // this mutates inj.InitContainers with our environment vars mutatedInjectedInitContainers := mergeEnvVars(inj.Environment, inj.InitContainers) mutatedInjectedInitContainers = mergeVolumeMounts(inj.VolumeMounts, mutatedInjectedInitContainers) - patch = append(patch, appendContainers(pod.Spec.InitContainers, mutatedInjectedInitContainers, "/spec/initContainers")...) + // then, add containers to the patch + if inj.PrependInitContainers { + patch = append(patch, prependContainers(pod.Spec.InitContainers, mutatedInjectedInitContainers, "/spec/initContainers")...) + } else { + patch = append(patch, appendContainers(pod.Spec.InitContainers, mutatedInjectedInitContainers, "/spec/initContainers")...) + } } { // container injections diff --git a/pkg/server/webhook_test.go b/pkg/server/webhook_test.go index 25662b5..7974992 100644 --- a/pkg/server/webhook_test.go +++ b/pkg/server/webhook_test.go @@ -38,6 +38,7 @@ var ( obj7v2 = "test/fixtures/k8s/object7-v2.yaml" obj7v3 = "test/fixtures/k8s/object7-badrequestformat.yaml" obj8 = "test/fixtures/k8s/object8.yaml" + obj9 = "test/fixtures/k8s/object9.yaml" badSidecar = "test/fixtures/k8s/bad-sidecar.yaml" // tests to check config loading of sidecars @@ -54,6 +55,7 @@ var ( {configuration: obj7v2, expectedSidecar: "init-containers:v2"}, {configuration: obj7v3, expectedSidecar: "", expectedError: ErrRequestedSidecarNotFound}, {configuration: obj8, expectedSidecar: "prepend-containers:latest"}, + {configuration: obj9, expectedSidecar: "prepend-init-containers:latest"}, {configuration: badSidecar, expectedSidecar: "", expectedError: ErrRequestedSidecarNotFound}, } @@ -63,6 +65,7 @@ var ( {name: "sidecar-test-1", allowed: true, patchExpected: true}, {name: "env-override", allowed: true, patchExpected: true}, {name: "prepend-containers", allowed: true, patchExpected: true}, + {name: "prepend-init-containers", allowed: true, patchExpected: true}, {name: "service-account", allowed: true, patchExpected: true}, {name: "service-account-already-set", allowed: true, patchExpected: true}, {name: "service-account-set-default", allowed: true, patchExpected: true}, diff --git a/test/fixtures/k8s/admissioncontrol/patch/prepend-init-containers.json b/test/fixtures/k8s/admissioncontrol/patch/prepend-init-containers.json new file mode 100644 index 0000000..2946d56 --- /dev/null +++ b/test/fixtures/k8s/admissioncontrol/patch/prepend-init-containers.json @@ -0,0 +1,38 @@ +[ + { + "op": "add", + "path": "/spec/initContainers", + "value": [ + { + "image": "foo:69", + "name": "sidecar-existing-vm", + "ports": [ + { + "containerPort": 420 + } + ], + "resources": {} + } + ] + }, + { + "op": "add", + "path": "/spec/initContainers/0", + "value": { + "image": "nginx:1.12.2", + "imagePullPolicy": "IfNotPresent", + "name": "sidecar-add-vm", + "ports": [ + { + "containerPort": 80 + } + ], + "resources": {} + } + }, + { + "op": "add", + "path": "/metadata/annotations/injector.unittest.com~1status", + "value": "injected" + } +] diff --git a/test/fixtures/k8s/admissioncontrol/request/prepend-init-containers.yaml b/test/fixtures/k8s/admissioncontrol/request/prepend-init-containers.yaml new file mode 100644 index 0000000..e949025 --- /dev/null +++ b/test/fixtures/k8s/admissioncontrol/request/prepend-init-containers.yaml @@ -0,0 +1,9 @@ +--- +# this is an AdmissionRequest object +# https://godoc.org/k8s.io/api/admission/v1#AdmissionRequest +object: + metadata: + annotations: + injector.unittest.com/request: "prepend-init-containers" + spec: + initContainers: [] diff --git a/test/fixtures/k8s/object9.yaml b/test/fixtures/k8s/object9.yaml new file mode 100644 index 0000000..0375ce9 --- /dev/null +++ b/test/fixtures/k8s/object9.yaml @@ -0,0 +1,4 @@ +name: object8 +namespace: unittest +annotations: + "injector.unittest.com/request": "prepend-init-containers" diff --git a/test/fixtures/sidecars/prepend-init-containers.yaml b/test/fixtures/sidecars/prepend-init-containers.yaml new file mode 100644 index 0000000..c539029 --- /dev/null +++ b/test/fixtures/sidecars/prepend-init-containers.yaml @@ -0,0 +1,12 @@ +name: prepend-init-containers +initContainers: + - name: sidecar-add-vm + image: nginx:1.12.2 + imagePullPolicy: IfNotPresent + ports: + - containerPort: 80 + - name: sidecar-existing-vm + image: foo:69 + ports: + - containerPort: 420 +prependInitContainers: true