Skip to content

Commit 067e266

Browse files
refactor: Cleaner way to patch init containers with ContainerType
1 parent 972c6f1 commit 067e266

File tree

2 files changed

+83
-44
lines changed

2 files changed

+83
-44
lines changed

pkg/webhook/webhook.go

Lines changed: 59 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,13 @@ import (
1818
"k8s.io/apimachinery/pkg/runtime/serializer"
1919
)
2020

21+
type ContainerType string
22+
23+
const (
24+
InitContainer ContainerType = "initContainer"
25+
Container ContainerType = "container"
26+
)
27+
2128
const (
2229
connectHostEnv = "OP_CONNECT_HOST"
2330
connectTokenEnv = "OP_CONNECT_TOKEN"
@@ -100,23 +107,26 @@ func mutationRequired(metadata *metav1.ObjectMeta) bool {
100107
return required
101108
}
102109

103-
func addContainers(target, added []corev1.Container, basePath string) (patch []patchOperation) {
104-
if len(target) == 0 {
105-
patch = append(patch, patchOperation{
106-
Op: "add",
107-
Path: basePath,
108-
Value: added,
109-
})
110-
return patch
111-
}
110+
func addContainers(target, containers []corev1.Container, basePath string) (patch []patchOperation) {
111+
first := len(target) == 0
112+
var value interface{}
113+
for _, c := range containers {
114+
value = c
115+
path := basePath
116+
if first {
117+
first = false
118+
value = []corev1.Container{c}
119+
} else {
120+
path = path + "/-"
121+
}
112122

113-
for _, c := range added {
114123
patch = append(patch, patchOperation{
115124
Op: "add",
116-
Path: basePath + "/-",
117-
Value: c,
125+
Path: path,
126+
Value: value,
118127
})
119128
}
129+
120130
return patch
121131
}
122132

@@ -212,7 +222,7 @@ func (s *SecretInjector) mutate(ar *admissionv1.AdmissionReview) *admissionv1.Ad
212222
var patch []patchOperation
213223

214224
mutateInitContainers := false
215-
if value, exists := pod.Annotations[injectorInitFirstAnnotation]; exists && strings.ToLower(value) == "true" {
225+
if val, ok := pod.Annotations[injectorInitFirstAnnotation]; ok && strings.ToLower(val) == "true" {
216226
mutateInitContainers = true
217227
}
218228

@@ -227,7 +237,7 @@ func (s *SecretInjector) mutate(ar *admissionv1.AdmissionReview) *admissionv1.Ad
227237
if !mutate {
228238
continue
229239
}
230-
didMutate, initContainerPatch, err := s.mutateContainer(ctx, &c, i)
240+
didMutate, initContainerPatch, err := s.mutateContainer(ctx, &c, i, InitContainer)
231241
if err != nil {
232242
return &admissionv1.AdmissionResponse{
233243
Result: &metav1.Status{
@@ -253,7 +263,7 @@ func (s *SecretInjector) mutate(ar *admissionv1.AdmissionReview) *admissionv1.Ad
253263
continue
254264
}
255265

256-
didMutate, containerPatch, err := s.mutateContainer(ctx, &c, i)
266+
didMutate, containerPatch, err := s.mutateContainer(ctx, &c, i, Container)
257267
if err != nil {
258268
glog.Error("Error occurred mutating container for secret injection: ", err)
259269
return &admissionv1.AdmissionResponse{
@@ -316,30 +326,22 @@ func createOPCLIPatch(pod *corev1.Pod, containers []corev1.Container, patch []pa
316326
annotations := map[string]string{injectionStatus: "injected"}
317327
patch = append(patch, addVolume(pod.Spec.Volumes, []corev1.Volume{binVolume}, "/spec/volumes")...)
318328

319-
if value, exists := pod.Annotations[injectorInitFirstAnnotation]; exists && strings.ToLower(value) == "true" {
320-
patch = append(patch, prependContainers(pod.Spec.InitContainers, containers, "/spec/initContainers")...)
321-
} else {
322-
patch = append(patch, addContainers(pod.Spec.InitContainers, containers, "/spec/initContainers")...)
329+
initFirst := false
330+
if val, ok := pod.Annotations[injectorInitFirstAnnotation]; ok && strings.ToLower(val) == "true" {
331+
initFirst = true
323332
}
324333

325-
patch = append(patch, updateAnnotation(pod.Annotations, annotations)...)
326-
return json.Marshal(patch)
327-
}
334+
if initFirst {
335+
if len(pod.Spec.InitContainers) > 0 {
336+
patch = append(patch, removeContainers(getContainerPath(InitContainer))...)
337+
}
328338

329-
// adds containers to the beginning of the target
330-
func prependContainers(target, added []corev1.Container, basePath string) (patch []patchOperation) {
331-
if len(target) == 0 {
332-
return addContainers(target, added, basePath)
339+
containers = append(containers, pod.Spec.InitContainers...)
333340
}
334341

335-
for i := len(added) - 1; i >= 0; i-- {
336-
patch = append(patch, patchOperation{
337-
Op: "add",
338-
Path: basePath + "/0",
339-
Value: added[i],
340-
})
341-
}
342-
return patch
342+
patch = append(patch, addContainers(pod.Spec.InitContainers, containers, "/spec/initContainers")...)
343+
patch = append(patch, updateAnnotation(pod.Annotations, annotations)...)
344+
return json.Marshal(patch)
343345
}
344346

345347
func isEnvVarSetup(envVarName string) func(c *corev1.Container) bool {
@@ -386,7 +388,7 @@ func checkOPCLIEnvSetup(container *corev1.Container) {
386388
}
387389
}
388390

389-
func passUserAgentInformationToCLI(container *corev1.Container, containerIndex int) []patchOperation {
391+
func passUserAgentInformationToCLI(container *corev1.Container, containerIndex int, containerType ContainerType) []patchOperation {
390392
userAgentEnvs := []corev1.EnvVar{
391393
{
392394
Name: "OP_INTEGRATION_NAME",
@@ -402,11 +404,11 @@ func passUserAgentInformationToCLI(container *corev1.Container, containerIndex i
402404
},
403405
}
404406

405-
return setEnvironment(*container, containerIndex, userAgentEnvs, "/spec/containers")
407+
return setEnvironment(*container, containerIndex, userAgentEnvs, getContainerPath(containerType))
406408
}
407409

408410
// mutates the container to allow for secrets to be injected into the container via the op cli
409-
func (s *SecretInjector) mutateContainer(cxt context.Context, container *corev1.Container, containerIndex int) (bool, []patchOperation, error) {
411+
func (s *SecretInjector) mutateContainer(cxt context.Context, container *corev1.Container, containerIndex int, containerType ContainerType) (bool, []patchOperation, error) {
410412
// prepending op run command to the container command so that secrets are injected before the main process is started
411413
if len(container.Command) == 0 {
412414
return false, nil, fmt.Errorf("not attaching OP to the container %s: the podspec does not define a command", container.Name)
@@ -418,15 +420,15 @@ func (s *SecretInjector) mutateContainer(cxt context.Context, container *corev1.
418420
var patch []patchOperation
419421

420422
// adding the cli to the container using a volume mount
421-
path := fmt.Sprintf("%s/%d/volumeMounts", "/spec/containers", containerIndex)
423+
path := fmt.Sprintf("%s/%d/volumeMounts", getContainerPath(containerType), containerIndex)
422424
patch = append(patch, patchOperation{
423425
Op: "add",
424426
Path: path,
425427
Value: append(container.VolumeMounts, binVolumeMount),
426428
})
427429

428430
// replacing the container command with a command prepended with op run
429-
path = fmt.Sprintf("%s/%d/command", "/spec/containers", containerIndex)
431+
path = fmt.Sprintf("%s/%d/command", getContainerPath(containerType), containerIndex)
430432
patch = append(patch, patchOperation{
431433
Op: "replace",
432434
Path: path,
@@ -436,7 +438,7 @@ func (s *SecretInjector) mutateContainer(cxt context.Context, container *corev1.
436438
checkOPCLIEnvSetup(container)
437439

438440
//creating patch for passing User-Agent information to the CLI.
439-
patch = append(patch, passUserAgentInformationToCLI(container, containerIndex)...)
441+
patch = append(patch, passUserAgentInformationToCLI(container, containerIndex, containerType)...)
440442
return true, patch, nil
441443
}
442444

@@ -521,3 +523,20 @@ func (s *SecretInjector) Serve(w http.ResponseWriter, r *http.Request) {
521523
http.Error(w, fmt.Sprintf("could not write response: %v", err), http.StatusInternalServerError)
522524
}
523525
}
526+
527+
func getContainerPath(containerType ContainerType) string {
528+
if containerType == InitContainer {
529+
return "/spec/initContainers"
530+
}
531+
return "/spec/containers"
532+
}
533+
534+
func removeContainers(path string) []patchOperation {
535+
return []patchOperation{
536+
{
537+
Op: "remove",
538+
Path: path,
539+
Value: nil,
540+
},
541+
}
542+
}

pkg/webhook/webhook_test.go

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -332,6 +332,15 @@ var testPatch = map[string]struct {
332332
},
333333
},
334334
},
335+
{
336+
"op": "add",
337+
"path": "/spec/initContainers/-",
338+
"value": map[string]interface{}{
339+
"command": []string{"echo", "hello"},
340+
"name": "init-app",
341+
"resources": map[string]interface{}{},
342+
},
343+
},
335344
{
336345
"op": "replace",
337346
"path": "/spec/initContainers/0/command",
@@ -461,7 +470,14 @@ var testPatch = map[string]struct {
461470
},
462471
{
463472
"op": "add",
464-
"path": "/spec/initContainers/0",
473+
"path": "/metadata/annotations",
474+
"value": map[string]string{
475+
"operator.1password.io/status": "injected",
476+
},
477+
},
478+
{
479+
"op": "add",
480+
"path": "/spec/initContainers/-",
465481
"value": map[string]interface{}{
466482
"name": "copy-op-bin",
467483
"image": "1password/op:2",
@@ -478,9 +494,13 @@ var testPatch = map[string]struct {
478494
},
479495
{
480496
"op": "add",
481-
"path": "/metadata/annotations",
482-
"value": map[string]string{
483-
"operator.1password.io/status": "injected",
497+
"path": "/spec/initContainers/0/volumeMounts",
498+
"value": []map[string]interface{}{
499+
{
500+
"mountPath": "/op/bin/",
501+
"name": "op-bin",
502+
"readOnly": true,
503+
},
484504
},
485505
},
486506
},

0 commit comments

Comments
 (0)