pkg/controller/common/container/defaulter.go (144 lines of code) (raw):

// Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one // or more contributor license agreements. Licensed under the Elastic License 2.0; // you may not use this file except in compliance with the Elastic License 2.0. package container import ( "sort" corev1 "k8s.io/api/core/v1" ) // Defaulter ensures that values are set if none exists in the base container. type Defaulter struct { base *corev1.Container } // Container returns a copy of the resulting container. func (d Defaulter) Container() corev1.Container { return *d.base.DeepCopy() } func NewDefaulter(base *corev1.Container) Defaulter { return Defaulter{ base: base, } } // From inherits default values from an other container. func (d Defaulter) From(other corev1.Container) Defaulter { if other.Lifecycle != nil { d.WithPreStopHook(other.Lifecycle.PreStop) } return d. WithImage(other.Image). WithCommand(other.Command). WithArgs(other.Args). WithPorts(other.Ports). WithEnv(other.Env). WithResources(other.Resources). WithVolumeMounts(other.VolumeMounts). WithReadinessProbe(other.ReadinessProbe). WithLivenessProbe(other.LivenessProbe). WithStartupProbe(other.StartupProbe) } func (d Defaulter) WithCommand(command []string) Defaulter { if len(d.base.Command) == 0 { d.base.Command = command } return d } func (d Defaulter) WithArgs(args []string) Defaulter { if len(d.base.Args) == 0 { d.base.Args = args } return d } func (d Defaulter) WithPorts(ports []corev1.ContainerPort) Defaulter { for _, p := range ports { if !d.portExists(p.Name) { d.base.Ports = append(d.base.Ports, p) } } // order ports by name to ensure stable pod spec comparison sort.SliceStable(d.base.Ports, func(i, j int) bool { return d.base.Ports[i].Name < d.base.Ports[j].Name }) return d } // portExists checks if a port with the given name already exists in the Container. func (d Defaulter) portExists(name string) bool { for _, p := range d.base.Ports { if p.Name == name { return true } } return false } // WithImage sets up the Container Docker image, unless already provided. // The default image will be used unless customImage is not empty. func (d Defaulter) WithImage(image string) Defaulter { if d.base.Image == "" { d.base.Image = image } return d } func (d Defaulter) WithReadinessProbe(readinessProbe *corev1.Probe) Defaulter { if d.base.ReadinessProbe == nil { d.base.ReadinessProbe = readinessProbe } return d } func (d Defaulter) WithLivenessProbe(livenessProbe *corev1.Probe) Defaulter { if d.base.LivenessProbe == nil { d.base.LivenessProbe = livenessProbe } return d } func (d Defaulter) WithStartupProbe(startupProbe *corev1.Probe) Defaulter { if d.base.StartupProbe == nil { d.base.StartupProbe = startupProbe } return d } // envExists checks if an env var with the given name already exists in the provided slice. func (d Defaulter) envExists(name string) bool { for _, v := range d.base.Env { if v.Name == name { return true } } return false } func (d Defaulter) WithEnv(vars []corev1.EnvVar) Defaulter { def, _ := d.WithNewEnv(vars) return def } func (d Defaulter) WithNewEnv(vars []corev1.EnvVar) (Defaulter, bool) { allNew := true for _, v := range vars { if d.envExists(v.Name) { allNew = false continue } d.base.Env = append(d.base.Env, v) } return d, allNew } // WithResources ensures that resource requirements are set in the container. func (d Defaulter) WithResources(resources corev1.ResourceRequirements) Defaulter { if d.base.Resources.Requests == nil && d.base.Resources.Limits == nil { d.base.Resources = resources } return d } // volumeExists checks if a volume mount with the given name already exists in the Container. func (d Defaulter) volumeMountExists(volumeMount corev1.VolumeMount) bool { for _, v := range d.base.VolumeMounts { if v.Name == volumeMount.Name || v.MountPath == volumeMount.MountPath { return true } } return false } func (d Defaulter) WithVolumeMounts(volumeMounts []corev1.VolumeMount) Defaulter { for _, v := range volumeMounts { if !d.volumeMountExists(v) { d.base.VolumeMounts = append(d.base.VolumeMounts, v) } } // order volume mounts by name to ensure stable pod spec comparison sort.SliceStable(d.base.VolumeMounts, func(i, j int) bool { return d.base.VolumeMounts[i].Name < d.base.VolumeMounts[j].Name }) return d } func (d Defaulter) WithPreStopHook(handler *corev1.LifecycleHandler) Defaulter { if d.base.Lifecycle == nil { d.base.Lifecycle = &corev1.Lifecycle{} } if d.base.Lifecycle.PreStop == nil { // no user-provided hook, we can use our own d.base.Lifecycle.PreStop = handler } return d }