mirror of
https://github.com/stakater/Reloader.git
synced 2026-05-17 06:06:39 +00:00
307 lines
9.3 KiB
Go
307 lines
9.3 KiB
Go
package utils
|
|
|
|
import (
|
|
"fmt"
|
|
|
|
corev1 "k8s.io/api/core/v1"
|
|
"k8s.io/utils/ptr"
|
|
)
|
|
|
|
// AddEnvFromSource adds ConfigMap or Secret envFrom to a container.
|
|
func AddEnvFromSource(spec *corev1.PodSpec, containerIdx int, name string, isSecret bool) {
|
|
if containerIdx >= len(spec.Containers) {
|
|
return
|
|
}
|
|
source := corev1.EnvFromSource{}
|
|
if isSecret {
|
|
source.SecretRef = &corev1.SecretEnvSource{
|
|
LocalObjectReference: corev1.LocalObjectReference{Name: name},
|
|
}
|
|
} else {
|
|
source.ConfigMapRef = &corev1.ConfigMapEnvSource{
|
|
LocalObjectReference: corev1.LocalObjectReference{Name: name},
|
|
}
|
|
}
|
|
spec.Containers[containerIdx].EnvFrom = append(spec.Containers[containerIdx].EnvFrom, source)
|
|
}
|
|
|
|
// AddVolume adds a volume and mount to a container.
|
|
func AddVolume(spec *corev1.PodSpec, containerIdx int, volume corev1.Volume, mountPath string) {
|
|
spec.Volumes = append(spec.Volumes, volume)
|
|
if containerIdx < len(spec.Containers) {
|
|
spec.Containers[containerIdx].VolumeMounts = append(
|
|
spec.Containers[containerIdx].VolumeMounts,
|
|
corev1.VolumeMount{Name: volume.Name, MountPath: mountPath},
|
|
)
|
|
}
|
|
}
|
|
|
|
// AddConfigMapVolume adds ConfigMap volume and mount.
|
|
func AddConfigMapVolume(spec *corev1.PodSpec, containerIdx int, name string) {
|
|
AddVolume(spec, containerIdx, corev1.Volume{
|
|
Name: "cm-" + name,
|
|
VolumeSource: corev1.VolumeSource{
|
|
ConfigMap: &corev1.ConfigMapVolumeSource{
|
|
LocalObjectReference: corev1.LocalObjectReference{Name: name},
|
|
},
|
|
},
|
|
}, "/etc/config/"+name)
|
|
}
|
|
|
|
// AddSecretVolume adds Secret volume and mount.
|
|
func AddSecretVolume(spec *corev1.PodSpec, containerIdx int, name string) {
|
|
AddVolume(spec, containerIdx, corev1.Volume{
|
|
Name: "secret-" + name,
|
|
VolumeSource: corev1.VolumeSource{
|
|
Secret: &corev1.SecretVolumeSource{SecretName: name},
|
|
},
|
|
}, "/etc/secrets/"+name)
|
|
}
|
|
|
|
// AddProjectedVolume adds projected volume with ConfigMap and/or Secret.
|
|
func AddProjectedVolume(spec *corev1.PodSpec, containerIdx int, cmName, secretName string) {
|
|
sources := []corev1.VolumeProjection{}
|
|
if cmName != "" {
|
|
sources = append(sources, corev1.VolumeProjection{
|
|
ConfigMap: &corev1.ConfigMapProjection{
|
|
LocalObjectReference: corev1.LocalObjectReference{Name: cmName},
|
|
},
|
|
})
|
|
}
|
|
if secretName != "" {
|
|
sources = append(sources, corev1.VolumeProjection{
|
|
Secret: &corev1.SecretProjection{
|
|
LocalObjectReference: corev1.LocalObjectReference{Name: secretName},
|
|
},
|
|
})
|
|
}
|
|
AddVolume(spec, containerIdx, corev1.Volume{
|
|
Name: "projected-config",
|
|
VolumeSource: corev1.VolumeSource{
|
|
Projected: &corev1.ProjectedVolumeSource{Sources: sources},
|
|
},
|
|
}, "/etc/projected")
|
|
}
|
|
|
|
// AddKeyRef adds env var from ConfigMap or Secret key.
|
|
func AddKeyRef(spec *corev1.PodSpec, containerIdx int, resourceName, key, envVarName string, isSecret bool) {
|
|
if containerIdx >= len(spec.Containers) {
|
|
return
|
|
}
|
|
envVar := corev1.EnvVar{Name: envVarName}
|
|
if isSecret {
|
|
envVar.ValueFrom = &corev1.EnvVarSource{
|
|
SecretKeyRef: &corev1.SecretKeySelector{
|
|
LocalObjectReference: corev1.LocalObjectReference{Name: resourceName},
|
|
Key: key,
|
|
},
|
|
}
|
|
} else {
|
|
envVar.ValueFrom = &corev1.EnvVarSource{
|
|
ConfigMapKeyRef: &corev1.ConfigMapKeySelector{
|
|
LocalObjectReference: corev1.LocalObjectReference{Name: resourceName},
|
|
Key: key,
|
|
},
|
|
}
|
|
}
|
|
spec.Containers[containerIdx].Env = append(spec.Containers[containerIdx].Env, envVar)
|
|
}
|
|
|
|
// AddCSIVolume adds CSI volume referencing SecretProviderClass.
|
|
func AddCSIVolume(spec *corev1.PodSpec, containerIdx int, spcName string) {
|
|
volumeName := "csi-" + spcName
|
|
mountPath := "/mnt/secrets-store/" + spcName
|
|
spec.Volumes = append(spec.Volumes, corev1.Volume{
|
|
Name: volumeName,
|
|
VolumeSource: corev1.VolumeSource{
|
|
CSI: &corev1.CSIVolumeSource{
|
|
Driver: CSIDriverName,
|
|
ReadOnly: ptr.To(true),
|
|
VolumeAttributes: map[string]string{
|
|
"secretProviderClass": spcName,
|
|
},
|
|
},
|
|
},
|
|
})
|
|
if containerIdx < len(spec.Containers) {
|
|
spec.Containers[containerIdx].VolumeMounts = append(
|
|
spec.Containers[containerIdx].VolumeMounts,
|
|
corev1.VolumeMount{Name: volumeName, MountPath: mountPath, ReadOnly: true},
|
|
)
|
|
}
|
|
}
|
|
|
|
// AddCSIInitContainer adds an init container that mounts a CSI SecretProviderClass volume.
|
|
// The init container is named "init-csi-{spcName}" to avoid collisions when multiple CSI
|
|
// volumes are mounted. The volume is only added if not already present (idempotent).
|
|
// This is distinct from AddCSIVolume which mounts into a regular container.
|
|
func AddCSIInitContainer(spec *corev1.PodSpec, spcName string) {
|
|
volumeName := "csi-" + spcName
|
|
mountPath := "/mnt/secrets-store/" + spcName
|
|
|
|
hasVolume := false
|
|
for _, v := range spec.Volumes {
|
|
if v.Name == volumeName {
|
|
hasVolume = true
|
|
break
|
|
}
|
|
}
|
|
if !hasVolume {
|
|
spec.Volumes = append(spec.Volumes, corev1.Volume{
|
|
Name: volumeName,
|
|
VolumeSource: corev1.VolumeSource{
|
|
CSI: &corev1.CSIVolumeSource{
|
|
Driver: CSIDriverName,
|
|
ReadOnly: ptr.To(true),
|
|
VolumeAttributes: map[string]string{
|
|
"secretProviderClass": spcName,
|
|
},
|
|
},
|
|
},
|
|
})
|
|
}
|
|
spec.InitContainers = append(spec.InitContainers, corev1.Container{
|
|
Name: "init-csi-" + spcName,
|
|
Image: DefaultImage,
|
|
Command: []string{"sh", "-c", "echo init done"},
|
|
VolumeMounts: []corev1.VolumeMount{
|
|
{Name: volumeName, MountPath: mountPath, ReadOnly: true},
|
|
},
|
|
})
|
|
}
|
|
|
|
// AddInitContainer adds init container with optional envFrom references.
|
|
func AddInitContainer(spec *corev1.PodSpec, cmName, secretName string) {
|
|
init := corev1.Container{
|
|
Name: "init",
|
|
Image: DefaultImage,
|
|
Command: []string{"sh", "-c", "echo init done"},
|
|
}
|
|
if cmName != "" {
|
|
init.EnvFrom = append(init.EnvFrom, corev1.EnvFromSource{
|
|
ConfigMapRef: &corev1.ConfigMapEnvSource{
|
|
LocalObjectReference: corev1.LocalObjectReference{Name: cmName},
|
|
},
|
|
})
|
|
}
|
|
if secretName != "" {
|
|
init.EnvFrom = append(init.EnvFrom, corev1.EnvFromSource{
|
|
SecretRef: &corev1.SecretEnvSource{
|
|
LocalObjectReference: corev1.LocalObjectReference{Name: secretName},
|
|
},
|
|
})
|
|
}
|
|
spec.InitContainers = append(spec.InitContainers, init)
|
|
}
|
|
|
|
// AddInitContainerWithVolumes adds init container with volume mounts.
|
|
func AddInitContainerWithVolumes(spec *corev1.PodSpec, cmName, secretName string) {
|
|
init := corev1.Container{
|
|
Name: "init",
|
|
Image: DefaultImage,
|
|
Command: []string{"sh", "-c", "echo init done"},
|
|
}
|
|
if cmName != "" {
|
|
volumeName := "init-cm-" + cmName
|
|
spec.Volumes = append(spec.Volumes, corev1.Volume{
|
|
Name: volumeName,
|
|
VolumeSource: corev1.VolumeSource{
|
|
ConfigMap: &corev1.ConfigMapVolumeSource{
|
|
LocalObjectReference: corev1.LocalObjectReference{Name: cmName},
|
|
},
|
|
},
|
|
})
|
|
init.VolumeMounts = append(init.VolumeMounts, corev1.VolumeMount{
|
|
Name: volumeName,
|
|
MountPath: "/etc/init-config/" + cmName,
|
|
})
|
|
}
|
|
if secretName != "" {
|
|
volumeName := "init-secret-" + secretName
|
|
spec.Volumes = append(spec.Volumes, corev1.Volume{
|
|
Name: volumeName,
|
|
VolumeSource: corev1.VolumeSource{
|
|
Secret: &corev1.SecretVolumeSource{SecretName: secretName},
|
|
},
|
|
})
|
|
init.VolumeMounts = append(init.VolumeMounts, corev1.VolumeMount{
|
|
Name: volumeName,
|
|
MountPath: "/etc/init-secrets/" + secretName,
|
|
})
|
|
}
|
|
spec.InitContainers = append(spec.InitContainers, init)
|
|
}
|
|
|
|
// ApplyWorkloadConfig applies all WorkloadConfig settings to a PodTemplateSpec.
|
|
// This includes both pod template annotations and pod spec configuration.
|
|
func ApplyWorkloadConfig(template *corev1.PodTemplateSpec, cfg WorkloadConfig) {
|
|
if len(cfg.PodTemplateAnnotations) > 0 {
|
|
if template.Annotations == nil {
|
|
template.Annotations = make(map[string]string)
|
|
}
|
|
for k, v := range cfg.PodTemplateAnnotations {
|
|
template.Annotations[k] = v
|
|
}
|
|
}
|
|
|
|
spec := &template.Spec
|
|
if cfg.UseConfigMapEnvFrom && cfg.ConfigMapName != "" {
|
|
AddEnvFromSource(spec, 0, cfg.ConfigMapName, false)
|
|
}
|
|
if cfg.UseSecretEnvFrom && cfg.SecretName != "" {
|
|
AddEnvFromSource(spec, 0, cfg.SecretName, true)
|
|
}
|
|
if cfg.UseConfigMapVolume && cfg.ConfigMapName != "" {
|
|
AddConfigMapVolume(spec, 0, cfg.ConfigMapName)
|
|
}
|
|
if cfg.UseSecretVolume && cfg.SecretName != "" {
|
|
AddSecretVolume(spec, 0, cfg.SecretName)
|
|
}
|
|
if cfg.UseProjectedVolume {
|
|
AddProjectedVolume(spec, 0, cfg.ConfigMapName, cfg.SecretName)
|
|
}
|
|
if cfg.UseConfigMapKeyRef && cfg.ConfigMapName != "" {
|
|
key := cfg.ConfigMapKey
|
|
if key == "" {
|
|
key = "key"
|
|
}
|
|
envVar := cfg.EnvVarName
|
|
if envVar == "" {
|
|
envVar = "CONFIG_VAR"
|
|
}
|
|
AddKeyRef(spec, 0, cfg.ConfigMapName, key, envVar, false)
|
|
}
|
|
if cfg.UseSecretKeyRef && cfg.SecretName != "" {
|
|
key := cfg.SecretKey
|
|
if key == "" {
|
|
key = "key"
|
|
}
|
|
envVar := cfg.EnvVarName
|
|
if envVar == "" {
|
|
envVar = "SECRET_VAR"
|
|
}
|
|
AddKeyRef(spec, 0, cfg.SecretName, key, envVar, true)
|
|
}
|
|
if cfg.UseCSIVolume && cfg.SPCName != "" {
|
|
AddCSIVolume(spec, 0, cfg.SPCName)
|
|
}
|
|
if cfg.UseInitContainer {
|
|
AddInitContainer(spec, cfg.ConfigMapName, cfg.SecretName)
|
|
}
|
|
if cfg.UseInitContainerVolume {
|
|
AddInitContainerWithVolumes(spec, cfg.ConfigMapName, cfg.SecretName)
|
|
}
|
|
if cfg.UseInitContainerCSI && cfg.SPCName != "" {
|
|
AddCSIInitContainer(spec, cfg.SPCName)
|
|
}
|
|
if cfg.MultipleContainers > 1 {
|
|
for i := 1; i < cfg.MultipleContainers; i++ {
|
|
spec.Containers = append(spec.Containers, corev1.Container{
|
|
Name: fmt.Sprintf("container-%d", i),
|
|
Image: DefaultImage,
|
|
Command: []string{"sh", "-c", DefaultCommand},
|
|
})
|
|
}
|
|
}
|
|
}
|