Skip to content

Commit c5cd4ff

Browse files
authored
feat: Add support for init containers and multiple volumes (#90)
1 parent 9c707d6 commit c5cd4ff

File tree

3 files changed

+233
-7
lines changed

3 files changed

+233
-7
lines changed

templates/deployment.yaml

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,9 @@ spec:
6666
{{- end }}
6767
{{- end }}
6868
{{- end }}
69+
{{- with .Values.relay.extraVolumes }}
70+
{{- toYaml . | nindent 6 }}
71+
{{- end }}
6972
serviceAccountName: {{ include "ld-relay.serviceAccountName" . }}
7073
{{- with .Values.pod.securityContext }}
7174
securityContext:
@@ -74,9 +77,13 @@ spec:
7477
{{- if .Values.terminationGracePeriodSeconds }}
7578
terminationGracePeriodSeconds: {{ .Values.terminationGracePeriodSeconds }}
7679
{{- end}}
80+
{{- with .Values.relay.initContainers }}
81+
initContainers:
82+
{{- toYaml . | nindent 8 }}
83+
{{- end }}
7784
containers:
7885
- name: {{ .Chart.Name }}
79-
{{- if $has_volumes }}
86+
{{- if or $has_volumes .Values.relay.extraVolumeMounts }}
8087
volumeMounts:
8188
{{- if .Values.relay.volume.definition }}
8289
- name: {{ include "ld-relay.name" . }}-volume
@@ -87,11 +94,21 @@ spec:
8794
mountPath: /mnt/secrets/
8895
readOnly: true
8996
{{- end }}
97+
{{- with .Values.relay.extraVolumeMounts }}
98+
{{- toYaml . | nindent 12 }}
99+
{{- end }}
90100
{{- end }}
91101

92-
{{- if .Values.relay.volume.config }}
102+
{{- if .Values.relay.command }}
103+
command:
104+
{{- toYaml .Values.relay.command | nindent 12 }}
105+
{{- else if .Values.relay.volume.config }}
93106
command: ["/usr/bin/ldr", "--config", "/mnt/volume/{{ .Values.relay.volume.config }}", "--allow-missing-file", "--from-env"]
94107
{{- end }}
108+
{{- if .Values.relay.args }}
109+
args:
110+
{{- toYaml .Values.relay.args | nindent 12 }}
111+
{{- end }}
95112

96113
env:
97114
{{- if .Values.relay.volume.offline }}

test/deployment_test.go

Lines changed: 178 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,7 @@ func (s *TemplateTest) TestCanSetEnvironmentVariablesFromEnvFromSecrets() {
133133
s.Require().Equal("ld-relay-test-secret-environment-variables", deployment.Spec.Template.Spec.Containers[0].EnvFrom[0].SecretRef.Name)
134134
s.Require().Len(deployment.Spec.Template.Spec.Containers[0].EnvFrom, 2)
135135
}
136+
136137
func (s *TemplateTest) TestNotSetEnvironmentVariablesFromEnvFromSecrets() {
137138
options := &helm.Options{
138139
KubectlOptions: k8s.NewKubectlOptions("", "", s.Namespace),
@@ -333,7 +334,6 @@ func (s *TemplateTest) TestCanAffectHttpGetProbes() {
333334
s.Require().Equal("/readiness", deployment.Spec.Template.Spec.Containers[0].ReadinessProbe.ProbeHandler.HTTPGet.Path)
334335
s.Require().Equal(int(9000), deployment.Spec.Template.Spec.Containers[0].ReadinessProbe.ProbeHandler.HTTPGet.Port.IntValue())
335336
s.Require().Equal(corev1.URISchemeHTTPS, deployment.Spec.Template.Spec.Containers[0].ReadinessProbe.ProbeHandler.HTTPGet.Scheme)
336-
337337
}
338338

339339
func (s *TemplateTest) TestCanDisableProbes() {
@@ -510,3 +510,180 @@ func (s *TemplateTest) TestCanSetCommonLabels() {
510510
s.Require().Equal("production", deployment.Spec.Template.Labels["environment"])
511511
s.Require().Equal("platform", deployment.Spec.Template.Labels["team"])
512512
}
513+
514+
func (s *TemplateTest) TestCanOverrideCommand() {
515+
options := &helm.Options{
516+
SetValues: map[string]string{
517+
"relay.command[0]": "/custom/bin/relay",
518+
"relay.command[1]": "--custom-flag",
519+
},
520+
KubectlOptions: k8s.NewKubectlOptions("", "", s.Namespace),
521+
}
522+
523+
output := helm.RenderTemplate(s.T(), options, s.ChartPath, s.Release, []string{"templates/deployment.yaml"})
524+
var deployment appsv1.Deployment
525+
helm.UnmarshalK8SYaml(s.T(), output, &deployment)
526+
527+
expectedCommand := []string{"/custom/bin/relay", "--custom-flag"}
528+
s.Require().Equal(expectedCommand, deployment.Spec.Template.Spec.Containers[0].Command)
529+
}
530+
531+
func (s *TemplateTest) TestCommandOverridesTakePrecedenceOverVolumeConfig() {
532+
options := &helm.Options{
533+
SetValues: map[string]string{
534+
"relay.volume.config": "my-config.config",
535+
"relay.volume.definition.persistentVolumeClaim.claimName": "ld-relay-pvc",
536+
"relay.command[0]": "/custom/bin/relay",
537+
"relay.command[1]": "--custom-flag",
538+
},
539+
KubectlOptions: k8s.NewKubectlOptions("", "", s.Namespace),
540+
}
541+
542+
output := helm.RenderTemplate(s.T(), options, s.ChartPath, s.Release, []string{"templates/deployment.yaml"})
543+
var deployment appsv1.Deployment
544+
helm.UnmarshalK8SYaml(s.T(), output, &deployment)
545+
546+
// When relay.command is set, it should override the default volume.config command generation
547+
expectedCommand := []string{"/custom/bin/relay", "--custom-flag"}
548+
s.Require().Equal(expectedCommand, deployment.Spec.Template.Spec.Containers[0].Command)
549+
}
550+
551+
func (s *TemplateTest) TestCanSetArgs() {
552+
options := &helm.Options{
553+
SetValues: map[string]string{
554+
"relay.args[0]": "--verbose",
555+
"relay.args[1]": "--debug",
556+
},
557+
KubectlOptions: k8s.NewKubectlOptions("", "", s.Namespace),
558+
}
559+
560+
output := helm.RenderTemplate(s.T(), options, s.ChartPath, s.Release, []string{"templates/deployment.yaml"})
561+
var deployment appsv1.Deployment
562+
helm.UnmarshalK8SYaml(s.T(), output, &deployment)
563+
564+
expectedArgs := []string{"--verbose", "--debug"}
565+
s.Require().Equal(expectedArgs, deployment.Spec.Template.Spec.Containers[0].Args)
566+
}
567+
568+
func (s *TemplateTest) TestCanAddExtraVolumes() {
569+
options := &helm.Options{
570+
SetValues: map[string]string{
571+
"relay.extraVolumes[0].name": "custom-config",
572+
"relay.extraVolumes[0].configMap.name": "my-custom-config",
573+
"relay.extraVolumes[1].name": "custom-secret",
574+
"relay.extraVolumes[1].secret.secretName": "my-secret",
575+
},
576+
KubectlOptions: k8s.NewKubectlOptions("", "", s.Namespace),
577+
}
578+
579+
output := helm.RenderTemplate(s.T(), options, s.ChartPath, s.Release, []string{"templates/deployment.yaml"})
580+
var deployment appsv1.Deployment
581+
helm.UnmarshalK8SYaml(s.T(), output, &deployment)
582+
583+
// Default volume + 2 extra volumes
584+
s.Require().Len(deployment.Spec.Template.Spec.Volumes, 3)
585+
586+
// Check the extra volumes
587+
s.Require().Equal("custom-config", deployment.Spec.Template.Spec.Volumes[1].Name)
588+
s.Require().Equal("my-custom-config", deployment.Spec.Template.Spec.Volumes[1].ConfigMap.Name)
589+
590+
s.Require().Equal("custom-secret", deployment.Spec.Template.Spec.Volumes[2].Name)
591+
s.Require().Equal("my-secret", deployment.Spec.Template.Spec.Volumes[2].Secret.SecretName)
592+
}
593+
594+
func (s *TemplateTest) TestCanAddExtraVolumeMounts() {
595+
options := &helm.Options{
596+
SetValues: map[string]string{
597+
"relay.extraVolumeMounts[0].name": "custom-mount",
598+
"relay.extraVolumeMounts[0].mountPath": "/mnt/custom",
599+
"relay.extraVolumeMounts[0].readOnly": "true",
600+
"relay.extraVolumeMounts[1].name": "another-mount",
601+
"relay.extraVolumeMounts[1].mountPath": "/mnt/another",
602+
},
603+
KubectlOptions: k8s.NewKubectlOptions("", "", s.Namespace),
604+
}
605+
606+
output := helm.RenderTemplate(s.T(), options, s.ChartPath, s.Release, []string{"templates/deployment.yaml"})
607+
var deployment appsv1.Deployment
608+
helm.UnmarshalK8SYaml(s.T(), output, &deployment)
609+
610+
// Should have volumeMounts even without default volumes
611+
s.Require().Len(deployment.Spec.Template.Spec.Containers[0].VolumeMounts, 2)
612+
613+
s.Require().Equal("custom-mount", deployment.Spec.Template.Spec.Containers[0].VolumeMounts[0].Name)
614+
s.Require().Equal("/mnt/custom", deployment.Spec.Template.Spec.Containers[0].VolumeMounts[0].MountPath)
615+
s.Require().True(deployment.Spec.Template.Spec.Containers[0].VolumeMounts[0].ReadOnly)
616+
617+
s.Require().Equal("another-mount", deployment.Spec.Template.Spec.Containers[0].VolumeMounts[1].Name)
618+
s.Require().Equal("/mnt/another", deployment.Spec.Template.Spec.Containers[0].VolumeMounts[1].MountPath)
619+
s.Require().False(deployment.Spec.Template.Spec.Containers[0].VolumeMounts[1].ReadOnly)
620+
}
621+
622+
func (s *TemplateTest) TestExtraVolumeMountsWorkWithDefaultVolumes() {
623+
options := &helm.Options{
624+
SetValues: map[string]string{
625+
"relay.volume.config": "my-config.config",
626+
"relay.volume.definition.persistentVolumeClaim.claimName": "ld-relay-pvc",
627+
"relay.extraVolumeMounts[0].name": "custom-mount",
628+
"relay.extraVolumeMounts[0].mountPath": "/mnt/custom",
629+
},
630+
KubectlOptions: k8s.NewKubectlOptions("", "", s.Namespace),
631+
}
632+
633+
output := helm.RenderTemplate(s.T(), options, s.ChartPath, s.Release, []string{"templates/deployment.yaml"})
634+
var deployment appsv1.Deployment
635+
helm.UnmarshalK8SYaml(s.T(), output, &deployment)
636+
637+
// Should have default volume mount + extra volume mount
638+
s.Require().Len(deployment.Spec.Template.Spec.Containers[0].VolumeMounts, 2)
639+
640+
s.Require().Equal("ld-relay-volume", deployment.Spec.Template.Spec.Containers[0].VolumeMounts[0].Name)
641+
s.Require().Equal("/mnt/volume", deployment.Spec.Template.Spec.Containers[0].VolumeMounts[0].MountPath)
642+
643+
s.Require().Equal("custom-mount", deployment.Spec.Template.Spec.Containers[0].VolumeMounts[1].Name)
644+
s.Require().Equal("/mnt/custom", deployment.Spec.Template.Spec.Containers[0].VolumeMounts[1].MountPath)
645+
}
646+
647+
func (s *TemplateTest) TestCanAddInitContainers() {
648+
options := &helm.Options{
649+
SetValues: map[string]string{
650+
"relay.initContainers[0].name": "init-config",
651+
"relay.initContainers[0].image": "busybox:1.28",
652+
"relay.initContainers[0].command[0]": "sh",
653+
"relay.initContainers[0].command[1]": "-c",
654+
"relay.initContainers[0].command[2]": "echo Initializing...",
655+
"relay.initContainers[1].name": "wait-for-db",
656+
"relay.initContainers[1].image": "busybox:1.28",
657+
"relay.initContainers[1].command[0]": "sh",
658+
"relay.initContainers[1].command[1]": "-c",
659+
"relay.initContainers[1].command[2]": "until nc -z db 5432; do sleep 1; done",
660+
},
661+
KubectlOptions: k8s.NewKubectlOptions("", "", s.Namespace),
662+
}
663+
664+
output := helm.RenderTemplate(s.T(), options, s.ChartPath, s.Release, []string{"templates/deployment.yaml"})
665+
var deployment appsv1.Deployment
666+
helm.UnmarshalK8SYaml(s.T(), output, &deployment)
667+
668+
s.Require().Len(deployment.Spec.Template.Spec.InitContainers, 2)
669+
670+
s.Require().Equal("init-config", deployment.Spec.Template.Spec.InitContainers[0].Name)
671+
s.Require().Equal("busybox:1.28", deployment.Spec.Template.Spec.InitContainers[0].Image)
672+
s.Require().Equal([]string{"sh", "-c", "echo Initializing..."}, deployment.Spec.Template.Spec.InitContainers[0].Command)
673+
674+
s.Require().Equal("wait-for-db", deployment.Spec.Template.Spec.InitContainers[1].Name)
675+
s.Require().Equal("busybox:1.28", deployment.Spec.Template.Spec.InitContainers[1].Image)
676+
s.Require().Equal([]string{"sh", "-c", "until nc -z db 5432; do sleep 1; done"}, deployment.Spec.Template.Spec.InitContainers[1].Command)
677+
}
678+
679+
func (s *TemplateTest) TestNoInitContainersByDefault() {
680+
options := &helm.Options{
681+
KubectlOptions: k8s.NewKubectlOptions("", "", s.Namespace),
682+
}
683+
684+
output := helm.RenderTemplate(s.T(), options, s.ChartPath, s.Release, []string{"templates/deployment.yaml"})
685+
var deployment appsv1.Deployment
686+
helm.UnmarshalK8SYaml(s.T(), output, &deployment)
687+
688+
s.Require().Empty(deployment.Spec.Template.Spec.InitContainers)
689+
}

values.yaml

Lines changed: 36 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ pod:
6565
# topologyKey: topology.kubernetes.io/zone
6666
# whenUnsatisfiable: DoNotSchedule
6767

68+
# Optional termination grace period in seconds for graceful pod shutdown
6869
# terminationGracePeriodSeconds: 90
6970

7071
securityContext: {}
@@ -141,6 +142,17 @@ tolerations: []
141142
affinity: {}
142143

143144
relay:
145+
# Optional command override for the relay container
146+
#
147+
# If specified, this overrides the default command generation strategy. This
148+
# includes special handling of other Chart features like the volume.config
149+
# mapping.
150+
command: []
151+
152+
# Optional args to pass to the relay container
153+
# These are appended to the command
154+
args: []
155+
144156
# Specify the relay environment variables here to load them into this chart's ConfigMap directly.
145157
# These environment variables should match the ones documented by the relay proxy at https://github.com/launchdarkly/ld-relay
146158
environment: {}
@@ -199,9 +211,9 @@ relay:
199211
path: /status
200212
port: api
201213
readinessProbe:
202-
httpGet:
203-
path: /status
204-
port: api
214+
httpGet:
215+
path: /status
216+
port: api
205217

206218
lifecycle: []
207219
# preStop:
@@ -211,7 +223,6 @@ relay:
211223
# - -c
212224
# - sleep 60
213225

214-
215226
# Enables mounting a k8s volume onto the relay container.
216227
#
217228
# This configuration option is used to optionally provide access to an
@@ -238,3 +249,24 @@ relay:
238249
definition: {}
239250
# persistentVolumeClaim:
240251
# claimName: ld-relay-pvc
252+
253+
# Additional volumes to mount in the relay pod
254+
# These are appended to the default volumes
255+
extraVolumes: []
256+
# - name: custom-volume
257+
# configMap:
258+
# name: custom-config
259+
260+
# Additional volume mounts for the relay container
261+
# These are appended to the default volume mounts
262+
extraVolumeMounts: []
263+
# - name: custom-volume
264+
# mountPath: /mnt/custom
265+
# readOnly: true
266+
267+
# Init containers to run before the relay container starts
268+
# Useful for setup tasks like downloading configuration or waiting for dependencies
269+
initContainers: []
270+
# - name: init-config
271+
# image: busybox:1.28
272+
# command: ['sh', '-c', 'echo "Initializing..."']

0 commit comments

Comments
 (0)