diff --git a/charts/library/common-test/ci/advanced-values.yaml b/charts/library/common-test/ci/advanced-values.yaml index a9853cfc..15be9c4d 100644 --- a/charts/library/common-test/ci/advanced-values.yaml +++ b/charts/library/common-test/ci/advanced-values.yaml @@ -2,7 +2,6 @@ controllers: main: containers: main: - order: 1 image: repository: ghcr.io/mendhak/http-https-echo tag: 30 @@ -21,6 +20,9 @@ controllers: enabled: true a-container: + dependsOn: + - main + - third-container image: repository: ghcr.io/mendhak/http-https-echo tag: 30 @@ -29,6 +31,7 @@ controllers: HTTPS_PORT: 9998 third-container: + dependsOn: main image: repository: ghcr.io/mendhak/http-https-echo tag: 30 diff --git a/charts/library/common-test/tests/pod/container_order_test.yaml b/charts/library/common-test/tests/pod/container_order_test.yaml index bc6e12b2..733b2708 100644 --- a/charts/library/common-test/tests/pod/container_order_test.yaml +++ b/charts/library/common-test/tests/pod/container_order_test.yaml @@ -19,7 +19,7 @@ tests: - documentIndex: &DeploymentDocument 0 isKind: of: Deployment - - documentIndex: &DeploymentDocument 0 + - documentIndex: *DeploymentDocument lengthEqual: path: spec.template.spec.containers count: 3 @@ -36,6 +36,7 @@ tests: path: spec.template.spec.containers[2].name value: additional2 + # TODO: Remove this test case after "order" removal in v3 - it: with custom order set: controllers.main.containers: @@ -59,7 +60,7 @@ tests: - documentIndex: &DeploymentDocument 0 isKind: of: Deployment - - documentIndex: &DeploymentDocument 0 + - documentIndex: *DeploymentDocument lengthEqual: path: spec.template.spec.containers count: 4 @@ -79,3 +80,91 @@ tests: equal: path: spec.template.spec.containers[3].name value: additional3 + + - it: with dependsOn + set: + controllers.main.containers: + additional1: + dependsOn: additional3 + image: + repository: test + tag: test + additional2: + dependsOn: additional3 + image: + repository: test + tag: test + additional3: + dependsOn: main + image: + repository: test + tag: test + asserts: + - documentIndex: &DeploymentDocument 0 + isKind: + of: Deployment + - documentIndex: *DeploymentDocument + lengthEqual: + path: spec.template.spec.containers + count: 4 + - documentIndex: *DeploymentDocument + equal: + path: spec.template.spec.containers[0].name + value: main + - documentIndex: *DeploymentDocument + equal: + path: spec.template.spec.containers[1].name + value: additional3 + - documentIndex: *DeploymentDocument + equal: + path: spec.template.spec.containers[2].name + value: additional1 + - documentIndex: *DeploymentDocument + equal: + path: spec.template.spec.containers[3].name + value: additional2 + + # TODO: Remove this test case after "order" removal in v3 + - it: with both order and dependsOn + set: + controllers.main.containers: + additional1: + dependsOn: additional3 + image: + repository: test + tag: test + additional2: + dependsOn: additional3 + order: 1 + image: + repository: test + tag: test + additional3: + dependsOn: main + image: + repository: test + tag: test + asserts: + - documentIndex: &DeploymentDocument 0 + isKind: + of: Deployment + - documentIndex: *DeploymentDocument + lengthEqual: + path: spec.template.spec.containers + count: 4 + - documentIndex: *DeploymentDocument + equal: + path: spec.template.spec.containers[0].name + value: main + - documentIndex: *DeploymentDocument + equal: + path: spec.template.spec.containers[1].name + value: additional3 + - documentIndex: *DeploymentDocument + equal: + path: spec.template.spec.containers[2].name + value: additional1 + - documentIndex: *DeploymentDocument + equal: + path: spec.template.spec.containers[3].name + value: additional2 diff --git a/charts/library/common-test/tests/pod/initcontainers_test.yaml b/charts/library/common-test/tests/pod/initcontainers_test.yaml index 62a8bfc1..0929cf18 100644 --- a/charts/library/common-test/tests/pod/initcontainers_test.yaml +++ b/charts/library/common-test/tests/pod/initcontainers_test.yaml @@ -60,6 +60,7 @@ tests: notExists: path: spec.template.spec.initContainers + # TODO: Remove this test case after "order" removal in v3 - it: custom order should pass set: controllers.main.initContainers: @@ -89,3 +90,32 @@ tests: equal: path: spec.template.spec.initContainers[1].name value: init1 + + - it: with dependsOn + set: + controllers.main.initContainers: + init1: + dependsOn: init2 + image: + repository: ghcr.io/mendhak/http-https-echo + tag: latest + init2: + image: + repository: ghcr.io/mendhak/http-https-echo + tag: latest + asserts: + - documentIndex: &DeploymentDocument 0 + isKind: + of: Deployment + - documentIndex: *DeploymentDocument + lengthEqual: + path: spec.template.spec.initContainers + count: 2 + - documentIndex: *DeploymentDocument + equal: + path: spec.template.spec.initContainers[0].name + value: init2 + - documentIndex: *DeploymentDocument + equal: + path: spec.template.spec.initContainers[1].name + value: init1 diff --git a/charts/library/common/Chart.yaml b/charts/library/common/Chart.yaml index 3c83ffca..48d99168 100644 --- a/charts/library/common/Chart.yaml +++ b/charts/library/common/Chart.yaml @@ -3,7 +3,7 @@ apiVersion: v2 name: common description: Function library for Helm charts type: library -version: 2.1.1 +version: 2.2.0 kubeVersion: ">=1.22.0-0" keywords: - common @@ -16,27 +16,6 @@ annotations: artifacthub.io/changes: |- - kind: added description: |- - Support v1 of Gateway APIs Route types - - kind: added - description: |- - Support setting CronJob timezones in Kubernetes versions >= 1.27 - - kind: added - description: |- - Support setting a defaultBackend per ingress - - kind: added - description: |- - Support using templates in Route hostnames - - kind: added - description: |- - Added support for dependsOn in environment variables - links: - - name: GitHub repo - url: https://github.com/dastrobu/helm-charts/tree/main/environment-variables - - name: Related blogpost - url: https://dastrobu.medium.com/an-advanced-api-for-environment-variables-in-helm-charts-e0bb1e0aa58a - - kind: fixed - description: |- - Improved "isEmpty" checks to be compatible with more Helm versions - - kind: fixed - description: |- - No longer quote numeric ports in probes + Add support for dependsOn to initContainers and containers. + Note that using dependsOn completely disables the "order" field within the controller. + The "order" field will be removed in v3. diff --git a/charts/library/common/README.md b/charts/library/common/README.md index 2bceb0fd..da8feeb5 100644 --- a/charts/library/common/README.md +++ b/charts/library/common/README.md @@ -1,6 +1,6 @@ # common -![Version: 2.1.1](https://img.shields.io/badge/Version-2.1.1-informational?style=flat-square) ![Type: library](https://img.shields.io/badge/Type-library-informational?style=flat-square) +![Version: 2.2.0](https://img.shields.io/badge/Version-2.2.0-informational?style=flat-square) ![Type: library](https://img.shields.io/badge/Type-library-informational?style=flat-square) Function library for Helm charts @@ -27,7 +27,7 @@ Include this chart as a dependency in your `Chart.yaml` e.g. # Chart.yaml dependencies: - name: common - version: 2.1.1 + version: 2.2.0 repository: https://bjw-s.github.io/helm-charts/ ``` @@ -56,6 +56,7 @@ The following table contains an overview of available values and their descripti | controllers.main.annotations | object | `{}` | Set annotations on the deployment/statefulset/daemonset/cronjob | | controllers.main.containers.main.args | list | `[]` | Override the args for the default container | | controllers.main.containers.main.command | list | `[]` | Override the command(s) for the default container | +| controllers.main.containers.main.dependsOn | list | `[]` | Specify if this container depends on any other containers This is used to determine the order in which the containers are rendered. The use of "dependsOn" completely disables the "order" field within the controller. | | controllers.main.containers.main.env | string | `nil` | Environment variables. Template enabled. Syntax options: A) TZ: UTC B) PASSWD: '{{ .Release.Name }}' B) TZ: value: UTC dependsOn: otherVar D) PASSWD: configMapKeyRef: name: config-map-name key: key-name E) PASSWD: dependsOn: - otherVar1 - otherVar2 valueFrom: secretKeyRef: name: secret-name key: key-name ... F) - name: TZ value: UTC G) - name: TZ value: '{{ .Release.Name }}' | | controllers.main.containers.main.envFrom | list | `[]` | Secrets and/or ConfigMaps that will be loaded as environment variables. [[ref]](https://unofficial-kubernetes.readthedocs.io/en/latest/tasks/configure-pod-container/configmap/#use-case-consume-configmap-in-environment-variables) | | controllers.main.containers.main.image.pullPolicy | string | `nil` | image pull policy | @@ -94,7 +95,7 @@ The following table contains an overview of available values and their descripti | controllers.main.cronjob.timeZone | string | `nil` | Sets the CronJob timezone (only works in Kubernetes >= 1.27) | | controllers.main.cronjob.ttlSecondsAfterFinished | string | `nil` | If this field is set, ttlSecondsAfterFinished after the Job finishes, it is eligible to be automatically deleted. | | controllers.main.enabled | bool | `true` | enable the controller. | -| controllers.main.initContainers | object | `{}` | Specify any initContainers here as dictionary items. Each initContainer should have its own key initContainers get sorted alphanumerically by the `-` combination. | +| controllers.main.initContainers | object | `{}` | Specify any initContainers here as dictionary items. Each initContainer should have its own key initContainers get sorted alphanumerically by the `-` combination if no order or dependsOn has been configured for them. | | controllers.main.labels | object | `{}` | Set labels on the deployment/statefulset/daemonset/cronjob | | controllers.main.pod | object | `{}` | | | controllers.main.replicas | int | `1` | Number of desired pods. When using a HorizontalPodAutoscaler, set this to `null`. | diff --git a/charts/library/common/templates/lib/chart/_getMapItemsWithKey.tpl b/charts/library/common/templates/lib/chart/_getMapItemsWithKey.tpl new file mode 100644 index 00000000..0a65d4dc --- /dev/null +++ b/charts/library/common/templates/lib/chart/_getMapItemsWithKey.tpl @@ -0,0 +1,17 @@ +{{/* +Returns the items in a map that have a certain key +*/}} +{{- define "bjw-s.common.lib.getMapItemsWithKey" -}} + {{- $map := .map -}} + {{- $keyToFind := .key -}} + {{- $output := dict -}} + + {{- if not (empty $keyToFind) -}} + {{- range $key, $item := $map -}} + {{- if not (empty (dig $keyToFind nil $item)) -}} + {{- $_ := set $output $key $item -}} + {{- end -}} + {{- end -}} + {{- end -}} + {{- $output | toYaml -}} +{{- end }} diff --git a/charts/library/common/templates/lib/pod/fields/_containers.tpl b/charts/library/common/templates/lib/pod/fields/_containers.tpl index 6fb99539..1152ddbb 100644 --- a/charts/library/common/templates/lib/pod/fields/_containers.tpl +++ b/charts/library/common/templates/lib/pod/fields/_containers.tpl @@ -6,11 +6,17 @@ Returns the value for containers {{- $controllerObject := .ctx.controllerObject -}} {{- /* Default to empty list */ -}} - {{- $orderedContainers := dict -}} + {{- $graph := dict -}} {{- $containers := list -}} {{- /* Fetch configured containers for this controller */ -}} {{- $enabledContainers := include "bjw-s.common.lib.controller.enabledContainers" (dict "rootContext" $rootContext "controllerObject" $controllerObject) | fromYaml }} + {{- $renderedContainers := dict -}} + + {{- /* TODO: Remove this logic after "order" removal in v3 */ -}} + {{- $containersWithDependsOn := include "bjw-s.common.lib.getMapItemsWithKey" (dict "map" $enabledContainers "key" "dependsOn") | fromYaml | keys -}} + {{- $useDependsOn := gt (len $containersWithDependsOn) 0 -}} + {{- range $key, $containerValues := $enabledContainers -}} {{- /* Create object from the container values */ -}} {{- $containerObject := (include "bjw-s.common.lib.container.valuesToObject" (dict "rootContext" $ "id" $key "values" $containerValues)) | fromYaml -}} @@ -20,13 +26,43 @@ Returns the value for containers {{- /* Generate the Container spec */ -}} {{- $renderedContainer := include "bjw-s.common.lib.container.spec" (dict "rootContext" $rootContext "controllerObject" $controllerObject "containerObject" $containerObject) | fromYaml -}} + {{- $_ := set $renderedContainers $key $renderedContainer -}} - {{- $containerOrder := (dig "order" 99 $containerValues) -}} - {{- $_ := set $orderedContainers (printf "%v-%s" $containerOrder $key) $renderedContainer -}} + {{- /* Determine the Container order */ -}} + {{- if $useDependsOn -}} + {{- if empty (dig "dependsOn" nil $containerValues) -}} + {{- $_ := set $graph $key ( list ) -}} + {{- else if kindIs "string" $containerValues.dependsOn -}} + {{- $_ := set $graph $key ( list $containerValues.dependsOn ) -}} + {{- else if kindIs "slice" $containerValues.dependsOn -}} + {{- $_ := set $graph $key $containerValues.dependsOn -}} + {{- end -}} + {{- else -}} + {{- /* TODO: Remove this logic after "order" removal in v3 */ -}} + {{- $containerOrder := (dig "order" 99 $containerValues) -}} + {{- $_ := set $graph $key $containerOrder -}} + {{- end -}} {{- end -}} - {{- range $key, $containerValues := $orderedContainers -}} - {{- $containers = append $containers $containerValues -}} + {{- /* Process graph */ -}} + {{- if $useDependsOn -}} + {{- $args := dict "graph" $graph "out" list -}} + {{- include "bjw-s.common.lib.kahn" $args -}} + + {{- range $name := $args.out -}} + {{- $containerItem := get $renderedContainers $name -}} + {{- $containers = append $containers $containerItem -}} + {{- end -}} + {{- else -}} + {{- /* TODO: Remove this logic after "order" removal in v3 */ -}} + {{- $orderedContainers := dict -}} + {{- range $key, $order := $graph -}} + {{- $containerItem := get $renderedContainers $key -}} + {{- $_ := set $orderedContainers (printf "%v-%s" $order $key) $containerItem -}} + {{- end -}} + {{- range $key, $containerValues := $orderedContainers -}} + {{- $containers = append $containers $containerValues -}} + {{- end -}} {{- end -}} {{- if not (empty $containers) -}} diff --git a/charts/library/common/templates/lib/pod/fields/_initContainers.tpl b/charts/library/common/templates/lib/pod/fields/_initContainers.tpl index fb737df2..d0a051a8 100644 --- a/charts/library/common/templates/lib/pod/fields/_initContainers.tpl +++ b/charts/library/common/templates/lib/pod/fields/_initContainers.tpl @@ -6,10 +6,16 @@ Returns the value for initContainers {{- $controllerObject := .ctx.controllerObject -}} {{- /* Default to empty list */ -}} - {{- $orderedContainers := dict -}} + {{- $graph := dict -}} {{- $containers := list -}} {{- /* Fetch configured containers for this controller */ -}} + {{- $renderedContainers := dict -}} + + {{- /* TODO: Remove this logic after "order" removal in v3 */ -}} + {{- $containersWithDependsOn := include "bjw-s.common.lib.getMapItemsWithKey" (dict "map" $controllerObject.initContainers "key" "dependsOn") | fromYaml | keys -}} + {{- $useDependsOn := gt (len $containersWithDependsOn) 0 -}} + {{- range $key, $containerValues := $controllerObject.initContainers -}} {{- /* Enable container by default, but allow override */ -}} {{- $containerEnabled := true -}} @@ -26,14 +32,44 @@ Returns the value for initContainers {{- /* Generate the Container spec */ -}} {{- $renderedContainer := include "bjw-s.common.lib.container.spec" (dict "rootContext" $rootContext "controllerObject" $controllerObject "containerObject" $containerObject) | fromYaml -}} + {{- $_ := set $renderedContainers $key $renderedContainer -}} - {{- $containerOrder := (dig "order" 99 $containerValues) -}} - {{- $_ := set $orderedContainers (printf "%v-%s" $containerOrder $key) $renderedContainer -}} + {{- /* Determine the Container order */ -}} + {{- if $useDependsOn -}} + {{- if empty (dig "dependsOn" nil $containerValues) -}} + {{- $_ := set $graph $key ( list ) -}} + {{- else if kindIs "string" $containerValues.dependsOn -}} + {{- $_ := set $graph $key ( list $containerValues.dependsOn ) -}} + {{- else if kindIs "slice" $containerValues.dependsOn -}} + {{- $_ := set $graph $key $containerValues.dependsOn -}} + {{- end -}} + {{- else -}} + {{- /* TODO: Remove this logic after "order" removal in v3 */ -}} + {{- $containerOrder := (dig "order" 99 $containerValues) -}} + {{- $_ := set $graph $key $containerOrder -}} + {{- end -}} {{- end -}} {{- end -}} - {{- range $key, $containerValues := $orderedContainers -}} - {{- $containers = append $containers $containerValues -}} + {{- /* Process graph */ -}} + {{- if $useDependsOn -}} + {{- $args := dict "graph" $graph "out" list -}} + {{- include "bjw-s.common.lib.kahn" $args -}} + + {{- range $name := $args.out -}} + {{- $containerItem := get $renderedContainers $name -}} + {{- $containers = append $containers $containerItem -}} + {{- end -}} + {{- else -}} + {{- /* TODO: Remove this logic after "order" removal in v3 */ -}} + {{- $orderedContainers := dict -}} + {{- range $key, $order := $graph -}} + {{- $containerItem := get $renderedContainers $key -}} + {{- $_ := set $orderedContainers (printf "%v-%s" $order $key) $containerItem -}} + {{- end -}} + {{- range $key, $containerValues := $orderedContainers -}} + {{- $containers = append $containers $containerValues -}} + {{- end -}} {{- end -}} {{- if not (empty $containers) -}} diff --git a/charts/library/common/values.yaml b/charts/library/common/values.yaml index 89241a84..9d91b847 100644 --- a/charts/library/common/values.yaml +++ b/charts/library/common/values.yaml @@ -186,6 +186,11 @@ controllers: # @default -- 99 order: 1 + # -- Specify if this container depends on any other containers + # This is used to determine the order in which the containers are rendered. + # The use of "dependsOn" completely disables the "order" field within the controller. + dependsOn: [] + image: # -- image repository repository: @@ -327,7 +332,8 @@ controllers: # -- Specify any initContainers here as dictionary items. # Each initContainer should have its own key - # initContainers get sorted alphanumerically by the `-` combination. + # initContainers get sorted alphanumerically by the `-` combination + # if no order or dependsOn has been configured for them. initContainers: {} serviceAccount: diff --git a/charts/other/app-template/Chart.yaml b/charts/other/app-template/Chart.yaml index 7632b6fd..3f528d84 100644 --- a/charts/other/app-template/Chart.yaml +++ b/charts/other/app-template/Chart.yaml @@ -2,7 +2,7 @@ apiVersion: v2 description: A common powered chart template. This can be useful for small projects that don't have their own chart. name: app-template -version: 2.1.1 +version: 2.2.0 kubeVersion: ">=1.22.0-0" maintainers: - name: bjw-s @@ -10,12 +10,12 @@ maintainers: dependencies: - name: common repository: https://bjw-s.github.io/helm-charts - version: 2.1.1 + version: 2.2.0 annotations: artifacthub.io/changes: |- - kind: changed description: | - Updated library version to 2.1.1. + Updated library version to 2.2.0. links: - name: Upgrade instructions from v1.x url: https://github.com/bjw-s/helm-charts/tree/main/charts/other/app-template#from-1xx-to-20x diff --git a/charts/other/app-template/README.md b/charts/other/app-template/README.md index 3ebbf83d..e5e1ac65 100644 --- a/charts/other/app-template/README.md +++ b/charts/other/app-template/README.md @@ -1,6 +1,6 @@ # app-template -![Version: 2.0.3](https://img.shields.io/badge/Version-2.0.3-informational?style=flat-square) +![Version: 2.2.0](https://img.shields.io/badge/Version-2.2.0-informational?style=flat-square) A common powered chart template. This can be useful for small projects that don't have their own chart. @@ -12,7 +12,7 @@ Kubernetes: `>=1.22.0-0` | Repository | Name | Version | |------------|------|---------| -| https://bjw-s.github.io/helm-charts | common | 2.0.3 | +| https://bjw-s.github.io/helm-charts | common | 2.2.0 | ## Installing the Chart