diff --git a/.github/workflows/charts-lint.yaml b/.github/workflows/charts-lint.yaml index 99259179..7a4a4705 100644 --- a/.github/workflows/charts-lint.yaml +++ b/.github/workflows/charts-lint.yaml @@ -74,15 +74,22 @@ jobs: - name: Run chart-testing (lint) run: ct lint --config .ci/ct/ct.yaml --charts "charts/${{ matrix.chart }}" - # Summarize matrix https://github.community/t/status-check-for-a-matrix-jobs/127354/7 lint_success: needs: - lint-chart if: | always() name: Lint successful - runs-on: ubuntu-22.04 + runs-on: ubuntu-latest steps: - - name: Check lint matrix status - if: ${{ (inputs.chartsToLint != '' && inputs.chartsToLint != '[]') && (needs.lint-chart.result != 'success') }} + - name: Check matrix status + if: >- + ${{ + ( + inputs.chartsToLint != '' && inputs.chartsToLint != '[]' + ) && + ( + contains(needs.*.result, 'failure') || contains(needs.*.result, 'cancelled') + ) + }} run: exit 1 diff --git a/.github/workflows/charts-test.yaml b/.github/workflows/charts-test.yaml index 29bd5a9e..c7f0444b 100644 --- a/.github/workflows/charts-test.yaml +++ b/.github/workflows/charts-test.yaml @@ -82,17 +82,24 @@ jobs: - name: Run chart-testing (install) run: ct install --config .ci/ct/ct.yaml --charts "charts/${{ matrix.chart }}" - # Summarize matrix https://github.community/t/status-check-for-a-matrix-jobs/127354/7 install_success: needs: - install-chart if: | always() name: Install successful - runs-on: ubuntu-22.04 + runs-on: ubuntu-latest steps: - - name: Check install matrix status - if: ${{ (inputs.chartsToTest != '[]' && inputs.chartsToTest != '') && needs.install-chart.result != 'success' }} + - name: Check matrix status + if: >- + ${{ + ( + inputs.chartsToTest != '' && inputs.chartsToTest != '[]' + ) && + ( + contains(needs.*.result, 'failure') || contains(needs.*.result, 'cancelled') + ) + }} run: exit 1 unittest-chart: @@ -130,15 +137,22 @@ jobs: helm dep update "charts/${{ matrix.chart }}" helm unittest -f "tests/**/*_test.yaml" "charts/${{ matrix.chart }}" - # Summarize matrix https://github.community/t/status-check-for-a-matrix-jobs/127354/7 unittest_success: needs: - unittest-chart if: | always() name: Unittest successful - runs-on: ubuntu-22.04 + runs-on: ubuntu-latest steps: - - name: Check unittest matrix status - if: ${{ (inputs.chartsToTest != '[]' && inputs.chartsToTest != '') && needs.unittest-chart.result != 'success' }} + - name: Check matrix status + if: >- + ${{ + ( + inputs.chartsToTest != '' && inputs.chartsToTest != '[]' + ) && + ( + contains(needs.*.result, 'failure') || contains(needs.*.result, 'cancelled') + ) + }} run: exit 1 diff --git a/charts/library/common-test/tests/container/envfrom_test.yaml b/charts/library/common-test/tests/container/envfrom_test.yaml index d0fd0325..61345ab0 100644 --- a/charts/library/common-test/tests/container/envfrom_test.yaml +++ b/charts/library/common-test/tests/container/envfrom_test.yaml @@ -18,6 +18,9 @@ tests: controllers.main.containers.main.envFrom: - secretRef: name: myCustomSecret + prefix: test + - configMapRef: + name: myCustomConfig asserts: - documentIndex: &DeploymentDoc 0 isKind: @@ -28,3 +31,100 @@ tests: value: secretRef: name: myCustomSecret + prefix: test + - documentIndex: *DeploymentDoc + equal: + path: spec.template.spec.containers[0].envFrom[1] + value: + configMapRef: + name: myCustomConfig + + - it: envFrom configmap identifier reference should pass + set: + controllers.main.containers.main.envFrom: + - configMap: config + prefix: test + - configMapRef: + identifier: config + asserts: + - documentIndex: &DeploymentDoc 0 + isKind: + of: Deployment + - documentIndex: *DeploymentDoc + equal: + path: spec.template.spec.containers[0].envFrom[0] + value: + configMapRef: + name: RELEASE-NAME-config + prefix: test + - documentIndex: *DeploymentDoc + equal: + path: spec.template.spec.containers[0].envFrom[1] + value: + configMapRef: + name: RELEASE-NAME-config + + - it: envFrom Secret identifier reference should pass + set: + controllers.main.containers.main.envFrom: + - secret: secret + prefix: test + - secretRef: + identifier: secret + prefix: test + asserts: + - documentIndex: &DeploymentDoc 0 + isKind: + of: Deployment + - documentIndex: *DeploymentDoc + equal: + path: spec.template.spec.containers[0].envFrom[0] + value: + secretRef: + name: RELEASE-NAME-secret + prefix: test + - documentIndex: *DeploymentDoc + equal: + path: spec.template.spec.containers[0].envFrom[1] + value: + secretRef: + name: RELEASE-NAME-secret + prefix: test + + - it: envFrom with templated name reference should pass + set: + controllers.main.containers.main.envFrom: + - configMap: "{{ .Release.Name }}-config" + - configMapRef: + name: "{{ .Release.Name }}-config2" + - secret: "{{ .Release.Name }}-secret" + - secretRef: + name: "{{ .Release.Name }}-secret2" + asserts: + - documentIndex: &DeploymentDoc 0 + isKind: + of: Deployment + - documentIndex: *DeploymentDoc + equal: + path: spec.template.spec.containers[0].envFrom[0] + value: + configMapRef: + name: RELEASE-NAME-config + - documentIndex: *DeploymentDoc + equal: + path: spec.template.spec.containers[0].envFrom[1] + value: + configMapRef: + name: RELEASE-NAME-config2 + - documentIndex: *DeploymentDoc + equal: + path: spec.template.spec.containers[0].envFrom[2] + value: + secretRef: + name: RELEASE-NAME-secret + - documentIndex: *DeploymentDoc + equal: + path: spec.template.spec.containers[0].envFrom[3] + value: + secretRef: + name: RELEASE-NAME-secret2 diff --git a/charts/library/common-test/tests/container/volumemounts_test.yaml b/charts/library/common-test/tests/container/volumemounts_test.yaml index b16d383d..ee999e27 100644 --- a/charts/library/common-test/tests/container/volumemounts_test.yaml +++ b/charts/library/common-test/tests/container/volumemounts_test.yaml @@ -56,6 +56,7 @@ tests: main: - path: /data/config.yaml readOnly: false + mountPropagation: HostToContainer subPath: config.yaml second-container: - path: /appdata/config @@ -79,6 +80,7 @@ tests: - mountPath: /data/config.yaml name: data subPath: config.yaml + mountPropagation: HostToContainer - documentIndex: *FirstDeploymentDoc equal: path: spec.template.spec.containers[1].volumeMounts diff --git a/charts/library/common-test/tests/controller/cronjob_test.yaml b/charts/library/common-test/tests/controller/cronjob_test.yaml index 07c6042a..663294d2 100644 --- a/charts/library/common-test/tests/controller/cronjob_test.yaml +++ b/charts/library/common-test/tests/controller/cronjob_test.yaml @@ -13,6 +13,9 @@ tests: - documentIndex: &ControllerDoc 0 isKind: of: CronJob + - documentIndex: *ControllerDoc + notExists: + path: spec.suspend - documentIndex: *ControllerDoc equal: path: spec.schedule @@ -45,6 +48,7 @@ tests: pod: restartPolicy: OnFailure cronjob: + suspend: &CronJobSuspended true schedule: &CronJobSchedule "0 3 * * *" concurrencyPolicy: &CronJobConcurrencyPolicy "Test" failedJobsHistory: &CronJobFailedJobsHistory 2 @@ -54,6 +58,10 @@ tests: - documentIndex: &ControllerDoc 0 isKind: of: CronJob + - documentIndex: *ControllerDoc + equal: + path: spec.suspend + value: *CronJobSuspended - documentIndex: *ControllerDoc equal: path: spec.schedule diff --git a/charts/library/common-test/tests/controller/job_test.yaml b/charts/library/common-test/tests/controller/job_test.yaml new file mode 100644 index 00000000..4de92a35 --- /dev/null +++ b/charts/library/common-test/tests/controller/job_test.yaml @@ -0,0 +1,57 @@ +--- +# yaml-language-server: $schema=https://raw.githubusercontent.com/helm-unittest/helm-unittest/main/schema/helm-testsuite.json +suite: job configuration +templates: + - common.yaml +tests: + - it: default job configuration should pass + set: + controllers: + main: + type: job + asserts: + - documentIndex: &ControllerDoc 0 + isKind: + of: Job + - documentIndex: *ControllerDoc + notExists: + path: spec.suspend + - documentIndex: *ControllerDoc + notExists: + path: spec.ttlSecondsAfterFinished + - documentIndex: *ControllerDoc + equal: + path: spec.template.spec.restartPolicy + value: Never + + - it: custom job configuration should pass + set: + controllers: + main: + type: job + pod: + restartPolicy: OnFailure + job: + suspend: &JobSuspended true + ttlSecondsAfterFinished: &ttlSecondsAfterFinished 3600 + backoffLimit: 3 + asserts: + - documentIndex: &ControllerDoc 0 + isKind: + of: Job + - documentIndex: *ControllerDoc + equal: + path: spec.suspend + value: *JobSuspended + - documentIndex: *ControllerDoc + equal: + path: spec.ttlSecondsAfterFinished + value: *ttlSecondsAfterFinished + - documentIndex: *ControllerDoc + equal: + path: spec.template.spec.restartPolicy + value: OnFailure + - documentIndex: *ControllerDoc + equal: + path: spec.backoffLimit + value: 3 diff --git a/charts/library/common-test/tests/controller/metadata_job_test.yaml b/charts/library/common-test/tests/controller/metadata_job_test.yaml new file mode 100644 index 00000000..688793c7 --- /dev/null +++ b/charts/library/common-test/tests/controller/metadata_job_test.yaml @@ -0,0 +1,118 @@ +--- +# yaml-language-server: $schema=https://raw.githubusercontent.com/helm-unittest/helm-unittest/main/schema/helm-testsuite.json +suite: controller metadata job +templates: + - common.yaml +tests: + - it: default metadata should pass + set: + controllers.main.type: job + asserts: + - documentIndex: &ControllerDoc 0 + isKind: + of: Job + - documentIndex: *ControllerDoc + notExists: + path: metadata.annotations + - documentIndex: *ControllerDoc + equal: + path: metadata.labels + value: + app.kubernetes.io/component: main + app.kubernetes.io/instance: RELEASE-NAME + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/name: RELEASE-NAME + helm.sh/chart: common-test-1.0.0 + + - it: custom metadata should pass + set: + controllers: + main: + type: job + annotations: + test_annotation: test + labels: + test_label: test + asserts: + - documentIndex: &ControllerDoc 0 + isKind: + of: Job + - documentIndex: *ControllerDoc + equal: + path: metadata.annotations + value: + test_annotation: test + - documentIndex: *ControllerDoc + equal: + path: metadata.labels + value: + app.kubernetes.io/component: main + app.kubernetes.io/instance: RELEASE-NAME + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/name: RELEASE-NAME + helm.sh/chart: common-test-1.0.0 + test_label: test + + - it: custom metadata with global metadata should pass + set: + global: + labels: + global_label: test + annotations: + global_annotation: test + controllers: + main: + type: job + annotations: + test_annotation: test + labels: + test_label: test + asserts: + - documentIndex: &ControllerDoc 0 + isKind: + of: Job + - documentIndex: *ControllerDoc + equal: + path: metadata.annotations + value: + global_annotation: test + test_annotation: test + - documentIndex: *ControllerDoc + equal: + path: metadata.labels + value: + app.kubernetes.io/component: main + app.kubernetes.io/instance: RELEASE-NAME + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/name: RELEASE-NAME + global_label: test + helm.sh/chart: common-test-1.0.0 + test_label: test + + - it: jobTemplate metadata should pass + set: + controllers: + main: + type: job + pod: + annotations: + test_annotation: test + labels: + test_label: test + asserts: + - documentIndex: &ControllerDoc 0 + isKind: + of: Job + - documentIndex: *ControllerDoc + equal: + path: spec.template.metadata.annotations + value: + test_annotation: test + - documentIndex: *ControllerDoc + equal: + path: spec.template.metadata.labels + value: + app.kubernetes.io/component: main + app.kubernetes.io/instance: RELEASE-NAME + app.kubernetes.io/name: RELEASE-NAME + test_label: test diff --git a/charts/library/common-test/tests/pvc/values_test.yaml b/charts/library/common-test/tests/pvc/values_test.yaml new file mode 100644 index 00000000..32793f11 --- /dev/null +++ b/charts/library/common-test/tests/pvc/values_test.yaml @@ -0,0 +1,54 @@ +--- +# yaml-language-server: $schema=https://raw.githubusercontent.com/helm-unittest/helm-unittest/main/schema/helm-testsuite.json +suite: pvc values +templates: + - common.yaml +tests: + - it: default enabled should pass + set: + persistence.test: + type: persistentVolumeClaim + accessMode: ReadWriteOnce + size: 1Gi + asserts: + - hasDocuments: + count: 3 + - documentIndex: &PersistentVolumeClaimDocument 0 + isKind: + of: PersistentVolumeClaim + - documentIndex: *PersistentVolumeClaimDocument + equal: + path: metadata.name + value: RELEASE-NAME-test + + - it: explicit enabled should pass + set: + persistence.test: + enabled: true + type: persistentVolumeClaim + accessMode: ReadWriteOnce + size: 1Gi + asserts: + - hasDocuments: + count: 3 + - documentIndex: &PersistentVolumeClaimDocument 0 + isKind: + of: PersistentVolumeClaim + - documentIndex: *PersistentVolumeClaimDocument + equal: + path: metadata.name + value: RELEASE-NAME-test + + - it: explicit disabled + set: + persistence.test: + enabled: false + type: persistentVolumeClaim + accessMode: ReadWriteOnce + size: 1Gi + asserts: + - hasDocuments: + count: 2 + - documentIndex: &PersistentVolumeClaimDocument 0 + isKind: + of: Deployment diff --git a/charts/library/common-test/tests/serviceMonitor/servicemonitor_test.yaml b/charts/library/common-test/tests/serviceMonitor/servicemonitor_test.yaml index 0a58ebfb..8f0b008f 100644 --- a/charts/library/common-test/tests/serviceMonitor/servicemonitor_test.yaml +++ b/charts/library/common-test/tests/serviceMonitor/servicemonitor_test.yaml @@ -151,3 +151,49 @@ tests: value: mySelector: test: "true" + - it: a serviceMonitor is created with targetLabels + set: + serviceMonitor: + main: + enabled: true + endpoints: + - port: http + scheme: http + path: /metrics + interval: 1m + scrapeTimeout: 10s + targetLabels: + - testlabel1 + - testlabel2 + asserts: + - hasDocuments: + count: 3 + - documentIndex: &ServiceMonitorDocument 2 + isKind: + of: ServiceMonitor + - documentIndex: *ServiceMonitorDocument + equal: + path: metadata.name + value: RELEASE-NAME + - documentIndex: *ServiceMonitorDocument + equal: + path: spec.selector.matchLabels + value: + app.kubernetes.io/instance: RELEASE-NAME + app.kubernetes.io/name: RELEASE-NAME + app.kubernetes.io/service: RELEASE-NAME + - documentIndex: *ServiceMonitorDocument + equal: + path: spec.endpoints + value: + - port: http + scheme: http + path: /metrics + interval: 1m + scrapeTimeout: 10s + - documentIndex: *ServiceMonitorDocument + equal: + path: spec.targetLabels + value: + - testlabel1 + - testlabel2 diff --git a/charts/library/common/Chart.yaml b/charts/library/common/Chart.yaml index 3a1e6c0f..7226186b 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.4.0 +version: 2.5.0 kubeVersion: ">=1.22.0-0" keywords: - common @@ -14,32 +14,21 @@ maintainers: email: me@bjw-s.dev annotations: artifacthub.io/changes: |- + - kind: fixed + description: |- + PersistentVolumeClaims now properly created based on `persistence.x.enabled` value - kind: added description: |- - Add support for `timeouts` in HTTPRoute. + Support suspending CronJobs - kind: added description: |- - Add support for `workingDir` for containers. - - kind: fixed + Add support for targetLabels in ServiceMonitor + - kind: added description: |- - Defaulting image tags to chart.Appversion was removed without a proper alternative - - kind: fixed + Re-add support for setting mountPropagation on volumemounts + - kind: added description: |- - Using RequestRedirect is not allowed with BackendRefs in Routes. - - kind: fixed + Support `envFrom` identifiers and name templates for Secrets and ConfigMaps + - kind: added description: |- - StatefulSet objects would not always fall back to proper defaults and error out - - kind: changed - description: |- - routes will no longer auto target its service. - It will need to be explicitly defined as below - - ```yaml - - backendRefs: - - group: "" - kind: Service - name: foo - namespace: foo-namespace - port: 8080 - weight: 1 - ``` + Support the `job` controller type to generate one-off jobs. diff --git a/charts/library/common/README.md b/charts/library/common/README.md index b5a490e7..da5b9dae 100644 --- a/charts/library/common/README.md +++ b/charts/library/common/README.md @@ -1,6 +1,6 @@ # common -![Version: 2.3.0](https://img.shields.io/badge/Version-2.3.0-informational?style=flat-square) ![Type: library](https://img.shields.io/badge/Type-library-informational?style=flat-square) +![Version: 2.5.0](https://img.shields.io/badge/Version-2.5.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.3.0 + version: 2.5.0 repository: https://bjw-s.github.io/helm-charts/ ``` @@ -58,7 +58,7 @@ The following table contains an overview of available values and their descripti | 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.envFrom | list | `[]` | Secrets and/or ConfigMaps that will be loaded as environment variables. Syntax options: A) Pass an app-template configMap identifier: - config: config B) Pass any configMap name that is not also an identifier (Template enabled): - config: random-configmap-name C) Pass an app-template configMap identifier, explicit syntax: - configMapRef: identifier: config D) Pass any configMap name, explicit syntax (Template enabled): - configMapRef: name: "{{ .Release.Name }}-config" E) Pass an app-template secret identifier: - secret: secret F) Pass any secret name that is not also an identifier (Template enabled): - secret: random-secret-name G) Pass an app-template secret identifier, explicit syntax: - secretRef: identifier: secret H) Pass any secret name, explicit syntax (Template enabled): - secretRef: name: "{{ .Release.Name }}-secret" | | controllers.main.containers.main.image.pullPolicy | string | `nil` | image pull policy | | controllers.main.containers.main.image.repository | string | `nil` | image repository | | controllers.main.containers.main.image.tag | string | `nil` | image tag | @@ -85,6 +85,7 @@ The following table contains an overview of available values and their descripti | controllers.main.containers.main.securityContext | object | `{}` | Configure the Security Context for the container | | controllers.main.containers.main.terminationMessagePath | string | `nil` | [[ref](https://kubernetes.io/docs/reference/kubernetes-api/workload-resources/pod-v1/#lifecycle-1)] | | controllers.main.containers.main.terminationMessagePolicy | string | `nil` | [[ref](https://kubernetes.io/docs/reference/kubernetes-api/workload-resources/pod-v1/#lifecycle-1)] | +| controllers.main.containers.main.workingDir | string | `nil` | Override the working directory for the default container | | controllers.main.cronjob | object | See below | CronJob configuration. Required only when using `controller.type: cronjob`. | | controllers.main.cronjob.backoffLimit | int | `6` | Limits the number of times a failed job will be retried | | controllers.main.cronjob.concurrencyPolicy | string | `"Forbid"` | Specifies how to treat concurrent executions of a job that is created by this cron job valid values are Allow, Forbid or Replace | @@ -92,6 +93,7 @@ The following table contains an overview of available values and their descripti | controllers.main.cronjob.schedule | string | `"*/20 * * * *"` | Sets the CronJob time when to execute your jobs | | controllers.main.cronjob.startingDeadlineSeconds | int | `30` | The deadline in seconds for starting the job if it misses its scheduled time for any reason | | controllers.main.cronjob.successfulJobsHistory | int | `1` | The number of succesful Jobs to keep | +| controllers.main.cronjob.suspend | string | false | Suspends the CronJob [[ref]](https://kubernetes.io/docs/concepts/workloads/controllers/cron-jobs/#schedule-suspension) | | 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. | @@ -157,7 +159,7 @@ The following table contains an overview of available values and their descripti | networkpolicies.main.rules.ingress | list | `[{}]` | The ingress rules for this networkPolicy. Allows all ingress traffic by default. | | persistence | object | See below | Configure persistence for the chart here. Additional items can be added by adding a dictionary key similar to the 'config' key. [[ref]](https://bjw-s.github.io/helm-charts/docs/common-library/common-library-storage) | | persistence.config.accessMode | string | `"ReadWriteOnce"` | AccessMode for the persistent volume. Make sure to select an access mode that is supported by your storage provider! [[ref]](https://kubernetes.io/docs/concepts/storage/persistent-volumes/#access-modes) | -| persistence.config.advancedMounts | object | `{}` | Explicitly configure mounts for specific controllers and containers. Example: advancedMounts: main: # the controller with the "main" identifier main: # the container with the "main" identifier - path: /data/config.yaml readOnly: true subPath: config.yaml second-container: # the container with the "second-container" identifier - path: /appdata/config readOnly: true second-controller: # the controller with the "second-controller" identifier main: # the container with the "main" identifier - path: /data/config.yaml readOnly: false subPath: config.yaml | +| persistence.config.advancedMounts | object | `{}` | Explicitly configure mounts for specific controllers and containers. Example: advancedMounts: main: # the controller with the "main" identifier main: # the container with the "main" identifier - path: /data/config.yaml readOnly: true mountPropagation: None subPath: config.yaml second-container: # the container with the "second-container" identifier - path: /appdata/config readOnly: true second-controller: # the controller with the "second-controller" identifier main: # the container with the "main" identifier - path: /data/config.yaml readOnly: false subPath: config.yaml | | persistence.config.dataSource | object | `{}` | The optional data source for the persistentVolumeClaim. [[ref]](https://kubernetes.io/docs/concepts/storage/persistent-volumes/#volume-populators-and-data-sources) | | persistence.config.dataSourceRef | object | `{}` | The optional volume populator for the persistentVolumeClaim. [[ref]](https://kubernetes.io/docs/concepts/storage/persistent-volumes/#volume-populators-and-data-sources) | | persistence.config.enabled | bool | `false` | Enables or disables the persistence item. Defaults to true | @@ -175,8 +177,8 @@ The following table contains an overview of available values and their descripti | route.main.labels | object | `{}` | Provide additional labels which may be required. | | route.main.nameOverride | string | `nil` | Override the name suffix that is used for this route. | | route.main.parentRefs | list | `[{"group":"gateway.networking.k8s.io","kind":"Gateway","name":null,"namespace":null,"sectionName":null}]` | Configure the resource the route attaches to. | -| route.main.rules | list | `[{"backendRefs":[{"group":"","kind":"Service","name":"main","namespace":null,"port":null,"weight":1}],"timeouts":{}"filters":[],"matches":[{"path":{"type":"PathPrefix","value":"/"}}]}]` | Configure rules for routing. Defaults to the primary service. | -| route.main.rules[0].backendRefs | list | `[{"group":"","kind":"Service","name":"main","namespace":null,"port":null,"weight":1}]` | Configure backends where matching requests should be sent. | +| route.main.rules | list | `[{"backendRefs":[],"filters":[],"matches":[{"path":{"type":"PathPrefix","value":"/"}}],"timeouts":{}}]` | Configure rules for routing. Defaults to the primary service. | +| route.main.rules[0].backendRefs | list | `[]` | Configure backends where matching requests should be sent. | | secrets | object | See below | Use this to populate secrets with the values you specify. Be aware that these values are not encrypted by default, and could therefore visible to anybody with access to the values.yaml file. Additional Secrets can be added by adding a dictionary key similar to the 'secret' object. | | secrets.secret.annotations | object | `{}` | Annotations to add to the Secret | | secrets.secret.enabled | bool | `false` | Enables or disables the Secret | @@ -214,6 +216,7 @@ The following table contains an overview of available values and their descripti | serviceMonitor.main.nameOverride | string | `nil` | Override the name suffix that is used for this serviceMonitor. | | serviceMonitor.main.selector | object | `{}` | Configures a custom selector for the serviceMonitor, this takes precedence over specifying a service name. Helm templates can be used. | | serviceMonitor.main.serviceName | string | `"{{ include \"bjw-s.common.lib.chart.names.fullname\" $ }}"` | Configures the target Service for the serviceMonitor. Helm templates can be used. | +| serviceMonitor.main.targetLabels | list | `[]` | Configures custom targetLabels for the serviceMonitor. (All collected meterics will have these labels, taking the value from the target service) [[ref]](https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md#servicemonitorspec/) | @@ -224,4 +227,4 @@ The following table contains an overview of available values and their descripti - Join the k8s-at-home [Discord](https://discord.gg/k8s-at-home) community ---------------------------------------------- -Autogenerated from chart metadata using [helm-docs v1.11.0](https://github.com/norwoodj/helm-docs/releases/v1.11.0) +Autogenerated from chart metadata using [helm-docs v1.11.3](https://github.com/norwoodj/helm-docs/releases/v1.11.3) diff --git a/charts/library/common/templates/classes/_cronjob.tpl b/charts/library/common/templates/classes/_cronjob.tpl index 472b8bd7..829f54fc 100644 --- a/charts/library/common/templates/classes/_cronjob.tpl +++ b/charts/library/common/templates/classes/_cronjob.tpl @@ -32,6 +32,9 @@ metadata: annotations: {{- toYaml . | nindent 4 -}} {{- end }} spec: + {{- with $cronjobObject.cronjob.suspend }} + suspend: {{ ternary "true" "false" . }} + {{- end }} concurrencyPolicy: "{{ $cronjobObject.cronjob.concurrencyPolicy }}" startingDeadlineSeconds: {{ $cronjobObject.cronjob.startingDeadlineSeconds }} {{- with $timeZone }} diff --git a/charts/library/common/templates/classes/_job.tpl b/charts/library/common/templates/classes/_job.tpl new file mode 100644 index 00000000..9c8a99ec --- /dev/null +++ b/charts/library/common/templates/classes/_job.tpl @@ -0,0 +1,46 @@ +{{/* +This template serves as the blueprint for the job objects that are created +within the common library. +*/}} +{{- define "bjw-s.common.class.job" -}} + {{- $rootContext := .rootContext -}} + {{- $jobObject := .object -}} + + {{- $labels := merge + (dict "app.kubernetes.io/component" $jobObject.identifier) + ($jobObject.labels | default dict) + (include "bjw-s.common.lib.metadata.allLabels" $rootContext | fromYaml) + -}} + {{- $annotations := merge + ($jobObject.annotations | default dict) + (include "bjw-s.common.lib.metadata.globalAnnotations" $rootContext | fromYaml) + -}} +--- +apiVersion: batch/v1 +kind: Job +metadata: + name: {{ $jobObject.name }} + {{- with $labels }} + labels: {{- toYaml . | nindent 4 -}} + {{- end }} + {{- with $annotations }} + annotations: {{- toYaml . | nindent 4 -}} + {{- end }} +spec: + {{- with $jobObject.job.suspend }} + suspend: {{ ternary "true" "false" . }} + {{- end }} + {{- with $jobObject.job.ttlSecondsAfterFinished }} + ttlSecondsAfterFinished: {{ . }} + {{- end }} + backoffLimit: {{ $jobObject.job.backoffLimit }} + template: + metadata: + {{- with (include "bjw-s.common.lib.pod.metadata.annotations" (dict "rootContext" $rootContext "controllerObject" $jobObject)) }} + annotations: {{ . | nindent 8 }} + {{- end -}} + {{- with (include "bjw-s.common.lib.pod.metadata.labels" (dict "rootContext" $rootContext "controllerObject" $jobObject)) }} + labels: {{ . | nindent 8 }} + {{- end }} + spec: {{ include "bjw-s.common.lib.pod.spec" (dict "rootContext" $rootContext "controllerObject" $jobObject) | nindent 6 }} +{{- end -}} diff --git a/charts/library/common/templates/classes/_serviceMonitor.tpl b/charts/library/common/templates/classes/_serviceMonitor.tpl index ee7238d4..b1418608 100644 --- a/charts/library/common/templates/classes/_serviceMonitor.tpl +++ b/charts/library/common/templates/classes/_serviceMonitor.tpl @@ -30,4 +30,8 @@ spec: {{- include "bjw-s.common.lib.metadata.selectorLabels" $rootContext | nindent 6 }} {{- end }} endpoints: {{- toYaml $serviceMonitorObject.endpoints | nindent 4 }} + {{- if not (empty $serviceMonitorObject.targetLabels )}} + targetLabels: + {{- toYaml $serviceMonitorObject.targetLabels | nindent 4 }} + {{- end }} {{- end }} diff --git a/charts/library/common/templates/lib/configMap/_getByIdentifier.tpl b/charts/library/common/templates/lib/configMap/_getByIdentifier.tpl new file mode 100644 index 00000000..87b10a3b --- /dev/null +++ b/charts/library/common/templates/lib/configMap/_getByIdentifier.tpl @@ -0,0 +1,12 @@ +{{/* +Return a configMap Object by its Identifier. +*/}} +{{- define "bjw-s.common.lib.configMap.getByIdentifier" -}} + {{- $rootContext := .rootContext -}} + {{- $identifier := .id -}} + + {{- $configMapValues := dig $identifier nil $rootContext.Values.configMaps -}} + {{- if not (empty $configMapValues) -}} + {{- include "bjw-s.common.lib.configMap.valuesToObject" (dict "rootContext" $rootContext "id" $identifier "values" $configMapValues) -}} + {{- end -}} +{{- end -}} diff --git a/charts/library/common/templates/lib/container/_spec.tpl b/charts/library/common/templates/lib/container/_spec.tpl index c17e450d..9dfd3d43 100644 --- a/charts/library/common/templates/lib/container/_spec.tpl +++ b/charts/library/common/templates/lib/container/_spec.tpl @@ -36,8 +36,8 @@ terminationMessagePolicy: {{ . | trim }} {{- with (include "bjw-s.common.lib.container.field.env" (dict "ctx" $ctx) | trim) }} env: {{ . | trim | nindent 2 }} {{- end -}} -{{- with $containerObject.envFrom }} -envFrom: {{ toYaml . | trim | nindent 2 }} + {{- with (include "bjw-s.common.lib.container.field.envFrom" (dict "ctx" $ctx) | trim) }} +envFrom: {{ . | trim | nindent 2 }} {{- end -}} {{- with $containerObject.ports }} ports: {{ toYaml . | trim | nindent 2 }} diff --git a/charts/library/common/templates/lib/container/fields/_envFrom.tpl b/charts/library/common/templates/lib/container/fields/_envFrom.tpl new file mode 100644 index 00000000..84e73129 --- /dev/null +++ b/charts/library/common/templates/lib/container/fields/_envFrom.tpl @@ -0,0 +1,58 @@ +{{/* +Env field used by the container. +*/}} +{{- define "bjw-s.common.lib.container.field.envFrom" -}} + {{- $ctx := .ctx -}} + {{- $rootContext := $ctx.rootContext -}} + {{- $containerObject := $ctx.containerObject -}} + + {{- if not (empty (get $containerObject "envFrom")) -}} + {{- $envFrom := list -}} + {{- range $containerObject.envFrom -}} + {{- $item := dict -}} + + {{- if hasKey . "configMap" -}} + {{- $configMap := include "bjw-s.common.lib.configMap.getByIdentifier" (dict "rootContext" $rootContext "id" .configMap) | fromYaml -}} + {{- $configMapName := default (tpl .configMap $rootContext) $configMap.name -}} + {{- $_ := set $item "configMapRef" (dict "name" $configMapName) -}} + {{- else if hasKey . "configMapRef" -}} + {{- if not (empty (dig "identifier" nil .configMapRef)) -}} + {{- $configMap := include "bjw-s.common.lib.configMap.getByIdentifier" (dict "rootContext" $rootContext "id" .configMapRef.identifier) | fromYaml -}} + {{- if empty $configMap -}} + {{- fail (printf "No configMap configured with identifier '%s'" .configMapRef.identifier) -}} + {{- end -}} + + {{- $_ := set $item "configMapRef" (dict "name" $configMap.name) -}} + {{- else -}} + {{- $_ := set $item "configMapRef" (dict "name" (tpl .configMapRef.name $rootContext)) -}} + {{- end -}} + + {{- else if hasKey . "secret" -}} + {{- $secret := include "bjw-s.common.lib.secret.getByIdentifier" (dict "rootContext" $rootContext "id" .secret) | fromYaml -}} + {{- $secretName := default (tpl .secret $rootContext) $secret.name -}} + {{- $_ := set $item "secretRef" (dict "name" $secretName) -}} + {{- else if hasKey . "secretRef" -}} + {{- if not (empty (dig "identifier" nil .secretRef)) -}} + {{- $secret := include "bjw-s.common.lib.secret.getByIdentifier" (dict "rootContext" $rootContext "id" .secretRef.identifier) | fromYaml -}} + {{- if empty $secret -}} + {{- fail (printf "No secret configured with identifier '%s'" .secretRef.identifier) -}} + {{- end -}} + + {{- $_ := set $item "secretRef" (dict "name" $secret.name) -}} + {{- else -}} + {{- $_ := set $item "secretRef" (dict "name" (tpl .secretRef.name $rootContext)) -}} + {{- end -}} + {{- end -}} + + {{- if not (empty (dig "prefix" nil .)) -}} + {{- $_ := set $item "prefix" .prefix -}} + {{- end -}} + + {{- if not (empty $item) -}} + {{- $envFrom = append $envFrom $item -}} + {{- end -}} + {{- end -}} + + {{- $envFrom | toYaml -}} + {{- end -}} +{{- end -}} diff --git a/charts/library/common/templates/lib/container/fields/_volumeMounts.tpl b/charts/library/common/templates/lib/container/fields/_volumeMounts.tpl index 8cdd9b75..5139866b 100644 --- a/charts/library/common/templates/lib/container/fields/_volumeMounts.tpl +++ b/charts/library/common/templates/lib/container/fields/_volumeMounts.tpl @@ -91,6 +91,12 @@ volumeMounts used by the container. {{- $_ := set $volumeMount "readOnly" $readOnly -}} {{- end -}} + {{- /* Use the specified mountPropagation setting if provided */ -}} + {{- with .mountPropagation -}} + {{- $mountPropagation := . -}} + {{- $_ := set $volumeMount "mountPropagation" $mountPropagation -}} + {{- end -}} + {{- $enabledVolumeMounts = append $enabledVolumeMounts $volumeMount -}} {{- end -}} diff --git a/charts/library/common/templates/lib/controller/_validate.tpl b/charts/library/common/templates/lib/controller/_validate.tpl index df13e9e6..5d61d1a0 100644 --- a/charts/library/common/templates/lib/controller/_validate.tpl +++ b/charts/library/common/templates/lib/controller/_validate.tpl @@ -5,7 +5,7 @@ Validate controller values {{- $rootContext := .rootContext -}} {{- $controllerValues := .object -}} - {{- $allowedControllerTypes := list "deployment" "daemonset" "statefulset" "cronjob" -}} + {{- $allowedControllerTypes := list "deployment" "daemonset" "statefulset" "cronjob" "job" -}} {{- if not (has $controllerValues.type $allowedControllerTypes) -}} {{- fail (printf "Not a valid controller.type (%s)" $controllerValues.type) -}} {{- end -}} diff --git a/charts/library/common/templates/lib/job/_validate.tpl b/charts/library/common/templates/lib/job/_validate.tpl new file mode 100644 index 00000000..75f71917 --- /dev/null +++ b/charts/library/common/templates/lib/job/_validate.tpl @@ -0,0 +1,12 @@ +{{/* +Validate job values +*/}} +{{- define "bjw-s.common.lib.job.validate" -}} + {{- $rootContext := .rootContext -}} + {{- $jobValues := .object -}} + + {{- $allowedRestartPolicy := list "Never" "OnFailure" -}} + {{- if not (has $jobValues.pod.restartPolicy $allowedRestartPolicy) -}} + {{- fail (printf "Not a valid restart policy for Job (controller: %s, strategy: %s)" $jobValues.identifier $jobValues.pod.restartPolicy) -}} + {{- end -}} +{{- end -}} diff --git a/charts/library/common/templates/lib/job/_valuesToObject.tpl b/charts/library/common/templates/lib/job/_valuesToObject.tpl new file mode 100644 index 00000000..5886d603 --- /dev/null +++ b/charts/library/common/templates/lib/job/_valuesToObject.tpl @@ -0,0 +1,14 @@ +{{/* +Convert job values to an object +*/}} +{{- define "bjw-s.common.lib.job.valuesToObject" -}} + {{- $rootContext := .rootContext -}} + {{- $identifier := .id -}} + {{- $objectValues := .values -}} + + {{- $restartPolicy := default "Never" $objectValues.pod.restartPolicy -}} + {{- $_ := set $objectValues.pod "restartPolicy" $restartPolicy -}} + + {{- /* Return the Job object */ -}} + {{- $objectValues | toYaml -}} +{{- end -}} diff --git a/charts/library/common/templates/lib/secret/_getByIdentifier.tpl b/charts/library/common/templates/lib/secret/_getByIdentifier.tpl new file mode 100644 index 00000000..ddcb4547 --- /dev/null +++ b/charts/library/common/templates/lib/secret/_getByIdentifier.tpl @@ -0,0 +1,12 @@ +{{/* +Return a secret Object by its Identifier. +*/}} +{{- define "bjw-s.common.lib.secret.getByIdentifier" -}} + {{- $rootContext := .rootContext -}} + {{- $identifier := .id -}} + + {{- $secretValues := dig $identifier nil $rootContext.Values.secrets -}} + {{- if not (empty $secretValues) -}} + {{- include "bjw-s.common.lib.secret.valuesToObject" (dict "rootContext" $rootContext "id" $identifier "values" $secretValues) -}} + {{- end -}} +{{- end -}} diff --git a/charts/library/common/templates/render/_controllers.tpl b/charts/library/common/templates/render/_controllers.tpl index a4703478..0d58998f 100644 --- a/charts/library/common/templates/render/_controllers.tpl +++ b/charts/library/common/templates/render/_controllers.tpl @@ -35,6 +35,10 @@ Renders the controller objects required by the chart. {{- $statefulsetObject := (include "bjw-s.common.lib.statefulset.valuesToObject" (dict "rootContext" $ "id" $key "values" $controllerObject)) | fromYaml -}} {{- include "bjw-s.common.lib.statefulset.validate" (dict "rootContext" $ "object" $statefulsetObject) -}} {{- include "bjw-s.common.class.statefulset" (dict "rootContext" $ "object" $statefulsetObject) | nindent 0 -}} + {{- else if eq $controllerObject.type "job" -}} + {{- $jobObject := (include "bjw-s.common.lib.job.valuesToObject" (dict "rootContext" $ "id" $key "values" $controllerObject)) | fromYaml -}} + {{- include "bjw-s.common.lib.job.validate" (dict "rootContext" $ "object" $jobObject) -}} + {{- include "bjw-s.common.class.job" (dict "rootContext" $ "object" $jobObject) | nindent 0 -}} {{- end -}} {{- end -}} {{- end -}} diff --git a/charts/library/common/templates/render/_pvcs.tpl b/charts/library/common/templates/render/_pvcs.tpl index f69947a8..98d7df5e 100644 --- a/charts/library/common/templates/render/_pvcs.tpl +++ b/charts/library/common/templates/render/_pvcs.tpl @@ -4,7 +4,13 @@ Renders the Persistent Volume Claim objects required by the chart. {{- define "bjw-s.common.render.pvcs" -}} {{- /* Generate pvc as required */ -}} {{- range $key, $pvc := .Values.persistence -}} - {{- if and $pvc.enabled (eq (default "persistentVolumeClaim" $pvc.type) "persistentVolumeClaim") (not $pvc.existingClaim) -}} + {{- /* Enable PVC by default, but allow override */ -}} + {{- $pvcEnabled := true -}} + {{- if hasKey $pvc "enabled" -}} + {{- $pvcEnabled = $pvc.enabled -}} + {{- end -}} + + {{- if and $pvcEnabled (eq (default "persistentVolumeClaim" $pvc.type) "persistentVolumeClaim") (not $pvc.existingClaim) -}} {{- $pvcValues := (mustDeepCopy $pvc) -}} {{- /* Create object from the raw PVC values */ -}} diff --git a/charts/library/common/values.yaml b/charts/library/common/values.yaml index 48ff7cdb..30b1bd13 100644 --- a/charts/library/common/values.yaml +++ b/charts/library/common/values.yaml @@ -105,18 +105,18 @@ controllers: enabled: true # -- Set the controller type. - # Valid options are deployment, daemonset, statefulset or cronjob + # Valid options are deployment, daemonset, statefulset, cronjob or job type: deployment - # -- Set annotations on the deployment/statefulset/daemonset/cronjob + # -- Set annotations on the deployment/statefulset/daemonset/cronjob/job annotations: {} - # -- Set labels on the deployment/statefulset/daemonset/cronjob + # -- Set labels on the deployment/statefulset/daemonset/cronjob/job labels: {} # -- Number of desired pods. When using a HorizontalPodAutoscaler, set this to `null`. replicas: 1 # -- Set the controller upgrade strategy # For Deployments, valid values are Recreate (default) and RollingUpdate. # For StatefulSets, valid values are OnDelete and RollingUpdate (default). - # DaemonSets/CronJobs ignore this. + # DaemonSets/CronJobs/Jobs ignore this. strategy: rollingUpdate: @@ -132,6 +132,10 @@ controllers: # -- CronJob configuration. Required only when using `controller.type: cronjob`. # @default -- See below cronjob: + # -- Suspends the CronJob + # [[ref]](https://kubernetes.io/docs/concepts/workloads/controllers/cron-jobs/#schedule-suspension) + # @default -- false + suspend: # -- Specifies how to treat concurrent executions of a job that is created by this cron job # valid values are Allow, Forbid or Replace concurrencyPolicy: Forbid @@ -145,7 +149,20 @@ controllers: successfulJobsHistory: 1 # -- The number of failed Jobs to keep failedJobsHistory: 1 - # -- If this field is set, ttlSecondsAfterFinished after the Job finishes, it is eligible to + # -- If this field is set, ttlSecondsAfterFinished after the Job finishes, it is eligible to + # be automatically deleted. + ttlSecondsAfterFinished: + # -- Limits the number of times a failed job will be retried + backoffLimit: 6 + + # -- Job configuration. Required only when using `controller.type: job`. + # @default -- See below + job: + # -- Suspends the Job + # [[ref]](https://kubernetes.io/docs/concepts/workloads/controllers/job/#suspending-a-job) + # @default -- false + suspend: + # -- If this field is set, ttlSecondsAfterFinished after the Job finishes, it is eligible to # be automatically deleted. ttlSecondsAfterFinished: # -- Limits the number of times a failed job will be retried @@ -239,12 +256,28 @@ controllers: env: # -- 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) + # Syntax options: + # A) Pass an app-template configMap identifier: + # - config: config + # B) Pass any configMap name that is not also an identifier (Template enabled): + # - config: random-configmap-name + # C) Pass an app-template configMap identifier, explicit syntax: + # - configMapRef: + # identifier: config + # D) Pass any configMap name, explicit syntax (Template enabled): + # - configMapRef: + # name: "{{ .Release.Name }}-config" + # E) Pass an app-template secret identifier: + # - secret: secret + # F) Pass any secret name that is not also an identifier (Template enabled): + # - secret: random-secret-name + # G) Pass an app-template secret identifier, explicit syntax: + # - secretRef: + # identifier: secret + # H) Pass any secret name, explicit syntax (Template enabled): + # - secretRef: + # name: "{{ .Release.Name }}-secret" envFrom: [] - # - configMapRef: - # name: config-map-name - # - secretRef: - # name: secret-name # -- Probe configuration # -- [[ref]](https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/) @@ -499,6 +532,11 @@ serviceMonitor: interval: 1m scrapeTimeout: 10s + # -- Configures custom targetLabels for the serviceMonitor. (All collected + # meterics will have these labels, taking the value from the target service) + # [[ref]](https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md#servicemonitorspec/) + targetLabels: [] + # -- Configure the ingresses for the chart here. # Additional ingresses can be added by adding a dictionary key similar to the 'main' ingress. # @default -- See below @@ -660,6 +698,7 @@ persistence: # main: # the container with the "main" identifier # - path: /data/config.yaml # readOnly: true + # mountPropagation: None # subPath: config.yaml # second-container: # the container with the "second-container" identifier # - path: /appdata/config