diff --git a/.github/labeler.yml b/.github/labeler.yml index a819bea..1429ea9 100644 --- a/.github/labeler.yml +++ b/.github/labeler.yml @@ -22,3 +22,7 @@ ci: documentation: - changed-files: - any-glob-to-any-file: "**/*.md" + +helm-chart: + - changed-files: + - any-glob-to-any-file: "chart/**" diff --git a/.github/workflows/pr-title-check.yaml b/.github/workflows/pr-title-check.yaml index d821d02..b8920f0 100644 --- a/.github/workflows/pr-title-check.yaml +++ b/.github/workflows/pr-title-check.yaml @@ -18,7 +18,6 @@ on: pull_request: types: - opened - - synchronize - reopened - edited diff --git a/.github/workflows/verify-helm.yaml b/.github/workflows/verify-helm.yaml new file mode 100644 index 0000000..64c42b6 --- /dev/null +++ b/.github/workflows/verify-helm.yaml @@ -0,0 +1,86 @@ +# Copyright 2024 cluetec GmbH +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +name: "Verify helm" + +on: + pull_request: + branches: + - main + paths: + - "chart/**" + workflow_dispatch: + +permissions: + contents: read + +jobs: + verify-helm-docs: + runs-on: ubuntu-latest + steps: + - name: Harden Runner + uses: step-security/harden-runner@eb238b55efaa70779f274895e782ed17c84f2895 # v2.6.1 + with: + allowed-endpoints: > + auth.docker.io:443 + github.com:443 + production.cloudflare.docker.com:443 + registry-1.docker.io:443 + disable-sudo: true + disable-telemetry: true + egress-policy: block + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + + - run: | + docker run --rm --volume "${{ github.workspace }}/chart:/helm-docs" -u $(id -u) jnorwood/helm-docs:latest + + if $(git diff --quiet --exit-code); then + echo "Helm chart docs up to date" + else + echo "Helm chart docs not up to date:" + git diff + exit 1 + fi + + verify-chart-snapshots: + runs-on: ubuntu-latest + steps: + - name: Harden Runner + uses: step-security/harden-runner@eb238b55efaa70779f274895e782ed17c84f2895 # v2.6.1 + with: + allowed-endpoints: > + get.helm.sh:443 + github.com:443 + objects.githubusercontent.com:443 + disable-sudo: true + disable-telemetry: true + egress-policy: block + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + + # Uses the default values.yaml + - uses: jlandowner/helm-chartsnap-action@0561d6d0132753ceb052cf1e7dcb7385dbb303c9 # fix + with: + chart: ${{ github.workspace }}/chart + update_snapshot: false + additional_args: --namespace default + disable_create_pull_request: true + + # Uses the special case test_*.yaml values files from test folder + - uses: jlandowner/helm-chartsnap-action@0561d6d0132753ceb052cf1e7dcb7385dbb303c9 # fix + with: + chart: ${{ github.workspace }}/chart + values: ${{ github.workspace }}/chart/test/ + update_snapshot: false + additional_args: --namespace default + disable_create_pull_request: true diff --git a/chart/.helmignore b/chart/.helmignore new file mode 100644 index 0000000..0e8a0eb --- /dev/null +++ b/chart/.helmignore @@ -0,0 +1,23 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*.orig +*~ +# Various IDEs +.project +.idea/ +*.tmproj +.vscode/ diff --git a/chart/Chart.yaml b/chart/Chart.yaml new file mode 100644 index 0000000..4cfbaba --- /dev/null +++ b/chart/Chart.yaml @@ -0,0 +1,34 @@ +apiVersion: v2 +name: lifeboat +description: Helm Chart for the lifeboat backup solution. +keywords: + - backup + - lifeboat +home: https://github.com/cluetec/lifeboat +sources: ["https://github.com/cluetec/lifeboat"] +maintainers: + - name: Ayhan Mesin + url: https://github.com/a-mesin + - name: Florian Rusch + url: https://github.com/florianrusch + +# A chart can be either an 'application' or a 'library' chart. +# +# Application charts are a collection of templates that can be packaged into versioned archives +# to be deployed. +# +# Library charts provide useful utilities or functions for the chart developer. They're included as +# a dependency of application charts to inject those utilities and functions into the rendering +# pipeline. Library charts do not define any templates and therefore cannot be deployed. +type: application + +# This is the chart version. This version number should be incremented each time you make changes +# to the chart and its templates, including the app version. +# Versions are expected to follow Semantic Versioning (https://semver.org/) +version: 0.1.0 + +# This is the version number of the application being deployed. This version number should be +# incremented each time you make changes to the application. Versions are not expected to +# follow Semantic Versioning. They should reflect the version the application is using. +# It is recommended to use it with quotes. +appVersion: "0.1.0" diff --git a/chart/LICENSE b/chart/LICENSE new file mode 100644 index 0000000..261eeb9 --- /dev/null +++ b/chart/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/chart/README.md b/chart/README.md new file mode 100644 index 0000000..f35897b --- /dev/null +++ b/chart/README.md @@ -0,0 +1,56 @@ +# lifeboat + +![Version: 0.1.0](https://img.shields.io/badge/Version-0.1.0-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: 0.1.0](https://img.shields.io/badge/AppVersion-0.1.0-informational?style=flat-square) + +## Values + +| Key | Type | Default | Description | +|-----|------|---------|-------------| +| affinity | object | `{}` | [Kubernetes affinity and anti-affinity](https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#affinity-and-anti-affinity) allows defining rules that determine on which nodes the pod should be run preferentially. | +| annotations | object | `{}` | [Additional cronjob annotations](https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/) | +| concurrencyPolicy | string | `"Forbid"` | Specifies how to treat concurrent executions of a Job. Valid values are: - "Allow": allows CronJobs to run concurrently; - "Forbid": forbids concurrent runs, skipping next run if previous run hasn't finished yet; - "Replace": cancels currently running job and replaces it with a new one | +| configuration | object | `{}` | Lifeboat configuration | +| env | object | `{}` | Extra environment variables that will be pass onto deployment pods. | +| envConfigMapNames | list | `[]` | [Kubernetes ConfigMap Resource](https://kubernetes.io/docs/concepts/configuration/configmap/) names to load environment variables from. | +| envSecretNames | list | `[]` | [Kubernetes Secret Resource](https://kubernetes.io/docs/concepts/configuration/secret/) names to load environment variables from. | +| envValueFrom | object | `{}` | ["valueFrom" environment variable references](https://kubernetes.io/docs/tasks/inject-data-application/define-environment-variable-container/) that will be added to deployment pods. Name is templated. | +| failedJobsHistoryLimit | int | `1` | The number of failed finished jobs to retain. Value must be non-negative integer. | +| fullnameOverride | string | `""` | | +| image.pullPolicy | string | `"IfNotPresent"` | The pull policy for the container image. | +| image.repository | string | `"cluetec/lifeboat"` | The repository path of the container image. | +| imagePullSecrets | list | `[]` | Container registry secret names as an array | +| jobAnnotations | object | `{}` | [Additional job annotations](https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/) | +| nameOverride | string | `""` | | +| nodeSelector | object | `{}` | [Kubernetes node selector](https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/) allows to select specific Kubernetes nodes (nodes) on which the pod should be scheduled. | +| podAnnotations | object | `{}` | [Additional pod annotations](https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/) | +| podSecurityContext | object | `{"fsGroup":2000,"runAsGroup":3000,"runAsUser":1000}` | [Pod security context](https://kubernetes.io/docs/tasks/configure-pod-container/security-context/#set-the-security-context-for-a-pod) | +| resources | object | `{}` | | +| restartPolicy | string | `"Never"` | | +| schedule | string | `"0 3 * * *"` | The schedule in Cron format, see . Default is everyday at 3am | +| securityContext | object | `{"capabilities":{"drop":["ALL"]},"readOnlyRootFilesystem":true,"runAsNonRoot":true,"runAsUser":1000}` | [Container security context](https://kubernetes.io/docs/tasks/configure-pod-container/security-context/#set-the-security-context-for-a-container) | +| serviceAccount.annotations | object | `{}` | Annotations to add to the service account | +| serviceAccount.enabled | bool | `false` | Specifies whether a service account should be created | +| serviceAccount.imagePullSecrets | list | `[]` | List of image pull secret names which should be used by the service account | +| serviceAccount.name | string | `""` | The name of the service account to use. If not set and create is true, a name is generated using the fullname template | +| startingDeadlineSeconds | int | `0` | Optional deadline in seconds for starting the job if it misses scheduled time for any reason. Missed jobs executions will be counted as failed ones. | +| storage.accessModes | list | `["ReadWriteOnce"]` | PV Access Mode | +| storage.annotation | list | `[]` | [Additional pvc annotations](https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/) | +| storage.enabled | bool | `false` | Enables/Disables the provisioning of an persistent volume claim | +| storage.existingClaim | string | `""` | Provide an existing `PersistentVolumeClaim`. If defined, PVC must be created manually before volume will be bound | +| storage.mountPath | string | `"/backups"` | | +| storage.size | string | `"10Gi"` | PVC Storage Request for the backup volume | +| storage.storageClass | string | `nil` | PVC Storage Class for the backup volume If defined, storageClassName: If undefined (the default) or set to null, no storageClassName spec is set, choosing the default provisioner. | +| successfulJobsHistoryLimit | int | `3` | The number of successful finished jobs to retain. Value must be non-negative integer. | +| suspend | bool | `false` | This flag tells the controller to suspend subsequent executions, it does not apply to already started executions. | +| timeZone | string | `""` | The time zone name for the given schedule, see . If not specified, this will default to the time zone of the kube-controller-manager process. The set of valid time zone names and the time zone offset is loaded from the system-wide time zone database by the API server during CronJob validation and the controller manager during execution. If no system-wide time zone database can be found a bundled version of the database is used instead. If the time zone name becomes invalid during the lifetime of a CronJob or due to a change in host configuration, the controller will stop creating new new Jobs and will create a system event with the reason UnknownTimeZone. More information can be found in | +| tolerations | list | `[]` | [Kubernetes tolerations](https://kubernetes.io/docs/concepts/scheduling-eviction/taint-and-toleration/) allow the scheduler to schedule pods with matching taints (constraints). | +| volumeMounts | list | `[]` | Additional volumeMounts to the backend container | +| volumes | list | `[]` | Additional volumes to the backend pod | + +## License + +The project is licensed under the "Apache-2.0" license. Details can be found in the `LICENSE` file within the helm chart +or in the [GitHub repository](https://github.com/cluetec/lifeboat). + +---------------------------------------------- +Autogenerated from chart metadata using [helm-docs](https://github.com/norwoodj/helm-docs/) diff --git a/chart/README.md.gotmpl b/chart/README.md.gotmpl new file mode 100644 index 0000000..7baf347 --- /dev/null +++ b/chart/README.md.gotmpl @@ -0,0 +1,14 @@ +{{ template "chart.header" . }} +{{ template "chart.deprecationWarning" . }} + +{{ template "chart.badgesSection" . }} + +{{ template "chart.valuesSection" . }} + +## License + +The project is licensed under the "Apache-2.0" license. Details can be found in the `LICENSE` file within the helm chart +or in the [GitHub repository](https://github.com/cluetec/lifeboat). + +---------------------------------------------- +Autogenerated from chart metadata using [helm-docs](https://github.com/norwoodj/helm-docs/) diff --git a/chart/__snapshots__/default.snap b/chart/__snapshots__/default.snap new file mode 100644 index 0000000..8d9a582 --- /dev/null +++ b/chart/__snapshots__/default.snap @@ -0,0 +1,60 @@ +[default] +SnapShot = """ +- object: + apiVersion: batch/v1 + kind: CronJob + metadata: + labels: + app.kubernetes.io/instance: chartsnap + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/name: lifeboat + app.kubernetes.io/version: 0.1.0 + helm.sh/chart: lifeboat-0.1.0 + name: chartsnap-lifeboat + namespace: default + spec: + concurrencyPolicy: Forbid + failedJobsHistoryLimit: 1 + jobTemplate: + metadata: + labels: + app.kubernetes.io/instance: chartsnap + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/name: lifeboat + app.kubernetes.io/version: 0.1.0 + helm.sh/chart: lifeboat-0.1.0 + spec: + template: + metadata: + labels: + app.kubernetes.io/instance: chartsnap + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/name: lifeboat + app.kubernetes.io/version: 0.1.0 + helm.sh/chart: lifeboat-0.1.0 + spec: + containers: + - env: null + envFrom: null + image: cluetec/lifeboat:0.1.0 + imagePullPolicy: IfNotPresent + name: lifeboat + securityContext: + capabilities: + drop: + - ALL + readOnlyRootFilesystem: true + runAsNonRoot: true + runAsUser: 1000 + volumeMounts: null + restartPolicy: Never + securityContext: + fsGroup: 2000 + runAsGroup: 3000 + runAsUser: 1000 + serviceAccountName: default + volumes: null + schedule: 0 3 * * * + successfulJobsHistoryLimit: 3 + suspend: false +""" diff --git a/chart/templates/NOTES.txt b/chart/templates/NOTES.txt new file mode 100644 index 0000000..e69de29 diff --git a/chart/templates/_helpers.tpl b/chart/templates/_helpers.tpl new file mode 100644 index 0000000..df51498 --- /dev/null +++ b/chart/templates/_helpers.tpl @@ -0,0 +1,55 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "lifeboat.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "lifeboat.fullname" -}} +{{- if .Values.fullnameOverride }} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- $name := default .Chart.Name .Values.nameOverride }} +{{- if contains $name .Release.Name }} +{{- .Release.Name | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} +{{- end }} +{{- end }} +{{- end }} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "lifeboat.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "lifeboat.labels" -}} +helm.sh/chart: {{ include "lifeboat.chart" . }} +app.kubernetes.io/name: {{ include "lifeboat.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end }} + +{{/* +Create the name of the service account to use +*/}} +{{- define "lifeboat.serviceAccountName" -}} +{{- if .Values.serviceAccount.enabled }} +{{- default (include "lifeboat.fullname" .) .Values.serviceAccount.name }} +{{- else }} +{{- default "default" .Values.serviceAccount.name }} +{{- end }} +{{- end }} diff --git a/chart/templates/configmap.yaml b/chart/templates/configmap.yaml new file mode 100644 index 0000000..e8b2dbc --- /dev/null +++ b/chart/templates/configmap.yaml @@ -0,0 +1,16 @@ +{{- if .Values.configuration }} +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ include "lifeboat.fullname" $ }} + namespace: {{ .Release.Namespace }} + labels: + {{- include "lifeboat.labels" $ | nindent 4 }} + {{- with .Values.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +data: + config.yaml: + {{- toYaml .Values.configuration | nindent 4 }} +{{- end }} diff --git a/chart/templates/cronjob.yaml b/chart/templates/cronjob.yaml new file mode 100644 index 0000000..2df61bb --- /dev/null +++ b/chart/templates/cronjob.yaml @@ -0,0 +1,142 @@ +apiVersion: batch/v1 +kind: CronJob +metadata: + name: {{ include "lifeboat.fullname" $ }} + namespace: {{ .Release.Namespace }} + labels: + {{- include "lifeboat.labels" $ | nindent 4 }} + {{- with .Values.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + concurrencyPolicy: {{ .Values.concurrencyPolicy }} + failedJobsHistoryLimit: {{ .Values.failedJobsHistoryLimit }} + schedule: {{ .Values.schedule | quote }} + {{- if .Values.startingDeadlineSeconds }} + startingDeadlineSeconds: {{ .Values.startingDeadlineSeconds }} + {{- end }} + successfulJobsHistoryLimit: {{ .Values.successfulJobsHistoryLimit }} + suspend: {{ .Values.suspend }} + {{- if .Values.timeZone }} + timeZone: {{ .Values.timeZone }} + {{- end }} + + jobTemplate: + metadata: + {{- with .Values.jobAnnotations }} + annotations: + {{- toYaml . | nindent 8 }} + {{- end }} + labels: + {{- include "lifeboat.labels" $ | nindent 8 }} + spec: + template: + metadata: + {{- with .Values.podAnnotations }} + annotations: + {{- toYaml . | nindent 12 }} + {{- end }} + labels: + {{- include "lifeboat.labels" $ | nindent 12 }} + spec: + serviceAccountName: {{ include "lifeboat.serviceAccountName" $ }} + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 12 }} + {{- end }} + + {{- with .Values.podSecurityContext }} + securityContext: + {{- toYaml . | nindent 12 }} + {{- end }} + restartPolicy: {{ .Values.restartPolicy }} + + containers: + - name: {{ .Chart.Name }} + + {{- with .Values.securityContext }} + securityContext: + {{- toYaml . | nindent 16 }} + {{- end }} + + image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + + env: + {{- range $key, $value := .Values.envValueFrom }} + - name: {{ $key | quote }} + valueFrom: + {{- tpl (toYaml $value) $ | nindent 20 }} + {{- end }} + {{- range $key, $value := .Values.env }} + - name: {{ $key | quote }} + value: {{ $value }} + {{- end }} + + envFrom: + {{- range $value := .Values.envSecretNames }} + - secretRef: + name: {{ $value | quote }} + {{- end }} + {{- range $value := .Values.envConfigMapNames }} + - configMapRef: + name: {{ $value | quote }} + {{- end }} + + {{- with .Values.resources }} + resources: + {{- toYaml . | nindent 16 }} + {{- end }} + + volumeMounts: + {{- if .Values.configuration }} + - name: config + mountPath: /app + readOnly: true + {{- end }} + {{- if .Values.storage.enabled }} + - name: backup + mountPath: {{ .Values.storage.mountPath}} + {{- end }} + + {{- with .Values.volumeMounts }} + {{- toYaml . | nindent 16 }} + {{- end }} + + {{- with .Values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 12 }} + {{- end }} + {{- with .Values.affinity }} + affinity: + {{- toYaml . | nindent 12 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: + {{- toYaml . | nindent 12 }} + {{- end }} + + volumes: + {{- if .Values.configuration }} + - name: config + configMap: + name: {{ include "lifeboat.fullname" $ }} + items: + - key: "config.yaml" + path: "config.yaml" + {{- end }} + {{- if .Values.storage.enabled }} + {{- if .Values.storage.existingClaim }} + - name: backup + persistentVolumeClaim: + claimName: {{ .Values.storage.existingClaim }} + {{- else }} + - name: backup + persistentVolumeClaim: + claimName: {{ include "lifeboat.fullname" $ }} + {{- end }} + {{- end }} + {{- with .Values.volumes }} + {{- toYaml . | nindent 12 }} + {{- end }} diff --git a/chart/templates/pvc.yaml b/chart/templates/pvc.yaml new file mode 100644 index 0000000..3f7a2c3 --- /dev/null +++ b/chart/templates/pvc.yaml @@ -0,0 +1,24 @@ +{{- if and .Values.storage.enabled (not .Values.storage.existingClaim) }} +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: {{ include "lifeboat.fullname" $ }} + namespace: {{ .Release.Namespace }} + labels: + {{- include "lifeboat.labels" $ | nindent 4 }} + {{- with .Values.storage.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + accessModes: + {{- range .Values.storage.accessModes }} + - {{ . | quote }} + {{- end }} + resources: + requests: + storage: {{ .Values.storage.size | quote }} + {{- with .Values.storage.storageClass }} + storageClassName: {{ . }} + {{- end }} +{{- end -}} diff --git a/chart/templates/serviceaccount.yaml b/chart/templates/serviceaccount.yaml new file mode 100644 index 0000000..b22b9e8 --- /dev/null +++ b/chart/templates/serviceaccount.yaml @@ -0,0 +1,17 @@ +{{- if .Values.serviceAccount.enabled -}} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "lifeboat.serviceAccountName" . }} + namespace: {{ .Release.Namespace }} + labels: + {{- include "lifeboat.labels" . | nindent 4 }} + {{- with .Values.serviceAccount.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +{{- with .Values.serviceAccount.imagePullSecrets }} +imagePullSecrets: + {{- toYaml . | nindent 2 }} +{{- end }} +{{- end }} diff --git a/chart/test/__snapshots__/test_enabled_pvc.snap b/chart/test/__snapshots__/test_enabled_pvc.snap new file mode 100644 index 0000000..501a647 --- /dev/null +++ b/chart/test/__snapshots__/test_enabled_pvc.snap @@ -0,0 +1,83 @@ +[test_enabled_pvc] +SnapShot = """ +- object: + apiVersion: batch/v1 + kind: CronJob + metadata: + labels: + app.kubernetes.io/instance: chartsnap + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/name: lifeboat + app.kubernetes.io/version: 0.1.0 + helm.sh/chart: lifeboat-0.1.0 + name: chartsnap-lifeboat + namespace: default + spec: + concurrencyPolicy: Forbid + failedJobsHistoryLimit: 1 + jobTemplate: + metadata: + labels: + app.kubernetes.io/instance: chartsnap + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/name: lifeboat + app.kubernetes.io/version: 0.1.0 + helm.sh/chart: lifeboat-0.1.0 + spec: + template: + metadata: + labels: + app.kubernetes.io/instance: chartsnap + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/name: lifeboat + app.kubernetes.io/version: 0.1.0 + helm.sh/chart: lifeboat-0.1.0 + spec: + containers: + - env: null + envFrom: null + image: cluetec/lifeboat:0.1.0 + imagePullPolicy: IfNotPresent + name: lifeboat + securityContext: + capabilities: + drop: + - ALL + readOnlyRootFilesystem: true + runAsNonRoot: true + runAsUser: 1000 + volumeMounts: + - mountPath: /backups + name: backup + restartPolicy: Never + securityContext: + fsGroup: 2000 + runAsGroup: 3000 + runAsUser: 1000 + serviceAccountName: default + volumes: + - name: backup + persistentVolumeClaim: + claimName: chartsnap-lifeboat + schedule: 0 3 * * * + successfulJobsHistoryLimit: 3 + suspend: false +- object: + apiVersion: v1 + kind: PersistentVolumeClaim + metadata: + labels: + app.kubernetes.io/instance: chartsnap + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/name: lifeboat + app.kubernetes.io/version: 0.1.0 + helm.sh/chart: lifeboat-0.1.0 + name: chartsnap-lifeboat + namespace: default + spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 10Gi +""" diff --git a/chart/test/__snapshots__/test_existing_pvc.snap b/chart/test/__snapshots__/test_existing_pvc.snap new file mode 100644 index 0000000..38003df --- /dev/null +++ b/chart/test/__snapshots__/test_existing_pvc.snap @@ -0,0 +1,65 @@ +[test_existing_pvc] +SnapShot = """ +- object: + apiVersion: batch/v1 + kind: CronJob + metadata: + labels: + app.kubernetes.io/instance: chartsnap + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/name: lifeboat + app.kubernetes.io/version: 0.1.0 + helm.sh/chart: lifeboat-0.1.0 + name: chartsnap-lifeboat + namespace: default + spec: + concurrencyPolicy: Forbid + failedJobsHistoryLimit: 1 + jobTemplate: + metadata: + labels: + app.kubernetes.io/instance: chartsnap + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/name: lifeboat + app.kubernetes.io/version: 0.1.0 + helm.sh/chart: lifeboat-0.1.0 + spec: + template: + metadata: + labels: + app.kubernetes.io/instance: chartsnap + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/name: lifeboat + app.kubernetes.io/version: 0.1.0 + helm.sh/chart: lifeboat-0.1.0 + spec: + containers: + - env: null + envFrom: null + image: cluetec/lifeboat:0.1.0 + imagePullPolicy: IfNotPresent + name: lifeboat + securityContext: + capabilities: + drop: + - ALL + readOnlyRootFilesystem: true + runAsNonRoot: true + runAsUser: 1000 + volumeMounts: + - mountPath: /backups + name: backup + restartPolicy: Never + securityContext: + fsGroup: 2000 + runAsGroup: 3000 + runAsUser: 1000 + serviceAccountName: default + volumes: + - name: backup + persistentVolumeClaim: + claimName: test-claim + schedule: 0 3 * * * + successfulJobsHistoryLimit: 3 + suspend: false +""" diff --git a/chart/test/__snapshots__/test_general_stuff.snap b/chart/test/__snapshots__/test_general_stuff.snap new file mode 100644 index 0000000..e0456b5 --- /dev/null +++ b/chart/test/__snapshots__/test_general_stuff.snap @@ -0,0 +1,94 @@ +[test_general_stuff] +SnapShot = """ +- object: + apiVersion: batch/v1 + kind: CronJob + metadata: + annotations: + test: 123 + labels: + app.kubernetes.io/instance: chartsnap + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/name: lifeboat + app.kubernetes.io/version: 0.1.0 + helm.sh/chart: lifeboat-0.1.0 + name: chartsnap-lifeboat + namespace: default + spec: + concurrencyPolicy: Forbid + failedJobsHistoryLimit: 1 + jobTemplate: + metadata: + annotations: + test2: 234 + labels: + app.kubernetes.io/instance: chartsnap + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/name: lifeboat + app.kubernetes.io/version: 0.1.0 + helm.sh/chart: lifeboat-0.1.0 + spec: + template: + metadata: + annotations: + test3: 345 + labels: + app.kubernetes.io/instance: chartsnap + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/name: lifeboat + app.kubernetes.io/version: 0.1.0 + helm.sh/chart: lifeboat-0.1.0 + spec: + containers: + - env: + - name: TEST_ENV_3 + valueFrom: + configMapKeyRef: + key: my-key + name: my-cm + - name: TEST_ENV_1 + value: env1 + - name: TEST_ENV_2 + value: env2 + envFrom: + - secretRef: + name: my-secret-1 + - configMapRef: + name: my-cm-2 + image: cluetec/lifeboat:0.1.0 + imagePullPolicy: IfNotPresent + name: lifeboat + securityContext: + capabilities: + drop: + - ALL + readOnlyRootFilesystem: true + runAsNonRoot: true + runAsUser: 1000 + volumeMounts: null + imagePullSecrets: + - name: my-pull-secret + restartPolicy: Never + securityContext: + fsGroup: 2000 + runAsGroup: 3000 + runAsUser: 1000 + serviceAccountName: chartsnap-lifeboat + volumes: null + schedule: 0 3 * * * + successfulJobsHistoryLimit: 3 + suspend: false + timeZone: Europe/Berlin +- object: + apiVersion: v1 + kind: ServiceAccount + metadata: + labels: + app.kubernetes.io/instance: chartsnap + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/name: lifeboat + app.kubernetes.io/version: 0.1.0 + helm.sh/chart: lifeboat-0.1.0 + name: chartsnap-lifeboat + namespace: default +""" diff --git a/chart/test/test_enabled_pvc.yaml b/chart/test/test_enabled_pvc.yaml new file mode 100644 index 0000000..18793f9 --- /dev/null +++ b/chart/test/test_enabled_pvc.yaml @@ -0,0 +1,2 @@ +storage: + enabled: true diff --git a/chart/test/test_existing_pvc.yaml b/chart/test/test_existing_pvc.yaml new file mode 100644 index 0000000..e432f4f --- /dev/null +++ b/chart/test/test_existing_pvc.yaml @@ -0,0 +1,3 @@ +storage: + enabled: true + existingClaim: test-claim diff --git a/chart/test/test_general_stuff.yaml b/chart/test/test_general_stuff.yaml new file mode 100644 index 0000000..5b00a15 --- /dev/null +++ b/chart/test/test_general_stuff.yaml @@ -0,0 +1,35 @@ +configuration: + test: 012 + +annotations: + test: 123 + +jobAnnotations: + test2: 234 + +podAnnotations: + test3: 345 + +timeZone: Europe/Berlin + +imagePullSecrets: + - name: my-pull-secret + +env: + TEST_ENV_1: env1 + TEST_ENV_2: env2 + +envValueFrom: + TEST_ENV_3: + configMapKeyRef: + name: my-cm + key: my-key + +envSecretNames: + - my-secret-1 + +envConfigMapNames: + - my-cm-2 + +serviceAccount: + enabled: true diff --git a/chart/values.yaml b/chart/values.yaml new file mode 100644 index 0000000..fa2d235 --- /dev/null +++ b/chart/values.yaml @@ -0,0 +1,143 @@ +# -- Lifeboat configuration +configuration: {} + +# -- [Additional cronjob annotations](https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/) +annotations: {} + +# -- [Additional job annotations](https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/) +jobAnnotations: {} + +# -- [Additional pod annotations](https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/) +podAnnotations: {} + +# -- Restart policy for all containers within the pod. One of Always, OnFailure, Never. More info: # -- Restart policy for all containers within the pod. One of Always, OnFailure, Never. In some contexts, only a subset of those values may be permitted. Default to Always. More info: +restartPolicy: Never + +# -- Specifies how to treat concurrent executions of a Job. Valid values are: - "Allow": allows CronJobs to run concurrently; - "Forbid": forbids concurrent runs, skipping next run if previous run hasn't finished yet; - "Replace": cancels currently running job and replaces it with a new one +concurrencyPolicy: Forbid + +# -- The number of failed finished jobs to retain. Value must be non-negative integer. +failedJobsHistoryLimit: 1 + +# -- The schedule in Cron format, see . Default is everyday at 3am +schedule: 0 3 * * * + +# -- Optional deadline in seconds for starting the job if it misses scheduled time for any reason. Missed jobs executions will be counted as failed ones. +startingDeadlineSeconds: 0 + +# -- The number of successful finished jobs to retain. Value must be non-negative integer. +successfulJobsHistoryLimit: 3 + +# -- This flag tells the controller to suspend subsequent executions, it does not apply to already started executions. +suspend: false + +# -- The time zone name for the given schedule, see . If not specified, this will default to the time zone of the kube-controller-manager process. The set of valid time zone names and the time zone offset is loaded from the system-wide time zone database by the API server during CronJob validation and the controller manager during execution. If no system-wide time zone database can be found a bundled version of the database is used instead. If the time zone name becomes invalid during the lifetime of a CronJob or due to a change in host configuration, the controller will stop creating new new Jobs and will create a system event with the reason UnknownTimeZone. More information can be found in +timeZone: "" + +image: + # -- The repository path of the container image. + repository: cluetec/lifeboat + # -- The pull policy for the container image. + pullPolicy: IfNotPresent + # -- Overrides the image tag whose default is the chart appVersion. + # tag: "latest" + +# -- Container registry secret names as an array +imagePullSecrets: [] +nameOverride: "" +fullnameOverride: "" + +# -- Extra environment variables that will be pass onto deployment pods. +env: {} +# ENV_NAME: value + +# -- ["valueFrom" environment variable references](https://kubernetes.io/docs/tasks/inject-data-application/define-environment-variable-container/) that will be added to deployment pods. Name is templated. +envValueFrom: {} +# ENV_NAME: +# configMapKeyRef: +# name: configmap-name +# key: value_key +# secretKeyRef: +# name: secret-name +# key: value_key + +# -- [Kubernetes Secret Resource](https://kubernetes.io/docs/concepts/configuration/secret/) names to load environment variables from. +envSecretNames: [] +# - first-secret +# - second-secret + +# -- [Kubernetes ConfigMap Resource](https://kubernetes.io/docs/concepts/configuration/configmap/) names to load environment variables from. +envConfigMapNames: [] +# - first-config-map +# - second-config-map + +# -- [Pod security context](https://kubernetes.io/docs/tasks/configure-pod-container/security-context/#set-the-security-context-for-a-pod) +podSecurityContext: + runAsUser: 1000 + runAsGroup: 3000 + fsGroup: 2000 + +# -- [Container security context](https://kubernetes.io/docs/tasks/configure-pod-container/security-context/#set-the-security-context-for-a-container) +securityContext: + capabilities: + drop: + - ALL + readOnlyRootFilesystem: true + runAsNonRoot: true + runAsUser: 1000 + +resources: {} + # limits: + # -- Maximum CPU limit + # cpu: 500m + # -- Maximum memory limit + # memory: 512Mi + # requests: + # -- Initial CPU request + # cpu: 100m + # -- Initial memory request + # memory: 256Mi + +# -- [Kubernetes node selector](https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/) allows to select specific Kubernetes nodes (nodes) on which the pod should be scheduled. +nodeSelector: {} + +# -- [Kubernetes tolerations](https://kubernetes.io/docs/concepts/scheduling-eviction/taint-and-toleration/) allow the scheduler to schedule pods with matching taints (constraints). +tolerations: [] + +# -- [Kubernetes affinity and anti-affinity](https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#affinity-and-anti-affinity) allows defining rules that determine on which nodes the pod should be run preferentially. +affinity: {} + +storage: + # -- Enables/Disables the provisioning of an persistent volume claim + enabled: false + # -- Provide an existing `PersistentVolumeClaim`. If defined, PVC must be created manually before volume will be bound + existingClaim: "" + # -- PVC Storage Class for the backup volume + # If defined, storageClassName: + # If undefined (the default) or set to null, no storageClassName spec is + # set, choosing the default provisioner. + storageClass: + # -- PV Access Mode + accessModes: + - ReadWriteOnce + # -- PVC Storage Request for the backup volume + size: 10Gi + mountPath: /backups + # -- [Additional pvc annotations](https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/) + annotation: [] + +# -- Additional volumeMounts to the backend container +volumeMounts: [] + +# -- Additional volumes to the backend pod +volumes: [] + +serviceAccount: + # -- Specifies whether a service account should be created + enabled: false + # -- Annotations to add to the service account + annotations: {} + # -- The name of the service account to use. If not set and create is true, a name is generated using the fullname template + name: "" + # -- List of image pull secret names which should be used by the service account + imagePullSecrets: []