diff --git a/library/common-test/tests/initcontainers_in_deployment/additional_containers_in_deployment_test.yaml b/library/common-test/tests/initcontainers_in_deployment/additional_containers_in_deployment_test.yaml new file mode 100644 index 00000000..e0f02eac --- /dev/null +++ b/library/common-test/tests/initcontainers_in_deployment/additional_containers_in_deployment_test.yaml @@ -0,0 +1,999 @@ +suite: additionalContainer in deployment test +templates: + - common.yaml +tests: + - it: should pass with default values + documentIndex: &deploymentDoc 0 + asserts: + - hasDocuments: + count: 3 + - isKind: + of: Deployment + + - it: should pass with image defined in additional container + documentIndex: *deploymentDoc + set: + image: + repository: some-repo + tag: some-tag + pullPolicy: Always + additionalImage: + repository: some-repo-additional + tag: some-tag-additional + pullPolicy: Never + additionalContainers: + some-name: + imageSelector: additionalImage + pullPolicy: Never + asserts: + - isSubset: + path: spec.template.spec.containers[0] + content: + image: some-repo:some-tag + imagePullPolicy: Always + - isSubset: + path: spec.template.spec.containers[1] + content: + image: some-repo-additional:some-tag-additional + imagePullPolicy: Never + + - it: should pass with image defined in multiple additional container + documentIndex: *deploymentDoc + set: + image: + repository: some-repo + tag: some-tag + pullPolicy: Always + additionalImage: + repository: some-repo-additional + tag: some-tag-additional + pullPolicy: Never + additionalImage2: + repository: some-repo-additional2 + tag: some-tag-additional2 + pullPolicy: IfNotPresent + additionalContainers: + some-name: + imageSelector: additionalImage + pullPolicy: Never + some-name2: + imageSelector: additionalImage2 + pullPolicy: Never + asserts: + - isSubset: + path: spec.template.spec.containers[0] + content: + image: some-repo:some-tag + imagePullPolicy: Always + - isSubset: + path: spec.template.spec.containers[1] + content: + image: some-repo-additional:some-tag-additional + imagePullPolicy: Never + - isSubset: + path: spec.template.spec.containers[2] + content: + image: some-repo-additional2:some-tag-additional2 + imagePullPolicy: IfNotPresent + + - it: should pass with tty and stdin defined in additional container + documentIndex: *deploymentDoc + set: + additionalContainers: + some-name: + tty: true + stdin: true + asserts: + - isSubset: + path: spec.template.spec.containers[0] + content: + tty: false + stdin: false + - isSubset: + path: spec.template.spec.containers[1] + content: + tty: true + stdin: true + + - it: should pass with command and args defined in additional container + documentIndex: *deploymentDoc + set: + port: 8080 + entrypoint: ./run.sh + additionalContainers: + some-name: + command: + - /bin/sh + - -c + - | + {{ .Values.entrypoint }} + args: + - --port + - "{{ .Values.port }}" + extraArgs: + - --data_dir + - /data + asserts: + - isNotSubset: + path: spec.template.spec.containers[0] + content: + command: + - /bin/sh + - -c + - | + ./run.sh + args: + - --port + - "8080" + - --data_dir + - /data + - isSubset: + path: spec.template.spec.containers[1] + content: + command: + - /bin/sh + - -c + - | + ./run.sh + args: + - --port + - "8080" + - --data_dir + - /data + + - it: should pass with termination defined in additional container + documentIndex: *deploymentDoc + set: + additionalContainers: + some-name: + termination: + messagePath: somePath + messagePolicy: File + asserts: + - isNotSubset: + path: spec.template.spec.containers[0] + content: + terminationMessagePath: somePath + terminationMessagePolicy: File + - isSubset: + path: spec.template.spec.containers[1] + content: + terminationMessagePath: somePath + terminationMessagePolicy: File + + - it: should pass with resources inherited from main container and modified in additional container + documentIndex: *deploymentDoc + set: + resources: + requests: + cpu: 25m + memory: 80Mi + additionalContainers: + some-name: + resources: + inherit: true + limits: + cpu: 1000m + memory: 1Gi + requests: + memory: 120Mi + asserts: + - isSubset: + path: spec.template.spec.containers[0] + content: + resources: + limits: + cpu: 4000m + memory: 8Gi + requests: + cpu: 25m + memory: 80Mi + - isSubset: + path: spec.template.spec.containers[1] + content: + resources: + limits: + cpu: 1000m + memory: 1Gi + requests: + cpu: 25m + memory: 120Mi + + - it: should pass with resources defined in additional container + documentIndex: *deploymentDoc + set: + additionalContainers: + some-name: + nvidiaCaps: + - compute + scaleGPU: + gpu.intel.com/i915: "1" + resources: + limits: + cpu: 3000m + memory: 4Gi + requests: + cpu: 20m + memory: 100Mi + asserts: + - isSubset: + path: spec.template.spec.containers[0] + content: + resources: + limits: + cpu: 4000m + memory: 8Gi + requests: + cpu: 10m + memory: 50Mi + - isSubset: + path: spec.template.spec.containers[1] + content: + resources: + limits: + cpu: 3000m + memory: 4Gi + gpu.intel.com/i915: "1" + requests: + cpu: 20m + memory: 100Mi + - notContains: + path: spec.template.spec.containers[0].env + content: + name: NVIDIA_DRIVER_CAPABILITIES + value: all + - contains: + path: spec.template.spec.containers[1].env + content: + name: NVIDIA_DRIVER_CAPABILITIES + value: compute + + - it: should pass with envFrom defined in additional container + documentIndex: *deploymentDoc + set: + some_name: a_name + some_name2: a_name2 + additionalContainers: + some-name: + envFrom: + - configMapRef: + name: "{{ .Values.some_name }}" + - configMapRef: + name: "{{ .Values.some_name2 }}" + asserts: + - isNotSubset: + path: spec.template.spec.containers[0] + content: + envFrom: + - configMapRef: + name: a_name + - configMapRef: + name: a_name2 + - isSubset: + path: spec.template.spec.containers[1] + content: + envFrom: + - configMapRef: + name: a_name + - configMapRef: + name: a_name2 + + - it: should pass with env and envList defined in additional container + documentIndex: *deploymentDoc + set: + some_value: value + some_value2: value2 + some_value3: value3 + some_value4: value4 + additionalContainers: + some-name: + env: + var1: "{{ .Values.some_value }}" + var2: "{{ .Values.some_value2 }}" + envList: + - name: var3 + value: "{{ .Values.some_value3 }}" + - name: var4 + value: "{{ .Values.some_value4 }}" + asserts: + - isNotSubset: + path: spec.template.spec.containers[0] + content: + env: + - name: var1 + value: value + - name: var2 + value: value2 + - name: var3 + value: value3 + - name: var4 + value: value4 + - isSubset: + path: spec.template.spec.containers[1] + content: + env: + - name: TZ + value: UTC + - name: UMASK + value: "002" + - name: UMASK_SET + value: "002" + - name: NVIDIA_VISIBLE_DEVICES + value: void + - name: S6_READ_ONLY_ROOT + value: "1" + - name: var1 + value: value + - name: var2 + value: value2 + - name: var3 + value: value3 + - name: var4 + value: value4 + + - it: should pass with changed PUID/UMASK + documentIndex: *deploymentDoc + set: + additionalContainers: + some-name: + securityContext: + runAsUser: 0 + runAsNonRoot: false + security: + UMASK: "003" + PUID: 1000 + asserts: + - isSubset: + path: spec.template.spec.containers[0] + content: + env: + - name: TZ + value: UTC + - name: UMASK + value: "002" + - name: UMASK_SET + value: "002" + - name: NVIDIA_VISIBLE_DEVICES + value: void + - name: S6_READ_ONLY_ROOT + value: "1" + - isSubset: + path: spec.template.spec.containers[1] + content: + env: + - name: TZ + value: UTC + - name: UMASK + value: "003" + - name: UMASK_SET + value: "003" + - name: NVIDIA_VISIBLE_DEVICES + value: void + - name: PUID + value: "1000" + - name: USER_ID + value: "1000" + - name: UID + value: "1000" + - name: PGID + value: "568" + - name: GROUP_ID + value: "568" + - name: GID + value: "568" + - name: S6_READ_ONLY_ROOT + value: "1" + + - it: should pass with disabled injectFixedEnvs + documentIndex: *deploymentDoc + set: + additionalContainers: + some-name: + securityContext: + runAsUser: 0 + runAsNonRoot: false + injectFixedEnvs: false + asserts: + - isSubset: + path: spec.template.spec.containers[0] + content: + env: + - name: TZ + value: UTC + - name: UMASK + value: "002" + - name: UMASK_SET + value: "002" + - name: NVIDIA_VISIBLE_DEVICES + value: void + - name: S6_READ_ONLY_ROOT + value: "1" + - isNull: + path: spec.template.spec.containers[0].e1v + + - it: should fail with lifecycle defined in additional container + documentIndex: *deploymentDoc + set: + additionalContainers: + some-name: + lifecycle: + postStart: + command: + - /bin/bash + - test1 + preStop: + command: + - /bin/bash + - test2 + asserts: + - isNull: + path: spec.template.spec.containers[0].lifecycle + - isSubset: + path: spec.template.spec.containers[1] + content: + lifecycle: + postStart: + exec: + command: + - /bin/bash + - test1 + preStop: + exec: + command: + - /bin/bash + - test2 + + - it: should fail with env trying to override fixedEnvs in additional container + documentIndex: *deploymentDoc + set: + additionalContainers: + some-name: + env: + TZ: something + asserts: + - failedTemplate: + errorMessage: Environment Variable (TZ) on container (RELEASE-NAME-common-test-some-name) is set more than once. [to (UTC) on (fixedEnv)] and [to (something) on (env)] + + - it: should fail with env trying to override configmap in additional container + documentIndex: *deploymentDoc + set: + configmap: + some-confmap: + enabled: true + parseAsEnv: true + content: + TZ: something + additionalContainers: + some-name: + envFrom: + - configMapRef: + name: '{{ include "ix.v1.common.names.fullname" . }}-some-confmap' + asserts: + - failedTemplate: + errorMessage: Environment Variable (TZ) on container (RELEASE-NAME-common-test-some-name) is set more than once. [to (UTC) on (fixedEnv)] and [to (something) on (configmap-RELEASE-NAME-common-test-some-confmap)] + + - it: should fail with env trying to override secret in additional container + documentIndex: *deploymentDoc + set: + secret: + some-secret: + enabled: true + parseAsEnv: true + content: + TZ: something + additionalContainers: + some-name: + envFrom: + - secretRef: + name: '{{ include "ix.v1.common.names.fullname" . }}-some-secret' + asserts: + - failedTemplate: + errorMessage: Environment Variable (TZ) on container (RELEASE-NAME-common-test-some-name) is set more than once. [to (UTC) on (fixedEnv)] and [to (something) on (secret-RELEASE-NAME-common-test-some-secret)] + + - it: should pass with securityContext inherited + documentIndex: *deploymentDoc + set: + securityContext: + runAsUser: 0 + runAsGroup: 0 + runAsNonRoot: false + readOnlyRootFilesystem: false + privileged: true + allowPrivilegeEscalation: true + capabilities: + add: + - Something + drop: + - Something_Else + additionalContainers: + some_container: + imageSelector: image + securityContext: + inherit: true + asserts: + - isSubset: + path: spec.template.spec.containers[0] + content: + securityContext: + runAsUser: 0 + runAsGroup: 0 + runAsNonRoot: false + readOnlyRootFilesystem: false + privileged: true + allowPrivilegeEscalation: true + capabilities: + add: + - Something + drop: + - Something_Else + - isSubset: + path: spec.template.spec.containers[1] + content: + securityContext: + allowPrivilegeEscalation: true + capabilities: + add: + - Something + drop: + - Something_Else + privileged: true + readOnlyRootFilesystem: false + runAsGroup: 0 + runAsNonRoot: false + runAsUser: 0 + + - it: should pass with securityContext default + documentIndex: *deploymentDoc + set: + additionalContainers: + some_container: + imageSelector: image + securityContext: + inherit: true + asserts: + - isSubset: + path: spec.template.spec.containers[0] + content: + securityContext: + allowPrivilegeEscalation: false + capabilities: + add: [] + drop: + - ALL + privileged: false + readOnlyRootFilesystem: true + runAsGroup: 568 + runAsNonRoot: true + runAsUser: 568 + - isSubset: + path: spec.template.spec.containers[1] + content: + securityContext: + allowPrivilegeEscalation: false + capabilities: + add: [] + drop: + - ALL + privileged: false + readOnlyRootFilesystem: true + runAsGroup: 568 + runAsNonRoot: true + runAsUser: 568 + + - it: should pass with securityContext changed + documentIndex: *deploymentDoc + set: + additionalContainers: + some_container: + imageSelector: image + securityContext: + runAsUser: 0 + runAsGroup: 0 + runAsNonRoot: false + readOnlyRootFilesystem: false + privileged: true + allowPrivilegeEscalation: true + capabilities: + add: + - Something + drop: + - Something_Else + asserts: + - isSubset: + path: spec.template.spec.containers[0] + content: + securityContext: + allowPrivilegeEscalation: false + capabilities: + add: [] + drop: + - ALL + privileged: false + readOnlyRootFilesystem: true + runAsGroup: 568 + runAsNonRoot: true + runAsUser: 568 + - isSubset: + path: spec.template.spec.containers[1] + content: + securityContext: + allowPrivilegeEscalation: true + capabilities: + add: + - Something + drop: + - Something_Else + privileged: true + readOnlyRootFilesystem: false + runAsGroup: 0 + runAsNonRoot: false + runAsUser: 0 + + - it: should pass with securityContext with some values changed + documentIndex: *deploymentDoc + set: + additionalContainers: + some_container: + imageSelector: image + securityContext: + runAsUser: 0 + runAsGroup: 0 + runAsNonRoot: false + capabilities: + add: + - Something + asserts: + - isSubset: + path: spec.template.spec.containers[0] + content: + securityContext: + allowPrivilegeEscalation: false + capabilities: + add: [] + drop: + - ALL + privileged: false + readOnlyRootFilesystem: true + runAsGroup: 568 + runAsNonRoot: true + runAsUser: 568 + - isSubset: + path: spec.template.spec.containers[1] + content: + securityContext: + allowPrivilegeEscalation: false + capabilities: + add: + - Something + drop: + - ALL + privileged: false + readOnlyRootFilesystem: true + runAsGroup: 0 + runAsNonRoot: false + runAsUser: 0 + + - it: should pass with securityContext with inherit and at least one value changed + documentIndex: *deploymentDoc + set: + securityContext: + privileged: true + allowPrivilegeEscalation: true + capabilities: + drop: + - something_else + additionalContainers: + some_container: + imageSelector: image + securityContext: + inherit: true + runAsNonRoot: false + runAsUser: 0 + asserts: + - isSubset: + path: spec.template.spec.containers[0] + content: + securityContext: + allowPrivilegeEscalation: true + capabilities: + add: [] + drop: + - something_else + privileged: true + readOnlyRootFilesystem: true + runAsGroup: 568 + runAsNonRoot: true + runAsUser: 568 + - isSubset: + path: spec.template.spec.containers[1] + content: + securityContext: + allowPrivilegeEscalation: true + capabilities: + add: [] + drop: + - something_else + privileged: true + readOnlyRootFilesystem: true + runAsGroup: 568 + runAsNonRoot: false + runAsUser: 0 + + - it: should fail with probe type set to auto in additional container + documentIndex: *deploymentDoc + set: + additionalContainers: + some-name: + probes: + liveness: + enabled: true + type: auto + asserts: + - failedTemplate: + errorMessage: probe type in probe (liveness) in (RELEASE-NAME-common-test-some-name) container, is only supported for the main container and only if there is at least 1 port enabled + + - it: should pass with probes defined in additional container + documentIndex: *deploymentDoc + set: + additionalContainers: + some-name: + probes: + liveness: + enabled: true + type: tcp + port: 3000 + readiness: + enabled: true + type: http + port: 3000 + path: / + startup: + enabled: true + type: exec + command: + - /bin/bash + - -c + - | + echo "start!" + asserts: + - isSubset: + path: spec.template.spec.containers[0] + content: + livenessProbe: + httpGet: + path: / + scheme: HTTP + port: 65535 + initialDelaySeconds: 10 + failureThreshold: 5 + timeoutSeconds: 5 + periodSeconds: 10 + readinessProbe: + httpGet: + path: / + scheme: HTTP + port: 65535 + initialDelaySeconds: 10 + failureThreshold: 5 + timeoutSeconds: 5 + periodSeconds: 10 + startupProbe: + httpGet: + path: / + scheme: HTTP + port: 65535 + initialDelaySeconds: 10 + failureThreshold: 60 + timeoutSeconds: 2 + periodSeconds: 5 + - isSubset: + path: spec.template.spec.containers[1] + content: + livenessProbe: + tcpSocket: + port: 3000 + initialDelaySeconds: 10 + failureThreshold: 5 + timeoutSeconds: 5 + periodSeconds: 10 + readinessProbe: + httpGet: + path: / + scheme: HTTP + port: 3000 + initialDelaySeconds: 10 + failureThreshold: 5 + timeoutSeconds: 5 + periodSeconds: 10 + startupProbe: + exec: + command: + - /bin/bash + - -c + - | + echo "start!" + initialDelaySeconds: 10 + failureThreshold: 60 + timeoutSeconds: 2 + periodSeconds: 5 + + - it: should fail with invalid protocol in ports in additional container + documentIndex: *deploymentDoc + set: + additionalContainers: + some-name: + ports: + - containerPort: 5678 + protocol: invalid-proto + name: tcp-port + asserts: + - failedTemplate: + errorMessage: Invalid (invalid-proto) in port (tcp-port) in (RELEASE-NAME-common-test-some-name) container. Valid protocols are TCP and UDP. + + - it: should fail without name in ports in additional container + documentIndex: *deploymentDoc + set: + additionalContainers: + some-name: + ports: + - containerPort: 5678 + protocol: TCP + name: "" + asserts: + - failedTemplate: + errorMessage: is required in all in (RELEASE-NAME-common-test-some-name) container. + + - it: should fail without containerPort in ports in additional container + documentIndex: *deploymentDoc + set: + additionalContainers: + some-name: + ports: + - containerPort: "" + name: tcp-port + asserts: + - failedTemplate: + errorMessage: is required in port (tcp-port) in (RELEASE-NAME-common-test-some-name) container. + + - it: should fail with non-int containerPort in ports in additional container + documentIndex: *deploymentDoc + set: + additionalContainers: + some-name: + ports: + - containerPort: not-int + name: tcp-port + asserts: + - failedTemplate: + errorMessage: Invalid (not-int) in port (tcp-port) in (RELEASE-NAME-common-test-some-name) container. Must be an int. + + - it: should fail with non-int hostPort in ports in additional container + documentIndex: *deploymentDoc + set: + additionalContainers: + some-name: + ports: + - containerPort: 1234 + hostPort: not-int + name: tcp-port + asserts: + - failedTemplate: + errorMessage: Invalid (not-int) in port (tcp-port) in (RELEASE-NAME-common-test-some-name) container. Must be an int. + + - it: should pass without protocol in ports in additional container + documentIndex: *deploymentDoc + set: + additionalContainers: + some-name: + ports: + - containerPort: 5678 + name: tcp-port + asserts: + - isSubset: + path: spec.template.spec.containers[1] + content: + ports: + - containerPort: 5678 + protocol: TCP + name: tcp-port + + - it: should pass with ports defined in additional container + documentIndex: *deploymentDoc + set: + additionalContainers: + some-name: + ports: + - containerPort: 5678 + protocol: TCP + name: tcp-port + - containerPort: 1234 + protocol: UDP + name: udp-port + asserts: + - isSubset: + path: spec.template.spec.containers[0] + content: + ports: + - containerPort: 65535 + protocol: TCP + name: main + - isSubset: + path: spec.template.spec.containers[1] + content: + ports: + - containerPort: 5678 + protocol: TCP + name: tcp-port + - containerPort: 1234 + protocol: UDP + name: udp-port + + - it: should fail without trying to mount a non existent volume in volumeMounts defined in additional container + documentIndex: *deploymentDoc + set: + additionalContainers: + some-name: + volumeMounts: + - name: some-volume + mountPath: /some/path + asserts: + - failedTemplate: + errorMessage: You are trying to mount a volume that does not exist (some-volume). Please define the volume in . + + - it: should fail without name in volumeMounts defined in additional container + documentIndex: *deploymentDoc + set: + additionalContainers: + some-name: + volumeMounts: + - name: + mountPath: /some/path + readOnly: false + subPath: /some/sub/path + asserts: + - failedTemplate: + errorMessage: is required in volumeMounts in init/install/upgrade/additional containers. + + - it: should pass with volumeMounts defined in additional container + documentIndex: *deploymentDoc + set: + persistence: + some-volume: + enabled: true + noMount: true + type: emptyDir + some-other-volume: + enabled: true + noMount: true + type: emptyDir + additionalContainers: + some-name: + volumeMounts: + - name: some-volume + mountPath: /some/path + readOnly: false + subPath: /some/sub/path + - name: some-other-volume + mountPath: /some/other/path + readOnly: false + subPath: /some/other/sub/path + asserts: + - isSubset: + path: spec.template.spec.containers[0] + content: + ports: + - containerPort: 65535 + protocol: TCP + name: main + - isSubset: + path: spec.template.spec.containers[1] + content: + volumeMounts: + - name: some-volume + mountPath: /some/path + readOnly: false + subPath: /some/sub/path + - name: some-other-volume + mountPath: /some/other/path + readOnly: false + subPath: /some/other/sub/path diff --git a/library/common/1.0.0/templates/lib/pod/_pod.tpl b/library/common/1.0.0/templates/lib/pod/_pod.tpl index f0919b81..ca9bda37 100644 --- a/library/common/1.0.0/templates/lib/pod/_pod.tpl +++ b/library/common/1.0.0/templates/lib/pod/_pod.tpl @@ -1,5 +1,6 @@ {{/* The pod definition included in the controller. */}} {{- define "ix.v1.common.controller.pod" -}} +{{- $root := . }} serviceAccountName: {{ (include "ix.v1.common.names.serviceAccountName" .) }} {{- with .Values.schedulerName }} schedulerName: {{ tpl . $ }} @@ -51,8 +52,9 @@ imagePullSecrets: runtimeClassName: {{ . }} {{- end -}} {{- with (include "ix.v1.common.controller.mainContainer" . | trim) }} -containers: {{/* TODO: Additional Containers */}} +containers: {{- . | nindent 2 }} + {{- (include "ix.v1.common.controller.extraContainers" (dict "root" $root "containerList" $root.Values.additionalContainers "type" "addititional") | trim) | nindent 2 }} {{- end -}} {{- if or .Values.initContainers .Values.installContainers .Values.upgradeContainers }} initContainers: