From 4965a40845cc79da45292ee434181e5d7e8de20c Mon Sep 17 00:00:00 2001 From: aguyot-ensae Date: Wed, 27 Nov 2024 10:39:05 +0100 Subject: [PATCH] update helm chart --- .../limesurvey-martial-ingress-v9/.helmignore | 24 + .../limesurvey-martial-ingress-v9/Chart.lock | 6 + .../limesurvey-martial-ingress-v9/Chart.yaml | 19 + .../limesurvey-martial-ingress-v9/README.md | 181 +++ .../charts/mariadb-11.5.7.tgz | Bin 0 -> 45541 bytes .../charts/mariadb/.helmignore | 21 + .../charts/mariadb/Chart.lock | 6 + .../charts/mariadb/Chart.yaml | 30 + .../charts/mariadb/README.md | 559 +++++++ .../charts/mariadb/charts/common/.helmignore | 22 + .../charts/mariadb/charts/common/Chart.yaml | 23 + .../charts/mariadb/charts/common/README.md | 351 +++++ .../charts/common/templates/_affinities.tpl | 106 ++ .../charts/common/templates/_capabilities.tpl | 154 ++ .../charts/common/templates/_errors.tpl | 23 + .../charts/common/templates/_images.tpl | 76 + .../charts/common/templates/_ingress.tpl | 68 + .../charts/common/templates/_labels.tpl | 18 + .../charts/common/templates/_names.tpl | 66 + .../charts/common/templates/_secrets.tpl | 165 +++ .../charts/common/templates/_storage.tpl | 23 + .../charts/common/templates/_tplvalues.tpl | 13 + .../charts/common/templates/_utils.tpl | 62 + .../charts/common/templates/_warnings.tpl | 14 + .../templates/validations/_cassandra.tpl | 72 + .../common/templates/validations/_mariadb.tpl | 103 ++ .../common/templates/validations/_mongodb.tpl | 108 ++ .../common/templates/validations/_mysql.tpl | 103 ++ .../templates/validations/_postgresql.tpl | 129 ++ .../common/templates/validations/_redis.tpl | 76 + .../templates/validations/_validations.tpl | 46 + .../charts/mariadb/charts/common/values.yaml | 5 + .../charts/mariadb/templates/NOTES.txt | 75 + .../charts/mariadb/templates/_helpers.tpl | 149 ++ .../charts/mariadb/templates/extra-list.yaml | 4 + .../templates/networkpolicy-egress.yaml | 33 + .../mariadb/templates/primary/configmap.yaml | 18 + .../primary/initialization-configmap.yaml | 11 + .../primary/networkpolicy-ingress.yaml | 56 + .../charts/mariadb/templates/primary/pdb.yaml | 25 + .../templates/primary/statefulset.yaml | 394 +++++ .../charts/mariadb/templates/primary/svc.yaml | 61 + .../mariadb/templates/prometheusrules.yaml | 26 + .../charts/mariadb/templates/role.yaml | 21 + .../charts/mariadb/templates/rolebinding.yaml | 21 + .../templates/secondary/configmap.yaml | 18 + .../secondary/networkpolicy-ingress.yaml | 49 + .../mariadb/templates/secondary/pdb.yaml | 25 + .../templates/secondary/statefulset.yaml | 365 +++++ .../mariadb/templates/secondary/svc.yaml | 63 + .../charts/mariadb/templates/secrets.yaml | 35 + .../mariadb/templates/serviceaccount.yaml | 19 + .../mariadb/templates/servicemonitor.yaml | 48 + .../charts/mariadb/values.schema.json | 176 +++ .../charts/mariadb/values.yaml | 1311 +++++++++++++++++ charts/limesurvey-martial-ingress-v9/icon.png | Bin 0 -> 8080 bytes .../limesurvey-martial-ingress-v9-0.8.0.tgz | Bin 0 -> 114058 bytes .../template.txt | 444 ++++++ .../templates/NOTES.txt | 29 + .../templates/_helpers.tpl | 108 ++ .../templates/deployment.yaml | 272 ++++ .../templates/hpa.yaml | 28 + .../templates/ingress.yaml | 55 + .../templates/pvc.yaml | 32 + .../templates/secrets.yaml | 46 + .../templates/service.yaml | 15 + .../templates/serviceaccount.yaml | 12 + .../templates/tests/test-connection.yaml | 15 + .../values.schema.json | 183 +++ .../limesurvey-martial-ingress-v9/values.yaml | 214 +++ 70 files changed, 7128 insertions(+) create mode 100644 charts/limesurvey-martial-ingress-v9/.helmignore create mode 100644 charts/limesurvey-martial-ingress-v9/Chart.lock create mode 100644 charts/limesurvey-martial-ingress-v9/Chart.yaml create mode 100644 charts/limesurvey-martial-ingress-v9/README.md create mode 100644 charts/limesurvey-martial-ingress-v9/charts/mariadb-11.5.7.tgz create mode 100644 charts/limesurvey-martial-ingress-v9/charts/mariadb/.helmignore create mode 100644 charts/limesurvey-martial-ingress-v9/charts/mariadb/Chart.lock create mode 100644 charts/limesurvey-martial-ingress-v9/charts/mariadb/Chart.yaml create mode 100644 charts/limesurvey-martial-ingress-v9/charts/mariadb/README.md create mode 100644 charts/limesurvey-martial-ingress-v9/charts/mariadb/charts/common/.helmignore create mode 100644 charts/limesurvey-martial-ingress-v9/charts/mariadb/charts/common/Chart.yaml create mode 100644 charts/limesurvey-martial-ingress-v9/charts/mariadb/charts/common/README.md create mode 100644 charts/limesurvey-martial-ingress-v9/charts/mariadb/charts/common/templates/_affinities.tpl create mode 100644 charts/limesurvey-martial-ingress-v9/charts/mariadb/charts/common/templates/_capabilities.tpl create mode 100644 charts/limesurvey-martial-ingress-v9/charts/mariadb/charts/common/templates/_errors.tpl create mode 100644 charts/limesurvey-martial-ingress-v9/charts/mariadb/charts/common/templates/_images.tpl create mode 100644 charts/limesurvey-martial-ingress-v9/charts/mariadb/charts/common/templates/_ingress.tpl create mode 100644 charts/limesurvey-martial-ingress-v9/charts/mariadb/charts/common/templates/_labels.tpl create mode 100644 charts/limesurvey-martial-ingress-v9/charts/mariadb/charts/common/templates/_names.tpl create mode 100644 charts/limesurvey-martial-ingress-v9/charts/mariadb/charts/common/templates/_secrets.tpl create mode 100644 charts/limesurvey-martial-ingress-v9/charts/mariadb/charts/common/templates/_storage.tpl create mode 100644 charts/limesurvey-martial-ingress-v9/charts/mariadb/charts/common/templates/_tplvalues.tpl create mode 100644 charts/limesurvey-martial-ingress-v9/charts/mariadb/charts/common/templates/_utils.tpl create mode 100644 charts/limesurvey-martial-ingress-v9/charts/mariadb/charts/common/templates/_warnings.tpl create mode 100644 charts/limesurvey-martial-ingress-v9/charts/mariadb/charts/common/templates/validations/_cassandra.tpl create mode 100644 charts/limesurvey-martial-ingress-v9/charts/mariadb/charts/common/templates/validations/_mariadb.tpl create mode 100644 charts/limesurvey-martial-ingress-v9/charts/mariadb/charts/common/templates/validations/_mongodb.tpl create mode 100644 charts/limesurvey-martial-ingress-v9/charts/mariadb/charts/common/templates/validations/_mysql.tpl create mode 100644 charts/limesurvey-martial-ingress-v9/charts/mariadb/charts/common/templates/validations/_postgresql.tpl create mode 100644 charts/limesurvey-martial-ingress-v9/charts/mariadb/charts/common/templates/validations/_redis.tpl create mode 100644 charts/limesurvey-martial-ingress-v9/charts/mariadb/charts/common/templates/validations/_validations.tpl create mode 100644 charts/limesurvey-martial-ingress-v9/charts/mariadb/charts/common/values.yaml create mode 100644 charts/limesurvey-martial-ingress-v9/charts/mariadb/templates/NOTES.txt create mode 100644 charts/limesurvey-martial-ingress-v9/charts/mariadb/templates/_helpers.tpl create mode 100644 charts/limesurvey-martial-ingress-v9/charts/mariadb/templates/extra-list.yaml create mode 100644 charts/limesurvey-martial-ingress-v9/charts/mariadb/templates/networkpolicy-egress.yaml create mode 100644 charts/limesurvey-martial-ingress-v9/charts/mariadb/templates/primary/configmap.yaml create mode 100644 charts/limesurvey-martial-ingress-v9/charts/mariadb/templates/primary/initialization-configmap.yaml create mode 100644 charts/limesurvey-martial-ingress-v9/charts/mariadb/templates/primary/networkpolicy-ingress.yaml create mode 100644 charts/limesurvey-martial-ingress-v9/charts/mariadb/templates/primary/pdb.yaml create mode 100644 charts/limesurvey-martial-ingress-v9/charts/mariadb/templates/primary/statefulset.yaml create mode 100644 charts/limesurvey-martial-ingress-v9/charts/mariadb/templates/primary/svc.yaml create mode 100644 charts/limesurvey-martial-ingress-v9/charts/mariadb/templates/prometheusrules.yaml create mode 100644 charts/limesurvey-martial-ingress-v9/charts/mariadb/templates/role.yaml create mode 100644 charts/limesurvey-martial-ingress-v9/charts/mariadb/templates/rolebinding.yaml create mode 100644 charts/limesurvey-martial-ingress-v9/charts/mariadb/templates/secondary/configmap.yaml create mode 100644 charts/limesurvey-martial-ingress-v9/charts/mariadb/templates/secondary/networkpolicy-ingress.yaml create mode 100644 charts/limesurvey-martial-ingress-v9/charts/mariadb/templates/secondary/pdb.yaml create mode 100644 charts/limesurvey-martial-ingress-v9/charts/mariadb/templates/secondary/statefulset.yaml create mode 100644 charts/limesurvey-martial-ingress-v9/charts/mariadb/templates/secondary/svc.yaml create mode 100644 charts/limesurvey-martial-ingress-v9/charts/mariadb/templates/secrets.yaml create mode 100644 charts/limesurvey-martial-ingress-v9/charts/mariadb/templates/serviceaccount.yaml create mode 100644 charts/limesurvey-martial-ingress-v9/charts/mariadb/templates/servicemonitor.yaml create mode 100644 charts/limesurvey-martial-ingress-v9/charts/mariadb/values.schema.json create mode 100644 charts/limesurvey-martial-ingress-v9/charts/mariadb/values.yaml create mode 100644 charts/limesurvey-martial-ingress-v9/icon.png create mode 100644 charts/limesurvey-martial-ingress-v9/limesurvey-martial-ingress-v9-0.8.0.tgz create mode 100644 charts/limesurvey-martial-ingress-v9/template.txt create mode 100644 charts/limesurvey-martial-ingress-v9/templates/NOTES.txt create mode 100644 charts/limesurvey-martial-ingress-v9/templates/_helpers.tpl create mode 100644 charts/limesurvey-martial-ingress-v9/templates/deployment.yaml create mode 100644 charts/limesurvey-martial-ingress-v9/templates/hpa.yaml create mode 100644 charts/limesurvey-martial-ingress-v9/templates/ingress.yaml create mode 100644 charts/limesurvey-martial-ingress-v9/templates/pvc.yaml create mode 100644 charts/limesurvey-martial-ingress-v9/templates/secrets.yaml create mode 100644 charts/limesurvey-martial-ingress-v9/templates/service.yaml create mode 100644 charts/limesurvey-martial-ingress-v9/templates/serviceaccount.yaml create mode 100644 charts/limesurvey-martial-ingress-v9/templates/tests/test-connection.yaml create mode 100644 charts/limesurvey-martial-ingress-v9/values.schema.json create mode 100644 charts/limesurvey-martial-ingress-v9/values.yaml diff --git a/charts/limesurvey-martial-ingress-v9/.helmignore b/charts/limesurvey-martial-ingress-v9/.helmignore new file mode 100644 index 0000000..faeb926 --- /dev/null +++ b/charts/limesurvey-martial-ingress-v9/.helmignore @@ -0,0 +1,24 @@ +# 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/ +tests/ diff --git a/charts/limesurvey-martial-ingress-v9/Chart.lock b/charts/limesurvey-martial-ingress-v9/Chart.lock new file mode 100644 index 0000000..4f6acb8 --- /dev/null +++ b/charts/limesurvey-martial-ingress-v9/Chart.lock @@ -0,0 +1,6 @@ +dependencies: +- name: mariadb + repository: https://charts.bitnami.com/bitnami + version: 11.5.7 +digest: sha256:4254008103034bb3ed9b3816a071a1aed1aacc049f9f993e56111fd82a574c3a +generated: "2024-04-24T17:16:59.0121179+02:00" diff --git a/charts/limesurvey-martial-ingress-v9/Chart.yaml b/charts/limesurvey-martial-ingress-v9/Chart.yaml new file mode 100644 index 0000000..f6925d7 --- /dev/null +++ b/charts/limesurvey-martial-ingress-v9/Chart.yaml @@ -0,0 +1,19 @@ +apiVersion: v2 +appVersion: 5-apache +dependencies: +- condition: mariadb.enabled + name: mariadb + repository: https://charts.bitnami.com/bitnami + version: 11.x +description: Limesurvey is the number one open-source survey software. +icon: https://raw.githubusercontent.com/martialblog/helm-charts/master/limesurvey/icon.png +maintainers: +- email: markus@martialblog.de + name: martialblog +name: limesurvey-martial-ingress-v9 +sources: +- https://github.com/martialblog/helm-charts +- https://github.com/martialblog/docker-limesurvey/ +- https://limesurvey.org/ +type: application +version: 0.8.0 \ No newline at end of file diff --git a/charts/limesurvey-martial-ingress-v9/README.md b/charts/limesurvey-martial-ingress-v9/README.md new file mode 100644 index 0000000..814e275 --- /dev/null +++ b/charts/limesurvey-martial-ingress-v9/README.md @@ -0,0 +1,181 @@ +# LimeSurvey + +[LimeSurvey](https://limesurvey.org/) is the number one open-source survey software. + +## TL;DR + +```console +helm repo add martialblog https://martialblog.github.io/helm-charts +helm repo update + +helm install my-release \ + --set mariadb.enabled=true \ + --set mariadb.auth.rootPassword=CHANGE-ME \ + --set mariadb.auth.password=CHANGE-ME \ + martialblog/limesurvey +``` + +## Introduction + +This chart bootstraps LimeSurvey deployment on a [Kubernetes](http://kubernetes.io) cluster using the [Helm](https://helm.sh) package manager. + +It also packages the [Bitnami MariaDB chart](https://artifacthub.io/packages/helm/bitnami/mariadb) which is required for bootstrapping a MariaDB deployment for the database requirements of the application. You can also provide your own database instance. + +## Prerequisites + +- Kubernetes 1.13+ +- Helm 3+ +- PV provisioner support in the underlying infrastructure + +## Parameters + +### Global parameters + +| Name | Description | Value | +| ------------------------- | ----------------------------------------------- | ----- | +| `global.imageRegistry` | Global Docker image registry | `nil` | + +### LimeSurvey Image parameters + +| Name | Description | Value | +| ------------------- | ---------------------------------------------------- | --------------------- | +| `image.registry` | LimeSurvey image registry | `docker.io` | +| `image.repository` | LimeSurvey image repository | `martialblog/limesurvey` | +| `image.tag` | LimeSurvey image tag (immutable tags are recommended) | `5-apache` | +| `image.pullPolicy` | LimeSurvey image pull policy | `IfNotPresent` | +| `image.pullSecrets` | LimeSurvey image pull secrets | `[]` | + +### LimeSurvey Configuration parameters + +| Name | Description | Value | +| -------------------------------------- | ----------------------------------------------- | ------------------ | +| `limesurvey.admin.user` | LimeSurvey initial Admin Username | `admin` | +| `limesurvey.admin.password` | LimeSurvey initial Admin Password | `nil` | +| `limesurvey.admin.name` | LimeSurvey initial Admin Full Name | `Administrator` | +| `limesurvey.admin.email` | LimeSurvey initial Admin Email | `admin@example.com` | +| `limesurvey.listenPort` | LimeSurvey Container port for webserver | `8080` | +| `limesurvey.publicUrl` | LimeSurvey Public URL for public scripts | `nil` | +| `limesurvey.baseUrl` | LimeSurvey Application Base URL | `nil` | +| `limesurvey.mysqlEngine` | MySQL engine used for survey tables (MyISAM or InnoDB) | `MyISAM` | +| `limesurvey.urlFormat` | LimeSurvey URL Format (path|get) | `nil` | +| `limesurvey.showScriptName` | LimeSurvey Script name in URL (true|false) | `true` | +| `limesurvey.tablePrefix` | LimeSurvey Database table prefix; set this to a single whitespace if you don't want a table prefix. | `lime_` | +| `limesurvey.tableSession` | LimeSurvey Table sessions; For storing sessions in the database | `false` | +| `limesurvey.debug` | LimeSurvey Debug level (0, 1, 2) | `0` | +| `limesurvey.debugSql` | LimeSurvey SQL Debug level (0, 1, 2) | `0` | +| `limesurvey.encrypt.keypair` | LimeSurvey Data encryption keypair | `nil` | +| `limesurvey.encrypt.publicKey` | LimeSurvey Data encryption public key | `nil` | +| `limesurvey.encrypt.secretKey` | LimeSurvey Data encryption secret key | `nil` | +| `limesurvey.encrypt.nonce` | LimeSurvey Data encryption nonce | `nil` | +| `limesurvey.encrypt.secretBoxKey` | LimeSurvey Data encryption secret box key | `nil` | + +### Persistence Parameters + +| Name | Description | Value | +| --------------------------------------------- | ----------------------------------------------------------------------------------------------- | ----------------------- | +| `persistence.enabled` | Enable persistence using Persistent Volume Claims | `true` | +| `persistence.accessModes` | Persistent Volume access modes | `[ReadWriteOnce]` | +| `persistence.size` | Persistent Volume size | `5Gi` | +| `persistence.storageClassName` | Persistent Volume storage class name | `nil` | +| `persistence.subPath` | Persistent Volume sub path | `nil` | +| `persistence.finalizers` | Persistent Volume finalizers | `[kubernetes.io/pvc-protection]` | +| `persistence.selectorLabels` | Persistent Volume selector labels | `{}` | +| `persistence.annotations` | persistent volume claim annotations | `{}` | +| `persistence.existingClaim` | The name of an existing PVC to use for persistence | `nil` | + +### Traffic Exposure Parameters + +| Name | Description | Value | +| ------------------------- | ----------------------------------------------- | ----- | +| `service.type` | LimeSurvey service type | `ClusterIP` | +| `service.port` | LimeSurvey service port | `80` | +| `ingress.enabled` | Enable ingress record generation for LimeSurvey | `false` | +| `ingress.className` | IngressClass that will be be used to implement the Ingress | `""` | +| `ingress.hosts` | An array with hosts for the Ingress | `limesurvey.local` | +| `ingress.annotations` | Additional annotations for the Ingress resource. To enable certificate autogeneration, place here your cert-manager annotations. | `{}` | +| `ingress.tls` | Enable TLS configuration for the host defined at `ingress.hostname` parameter | `false` | + +### Other parameters + +| Name | Description | Value | +| ------------------------- | ------------------------------------------------ | ----- | +| `imagePullSecrets` | Docker registry secret names as an array | `[]` | +| `nameOverride` | String to override the Chart Name | `nil` | +| `fullnameOverride` | String to fully override the Chart Name | `nil` | +| `extraVolumeMounts` | Additional volumes as an array | `[]` | +| `extraEmptyDirMounts` | Additional emptyDir volumes as an array | `[]` | +| `nodeSelector` | Node labels for pod assignment | `{}` | +| `tolerations` | Tolerations for pod assignment | `{}` | +| `affinity` | Affinity for pod assignment | `{}` | +| `podAnnotations` | Annotations for LimeSurvey pods | `[]` | +| `updateStrategy.type` | Deployment strategy type | `RollingUpdate` | +| `updateStrategy.rollingUpdate` | Deployment rolling update configuration parameters | `{}` | +| `replicaCount` | Number of LimeSurvey replicas to deploy | `1` | +| `autoscaling.enabled` | Enable Horizontal POD autoscaling for LimeSurvey | `false` | +| `autoscaling.minReplicas` | Minimum number of LimeSurvey replicas | `1` | +| `autoscaling.maxReplicas` | Maximum number of LimeSurvey replicas | `11` | +| `autoscaling.targetCPUUtilizationPercentage` | Target CPU utilization percentage | `80` | +| `podSecurityContext.fsGroup` | Set LimeSurvey pod's Security Context fsGroup | `33` | +| `podSecurityContext.runAsUser` | Set LimeSurvey pod's Security Context runAsUser | `33` | +| `podSecurityContext.runAsGroup` | Set LimeSurvey pod's Security Context runAsGroup | `33` | +| `containerSecurityContext.enabled` | Enable LimeSurvey containers' Security Context | `true` | +| `containerSecurityContext.allowPrivilegeEscalation` | Default LimeSurvey containers' Security Context | `true` | + +### Database Parameters + +LimeSurvey requires a [MySQL- or PostgreSQL-compatible database](https://manual.limesurvey.org/Installation_-_LimeSurvey_CE#Create_a_database_user). + +You can either provide your own: +```yaml +externalDatabase: + host: hostname.example + database: limesurvey-db + username: limesurvey + password: "your-super-secret-password" +``` + +or you can let the Helm chart provision one for you (based on [Bitnami MariaDB Helm chart](https://artifacthub.io/packages/helm/bitnami/mariadb)): +```yaml +mariadb: + enabled: true + auth: + rootPassword: "please-change-me" + database: limesurvey + username: limesurvey + password: "please-change-me" +``` + +In both cases the application will automatically be configured to use these credentials. +Please refer to the [values.yaml](./values.yaml) for all possible configuration values. + +## Configuration and installation details + +### LimeSurvey Administrator Password + +If the initial Admin Password `limesurvey.admin.password` is not provided it will be set to a random string. You can extract the password from the Secret: + +```bash +kubectl get secrets --template={{.data.limesurvey-admin-password}} | base64 -d +``` + +## Upgrading + +### To 0.6.0 + +This release bumps the Bitnami MariaDB to 10.6. Follow the official instructions [official instructions](https://mariadb.com/kb/en/upgrading-from-mariadb-105-to-mariadb-106/). + +## Testing + +This Helm chart is tested with [helm unittest](https://github.com/quintush/helm-unittest) ([test format spec](https://github.com/quintush/helm-unittest/blob/master/DOCUMENT.md)). +You can find the test specifications in the `./tests/` directory. +Tests are automatically run in CI. + +To run the tests locally, use the following command: + +``` +# Required for pulling the MariaDB chart +helm repo add bitnami https://charts.bitnami.com/bitnami +helm dependency build + +podman run --rm -v "${PWD}:/apps" docker.io/quintush/helm-unittest:3.7.1-0.2.8 --helm3 . +```` diff --git a/charts/limesurvey-martial-ingress-v9/charts/mariadb-11.5.7.tgz b/charts/limesurvey-martial-ingress-v9/charts/mariadb-11.5.7.tgz new file mode 100644 index 0000000000000000000000000000000000000000..2a580e30827148932a55c18fb72b21006a550491 GIT binary patch literal 45541 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 literal 0 HcmV?d00001 diff --git a/charts/limesurvey-martial-ingress-v9/charts/mariadb/.helmignore b/charts/limesurvey-martial-ingress-v9/charts/mariadb/.helmignore new file mode 100644 index 0000000..f0c1319 --- /dev/null +++ b/charts/limesurvey-martial-ingress-v9/charts/mariadb/.helmignore @@ -0,0 +1,21 @@ +# 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 +*~ +# Various IDEs +.project +.idea/ +*.tmproj diff --git a/charts/limesurvey-martial-ingress-v9/charts/mariadb/Chart.lock b/charts/limesurvey-martial-ingress-v9/charts/mariadb/Chart.lock new file mode 100644 index 0000000..5d7370a --- /dev/null +++ b/charts/limesurvey-martial-ingress-v9/charts/mariadb/Chart.lock @@ -0,0 +1,6 @@ +dependencies: +- name: common + repository: https://charts.bitnami.com/bitnami + version: 2.2.2 +digest: sha256:49ca75cf23ba5eb7df4becef52580f98c8bd8194eb80368b9d7b875f6eefa8e5 +generated: "2022-12-15T08:09:23.256191892Z" diff --git a/charts/limesurvey-martial-ingress-v9/charts/mariadb/Chart.yaml b/charts/limesurvey-martial-ingress-v9/charts/mariadb/Chart.yaml new file mode 100644 index 0000000..6028225 --- /dev/null +++ b/charts/limesurvey-martial-ingress-v9/charts/mariadb/Chart.yaml @@ -0,0 +1,30 @@ +annotations: + category: Database +apiVersion: v2 +appVersion: 10.6.11 +dependencies: +- name: common + repository: https://charts.bitnami.com/bitnami + tags: + - bitnami-common + version: 2.x.x +description: MariaDB is an open source, community-developed SQL database server that + is widely in use around the world due to its enterprise features, flexibility, and + collaboration with leading tech firms. +home: https://github.com/bitnami/charts/tree/main/bitnami/mariadb +icon: https://bitnami.com/assets/stacks/mariadb/img/mariadb-stack-220x234.png +keywords: +- mariadb +- mysql +- database +- sql +- prometheus +maintainers: +- name: Bitnami + url: https://github.com/bitnami/charts +name: mariadb +sources: +- https://github.com/bitnami/containers/tree/main/bitnami/mariadb +- https://github.com/prometheus/mysqld_exporter +- https://mariadb.org +version: 11.4.2 diff --git a/charts/limesurvey-martial-ingress-v9/charts/mariadb/README.md b/charts/limesurvey-martial-ingress-v9/charts/mariadb/README.md new file mode 100644 index 0000000..3e46799 --- /dev/null +++ b/charts/limesurvey-martial-ingress-v9/charts/mariadb/README.md @@ -0,0 +1,559 @@ + + +# MariaDB packaged by Bitnami + +MariaDB is an open source, community-developed SQL database server that is widely in use around the world due to its enterprise features, flexibility, and collaboration with leading tech firms. + +[Overview of MariaDB](https://mariadb.org/) + +Trademarks: This software listing is packaged by Bitnami. The respective trademarks mentioned in the offering are owned by the respective companies, and use of them does not imply any affiliation or endorsement. + +## TL;DR + +```bash +$ helm repo add my-repo https://charts.bitnami.com/bitnami +$ helm install my-release my-repo/mariadb +``` + +## Introduction + +This chart bootstraps a [MariaDB](https://github.com/bitnami/containers/tree/main/bitnami/mariadb) replication cluster deployment on a [Kubernetes](https://kubernetes.io) cluster using the [Helm](https://helm.sh) package manager. + +MariaDB is developed as open source software and as a relational database it provides an SQL interface for accessing data. The latest versions of MariaDB also include GIS and JSON features. + +Bitnami charts can be used with [Kubeapps](https://kubeapps.dev/) for deployment and management of Helm Charts in clusters. + +## Prerequisites + +- Kubernetes 1.19+ +- Helm 3.2.0+ +- PV provisioner support in the underlying infrastructure + +## Installing the Chart + +To install the chart with the release name `my-release`: + +```bash +$ helm install my-release my-repo/mariadb +``` + +The command deploys MariaDB on the Kubernetes cluster in the default configuration. The [Parameters](#parameters) section lists the parameters that can be configured during installation. + +> **Tip**: List all releases using `helm list` + +## Uninstalling the Chart + +To uninstall/delete the `my-release` deployment: + +```bash +$ helm delete my-release +``` + +The command removes all the Kubernetes components associated with the chart and deletes the release. + +## Parameters + +### Global parameters + +| Name | Description | Value | +| ------------------------- | ----------------------------------------------- | ----- | +| `global.imageRegistry` | Global Docker Image registry | `""` | +| `global.imagePullSecrets` | Global Docker registry secret names as an array | `[]` | +| `global.storageClass` | Global storage class for dynamic provisioning | `""` | + + +### Common parameters + +| Name | Description | Value | +| ------------------------ | --------------------------------------------------------------------------------------- | --------------- | +| `kubeVersion` | Force target Kubernetes version (using Helm capabilities if not set) | `""` | +| `nameOverride` | String to partially override mariadb.fullname | `""` | +| `fullnameOverride` | String to fully override mariadb.fullname | `""` | +| `clusterDomain` | Default Kubernetes cluster domain | `cluster.local` | +| `commonAnnotations` | Common annotations to add to all MariaDB resources (sub-charts are not considered) | `{}` | +| `commonLabels` | Common labels to add to all MariaDB resources (sub-charts are not considered) | `{}` | +| `schedulerName` | Name of the scheduler (other than default) to dispatch pods | `""` | +| `runtimeClassName` | Name of the Runtime Class for all MariaDB pods | `""` | +| `extraDeploy` | Array of extra objects to deploy with the release (evaluated as a template) | `[]` | +| `diagnosticMode.enabled` | Enable diagnostic mode (all probes will be disabled and the command will be overridden) | `false` | +| `diagnosticMode.command` | Command to override all containers in the deployment | `["sleep"]` | +| `diagnosticMode.args` | Args to override all containers in the deployment | `["infinity"]` | + + +### MariaDB common parameters + +| Name | Description | Value | +| -------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------- | +| `image.registry` | MariaDB image registry | `docker.io` | +| `image.repository` | MariaDB image repository | `bitnami/mariadb` | +| `image.tag` | MariaDB image tag (immutable tags are recommended) | `10.6.11-debian-11-r12` | +| `image.digest` | MariaDB image digest in the way sha256:aa.... Please note this parameter, if set, will override the tag | `""` | +| `image.pullPolicy` | MariaDB image pull policy | `IfNotPresent` | +| `image.pullSecrets` | Specify docker-registry secret names as an array | `[]` | +| `image.debug` | Specify if debug logs should be enabled | `false` | +| `architecture` | MariaDB architecture (`standalone` or `replication`) | `standalone` | +| `auth.rootPassword` | Password for the `root` user. Ignored if existing secret is provided. | `""` | +| `auth.database` | Name for a custom database to create | `my_database` | +| `auth.username` | Name for a custom user to create | `""` | +| `auth.password` | Password for the new user. Ignored if existing secret is provided | `""` | +| `auth.replicationUser` | MariaDB replication user | `replicator` | +| `auth.replicationPassword` | MariaDB replication user password. Ignored if existing secret is provided | `""` | +| `auth.existingSecret` | Use existing secret for password details (`auth.rootPassword`, `auth.password`, `auth.replicationPassword` will be ignored and picked up from this secret). The secret has to contain the keys `mariadb-root-password`, `mariadb-replication-password` and `mariadb-password` | `""` | +| `auth.forcePassword` | Force users to specify required passwords | `false` | +| `auth.usePasswordFiles` | Mount credentials as files instead of using environment variables | `false` | +| `auth.customPasswordFiles` | Use custom password files when `auth.usePasswordFiles` is set to `true`. Define path for keys `root` and `user`, also define `replicator` if `architecture` is set to `replication` | `{}` | +| `initdbScripts` | Dictionary of initdb scripts | `{}` | +| `initdbScriptsConfigMap` | ConfigMap with the initdb scripts (Note: Overrides `initdbScripts`) | `""` | + + +### MariaDB Primary parameters + +| Name | Description | Value | +| ----------------------------------------------- | ----------------------------------------------------------------------------------------------------------------- | ------------------- | +| `primary.name` | Name of the primary database (eg primary, master, leader, ...) | `primary` | +| `primary.command` | Override default container command on MariaDB Primary container(s) (useful when using custom images) | `[]` | +| `primary.args` | Override default container args on MariaDB Primary container(s) (useful when using custom images) | `[]` | +| `primary.lifecycleHooks` | for the MariaDB Primary container(s) to automate configuration before or after startup | `{}` | +| `primary.hostAliases` | Add deployment host aliases | `[]` | +| `primary.configuration` | MariaDB Primary configuration to be injected as ConfigMap | `""` | +| `primary.existingConfigmap` | Name of existing ConfigMap with MariaDB Primary configuration. | `""` | +| `primary.updateStrategy.type` | MariaDB primary statefulset strategy type | `RollingUpdate` | +| `primary.rollingUpdatePartition` | Partition update strategy for Mariadb Primary statefulset | `""` | +| `primary.podAnnotations` | Additional pod annotations for MariaDB primary pods | `{}` | +| `primary.podLabels` | Extra labels for MariaDB primary pods | `{}` | +| `primary.podAffinityPreset` | MariaDB primary pod affinity preset. Ignored if `primary.affinity` is set. Allowed values: `soft` or `hard` | `""` | +| `primary.podAntiAffinityPreset` | MariaDB primary pod anti-affinity preset. Ignored if `primary.affinity` is set. Allowed values: `soft` or `hard` | `soft` | +| `primary.nodeAffinityPreset.type` | MariaDB primary node affinity preset type. Ignored if `primary.affinity` is set. Allowed values: `soft` or `hard` | `""` | +| `primary.nodeAffinityPreset.key` | MariaDB primary node label key to match Ignored if `primary.affinity` is set. | `""` | +| `primary.nodeAffinityPreset.values` | MariaDB primary node label values to match. Ignored if `primary.affinity` is set. | `[]` | +| `primary.affinity` | Affinity for MariaDB primary pods assignment | `{}` | +| `primary.nodeSelector` | Node labels for MariaDB primary pods assignment | `{}` | +| `primary.tolerations` | Tolerations for MariaDB primary pods assignment | `[]` | +| `primary.schedulerName` | Name of the k8s scheduler (other than default) | `""` | +| `primary.podManagementPolicy` | podManagementPolicy to manage scaling operation of MariaDB primary pods | `""` | +| `primary.topologySpreadConstraints` | Topology Spread Constraints for MariaDB primary pods assignment | `[]` | +| `primary.priorityClassName` | Priority class for MariaDB primary pods assignment | `""` | +| `primary.runtimeClassName` | Runtime Class for MariaDB primary pods | `""` | +| `primary.podSecurityContext.enabled` | Enable security context for MariaDB primary pods | `true` | +| `primary.podSecurityContext.fsGroup` | Group ID for the mounted volumes' filesystem | `1001` | +| `primary.containerSecurityContext.enabled` | MariaDB primary container securityContext | `true` | +| `primary.containerSecurityContext.runAsUser` | User ID for the MariaDB primary container | `1001` | +| `primary.containerSecurityContext.runAsNonRoot` | Set Controller container's Security Context runAsNonRoot | `true` | +| `primary.resources.limits` | The resources limits for MariaDB primary containers | `{}` | +| `primary.resources.requests` | The requested resources for MariaDB primary containers | `{}` | +| `primary.startupProbe.enabled` | Enable startupProbe | `false` | +| `primary.startupProbe.initialDelaySeconds` | Initial delay seconds for startupProbe | `120` | +| `primary.startupProbe.periodSeconds` | Period seconds for startupProbe | `15` | +| `primary.startupProbe.timeoutSeconds` | Timeout seconds for startupProbe | `5` | +| `primary.startupProbe.failureThreshold` | Failure threshold for startupProbe | `10` | +| `primary.startupProbe.successThreshold` | Success threshold for startupProbe | `1` | +| `primary.livenessProbe.enabled` | Enable livenessProbe | `true` | +| `primary.livenessProbe.initialDelaySeconds` | Initial delay seconds for livenessProbe | `120` | +| `primary.livenessProbe.periodSeconds` | Period seconds for livenessProbe | `10` | +| `primary.livenessProbe.timeoutSeconds` | Timeout seconds for livenessProbe | `1` | +| `primary.livenessProbe.failureThreshold` | Failure threshold for livenessProbe | `3` | +| `primary.livenessProbe.successThreshold` | Success threshold for livenessProbe | `1` | +| `primary.readinessProbe.enabled` | Enable readinessProbe | `true` | +| `primary.readinessProbe.initialDelaySeconds` | Initial delay seconds for readinessProbe | `30` | +| `primary.readinessProbe.periodSeconds` | Period seconds for readinessProbe | `10` | +| `primary.readinessProbe.timeoutSeconds` | Timeout seconds for readinessProbe | `1` | +| `primary.readinessProbe.failureThreshold` | Failure threshold for readinessProbe | `3` | +| `primary.readinessProbe.successThreshold` | Success threshold for readinessProbe | `1` | +| `primary.customStartupProbe` | Override default startup probe for MariaDB primary containers | `{}` | +| `primary.customLivenessProbe` | Override default liveness probe for MariaDB primary containers | `{}` | +| `primary.customReadinessProbe` | Override default readiness probe for MariaDB primary containers | `{}` | +| `primary.startupWaitOptions` | Override default builtin startup wait check options for MariaDB primary containers | `{}` | +| `primary.extraFlags` | MariaDB primary additional command line flags | `""` | +| `primary.extraEnvVars` | Extra environment variables to be set on MariaDB primary containers | `[]` | +| `primary.extraEnvVarsCM` | Name of existing ConfigMap containing extra env vars for MariaDB primary containers | `""` | +| `primary.extraEnvVarsSecret` | Name of existing Secret containing extra env vars for MariaDB primary containers | `""` | +| `primary.persistence.enabled` | Enable persistence on MariaDB primary replicas using a `PersistentVolumeClaim`. If false, use emptyDir | `true` | +| `primary.persistence.existingClaim` | Name of an existing `PersistentVolumeClaim` for MariaDB primary replicas | `""` | +| `primary.persistence.subPath` | Subdirectory of the volume to mount at | `""` | +| `primary.persistence.storageClass` | MariaDB primary persistent volume storage Class | `""` | +| `primary.persistence.annotations` | MariaDB primary persistent volume claim annotations | `{}` | +| `primary.persistence.accessModes` | MariaDB primary persistent volume access Modes | `["ReadWriteOnce"]` | +| `primary.persistence.size` | MariaDB primary persistent volume size | `8Gi` | +| `primary.persistence.selector` | Selector to match an existing Persistent Volume | `{}` | +| `primary.extraVolumes` | Optionally specify extra list of additional volumes to the MariaDB Primary pod(s) | `[]` | +| `primary.extraVolumeMounts` | Optionally specify extra list of additional volumeMounts for the MariaDB Primary container(s) | `[]` | +| `primary.initContainers` | Add additional init containers for the MariaDB Primary pod(s) | `[]` | +| `primary.sidecars` | Add additional sidecar containers for the MariaDB Primary pod(s) | `[]` | +| `primary.service.type` | MariaDB Primary Kubernetes service type | `ClusterIP` | +| `primary.service.ports.mysql` | MariaDB Primary Kubernetes service port for MariaDB | `3306` | +| `primary.service.ports.metrics` | MariaDB Primary Kubernetes service port for metrics | `9104` | +| `primary.service.nodePorts.mysql` | MariaDB Primary Kubernetes service node port | `""` | +| `primary.service.clusterIP` | MariaDB Primary Kubernetes service clusterIP IP | `""` | +| `primary.service.loadBalancerIP` | MariaDB Primary loadBalancerIP if service type is `LoadBalancer` | `""` | +| `primary.service.externalTrafficPolicy` | Enable client source IP preservation | `Cluster` | +| `primary.service.loadBalancerSourceRanges` | Address that are allowed when MariaDB Primary service is LoadBalancer | `[]` | +| `primary.service.extraPorts` | Extra ports to expose (normally used with the `sidecar` value) | `[]` | +| `primary.service.annotations` | Provide any additional annotations which may be required | `{}` | +| `primary.service.sessionAffinity` | Session Affinity for Kubernetes service, can be "None" or "ClientIP" | `None` | +| `primary.service.sessionAffinityConfig` | Additional settings for the sessionAffinity | `{}` | +| `primary.pdb.create` | Enable/disable a Pod Disruption Budget creation for MariaDB primary pods | `false` | +| `primary.pdb.minAvailable` | Minimum number/percentage of MariaDB primary pods that must still be available after the eviction | `1` | +| `primary.pdb.maxUnavailable` | Maximum number/percentage of MariaDB primary pods that can be unavailable after the eviction | `""` | +| `primary.revisionHistoryLimit` | Maximum number of revisions that will be maintained in the StatefulSet | `10` | + + +### MariaDB Secondary parameters + +| Name | Description | Value | +| ------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------- | ------------------- | +| `secondary.name` | Name of the secondary database (eg secondary, slave, ...) | `secondary` | +| `secondary.replicaCount` | Number of MariaDB secondary replicas | `1` | +| `secondary.command` | Override default container command on MariaDB Secondary container(s) (useful when using custom images) | `[]` | +| `secondary.args` | Override default container args on MariaDB Secondary container(s) (useful when using custom images) | `[]` | +| `secondary.lifecycleHooks` | for the MariaDB Secondary container(s) to automate configuration before or after startup | `{}` | +| `secondary.hostAliases` | Add deployment host aliases | `[]` | +| `secondary.configuration` | MariaDB Secondary configuration to be injected as ConfigMap | `""` | +| `secondary.existingConfigmap` | Name of existing ConfigMap with MariaDB Secondary configuration. | `""` | +| `secondary.updateStrategy.type` | MariaDB secondary statefulset strategy type | `RollingUpdate` | +| `secondary.rollingUpdatePartition` | Partition update strategy for Mariadb Secondary statefulset | `""` | +| `secondary.podAnnotations` | Additional pod annotations for MariaDB secondary pods | `{}` | +| `secondary.podLabels` | Extra labels for MariaDB secondary pods | `{}` | +| `secondary.podAffinityPreset` | MariaDB secondary pod affinity preset. Ignored if `secondary.affinity` is set. Allowed values: `soft` or `hard` | `""` | +| `secondary.podAntiAffinityPreset` | MariaDB secondary pod anti-affinity preset. Ignored if `secondary.affinity` is set. Allowed values: `soft` or `hard` | `soft` | +| `secondary.nodeAffinityPreset.type` | MariaDB secondary node affinity preset type. Ignored if `secondary.affinity` is set. Allowed values: `soft` or `hard` | `""` | +| `secondary.nodeAffinityPreset.key` | MariaDB secondary node label key to match Ignored if `secondary.affinity` is set. | `""` | +| `secondary.nodeAffinityPreset.values` | MariaDB secondary node label values to match. Ignored if `secondary.affinity` is set. | `[]` | +| `secondary.affinity` | Affinity for MariaDB secondary pods assignment | `{}` | +| `secondary.nodeSelector` | Node labels for MariaDB secondary pods assignment | `{}` | +| `secondary.tolerations` | Tolerations for MariaDB secondary pods assignment | `[]` | +| `secondary.topologySpreadConstraints` | Topology Spread Constraints for MariaDB secondary pods assignment | `[]` | +| `secondary.priorityClassName` | Priority class for MariaDB secondary pods assignment | `""` | +| `secondary.runtimeClassName` | Runtime Class for MariaDB secondary pods | `""` | +| `secondary.schedulerName` | Name of the k8s scheduler (other than default) | `""` | +| `secondary.podManagementPolicy` | podManagementPolicy to manage scaling operation of MariaDB secondary pods | `""` | +| `secondary.podSecurityContext.enabled` | Enable security context for MariaDB secondary pods | `true` | +| `secondary.podSecurityContext.fsGroup` | Group ID for the mounted volumes' filesystem | `1001` | +| `secondary.containerSecurityContext.enabled` | MariaDB secondary container securityContext | `true` | +| `secondary.containerSecurityContext.runAsUser` | User ID for the MariaDB secondary container | `1001` | +| `secondary.containerSecurityContext.runAsNonRoot` | Set Controller container's Security Context runAsNonRoot | `true` | +| `secondary.resources.limits` | The resources limits for MariaDB secondary containers | `{}` | +| `secondary.resources.requests` | The requested resources for MariaDB secondary containers | `{}` | +| `secondary.startupProbe.enabled` | Enable startupProbe | `false` | +| `secondary.startupProbe.initialDelaySeconds` | Initial delay seconds for startupProbe | `120` | +| `secondary.startupProbe.periodSeconds` | Period seconds for startupProbe | `15` | +| `secondary.startupProbe.timeoutSeconds` | Timeout seconds for startupProbe | `5` | +| `secondary.startupProbe.failureThreshold` | Failure threshold for startupProbe | `10` | +| `secondary.startupProbe.successThreshold` | Success threshold for startupProbe | `1` | +| `secondary.livenessProbe.enabled` | Enable livenessProbe | `true` | +| `secondary.livenessProbe.initialDelaySeconds` | Initial delay seconds for livenessProbe | `120` | +| `secondary.livenessProbe.periodSeconds` | Period seconds for livenessProbe | `10` | +| `secondary.livenessProbe.timeoutSeconds` | Timeout seconds for livenessProbe | `1` | +| `secondary.livenessProbe.failureThreshold` | Failure threshold for livenessProbe | `3` | +| `secondary.livenessProbe.successThreshold` | Success threshold for livenessProbe | `1` | +| `secondary.readinessProbe.enabled` | Enable readinessProbe | `true` | +| `secondary.readinessProbe.initialDelaySeconds` | Initial delay seconds for readinessProbe | `30` | +| `secondary.readinessProbe.periodSeconds` | Period seconds for readinessProbe | `10` | +| `secondary.readinessProbe.timeoutSeconds` | Timeout seconds for readinessProbe | `1` | +| `secondary.readinessProbe.failureThreshold` | Failure threshold for readinessProbe | `3` | +| `secondary.readinessProbe.successThreshold` | Success threshold for readinessProbe | `1` | +| `secondary.customStartupProbe` | Override default startup probe for MariaDB secondary containers | `{}` | +| `secondary.customLivenessProbe` | Override default liveness probe for MariaDB secondary containers | `{}` | +| `secondary.customReadinessProbe` | Override default readiness probe for MariaDB secondary containers | `{}` | +| `secondary.startupWaitOptions` | Override default builtin startup wait check options for MariaDB secondary containers | `{}` | +| `secondary.extraFlags` | MariaDB secondary additional command line flags | `""` | +| `secondary.extraEnvVars` | Extra environment variables to be set on MariaDB secondary containers | `[]` | +| `secondary.extraEnvVarsCM` | Name of existing ConfigMap containing extra env vars for MariaDB secondary containers | `""` | +| `secondary.extraEnvVarsSecret` | Name of existing Secret containing extra env vars for MariaDB secondary containers | `""` | +| `secondary.persistence.enabled` | Enable persistence on MariaDB secondary replicas using a `PersistentVolumeClaim` | `true` | +| `secondary.persistence.subPath` | Subdirectory of the volume to mount at | `""` | +| `secondary.persistence.storageClass` | MariaDB secondary persistent volume storage Class | `""` | +| `secondary.persistence.annotations` | MariaDB secondary persistent volume claim annotations | `{}` | +| `secondary.persistence.accessModes` | MariaDB secondary persistent volume access Modes | `["ReadWriteOnce"]` | +| `secondary.persistence.size` | MariaDB secondary persistent volume size | `8Gi` | +| `secondary.persistence.selector` | Selector to match an existing Persistent Volume | `{}` | +| `secondary.extraVolumes` | Optionally specify extra list of additional volumes to the MariaDB secondary pod(s) | `[]` | +| `secondary.extraVolumeMounts` | Optionally specify extra list of additional volumeMounts for the MariaDB secondary container(s) | `[]` | +| `secondary.initContainers` | Add additional init containers for the MariaDB secondary pod(s) | `[]` | +| `secondary.sidecars` | Add additional sidecar containers for the MariaDB secondary pod(s) | `[]` | +| `secondary.service.type` | MariaDB secondary Kubernetes service type | `ClusterIP` | +| `secondary.service.ports.mysql` | MariaDB secondary Kubernetes service port for MariaDB | `3306` | +| `secondary.service.ports.metrics` | MariaDB secondary Kubernetes service port for metrics | `9104` | +| `secondary.service.nodePorts.mysql` | MariaDB secondary Kubernetes service node port | `""` | +| `secondary.service.clusterIP` | MariaDB secondary Kubernetes service clusterIP IP | `""` | +| `secondary.service.loadBalancerIP` | MariaDB secondary loadBalancerIP if service type is `LoadBalancer` | `""` | +| `secondary.service.externalTrafficPolicy` | Enable client source IP preservation | `Cluster` | +| `secondary.service.loadBalancerSourceRanges` | Address that are allowed when MariaDB secondary service is LoadBalancer | `[]` | +| `secondary.service.extraPorts` | Extra ports to expose (normally used with the `sidecar` value) | `[]` | +| `secondary.service.annotations` | Provide any additional annotations which may be required | `{}` | +| `secondary.service.sessionAffinity` | Session Affinity for Kubernetes service, can be "None" or "ClientIP" | `None` | +| `secondary.service.sessionAffinityConfig` | Additional settings for the sessionAffinity | `{}` | +| `secondary.pdb.create` | Enable/disable a Pod Disruption Budget creation for MariaDB secondary pods | `false` | +| `secondary.pdb.minAvailable` | Minimum number/percentage of MariaDB secondary pods that should remain scheduled | `1` | +| `secondary.pdb.maxUnavailable` | Maximum number/percentage of MariaDB secondary pods that may be made unavailable | `""` | +| `secondary.revisionHistoryLimit` | Maximum number of revisions that will be maintained in the StatefulSet | `10` | + + +### RBAC parameters + +| Name | Description | Value | +| --------------------------------------------- | -------------------------------------------------------------- | ------- | +| `serviceAccount.create` | Enable the creation of a ServiceAccount for MariaDB pods | `true` | +| `serviceAccount.name` | Name of the created ServiceAccount | `""` | +| `serviceAccount.annotations` | Annotations for MariaDB Service Account | `{}` | +| `serviceAccount.automountServiceAccountToken` | Automount service account token for the server service account | `false` | +| `rbac.create` | Whether to create and use RBAC resources or not | `false` | + + +### Volume Permissions parameters + +| Name | Description | Value | +| -------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------- | ----------------------- | +| `volumePermissions.enabled` | Enable init container that changes the owner and group of the persistent volume(s) mountpoint to `runAsUser:fsGroup` | `false` | +| `volumePermissions.image.registry` | Init container volume-permissions image registry | `docker.io` | +| `volumePermissions.image.repository` | Init container volume-permissions image repository | `bitnami/bitnami-shell` | +| `volumePermissions.image.tag` | Init container volume-permissions image tag (immutable tags are recommended) | `11-debian-11-r61` | +| `volumePermissions.image.digest` | Init container volume-permissions image digest in the way sha256:aa.... Please note this parameter, if set, will override the tag | `""` | +| `volumePermissions.image.pullPolicy` | Init container volume-permissions image pull policy | `IfNotPresent` | +| `volumePermissions.image.pullSecrets` | Specify docker-registry secret names as an array | `[]` | +| `volumePermissions.resources.limits` | Init container volume-permissions resource limits | `{}` | +| `volumePermissions.resources.requests` | Init container volume-permissions resource requests | `{}` | + + +### Metrics parameters + +| Name | Description | Value | +| -------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------- | ------------------------- | +| `metrics.enabled` | Start a side-car prometheus exporter | `false` | +| `metrics.image.registry` | Exporter image registry | `docker.io` | +| `metrics.image.repository` | Exporter image repository | `bitnami/mysqld-exporter` | +| `metrics.image.tag` | Exporter image tag (immutable tags are recommended) | `0.14.0-debian-11-r67` | +| `metrics.image.digest` | Exporter image digest in the way sha256:aa.... Please note this parameter, if set, will override the tag | `""` | +| `metrics.image.pullPolicy` | Exporter image pull policy | `IfNotPresent` | +| `metrics.image.pullSecrets` | Specify docker-registry secret names as an array | `[]` | +| `metrics.annotations` | Annotations for the Exporter pod | `{}` | +| `metrics.extraArgs` | Extra args to be passed to mysqld_exporter | `{}` | +| `metrics.extraVolumeMounts` | Optionally specify extra list of additional volumeMounts for the MariaDB metrics container(s) | `{}` | +| `metrics.containerSecurityContext.enabled` | Enable security context for MariaDB metrics container | `false` | +| `metrics.resources.limits` | The resources limits for MariaDB prometheus exporter containers | `{}` | +| `metrics.resources.requests` | The requested resources for MariaDB prometheus exporter containers | `{}` | +| `metrics.livenessProbe.enabled` | Enable livenessProbe | `true` | +| `metrics.livenessProbe.initialDelaySeconds` | Initial delay seconds for livenessProbe | `120` | +| `metrics.livenessProbe.periodSeconds` | Period seconds for livenessProbe | `10` | +| `metrics.livenessProbe.timeoutSeconds` | Timeout seconds for livenessProbe | `1` | +| `metrics.livenessProbe.failureThreshold` | Failure threshold for livenessProbe | `3` | +| `metrics.livenessProbe.successThreshold` | Success threshold for livenessProbe | `1` | +| `metrics.readinessProbe.enabled` | Enable readinessProbe | `true` | +| `metrics.readinessProbe.initialDelaySeconds` | Initial delay seconds for readinessProbe | `30` | +| `metrics.readinessProbe.periodSeconds` | Period seconds for readinessProbe | `10` | +| `metrics.readinessProbe.timeoutSeconds` | Timeout seconds for readinessProbe | `1` | +| `metrics.readinessProbe.failureThreshold` | Failure threshold for readinessProbe | `3` | +| `metrics.readinessProbe.successThreshold` | Success threshold for readinessProbe | `1` | +| `metrics.serviceMonitor.enabled` | Create ServiceMonitor Resource for scraping metrics using PrometheusOperator | `false` | +| `metrics.serviceMonitor.namespace` | Namespace which Prometheus is running in | `""` | +| `metrics.serviceMonitor.jobLabel` | The name of the label on the target service to use as the job name in prometheus. | `""` | +| `metrics.serviceMonitor.interval` | Interval at which metrics should be scraped | `30s` | +| `metrics.serviceMonitor.scrapeTimeout` | Specify the timeout after which the scrape is ended | `""` | +| `metrics.serviceMonitor.relabelings` | RelabelConfigs to apply to samples before scraping | `[]` | +| `metrics.serviceMonitor.metricRelabelings` | MetricRelabelConfigs to apply to samples before ingestion | `[]` | +| `metrics.serviceMonitor.honorLabels` | honorLabels chooses the metric's labels on collisions with target labels | `false` | +| `metrics.serviceMonitor.selector` | ServiceMonitor selector labels | `{}` | +| `metrics.serviceMonitor.labels` | Extra labels for the ServiceMonitor | `{}` | +| `metrics.prometheusRule.enabled` | if `true`, creates a Prometheus Operator PrometheusRule (also requires `metrics.enabled` to be `true` and `metrics.prometheusRule.rules`) | `false` | +| `metrics.prometheusRule.namespace` | Namespace for the PrometheusRule Resource (defaults to the Release Namespace) | `""` | +| `metrics.prometheusRule.additionalLabels` | Additional labels that can be used so PrometheusRule will be discovered by Prometheus | `{}` | +| `metrics.prometheusRule.rules` | Prometheus Rule definitions | `[]` | + + +### NetworkPolicy parameters + +| Name | Description | Value | +| ---------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------- | ------- | +| `networkPolicy.enabled` | Enable network policies | `false` | +| `networkPolicy.metrics.enabled` | Enable network policy for metrics (prometheus) | `false` | +| `networkPolicy.metrics.namespaceSelector` | Monitoring namespace selector labels. These labels will be used to identify the prometheus' namespace. | `{}` | +| `networkPolicy.metrics.podSelector` | Monitoring pod selector labels. These labels will be used to identify the Prometheus pods. | `{}` | +| `networkPolicy.ingressRules.primaryAccessOnlyFrom.enabled` | Enable ingress rule that makes primary mariadb nodes only accessible from a particular origin. | `false` | +| `networkPolicy.ingressRules.primaryAccessOnlyFrom.namespaceSelector` | Namespace selector label that is allowed to access the primary node. This label will be used to identified the allowed namespace(s). | `{}` | +| `networkPolicy.ingressRules.primaryAccessOnlyFrom.podSelector` | Pods selector label that is allowed to access the primary node. This label will be used to identified the allowed pod(s). | `{}` | +| `networkPolicy.ingressRules.primaryAccessOnlyFrom.customRules` | Custom network policy for the primary node. | `{}` | +| `networkPolicy.ingressRules.secondaryAccessOnlyFrom.enabled` | Enable ingress rule that makes primary mariadb nodes only accessible from a particular origin. | `false` | +| `networkPolicy.ingressRules.secondaryAccessOnlyFrom.namespaceSelector` | Namespace selector label that is allowed to acces the secondary nodes. This label will be used to identified the allowed namespace(s). | `{}` | +| `networkPolicy.ingressRules.secondaryAccessOnlyFrom.podSelector` | Pods selector label that is allowed to access the secondary nodes. This label will be used to identified the allowed pod(s). | `{}` | +| `networkPolicy.ingressRules.secondaryAccessOnlyFrom.customRules` | Custom network policy for the secondary nodes. | `{}` | +| `networkPolicy.egressRules.denyConnectionsToExternal` | Enable egress rule that denies outgoing traffic outside the cluster, except for DNS (port 53). | `false` | +| `networkPolicy.egressRules.customRules` | Custom network policy rule | `{}` | + + +The above parameters map to the env variables defined in [bitnami/mariadb](https://github.com/bitnami/containers/tree/main/bitnami/mariadb). For more information please refer to the [bitnami/mariadb](https://github.com/bitnami/containers/tree/main/bitnami/mariadb) image documentation. + +Specify each parameter using the `--set key=value[,key=value]` argument to `helm install`. For example, + +```bash +$ helm install my-release \ + --set auth.rootPassword=secretpassword,auth.database=app_database \ + my-repo/mariadb +``` + +The above command sets the MariaDB `root` account password to `secretpassword`. Additionally it creates a database named `my_database`. + +> NOTE: Once this chart is deployed, it is not possible to change the application's access credentials, such as usernames or passwords, using Helm. To change these application credentials after deployment, delete any persistent volumes (PVs) used by the chart and re-deploy it, or use the application's built-in administrative tools if available. + +Alternatively, a YAML file that specifies the values for the parameters can be provided while installing the chart. For example, + +```bash +$ helm install my-release -f values.yaml my-repo/mariadb +``` + +> **Tip**: You can use the default [values.yaml](values.yaml) + +## Configuration and installation details + +### [Rolling VS Immutable tags](https://docs.bitnami.com/containers/how-to/understand-rolling-tags-containers/) + +It is strongly recommended to use immutable tags in a production environment. This ensures your deployment does not change automatically if the same tag is updated with a different image. + +Bitnami will release a new chart updating its containers if a new version of the main container, significant changes, or critical vulnerabilities exist. + +### Change MariaDB version + +To modify the MariaDB version used in this chart you can specify a [valid image tag](https://hub.docker.com/r/bitnami/mariadb/tags/) using the `image.tag` parameter. For example, `image.tag=X.Y.Z`. This approach is also applicable to other images like exporters. + +### Initialize a fresh instance + +The [Bitnami MariaDB](https://github.com/bitnami/containers/tree/main/bitnami/mariadb) image allows you to use your custom scripts to initialize a fresh instance. Custom scripts may be specified using the `initdbScripts` parameter. Alternatively, an external ConfigMap may be created with all the initialization scripts and the ConfigMap passed to the chart via the `initdbScriptsConfigMap` parameter. Note that this will override the `initdbScripts` parameter. + +The allowed extensions are `.sh`, `.sql` and `.sql.gz`. + +These scripts are treated differently depending on their extension. While `.sh` scripts are executed on all the nodes, `.sql` and `.sql.gz` scripts are only executed on the primary nodes. This is because `.sh` scripts support conditional tests to identify the type of node they are running on, while such tests are not supported in `.sql` or `.sql.gz` files. + +[Refer to the chart documentation for more information and a usage example](https://docs.bitnami.com/kubernetes/infrastructure/mariadb/configuration/customize-new-instance/). + +### Sidecars and Init Containers + +If additional containers are needed in the same pod as MariaDB (such as additional metrics or logging exporters), they can be defined using the sidecars parameter. + +The Helm chart already includes sidecar containers for the Prometheus exporters. These can be activated by adding the `--set enable-metrics=true` parameter at deployment time. The `sidecars` parameter should therefore only be used for any extra sidecar containers. [See an example of configuring and using sidecar containers](https://docs.bitnami.com/kubernetes/infrastructure/mariadb/configuration/configure-sidecar-init-containers/). + +Similarly, additional containers can be added to MariaDB pods using the `initContainers` parameter. [See an example of configuring and using init containers](https://docs.bitnami.com/kubernetes/infrastructure/mariadb/configuration/configure-sidecar-init-containers/). + +## Persistence + +The [Bitnami MariaDB](https://github.com/bitnami/containers/tree/main/bitnami/mariadb) image stores the MariaDB data and configurations at the `/bitnami/mariadb` path of the container. + +The chart mounts a [Persistent Volume](https://kubernetes.io/docs/concepts/storage/persistent-volumes/) volume at this location. The volume is created using dynamic volume provisioning, by default. An existing PersistentVolumeClaim can also be defined. + +If you encounter errors when working with persistent volumes, refer to our [troubleshooting guide for persistent volumes](https://docs.bitnami.com/kubernetes/faq/troubleshooting/troubleshooting-persistence-volumes/). + +### Adjust permissions of persistent volume mountpoint + +As the image run as non-root by default, it is necessary to adjust the ownership of the persistent volume so that the container can write data into it. + +By default, the chart is configured to use Kubernetes Security Context to automatically change the ownership of the volume. However, this feature does not work in all Kubernetes distributions. + +As an alternative, this chart supports using an initContainer to change the ownership of the volume before mounting it in the final destination. You can enable this initContainer by setting `volumePermissions.enabled` to `true`. + +## Troubleshooting + +Find more information about how to deal with common errors related to Bitnami's Helm charts in [this troubleshooting guide](https://docs.bitnami.com/general/how-to/troubleshoot-helm-chart-issues). + +## Upgrading + +It's necessary to set the `auth.rootPassword` parameter when upgrading for readiness/liveness probes to work properly. When you install this chart for the first time, some notes will be displayed providing the credentials you must use under the 'Administrator credentials' section. Please note down the password and run the command below to upgrade your chart: + +```bash +$ helm upgrade my-release my-repo/mariadb --set auth.rootPassword=[ROOT_PASSWORD] +``` + +| Note: you need to substitute the placeholder _[ROOT_PASSWORD]_ with the value obtained in the installation notes. + +### To 11.0.0 + +This major release bumps default MariaDB branch to 10.6. Follow the [official instructions](https://mariadb.com/kb/en/upgrading-from-mariadb-105-to-mariadb-106/) from upgrading between 10.5 and 10.6. + +No major issues are expected during the upgrade. + +### To 10.0.0 + +This major release renames several values in this chart and adds missing features, in order to be inline with the rest of assets in the Bitnami charts repository. + +Affected values: + +- `primary.service.port` was deprecated, we recommend using `primary.service.ports.mysql` instead. +- `primary.service.nodePort` was deprecated, we recommend using `primary.service.nodePorts.mysql` instead. +- `secondary.service.port` was deprecated, we recommend using `secondary.service.ports.mysql` instead. +- `secondary.service.nodePort` was deprecated, we recommend using `secondary.service.nodePorts.mysql` instead. +- `metrics.serviceMonitor.additionalLabels` was deprecated, we recommend using `metrics.serviceMonitor.selector` instead. +- `primary.pdb.enabled` renamed as `primary.pdb.create`. +- `secondary.pdb.enabled` renamed as `secondary.pdb.create`. +- `primary.updateStrategy` changed from String type (previously default to 'rollingUpdate') to Object type, allowing users to configure other updateStrategy parameters, similar to other charts. +- Removed value `primary.rollingUpdatePartition`, now configured using `primary.updateStrategy` setting `primary.updateStrategy.rollingUpdate.partition`. +- `secondary.updateStrategy` changed from String type (previously default to 'rollingUpdate') to Object type, allowing users to configure other updateStrategy parameters, similar to other charts. +- Removed value `secondary.rollingUpdatePartition`, now configured using `secondary.updateStrategy` setting `secondary.updateStrategy.rollingUpdate.partition`. +- `metrics.serviceMonitor.relabellings`, previously used to configure ServiceMonitor metricRelabelings, has been replaced with the value `metrics.serviceMonitor.metricRelabelings`, and new value `metrics.serviceMonitor.relabelings` can be used to set ServiceMonitor relabelings parameter + +### To 9.0.0 + +[On November 13, 2020, Helm v2 support was formally finished](https://github.com/helm/charts#status-of-the-project), this major version is the result of the required changes applied to the Helm Chart to be able to incorporate the different features added in Helm v3 and to be consistent with the Helm project itself regarding the Helm v2 EOL. + +[Learn more about this change and related upgrade considerations](https://docs.bitnami.com/kubernetes/infrastructure/mariadb/administration/upgrade-helm3/). + +### To 8.0.0 + +- Several parameters were renamed or disappeared in favor of new ones on this major version: + - The terms _master_ and _slave_ have been replaced by the terms _primary_ and _secondary_. Therefore, parameters prefixed with `master` or `slave` are now prefixed with `primary` or `secondary`, respectively. + - `securityContext.*` is deprecated in favor of `primary.podSecurityContext`, `primary.containerSecurityContext`, `secondary.podSecurityContext`, and `secondary.containerSecurityContext`. + - Credentials parameter are reorganized under the `auth` parameter. + - `replication.enabled` parameter is deprecated in favor of `architecture` parameter that accepts two values: `standalone` and `replication`. +- The default MariaDB version was updated from 10.3 to 10.5. According to the official documentation, upgrading from 10.3 should be painless. However, there are some things that have changed which could affect an upgrade: + - [Incompatible changes upgrading from MariaDB 10.3 to MariaDB 10.4](https://mariadb.com/kb/en/upgrading-from-mariadb-103-to-mariadb-104/#incompatible-changes-between-103-and-104). + - [Incompatible changes upgrading from MariaDB 10.4 to MariaDB 10.5](https://mariadb.com/kb/en/upgrading-from-mariadb-104-to-mariadb-105/#incompatible-changes-between-104-and-105). +- Chart labels were adapted to follow the [Helm charts standard labels](https://helm.sh/docs/chart_best_practices/labels/#standard-labels). +- This version also introduces `bitnami/common`, a [library chart](https://helm.sh/docs/topics/library_charts/#helm) as a dependency. More documentation about this new utility could be found [here](https://github.com/bitnami/charts/tree/main/bitnami/common#bitnami-common-library-chart). Please, make sure that you have updated the chart dependencies before executing any upgrade. + +Consequences: + +Backwards compatibility is not guaranteed. To upgrade to `8.0.0`, install a new release of the MariaDB chart, and migrate the data from your previous release. You have 2 alternatives to do so: + +- Create a backup of the database, and restore it on the new release using tools such as [mysqldump](https://mariadb.com/kb/en/mysqldump/). +- Reuse the PVC used to hold the master data on your previous release. To do so, use the `primary.persistence.existingClaim` parameter. The following example assumes that the release name is `mariadb`: + +```bash +$ helm install mariadb my-repo/mariadb --set auth.rootPassword=[ROOT_PASSWORD] --set primary.persistence.existingClaim=[EXISTING_PVC] +``` + +| Note: you need to substitute the placeholder _[EXISTING_PVC]_ with the name of the PVC used on your previous release, and _[ROOT_PASSWORD]_ with the root password used in your previous release. + +### To 7.0.0 + +Helm performs a lookup for the object based on its group (apps), version (v1), and kind (Deployment). Also known as its GroupVersionKind, or GVK. Changing the GVK is considered a compatibility breaker from Kubernetes' point of view, so you cannot "upgrade" those objects to the new GVK in-place. Earlier versions of Helm 3 did not perform the lookup correctly which has since been fixed to match the spec. + +In https://github.com/helm/charts/pull/17308 the `apiVersion` of the statefulset resources was updated to `apps/v1` in tune with the api's deprecated, resulting in compatibility breakage. + +This major version bump signifies this change. + +### To 6.0.0 + +MariaDB version was updated from 10.1 to 10.3, there are no changes in the chart itself. According to the official documentation, upgrading from 10.1 should be painless. However, there are some things that have changed which could affect an upgrade: + +- [Incompatible changes upgrading from MariaDB 10.1 to MariaDB 10.2](https://mariadb.com/kb/en/library/upgrading-from-mariadb-101-to-mariadb-102//#incompatible-changes-between-101-and-102) +- [Incompatible changes upgrading from MariaDB 10.2 to MariaDB 10.3](https://mariadb.com/kb/en/library/upgrading-from-mariadb-102-to-mariadb-103/#incompatible-changes-between-102-and-103) + +### To 5.0.0 + +Backwards compatibility is not guaranteed unless you modify the labels used on the chart's deployments. +Use the workaround below to upgrade from versions previous to 5.0.0. The following example assumes that the release name is mariadb: + +```console +$ kubectl delete statefulset opencart-mariadb --cascade=false +``` + +## License + +Copyright © 2022 Bitnami + +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. \ No newline at end of file diff --git a/charts/limesurvey-martial-ingress-v9/charts/mariadb/charts/common/.helmignore b/charts/limesurvey-martial-ingress-v9/charts/mariadb/charts/common/.helmignore new file mode 100644 index 0000000..50af031 --- /dev/null +++ b/charts/limesurvey-martial-ingress-v9/charts/mariadb/charts/common/.helmignore @@ -0,0 +1,22 @@ +# 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 +*~ +# Various IDEs +.project +.idea/ +*.tmproj +.vscode/ diff --git a/charts/limesurvey-martial-ingress-v9/charts/mariadb/charts/common/Chart.yaml b/charts/limesurvey-martial-ingress-v9/charts/mariadb/charts/common/Chart.yaml new file mode 100644 index 0000000..f9ba944 --- /dev/null +++ b/charts/limesurvey-martial-ingress-v9/charts/mariadb/charts/common/Chart.yaml @@ -0,0 +1,23 @@ +annotations: + category: Infrastructure +apiVersion: v2 +appVersion: 2.2.2 +description: A Library Helm Chart for grouping common logic between bitnami charts. + This chart is not deployable by itself. +home: https://github.com/bitnami/charts/tree/main/bitnami/common +icon: https://bitnami.com/downloads/logos/bitnami-mark.png +keywords: +- common +- helper +- template +- function +- bitnami +maintainers: +- name: Bitnami + url: https://github.com/bitnami/charts +name: common +sources: +- https://github.com/bitnami/charts +- https://www.bitnami.com/ +type: library +version: 2.2.2 diff --git a/charts/limesurvey-martial-ingress-v9/charts/mariadb/charts/common/README.md b/charts/limesurvey-martial-ingress-v9/charts/mariadb/charts/common/README.md new file mode 100644 index 0000000..ec43a5f --- /dev/null +++ b/charts/limesurvey-martial-ingress-v9/charts/mariadb/charts/common/README.md @@ -0,0 +1,351 @@ +# Bitnami Common Library Chart + +A [Helm Library Chart](https://helm.sh/docs/topics/library_charts/#helm) for grouping common logic between bitnami charts. + +## TL;DR + +```yaml +dependencies: + - name: common + version: 1.x.x + repository: https://charts.bitnami.com/bitnami +``` + +```bash +$ helm dependency update +``` + +```yaml +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ include "common.names.fullname" . }} +data: + myvalue: "Hello World" +``` + +## Introduction + +This chart provides a common template helpers which can be used to develop new charts using [Helm](https://helm.sh) package manager. + +Bitnami charts can be used with [Kubeapps](https://kubeapps.dev/) for deployment and management of Helm Charts in clusters. + +## Prerequisites + +- Kubernetes 1.19+ +- Helm 3.2.0+ + +## Parameters + +The following table lists the helpers available in the library which are scoped in different sections. + +### Affinities + +| Helper identifier | Description | Expected Input | +|-------------------------------|------------------------------------------------------|------------------------------------------------| +| `common.affinities.nodes.soft` | Return a soft nodeAffinity definition | `dict "key" "FOO" "values" (list "BAR" "BAZ")` | +| `common.affinities.nodes.hard` | Return a hard nodeAffinity definition | `dict "key" "FOO" "values" (list "BAR" "BAZ")` | +| `common.affinities.pods.soft` | Return a soft podAffinity/podAntiAffinity definition | `dict "component" "FOO" "context" $` | +| `common.affinities.pods.hard` | Return a hard podAffinity/podAntiAffinity definition | `dict "component" "FOO" "context" $` | +| `common.affinities.topologyKey` | Return a topologyKey definition | `dict "topologyKey" "FOO"` | + +### Capabilities + +| Helper identifier | Description | Expected Input | +|------------------------------------------------|------------------------------------------------------------------------------------------------|-------------------| +| `common.capabilities.kubeVersion` | Return the target Kubernetes version (using client default if .Values.kubeVersion is not set). | `.` Chart context | +| `common.capabilities.cronjob.apiVersion` | Return the appropriate apiVersion for cronjob. | `.` Chart context | +| `common.capabilities.deployment.apiVersion` | Return the appropriate apiVersion for deployment. | `.` Chart context | +| `common.capabilities.statefulset.apiVersion` | Return the appropriate apiVersion for statefulset. | `.` Chart context | +| `common.capabilities.ingress.apiVersion` | Return the appropriate apiVersion for ingress. | `.` Chart context | +| `common.capabilities.rbac.apiVersion` | Return the appropriate apiVersion for RBAC resources. | `.` Chart context | +| `common.capabilities.crd.apiVersion` | Return the appropriate apiVersion for CRDs. | `.` Chart context | +| `common.capabilities.policy.apiVersion` | Return the appropriate apiVersion for podsecuritypolicy. | `.` Chart context | +| `common.capabilities.networkPolicy.apiVersion` | Return the appropriate apiVersion for networkpolicy. | `.` Chart context | +| `common.capabilities.apiService.apiVersion` | Return the appropriate apiVersion for APIService. | `.` Chart context | +| `common.capabilities.hpa.apiVersion` | Return the appropriate apiVersion for Horizontal Pod Autoscaler | `.` Chart context | +| `common.capabilities.supportsHelmVersion` | Returns true if the used Helm version is 3.3+ | `.` Chart context | + +### Errors + +| Helper identifier | Description | Expected Input | +|-----------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------| +| `common.errors.upgrade.passwords.empty` | It will ensure required passwords are given when we are upgrading a chart. If `validationErrors` is not empty it will throw an error and will stop the upgrade action. | `dict "validationErrors" (list $validationError00 $validationError01) "context" $` | + +### Images + +| Helper identifier | Description | Expected Input | +|-----------------------------|------------------------------------------------------|---------------------------------------------------------------------------------------------------------| +| `common.images.image` | Return the proper and full image name | `dict "imageRoot" .Values.path.to.the.image "global" $`, see [ImageRoot](#imageroot) for the structure. | +| `common.images.pullSecrets` | Return the proper Docker Image Registry Secret Names (deprecated: use common.images.renderPullSecrets instead) | `dict "images" (list .Values.path.to.the.image1, .Values.path.to.the.image2) "global" .Values.global` | +| `common.images.renderPullSecrets` | Return the proper Docker Image Registry Secret Names (evaluates values as templates) | `dict "images" (list .Values.path.to.the.image1, .Values.path.to.the.image2) "context" $` | + +### Ingress + +| Helper identifier | Description | Expected Input | +|-------------------------------------------|-------------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `common.ingress.backend` | Generate a proper Ingress backend entry depending on the API version | `dict "serviceName" "foo" "servicePort" "bar"`, see the [Ingress deprecation notice](https://kubernetes.io/blog/2019/07/18/api-deprecations-in-1-16/) for the syntax differences | +| `common.ingress.supportsPathType` | Prints "true" if the pathType field is supported | `.` Chart context | +| `common.ingress.supportsIngressClassname` | Prints "true" if the ingressClassname field is supported | `.` Chart context | +| `common.ingress.certManagerRequest` | Prints "true" if required cert-manager annotations for TLS signed certificates are set in the Ingress annotations | `dict "annotations" .Values.path.to.the.ingress.annotations` | + +### Labels + +| Helper identifier | Description | Expected Input | +|-----------------------------|-----------------------------------------------------------------------------|-------------------| +| `common.labels.standard` | Return Kubernetes standard labels | `.` Chart context | +| `common.labels.matchLabels` | Labels to use on `deploy.spec.selector.matchLabels` and `svc.spec.selector` | `.` Chart context | + +### Names + +| Helper identifier | Description | Expected Input | +|-----------------------------------|-----------------------------------------------------------------------|-------------------| +| `common.names.name` | Expand the name of the chart or use `.Values.nameOverride` | `.` Chart context | +| `common.names.fullname` | Create a default fully qualified app name. | `.` Chart context | +| `common.names.namespace` | Allow the release namespace to be overridden | `.` Chart context | +| `common.names.fullname.namespace` | Create a fully qualified app name adding the installation's namespace | `.` Chart context | +| `common.names.chart` | Chart name plus version | `.` Chart context | + +### Secrets + +| Helper identifier | Description | Expected Input | +|-----------------------------------|--------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `common.secrets.name` | Generate the name of the secret. | `dict "existingSecret" .Values.path.to.the.existingSecret "defaultNameSuffix" "mySuffix" "context" $` see [ExistingSecret](#existingsecret) for the structure. | +| `common.secrets.key` | Generate secret key. | `dict "existingSecret" .Values.path.to.the.existingSecret "key" "keyName"` see [ExistingSecret](#existingsecret) for the structure. | +| `common.secrets.passwords.manage` | Generate secret password or retrieve one if already created. | `dict "secret" "secret-name" "key" "keyName" "providedValues" (list "path.to.password1" "path.to.password2") "length" 10 "strong" false "chartName" "chartName" "context" $`, length, strong and chartNAme fields are optional. | +| `common.secrets.exists` | Returns whether a previous generated secret already exists. | `dict "secret" "secret-name" "context" $` | + +### Storage + +| Helper identifier | Description | Expected Input | +|-------------------------------|---------------------------------------|---------------------------------------------------------------------------------------------------------------------| +| `common.storage.class` | Return the proper Storage Class | `dict "persistence" .Values.path.to.the.persistence "global" $`, see [Persistence](#persistence) for the structure. | + +### TplValues + +| Helper identifier | Description | Expected Input | +|---------------------------|----------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------| +| `common.tplvalues.render` | Renders a value that contains template | `dict "value" .Values.path.to.the.Value "context" $`, value is the value should rendered as template, context frequently is the chart context `$` or `.` | + +### Utils + +| Helper identifier | Description | Expected Input | +|--------------------------------|------------------------------------------------------------------------------------------|------------------------------------------------------------------------| +| `common.utils.fieldToEnvVar` | Build environment variable name given a field. | `dict "field" "my-password"` | +| `common.utils.secret.getvalue` | Print instructions to get a secret value. | `dict "secret" "secret-name" "field" "secret-value-field" "context" $` | +| `common.utils.getValueFromKey` | Gets a value from `.Values` object given its key path | `dict "key" "path.to.key" "context" $` | +| `common.utils.getKeyFromList` | Returns first `.Values` key with a defined value or first of the list if all non-defined | `dict "keys" (list "path.to.key1" "path.to.key2") "context" $` | + +### Validations + +| Helper identifier | Description | Expected Input | +|--------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `common.validations.values.single.empty` | Validate a value must not be empty. | `dict "valueKey" "path.to.value" "secret" "secret.name" "field" "my-password" "subchart" "subchart" "context" $` secret, field and subchart are optional. In case they are given, the helper will generate a how to get instruction. See [ValidateValue](#validatevalue) | +| `common.validations.values.multiple.empty` | Validate a multiple values must not be empty. It returns a shared error for all the values. | `dict "required" (list $validateValueConf00 $validateValueConf01) "context" $`. See [ValidateValue](#validatevalue) | +| `common.validations.values.mariadb.passwords` | This helper will ensure required password for MariaDB are not empty. It returns a shared error for all the values. | `dict "secret" "mariadb-secret" "subchart" "true" "context" $` subchart field is optional and could be true or false it depends on where you will use mariadb chart and the helper. | +| `common.validations.values.mysql.passwords` | This helper will ensure required password for MySQL are not empty. It returns a shared error for all the values. | `dict "secret" "mysql-secret" "subchart" "true" "context" $` subchart field is optional and could be true or false it depends on where you will use mysql chart and the helper. | +| `common.validations.values.postgresql.passwords` | This helper will ensure required password for PostgreSQL are not empty. It returns a shared error for all the values. | `dict "secret" "postgresql-secret" "subchart" "true" "context" $` subchart field is optional and could be true or false it depends on where you will use postgresql chart and the helper. | +| `common.validations.values.redis.passwords` | This helper will ensure required password for Redis® are not empty. It returns a shared error for all the values. | `dict "secret" "redis-secret" "subchart" "true" "context" $` subchart field is optional and could be true or false it depends on where you will use redis chart and the helper. | +| `common.validations.values.cassandra.passwords` | This helper will ensure required password for Cassandra are not empty. It returns a shared error for all the values. | `dict "secret" "cassandra-secret" "subchart" "true" "context" $` subchart field is optional and could be true or false it depends on where you will use cassandra chart and the helper. | +| `common.validations.values.mongodb.passwords` | This helper will ensure required password for MongoDB® are not empty. It returns a shared error for all the values. | `dict "secret" "mongodb-secret" "subchart" "true" "context" $` subchart field is optional and could be true or false it depends on where you will use mongodb chart and the helper. | + +### Warnings + +| Helper identifier | Description | Expected Input | +|------------------------------|----------------------------------|------------------------------------------------------------| +| `common.warnings.rollingTag` | Warning about using rolling tag. | `ImageRoot` see [ImageRoot](#imageroot) for the structure. | + +## Special input schemas + +### ImageRoot + +```yaml +registry: + type: string + description: Docker registry where the image is located + example: docker.io + +repository: + type: string + description: Repository and image name + example: bitnami/nginx + +tag: + type: string + description: image tag + example: 1.16.1-debian-10-r63 + +pullPolicy: + type: string + description: Specify a imagePullPolicy. Defaults to 'Always' if image tag is 'latest', else set to 'IfNotPresent' + +pullSecrets: + type: array + items: + type: string + description: Optionally specify an array of imagePullSecrets (evaluated as templates). + +debug: + type: boolean + description: Set to true if you would like to see extra information on logs + example: false + +## An instance would be: +# registry: docker.io +# repository: bitnami/nginx +# tag: 1.16.1-debian-10-r63 +# pullPolicy: IfNotPresent +# debug: false +``` + +### Persistence + +```yaml +enabled: + type: boolean + description: Whether enable persistence. + example: true + +storageClass: + type: string + description: Ghost data Persistent Volume Storage Class, If set to "-", storageClassName: "" which disables dynamic provisioning. + example: "-" + +accessMode: + type: string + description: Access mode for the Persistent Volume Storage. + example: ReadWriteOnce + +size: + type: string + description: Size the Persistent Volume Storage. + example: 8Gi + +path: + type: string + description: Path to be persisted. + example: /bitnami + +## An instance would be: +# enabled: true +# storageClass: "-" +# accessMode: ReadWriteOnce +# size: 8Gi +# path: /bitnami +``` + +### ExistingSecret + +```yaml +name: + type: string + description: Name of the existing secret. + example: mySecret +keyMapping: + description: Mapping between the expected key name and the name of the key in the existing secret. + type: object + +## An instance would be: +# name: mySecret +# keyMapping: +# password: myPasswordKey +``` + +#### Example of use + +When we store sensitive data for a deployment in a secret, some times we want to give to users the possibility of using theirs existing secrets. + +```yaml +# templates/secret.yaml +--- +apiVersion: v1 +kind: Secret +metadata: + name: {{ include "common.names.fullname" . }} + labels: + app: {{ include "common.names.fullname" . }} +type: Opaque +data: + password: {{ .Values.password | b64enc | quote }} + +# templates/dpl.yaml +--- +... + env: + - name: PASSWORD + valueFrom: + secretKeyRef: + name: {{ include "common.secrets.name" (dict "existingSecret" .Values.existingSecret "context" $) }} + key: {{ include "common.secrets.key" (dict "existingSecret" .Values.existingSecret "key" "password") }} +... + +# values.yaml +--- +name: mySecret +keyMapping: + password: myPasswordKey +``` + +### ValidateValue + +#### NOTES.txt + +```console +{{- $validateValueConf00 := (dict "valueKey" "path.to.value00" "secret" "secretName" "field" "password-00") -}} +{{- $validateValueConf01 := (dict "valueKey" "path.to.value01" "secret" "secretName" "field" "password-01") -}} + +{{ include "common.validations.values.multiple.empty" (dict "required" (list $validateValueConf00 $validateValueConf01) "context" $) }} +``` + +If we force those values to be empty we will see some alerts + +```console +$ helm install test mychart --set path.to.value00="",path.to.value01="" + 'path.to.value00' must not be empty, please add '--set path.to.value00=$PASSWORD_00' to the command. To get the current value: + + export PASSWORD_00=$(kubectl get secret --namespace default secretName -o jsonpath="{.data.password-00}" | base64 -d) + + 'path.to.value01' must not be empty, please add '--set path.to.value01=$PASSWORD_01' to the command. To get the current value: + + export PASSWORD_01=$(kubectl get secret --namespace default secretName -o jsonpath="{.data.password-01}" | base64 -d) +``` + +## Upgrading + +### To 1.0.0 + +[On November 13, 2020, Helm v2 support was formally finished](https://github.com/helm/charts#status-of-the-project), this major version is the result of the required changes applied to the Helm Chart to be able to incorporate the different features added in Helm v3 and to be consistent with the Helm project itself regarding the Helm v2 EOL. + +**What changes were introduced in this major version?** + +- Previous versions of this Helm Chart use `apiVersion: v1` (installable by both Helm 2 and 3), this Helm Chart was updated to `apiVersion: v2` (installable by Helm 3 only). [Here](https://helm.sh/docs/topics/charts/#the-apiversion-field) you can find more information about the `apiVersion` field. +- Use `type: library`. [Here](https://v3.helm.sh/docs/faq/#library-chart-support) you can find more information. +- The different fields present in the *Chart.yaml* file has been ordered alphabetically in a homogeneous way for all the Bitnami Helm Charts + +**Considerations when upgrading to this version** + +- If you want to upgrade to this version from a previous one installed with Helm v3, you shouldn't face any issues +- If you want to upgrade to this version using Helm v2, this scenario is not supported as this version doesn't support Helm v2 anymore +- If you installed the previous version with Helm v2 and wants to upgrade to this version with Helm v3, please refer to the [official Helm documentation](https://helm.sh/docs/topics/v2_v3_migration/#migration-use-cases) about migrating from Helm v2 to v3 + +**Useful links** + +- https://docs.bitnami.com/tutorials/resolve-helm2-helm3-post-migration-issues/ +- https://helm.sh/docs/topics/v2_v3_migration/ +- https://helm.sh/blog/migrate-from-helm-v2-to-helm-v3/ + +## License + +Copyright © 2022 Bitnami + +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/charts/limesurvey-martial-ingress-v9/charts/mariadb/charts/common/templates/_affinities.tpl b/charts/limesurvey-martial-ingress-v9/charts/mariadb/charts/common/templates/_affinities.tpl new file mode 100644 index 0000000..81902a6 --- /dev/null +++ b/charts/limesurvey-martial-ingress-v9/charts/mariadb/charts/common/templates/_affinities.tpl @@ -0,0 +1,106 @@ +{{/* vim: set filetype=mustache: */}} + +{{/* +Return a soft nodeAffinity definition +{{ include "common.affinities.nodes.soft" (dict "key" "FOO" "values" (list "BAR" "BAZ")) -}} +*/}} +{{- define "common.affinities.nodes.soft" -}} +preferredDuringSchedulingIgnoredDuringExecution: + - preference: + matchExpressions: + - key: {{ .key }} + operator: In + values: + {{- range .values }} + - {{ . | quote }} + {{- end }} + weight: 1 +{{- end -}} + +{{/* +Return a hard nodeAffinity definition +{{ include "common.affinities.nodes.hard" (dict "key" "FOO" "values" (list "BAR" "BAZ")) -}} +*/}} +{{- define "common.affinities.nodes.hard" -}} +requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: {{ .key }} + operator: In + values: + {{- range .values }} + - {{ . | quote }} + {{- end }} +{{- end -}} + +{{/* +Return a nodeAffinity definition +{{ include "common.affinities.nodes" (dict "type" "soft" "key" "FOO" "values" (list "BAR" "BAZ")) -}} +*/}} +{{- define "common.affinities.nodes" -}} + {{- if eq .type "soft" }} + {{- include "common.affinities.nodes.soft" . -}} + {{- else if eq .type "hard" }} + {{- include "common.affinities.nodes.hard" . -}} + {{- end -}} +{{- end -}} + +{{/* +Return a topologyKey definition +{{ include "common.affinities.topologyKey" (dict "topologyKey" "BAR") -}} +*/}} +{{- define "common.affinities.topologyKey" -}} +{{ .topologyKey | default "kubernetes.io/hostname" -}} +{{- end -}} + +{{/* +Return a soft podAffinity/podAntiAffinity definition +{{ include "common.affinities.pods.soft" (dict "component" "FOO" "extraMatchLabels" .Values.extraMatchLabels "topologyKey" "BAR" "context" $) -}} +*/}} +{{- define "common.affinities.pods.soft" -}} +{{- $component := default "" .component -}} +{{- $extraMatchLabels := default (dict) .extraMatchLabels -}} +preferredDuringSchedulingIgnoredDuringExecution: + - podAffinityTerm: + labelSelector: + matchLabels: {{- (include "common.labels.matchLabels" .context) | nindent 10 }} + {{- if not (empty $component) }} + {{ printf "app.kubernetes.io/component: %s" $component }} + {{- end }} + {{- range $key, $value := $extraMatchLabels }} + {{ $key }}: {{ $value | quote }} + {{- end }} + topologyKey: {{ include "common.affinities.topologyKey" (dict "topologyKey" .topologyKey) }} + weight: 1 +{{- end -}} + +{{/* +Return a hard podAffinity/podAntiAffinity definition +{{ include "common.affinities.pods.hard" (dict "component" "FOO" "extraMatchLabels" .Values.extraMatchLabels "topologyKey" "BAR" "context" $) -}} +*/}} +{{- define "common.affinities.pods.hard" -}} +{{- $component := default "" .component -}} +{{- $extraMatchLabels := default (dict) .extraMatchLabels -}} +requiredDuringSchedulingIgnoredDuringExecution: + - labelSelector: + matchLabels: {{- (include "common.labels.matchLabels" .context) | nindent 8 }} + {{- if not (empty $component) }} + {{ printf "app.kubernetes.io/component: %s" $component }} + {{- end }} + {{- range $key, $value := $extraMatchLabels }} + {{ $key }}: {{ $value | quote }} + {{- end }} + topologyKey: {{ include "common.affinities.topologyKey" (dict "topologyKey" .topologyKey) }} +{{- end -}} + +{{/* +Return a podAffinity/podAntiAffinity definition +{{ include "common.affinities.pods" (dict "type" "soft" "key" "FOO" "values" (list "BAR" "BAZ")) -}} +*/}} +{{- define "common.affinities.pods" -}} + {{- if eq .type "soft" }} + {{- include "common.affinities.pods.soft" . -}} + {{- else if eq .type "hard" }} + {{- include "common.affinities.pods.hard" . -}} + {{- end -}} +{{- end -}} diff --git a/charts/limesurvey-martial-ingress-v9/charts/mariadb/charts/common/templates/_capabilities.tpl b/charts/limesurvey-martial-ingress-v9/charts/mariadb/charts/common/templates/_capabilities.tpl new file mode 100644 index 0000000..9d9b760 --- /dev/null +++ b/charts/limesurvey-martial-ingress-v9/charts/mariadb/charts/common/templates/_capabilities.tpl @@ -0,0 +1,154 @@ +{{/* vim: set filetype=mustache: */}} + +{{/* +Return the target Kubernetes version +*/}} +{{- define "common.capabilities.kubeVersion" -}} +{{- if .Values.global }} + {{- if .Values.global.kubeVersion }} + {{- .Values.global.kubeVersion -}} + {{- else }} + {{- default .Capabilities.KubeVersion.Version .Values.kubeVersion -}} + {{- end -}} +{{- else }} +{{- default .Capabilities.KubeVersion.Version .Values.kubeVersion -}} +{{- end -}} +{{- end -}} + +{{/* +Return the appropriate apiVersion for poddisruptionbudget. +*/}} +{{- define "common.capabilities.policy.apiVersion" -}} +{{- if semverCompare "<1.21-0" (include "common.capabilities.kubeVersion" .) -}} +{{- print "policy/v1beta1" -}} +{{- else -}} +{{- print "policy/v1" -}} +{{- end -}} +{{- end -}} + +{{/* +Return the appropriate apiVersion for networkpolicy. +*/}} +{{- define "common.capabilities.networkPolicy.apiVersion" -}} +{{- if semverCompare "<1.7-0" (include "common.capabilities.kubeVersion" .) -}} +{{- print "extensions/v1beta1" -}} +{{- else -}} +{{- print "networking.k8s.io/v1" -}} +{{- end -}} +{{- end -}} + +{{/* +Return the appropriate apiVersion for cronjob. +*/}} +{{- define "common.capabilities.cronjob.apiVersion" -}} +{{- if semverCompare "<1.21-0" (include "common.capabilities.kubeVersion" .) -}} +{{- print "batch/v1beta1" -}} +{{- else -}} +{{- print "batch/v1" -}} +{{- end -}} +{{- end -}} + +{{/* +Return the appropriate apiVersion for deployment. +*/}} +{{- define "common.capabilities.deployment.apiVersion" -}} +{{- if semverCompare "<1.14-0" (include "common.capabilities.kubeVersion" .) -}} +{{- print "extensions/v1beta1" -}} +{{- else -}} +{{- print "apps/v1" -}} +{{- end -}} +{{- end -}} + +{{/* +Return the appropriate apiVersion for statefulset. +*/}} +{{- define "common.capabilities.statefulset.apiVersion" -}} +{{- if semverCompare "<1.14-0" (include "common.capabilities.kubeVersion" .) -}} +{{- print "apps/v1beta1" -}} +{{- else -}} +{{- print "apps/v1" -}} +{{- end -}} +{{- end -}} + +{{/* +Return the appropriate apiVersion for ingress. +*/}} +{{- define "common.capabilities.ingress.apiVersion" -}} +{{- if .Values.ingress -}} +{{- if .Values.ingress.apiVersion -}} +{{- .Values.ingress.apiVersion -}} +{{- else if semverCompare "<1.14-0" (include "common.capabilities.kubeVersion" .) -}} +{{- print "extensions/v1beta1" -}} +{{- else if semverCompare "<1.19-0" (include "common.capabilities.kubeVersion" .) -}} +{{- print "networking.k8s.io/v1beta1" -}} +{{- else -}} +{{- print "networking.k8s.io/v1" -}} +{{- end }} +{{- else if semverCompare "<1.14-0" (include "common.capabilities.kubeVersion" .) -}} +{{- print "extensions/v1beta1" -}} +{{- else if semverCompare "<1.19-0" (include "common.capabilities.kubeVersion" .) -}} +{{- print "networking.k8s.io/v1beta1" -}} +{{- else -}} +{{- print "networking.k8s.io/v1" -}} +{{- end -}} +{{- end -}} + +{{/* +Return the appropriate apiVersion for RBAC resources. +*/}} +{{- define "common.capabilities.rbac.apiVersion" -}} +{{- if semverCompare "<1.17-0" (include "common.capabilities.kubeVersion" .) -}} +{{- print "rbac.authorization.k8s.io/v1beta1" -}} +{{- else -}} +{{- print "rbac.authorization.k8s.io/v1" -}} +{{- end -}} +{{- end -}} + +{{/* +Return the appropriate apiVersion for CRDs. +*/}} +{{- define "common.capabilities.crd.apiVersion" -}} +{{- if semverCompare "<1.19-0" (include "common.capabilities.kubeVersion" .) -}} +{{- print "apiextensions.k8s.io/v1beta1" -}} +{{- else -}} +{{- print "apiextensions.k8s.io/v1" -}} +{{- end -}} +{{- end -}} + +{{/* +Return the appropriate apiVersion for APIService. +*/}} +{{- define "common.capabilities.apiService.apiVersion" -}} +{{- if semverCompare "<1.10-0" (include "common.capabilities.kubeVersion" .) -}} +{{- print "apiregistration.k8s.io/v1beta1" -}} +{{- else -}} +{{- print "apiregistration.k8s.io/v1" -}} +{{- end -}} +{{- end -}} + +{{/* +Return the appropriate apiVersion for Horizontal Pod Autoscaler. +*/}} +{{- define "common.capabilities.hpa.apiVersion" -}} +{{- if semverCompare "<1.23-0" (include "common.capabilities.kubeVersion" .context) -}} +{{- if .beta2 -}} +{{- print "autoscaling/v2beta2" -}} +{{- else -}} +{{- print "autoscaling/v2beta1" -}} +{{- end -}} +{{- else -}} +{{- print "autoscaling/v2" -}} +{{- end -}} +{{- end -}} + +{{/* +Returns true if the used Helm version is 3.3+. +A way to check the used Helm version was not introduced until version 3.3.0 with .Capabilities.HelmVersion, which contains an additional "{}}" structure. +This check is introduced as a regexMatch instead of {{ if .Capabilities.HelmVersion }} because checking for the key HelmVersion in <3.3 results in a "interface not found" error. +**To be removed when the catalog's minimun Helm version is 3.3** +*/}} +{{- define "common.capabilities.supportsHelmVersion" -}} +{{- if regexMatch "{(v[0-9])*[^}]*}}$" (.Capabilities | toString ) }} + {{- true -}} +{{- end -}} +{{- end -}} diff --git a/charts/limesurvey-martial-ingress-v9/charts/mariadb/charts/common/templates/_errors.tpl b/charts/limesurvey-martial-ingress-v9/charts/mariadb/charts/common/templates/_errors.tpl new file mode 100644 index 0000000..a79cc2e --- /dev/null +++ b/charts/limesurvey-martial-ingress-v9/charts/mariadb/charts/common/templates/_errors.tpl @@ -0,0 +1,23 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Through error when upgrading using empty passwords values that must not be empty. + +Usage: +{{- $validationError00 := include "common.validations.values.single.empty" (dict "valueKey" "path.to.password00" "secret" "secretName" "field" "password-00") -}} +{{- $validationError01 := include "common.validations.values.single.empty" (dict "valueKey" "path.to.password01" "secret" "secretName" "field" "password-01") -}} +{{ include "common.errors.upgrade.passwords.empty" (dict "validationErrors" (list $validationError00 $validationError01) "context" $) }} + +Required password params: + - validationErrors - String - Required. List of validation strings to be return, if it is empty it won't throw error. + - context - Context - Required. Parent context. +*/}} +{{- define "common.errors.upgrade.passwords.empty" -}} + {{- $validationErrors := join "" .validationErrors -}} + {{- if and $validationErrors .context.Release.IsUpgrade -}} + {{- $errorString := "\nPASSWORDS ERROR: You must provide your current passwords when upgrading the release." -}} + {{- $errorString = print $errorString "\n Note that even after reinstallation, old credentials may be needed as they may be kept in persistent volume claims." -}} + {{- $errorString = print $errorString "\n Further information can be obtained at https://docs.bitnami.com/general/how-to/troubleshoot-helm-chart-issues/#credential-errors-while-upgrading-chart-releases" -}} + {{- $errorString = print $errorString "\n%s" -}} + {{- printf $errorString $validationErrors | fail -}} + {{- end -}} +{{- end -}} diff --git a/charts/limesurvey-martial-ingress-v9/charts/mariadb/charts/common/templates/_images.tpl b/charts/limesurvey-martial-ingress-v9/charts/mariadb/charts/common/templates/_images.tpl new file mode 100644 index 0000000..46c659e --- /dev/null +++ b/charts/limesurvey-martial-ingress-v9/charts/mariadb/charts/common/templates/_images.tpl @@ -0,0 +1,76 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Return the proper image name +{{ include "common.images.image" ( dict "imageRoot" .Values.path.to.the.image "global" $) }} +*/}} +{{- define "common.images.image" -}} +{{- $registryName := .imageRoot.registry -}} +{{- $repositoryName := .imageRoot.repository -}} +{{- $separator := ":" -}} +{{- $termination := .imageRoot.tag | toString -}} +{{- if .global }} + {{- if .global.imageRegistry }} + {{- $registryName = .global.imageRegistry -}} + {{- end -}} +{{- end -}} +{{- if .imageRoot.digest }} + {{- $separator = "@" -}} + {{- $termination = .imageRoot.digest | toString -}} +{{- end -}} +{{- printf "%s/%s%s%s" $registryName $repositoryName $separator $termination -}} +{{- end -}} + +{{/* +Return the proper Docker Image Registry Secret Names (deprecated: use common.images.renderPullSecrets instead) +{{ include "common.images.pullSecrets" ( dict "images" (list .Values.path.to.the.image1, .Values.path.to.the.image2) "global" .Values.global) }} +*/}} +{{- define "common.images.pullSecrets" -}} + {{- $pullSecrets := list }} + + {{- if .global }} + {{- range .global.imagePullSecrets -}} + {{- $pullSecrets = append $pullSecrets . -}} + {{- end -}} + {{- end -}} + + {{- range .images -}} + {{- range .pullSecrets -}} + {{- $pullSecrets = append $pullSecrets . -}} + {{- end -}} + {{- end -}} + + {{- if (not (empty $pullSecrets)) }} +imagePullSecrets: + {{- range $pullSecrets }} + - name: {{ . }} + {{- end }} + {{- end }} +{{- end -}} + +{{/* +Return the proper Docker Image Registry Secret Names evaluating values as templates +{{ include "common.images.renderPullSecrets" ( dict "images" (list .Values.path.to.the.image1, .Values.path.to.the.image2) "context" $) }} +*/}} +{{- define "common.images.renderPullSecrets" -}} + {{- $pullSecrets := list }} + {{- $context := .context }} + + {{- if $context.Values.global }} + {{- range $context.Values.global.imagePullSecrets -}} + {{- $pullSecrets = append $pullSecrets (include "common.tplvalues.render" (dict "value" . "context" $context)) -}} + {{- end -}} + {{- end -}} + + {{- range .images -}} + {{- range .pullSecrets -}} + {{- $pullSecrets = append $pullSecrets (include "common.tplvalues.render" (dict "value" . "context" $context)) -}} + {{- end -}} + {{- end -}} + + {{- if (not (empty $pullSecrets)) }} +imagePullSecrets: + {{- range $pullSecrets }} + - name: {{ . }} + {{- end }} + {{- end }} +{{- end -}} diff --git a/charts/limesurvey-martial-ingress-v9/charts/mariadb/charts/common/templates/_ingress.tpl b/charts/limesurvey-martial-ingress-v9/charts/mariadb/charts/common/templates/_ingress.tpl new file mode 100644 index 0000000..831da9c --- /dev/null +++ b/charts/limesurvey-martial-ingress-v9/charts/mariadb/charts/common/templates/_ingress.tpl @@ -0,0 +1,68 @@ +{{/* vim: set filetype=mustache: */}} + +{{/* +Generate backend entry that is compatible with all Kubernetes API versions. + +Usage: +{{ include "common.ingress.backend" (dict "serviceName" "backendName" "servicePort" "backendPort" "context" $) }} + +Params: + - serviceName - String. Name of an existing service backend + - servicePort - String/Int. Port name (or number) of the service. It will be translated to different yaml depending if it is a string or an integer. + - context - Dict - Required. The context for the template evaluation. +*/}} +{{- define "common.ingress.backend" -}} +{{- $apiVersion := (include "common.capabilities.ingress.apiVersion" .context) -}} +{{- if or (eq $apiVersion "extensions/v1beta1") (eq $apiVersion "networking.k8s.io/v1beta1") -}} +serviceName: {{ .serviceName }} +servicePort: {{ .servicePort }} +{{- else -}} +service: + name: {{ .serviceName }} + port: + {{- if typeIs "string" .servicePort }} + name: {{ .servicePort }} + {{- else if or (typeIs "int" .servicePort) (typeIs "float64" .servicePort) }} + number: {{ .servicePort | int }} + {{- end }} +{{- end -}} +{{- end -}} + +{{/* +Print "true" if the API pathType field is supported +Usage: +{{ include "common.ingress.supportsPathType" . }} +*/}} +{{- define "common.ingress.supportsPathType" -}} +{{- if (semverCompare "<1.18-0" (include "common.capabilities.kubeVersion" .)) -}} +{{- print "false" -}} +{{- else -}} +{{- print "true" -}} +{{- end -}} +{{- end -}} + +{{/* +Returns true if the ingressClassname field is supported +Usage: +{{ include "common.ingress.supportsIngressClassname" . }} +*/}} +{{- define "common.ingress.supportsIngressClassname" -}} +{{- if semverCompare "<1.18-0" (include "common.capabilities.kubeVersion" .) -}} +{{- print "false" -}} +{{- else -}} +{{- print "true" -}} +{{- end -}} +{{- end -}} + +{{/* +Return true if cert-manager required annotations for TLS signed +certificates are set in the Ingress annotations +Ref: https://cert-manager.io/docs/usage/ingress/#supported-annotations +Usage: +{{ include "common.ingress.certManagerRequest" ( dict "annotations" .Values.path.to.the.ingress.annotations ) }} +*/}} +{{- define "common.ingress.certManagerRequest" -}} +{{ if or (hasKey .annotations "cert-manager.io/cluster-issuer") (hasKey .annotations "cert-manager.io/issuer") (hasKey .annotations "kubernetes.io/tls-acme") }} + {{- true -}} +{{- end -}} +{{- end -}} diff --git a/charts/limesurvey-martial-ingress-v9/charts/mariadb/charts/common/templates/_labels.tpl b/charts/limesurvey-martial-ingress-v9/charts/mariadb/charts/common/templates/_labels.tpl new file mode 100644 index 0000000..252066c --- /dev/null +++ b/charts/limesurvey-martial-ingress-v9/charts/mariadb/charts/common/templates/_labels.tpl @@ -0,0 +1,18 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Kubernetes standard labels +*/}} +{{- define "common.labels.standard" -}} +app.kubernetes.io/name: {{ include "common.names.name" . }} +helm.sh/chart: {{ include "common.names.chart" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end -}} + +{{/* +Labels to use on deploy.spec.selector.matchLabels and svc.spec.selector +*/}} +{{- define "common.labels.matchLabels" -}} +app.kubernetes.io/name: {{ include "common.names.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end -}} diff --git a/charts/limesurvey-martial-ingress-v9/charts/mariadb/charts/common/templates/_names.tpl b/charts/limesurvey-martial-ingress-v9/charts/mariadb/charts/common/templates/_names.tpl new file mode 100644 index 0000000..617a234 --- /dev/null +++ b/charts/limesurvey-martial-ingress-v9/charts/mariadb/charts/common/templates/_names.tpl @@ -0,0 +1,66 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Expand the name of the chart. +*/}} +{{- define "common.names.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "common.names.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | 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 "common.names.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 a default fully qualified dependency 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. +Usage: +{{ include "common.names.dependency.fullname" (dict "chartName" "dependency-chart-name" "chartValues" .Values.dependency-chart "context" $) }} +*/}} +{{- define "common.names.dependency.fullname" -}} +{{- if .chartValues.fullnameOverride -}} +{{- .chartValues.fullnameOverride | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- $name := default .chartName .chartValues.nameOverride -}} +{{- if contains $name .context.Release.Name -}} +{{- .context.Release.Name | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- printf "%s-%s" .context.Release.Name $name | trunc 63 | trimSuffix "-" -}} +{{- end -}} +{{- end -}} +{{- end -}} + +{{/* +Allow the release namespace to be overridden for multi-namespace deployments in combined charts. +*/}} +{{- define "common.names.namespace" -}} +{{- default .Release.Namespace .Values.namespaceOverride | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Create a fully qualified app name adding the installation's namespace. +*/}} +{{- define "common.names.fullname.namespace" -}} +{{- printf "%s-%s" (include "common.names.fullname" .) (include "common.names.namespace" .) | trunc 63 | trimSuffix "-" -}} +{{- end -}} diff --git a/charts/limesurvey-martial-ingress-v9/charts/mariadb/charts/common/templates/_secrets.tpl b/charts/limesurvey-martial-ingress-v9/charts/mariadb/charts/common/templates/_secrets.tpl new file mode 100644 index 0000000..a1708b2 --- /dev/null +++ b/charts/limesurvey-martial-ingress-v9/charts/mariadb/charts/common/templates/_secrets.tpl @@ -0,0 +1,165 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Generate secret name. + +Usage: +{{ include "common.secrets.name" (dict "existingSecret" .Values.path.to.the.existingSecret "defaultNameSuffix" "mySuffix" "context" $) }} + +Params: + - existingSecret - ExistingSecret/String - Optional. The path to the existing secrets in the values.yaml given by the user + to be used instead of the default one. Allows for it to be of type String (just the secret name) for backwards compatibility. + +info: https://github.com/bitnami/charts/tree/main/bitnami/common#existingsecret + - defaultNameSuffix - String - Optional. It is used only if we have several secrets in the same deployment. + - context - Dict - Required. The context for the template evaluation. +*/}} +{{- define "common.secrets.name" -}} +{{- $name := (include "common.names.fullname" .context) -}} + +{{- if .defaultNameSuffix -}} +{{- $name = printf "%s-%s" $name .defaultNameSuffix | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{- with .existingSecret -}} +{{- if not (typeIs "string" .) -}} +{{- with .name -}} +{{- $name = . -}} +{{- end -}} +{{- else -}} +{{- $name = . -}} +{{- end -}} +{{- end -}} + +{{- printf "%s" $name -}} +{{- end -}} + +{{/* +Generate secret key. + +Usage: +{{ include "common.secrets.key" (dict "existingSecret" .Values.path.to.the.existingSecret "key" "keyName") }} + +Params: + - existingSecret - ExistingSecret/String - Optional. The path to the existing secrets in the values.yaml given by the user + to be used instead of the default one. Allows for it to be of type String (just the secret name) for backwards compatibility. + +info: https://github.com/bitnami/charts/tree/main/bitnami/common#existingsecret + - key - String - Required. Name of the key in the secret. +*/}} +{{- define "common.secrets.key" -}} +{{- $key := .key -}} + +{{- if .existingSecret -}} + {{- if not (typeIs "string" .existingSecret) -}} + {{- if .existingSecret.keyMapping -}} + {{- $key = index .existingSecret.keyMapping $.key -}} + {{- end -}} + {{- end }} +{{- end -}} + +{{- printf "%s" $key -}} +{{- end -}} + +{{/* +Generate secret password or retrieve one if already created. + +Usage: +{{ include "common.secrets.passwords.manage" (dict "secret" "secret-name" "key" "keyName" "providedValues" (list "path.to.password1" "path.to.password2") "length" 10 "strong" false "chartName" "chartName" "context" $) }} + +Params: + - secret - String - Required - Name of the 'Secret' resource where the password is stored. + - key - String - Required - Name of the key in the secret. + - providedValues - List - Required - The path to the validating value in the values.yaml, e.g: "mysql.password". Will pick first parameter with a defined value. + - length - int - Optional - Length of the generated random password. + - strong - Boolean - Optional - Whether to add symbols to the generated random password. + - chartName - String - Optional - Name of the chart used when said chart is deployed as a subchart. + - context - Context - Required - Parent context. + +The order in which this function returns a secret password: + 1. Already existing 'Secret' resource + (If a 'Secret' resource is found under the name provided to the 'secret' parameter to this function and that 'Secret' resource contains a key with the name passed as the 'key' parameter to this function then the value of this existing secret password will be returned) + 2. Password provided via the values.yaml + (If one of the keys passed to the 'providedValues' parameter to this function is a valid path to a key in the values.yaml and has a value, the value of the first key with a value will be returned) + 3. Randomly generated secret password + (A new random secret password with the length specified in the 'length' parameter will be generated and returned) + +*/}} +{{- define "common.secrets.passwords.manage" -}} + +{{- $password := "" }} +{{- $subchart := "" }} +{{- $chartName := default "" .chartName }} +{{- $passwordLength := default 10 .length }} +{{- $providedPasswordKey := include "common.utils.getKeyFromList" (dict "keys" .providedValues "context" $.context) }} +{{- $providedPasswordValue := include "common.utils.getValueFromKey" (dict "key" $providedPasswordKey "context" $.context) }} +{{- $secretData := (lookup "v1" "Secret" (include "common.names.namespace" .context) .secret).data }} +{{- if $secretData }} + {{- if hasKey $secretData .key }} + {{- $password = index $secretData .key | quote }} + {{- else }} + {{- printf "\nPASSWORDS ERROR: The secret \"%s\" does not contain the key \"%s\"\n" .secret .key | fail -}} + {{- end -}} +{{- else if $providedPasswordValue }} + {{- $password = $providedPasswordValue | toString | b64enc | quote }} +{{- else }} + + {{- if .context.Values.enabled }} + {{- $subchart = $chartName }} + {{- end -}} + + {{- $requiredPassword := dict "valueKey" $providedPasswordKey "secret" .secret "field" .key "subchart" $subchart "context" $.context -}} + {{- $requiredPasswordError := include "common.validations.values.single.empty" $requiredPassword -}} + {{- $passwordValidationErrors := list $requiredPasswordError -}} + {{- include "common.errors.upgrade.passwords.empty" (dict "validationErrors" $passwordValidationErrors "context" $.context) -}} + + {{- if .strong }} + {{- $subStr := list (lower (randAlpha 1)) (randNumeric 1) (upper (randAlpha 1)) | join "_" }} + {{- $password = randAscii $passwordLength }} + {{- $password = regexReplaceAllLiteral "\\W" $password "@" | substr 5 $passwordLength }} + {{- $password = printf "%s%s" $subStr $password | toString | shuffle | b64enc | quote }} + {{- else }} + {{- $password = randAlphaNum $passwordLength | b64enc | quote }} + {{- end }} +{{- end -}} +{{- printf "%s" $password -}} +{{- end -}} + +{{/* +Reuses the value from an existing secret, otherwise sets its value to a default value. + +Usage: +{{ include "common.secrets.lookup" (dict "secret" "secret-name" "key" "keyName" "defaultValue" .Values.myValue "context" $) }} + +Params: + - secret - String - Required - Name of the 'Secret' resource where the password is stored. + - key - String - Required - Name of the key in the secret. + - defaultValue - String - Required - The path to the validating value in the values.yaml, e.g: "mysql.password". Will pick first parameter with a defined value. + - context - Context - Required - Parent context. + +*/}} +{{- define "common.secrets.lookup" -}} +{{- $value := "" -}} +{{- $defaultValue := required "\n'common.secrets.lookup': Argument 'defaultValue' missing or empty" .defaultValue -}} +{{- $secretData := (lookup "v1" "Secret" (include "common.names.namespace" .context) .secret).data -}} +{{- if and $secretData (hasKey $secretData .key) -}} + {{- $value = index $secretData .key -}} +{{- else -}} + {{- $value = $defaultValue | toString | b64enc -}} +{{- end -}} +{{- printf "%s" $value -}} +{{- end -}} + +{{/* +Returns whether a previous generated secret already exists + +Usage: +{{ include "common.secrets.exists" (dict "secret" "secret-name" "context" $) }} + +Params: + - secret - String - Required - Name of the 'Secret' resource where the password is stored. + - context - Context - Required - Parent context. +*/}} +{{- define "common.secrets.exists" -}} +{{- $secret := (lookup "v1" "Secret" (include "common.names.namespace" .context) .secret) }} +{{- if $secret }} + {{- true -}} +{{- end -}} +{{- end -}} diff --git a/charts/limesurvey-martial-ingress-v9/charts/mariadb/charts/common/templates/_storage.tpl b/charts/limesurvey-martial-ingress-v9/charts/mariadb/charts/common/templates/_storage.tpl new file mode 100644 index 0000000..60e2a84 --- /dev/null +++ b/charts/limesurvey-martial-ingress-v9/charts/mariadb/charts/common/templates/_storage.tpl @@ -0,0 +1,23 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Return the proper Storage Class +{{ include "common.storage.class" ( dict "persistence" .Values.path.to.the.persistence "global" $) }} +*/}} +{{- define "common.storage.class" -}} + +{{- $storageClass := .persistence.storageClass -}} +{{- if .global -}} + {{- if .global.storageClass -}} + {{- $storageClass = .global.storageClass -}} + {{- end -}} +{{- end -}} + +{{- if $storageClass -}} + {{- if (eq "-" $storageClass) -}} + {{- printf "storageClassName: \"\"" -}} + {{- else }} + {{- printf "storageClassName: %s" $storageClass -}} + {{- end -}} +{{- end -}} + +{{- end -}} diff --git a/charts/limesurvey-martial-ingress-v9/charts/mariadb/charts/common/templates/_tplvalues.tpl b/charts/limesurvey-martial-ingress-v9/charts/mariadb/charts/common/templates/_tplvalues.tpl new file mode 100644 index 0000000..2db1668 --- /dev/null +++ b/charts/limesurvey-martial-ingress-v9/charts/mariadb/charts/common/templates/_tplvalues.tpl @@ -0,0 +1,13 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Renders a value that contains template. +Usage: +{{ include "common.tplvalues.render" ( dict "value" .Values.path.to.the.Value "context" $) }} +*/}} +{{- define "common.tplvalues.render" -}} + {{- if typeIs "string" .value }} + {{- tpl .value .context }} + {{- else }} + {{- tpl (.value | toYaml) .context }} + {{- end }} +{{- end -}} diff --git a/charts/limesurvey-martial-ingress-v9/charts/mariadb/charts/common/templates/_utils.tpl b/charts/limesurvey-martial-ingress-v9/charts/mariadb/charts/common/templates/_utils.tpl new file mode 100644 index 0000000..b1ead50 --- /dev/null +++ b/charts/limesurvey-martial-ingress-v9/charts/mariadb/charts/common/templates/_utils.tpl @@ -0,0 +1,62 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Print instructions to get a secret value. +Usage: +{{ include "common.utils.secret.getvalue" (dict "secret" "secret-name" "field" "secret-value-field" "context" $) }} +*/}} +{{- define "common.utils.secret.getvalue" -}} +{{- $varname := include "common.utils.fieldToEnvVar" . -}} +export {{ $varname }}=$(kubectl get secret --namespace {{ include "common.names.namespace" .context | quote }} {{ .secret }} -o jsonpath="{.data.{{ .field }}}" | base64 -d) +{{- end -}} + +{{/* +Build env var name given a field +Usage: +{{ include "common.utils.fieldToEnvVar" dict "field" "my-password" }} +*/}} +{{- define "common.utils.fieldToEnvVar" -}} + {{- $fieldNameSplit := splitList "-" .field -}} + {{- $upperCaseFieldNameSplit := list -}} + + {{- range $fieldNameSplit -}} + {{- $upperCaseFieldNameSplit = append $upperCaseFieldNameSplit ( upper . ) -}} + {{- end -}} + + {{ join "_" $upperCaseFieldNameSplit }} +{{- end -}} + +{{/* +Gets a value from .Values given +Usage: +{{ include "common.utils.getValueFromKey" (dict "key" "path.to.key" "context" $) }} +*/}} +{{- define "common.utils.getValueFromKey" -}} +{{- $splitKey := splitList "." .key -}} +{{- $value := "" -}} +{{- $latestObj := $.context.Values -}} +{{- range $splitKey -}} + {{- if not $latestObj -}} + {{- printf "please review the entire path of '%s' exists in values" $.key | fail -}} + {{- end -}} + {{- $value = ( index $latestObj . ) -}} + {{- $latestObj = $value -}} +{{- end -}} +{{- printf "%v" (default "" $value) -}} +{{- end -}} + +{{/* +Returns first .Values key with a defined value or first of the list if all non-defined +Usage: +{{ include "common.utils.getKeyFromList" (dict "keys" (list "path.to.key1" "path.to.key2") "context" $) }} +*/}} +{{- define "common.utils.getKeyFromList" -}} +{{- $key := first .keys -}} +{{- $reverseKeys := reverse .keys }} +{{- range $reverseKeys }} + {{- $value := include "common.utils.getValueFromKey" (dict "key" . "context" $.context ) }} + {{- if $value -}} + {{- $key = . }} + {{- end -}} +{{- end -}} +{{- printf "%s" $key -}} +{{- end -}} diff --git a/charts/limesurvey-martial-ingress-v9/charts/mariadb/charts/common/templates/_warnings.tpl b/charts/limesurvey-martial-ingress-v9/charts/mariadb/charts/common/templates/_warnings.tpl new file mode 100644 index 0000000..ae10fa4 --- /dev/null +++ b/charts/limesurvey-martial-ingress-v9/charts/mariadb/charts/common/templates/_warnings.tpl @@ -0,0 +1,14 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Warning about using rolling tag. +Usage: +{{ include "common.warnings.rollingTag" .Values.path.to.the.imageRoot }} +*/}} +{{- define "common.warnings.rollingTag" -}} + +{{- if and (contains "bitnami/" .repository) (not (.tag | toString | regexFind "-r\\d+$|sha256:")) }} +WARNING: Rolling tag detected ({{ .repository }}:{{ .tag }}), please note that it is strongly recommended to avoid using rolling tags in a production environment. ++info https://docs.bitnami.com/containers/how-to/understand-rolling-tags-containers/ +{{- end }} + +{{- end -}} diff --git a/charts/limesurvey-martial-ingress-v9/charts/mariadb/charts/common/templates/validations/_cassandra.tpl b/charts/limesurvey-martial-ingress-v9/charts/mariadb/charts/common/templates/validations/_cassandra.tpl new file mode 100644 index 0000000..ded1ae3 --- /dev/null +++ b/charts/limesurvey-martial-ingress-v9/charts/mariadb/charts/common/templates/validations/_cassandra.tpl @@ -0,0 +1,72 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Validate Cassandra required passwords are not empty. + +Usage: +{{ include "common.validations.values.cassandra.passwords" (dict "secret" "secretName" "subchart" false "context" $) }} +Params: + - secret - String - Required. Name of the secret where Cassandra values are stored, e.g: "cassandra-passwords-secret" + - subchart - Boolean - Optional. Whether Cassandra is used as subchart or not. Default: false +*/}} +{{- define "common.validations.values.cassandra.passwords" -}} + {{- $existingSecret := include "common.cassandra.values.existingSecret" . -}} + {{- $enabled := include "common.cassandra.values.enabled" . -}} + {{- $dbUserPrefix := include "common.cassandra.values.key.dbUser" . -}} + {{- $valueKeyPassword := printf "%s.password" $dbUserPrefix -}} + + {{- if and (or (not $existingSecret) (eq $existingSecret "\"\"")) (eq $enabled "true") -}} + {{- $requiredPasswords := list -}} + + {{- $requiredPassword := dict "valueKey" $valueKeyPassword "secret" .secret "field" "cassandra-password" -}} + {{- $requiredPasswords = append $requiredPasswords $requiredPassword -}} + + {{- include "common.validations.values.multiple.empty" (dict "required" $requiredPasswords "context" .context) -}} + + {{- end -}} +{{- end -}} + +{{/* +Auxiliary function to get the right value for existingSecret. + +Usage: +{{ include "common.cassandra.values.existingSecret" (dict "context" $) }} +Params: + - subchart - Boolean - Optional. Whether Cassandra is used as subchart or not. Default: false +*/}} +{{- define "common.cassandra.values.existingSecret" -}} + {{- if .subchart -}} + {{- .context.Values.cassandra.dbUser.existingSecret | quote -}} + {{- else -}} + {{- .context.Values.dbUser.existingSecret | quote -}} + {{- end -}} +{{- end -}} + +{{/* +Auxiliary function to get the right value for enabled cassandra. + +Usage: +{{ include "common.cassandra.values.enabled" (dict "context" $) }} +*/}} +{{- define "common.cassandra.values.enabled" -}} + {{- if .subchart -}} + {{- printf "%v" .context.Values.cassandra.enabled -}} + {{- else -}} + {{- printf "%v" (not .context.Values.enabled) -}} + {{- end -}} +{{- end -}} + +{{/* +Auxiliary function to get the right value for the key dbUser + +Usage: +{{ include "common.cassandra.values.key.dbUser" (dict "subchart" "true" "context" $) }} +Params: + - subchart - Boolean - Optional. Whether Cassandra is used as subchart or not. Default: false +*/}} +{{- define "common.cassandra.values.key.dbUser" -}} + {{- if .subchart -}} + cassandra.dbUser + {{- else -}} + dbUser + {{- end -}} +{{- end -}} diff --git a/charts/limesurvey-martial-ingress-v9/charts/mariadb/charts/common/templates/validations/_mariadb.tpl b/charts/limesurvey-martial-ingress-v9/charts/mariadb/charts/common/templates/validations/_mariadb.tpl new file mode 100644 index 0000000..b6906ff --- /dev/null +++ b/charts/limesurvey-martial-ingress-v9/charts/mariadb/charts/common/templates/validations/_mariadb.tpl @@ -0,0 +1,103 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Validate MariaDB required passwords are not empty. + +Usage: +{{ include "common.validations.values.mariadb.passwords" (dict "secret" "secretName" "subchart" false "context" $) }} +Params: + - secret - String - Required. Name of the secret where MariaDB values are stored, e.g: "mysql-passwords-secret" + - subchart - Boolean - Optional. Whether MariaDB is used as subchart or not. Default: false +*/}} +{{- define "common.validations.values.mariadb.passwords" -}} + {{- $existingSecret := include "common.mariadb.values.auth.existingSecret" . -}} + {{- $enabled := include "common.mariadb.values.enabled" . -}} + {{- $architecture := include "common.mariadb.values.architecture" . -}} + {{- $authPrefix := include "common.mariadb.values.key.auth" . -}} + {{- $valueKeyRootPassword := printf "%s.rootPassword" $authPrefix -}} + {{- $valueKeyUsername := printf "%s.username" $authPrefix -}} + {{- $valueKeyPassword := printf "%s.password" $authPrefix -}} + {{- $valueKeyReplicationPassword := printf "%s.replicationPassword" $authPrefix -}} + + {{- if and (or (not $existingSecret) (eq $existingSecret "\"\"")) (eq $enabled "true") -}} + {{- $requiredPasswords := list -}} + + {{- $requiredRootPassword := dict "valueKey" $valueKeyRootPassword "secret" .secret "field" "mariadb-root-password" -}} + {{- $requiredPasswords = append $requiredPasswords $requiredRootPassword -}} + + {{- $valueUsername := include "common.utils.getValueFromKey" (dict "key" $valueKeyUsername "context" .context) }} + {{- if not (empty $valueUsername) -}} + {{- $requiredPassword := dict "valueKey" $valueKeyPassword "secret" .secret "field" "mariadb-password" -}} + {{- $requiredPasswords = append $requiredPasswords $requiredPassword -}} + {{- end -}} + + {{- if (eq $architecture "replication") -}} + {{- $requiredReplicationPassword := dict "valueKey" $valueKeyReplicationPassword "secret" .secret "field" "mariadb-replication-password" -}} + {{- $requiredPasswords = append $requiredPasswords $requiredReplicationPassword -}} + {{- end -}} + + {{- include "common.validations.values.multiple.empty" (dict "required" $requiredPasswords "context" .context) -}} + + {{- end -}} +{{- end -}} + +{{/* +Auxiliary function to get the right value for existingSecret. + +Usage: +{{ include "common.mariadb.values.auth.existingSecret" (dict "context" $) }} +Params: + - subchart - Boolean - Optional. Whether MariaDB is used as subchart or not. Default: false +*/}} +{{- define "common.mariadb.values.auth.existingSecret" -}} + {{- if .subchart -}} + {{- .context.Values.mariadb.auth.existingSecret | quote -}} + {{- else -}} + {{- .context.Values.auth.existingSecret | quote -}} + {{- end -}} +{{- end -}} + +{{/* +Auxiliary function to get the right value for enabled mariadb. + +Usage: +{{ include "common.mariadb.values.enabled" (dict "context" $) }} +*/}} +{{- define "common.mariadb.values.enabled" -}} + {{- if .subchart -}} + {{- printf "%v" .context.Values.mariadb.enabled -}} + {{- else -}} + {{- printf "%v" (not .context.Values.enabled) -}} + {{- end -}} +{{- end -}} + +{{/* +Auxiliary function to get the right value for architecture + +Usage: +{{ include "common.mariadb.values.architecture" (dict "subchart" "true" "context" $) }} +Params: + - subchart - Boolean - Optional. Whether MariaDB is used as subchart or not. Default: false +*/}} +{{- define "common.mariadb.values.architecture" -}} + {{- if .subchart -}} + {{- .context.Values.mariadb.architecture -}} + {{- else -}} + {{- .context.Values.architecture -}} + {{- end -}} +{{- end -}} + +{{/* +Auxiliary function to get the right value for the key auth + +Usage: +{{ include "common.mariadb.values.key.auth" (dict "subchart" "true" "context" $) }} +Params: + - subchart - Boolean - Optional. Whether MariaDB is used as subchart or not. Default: false +*/}} +{{- define "common.mariadb.values.key.auth" -}} + {{- if .subchart -}} + mariadb.auth + {{- else -}} + auth + {{- end -}} +{{- end -}} diff --git a/charts/limesurvey-martial-ingress-v9/charts/mariadb/charts/common/templates/validations/_mongodb.tpl b/charts/limesurvey-martial-ingress-v9/charts/mariadb/charts/common/templates/validations/_mongodb.tpl new file mode 100644 index 0000000..f820ec1 --- /dev/null +++ b/charts/limesurvey-martial-ingress-v9/charts/mariadb/charts/common/templates/validations/_mongodb.tpl @@ -0,0 +1,108 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Validate MongoDB® required passwords are not empty. + +Usage: +{{ include "common.validations.values.mongodb.passwords" (dict "secret" "secretName" "subchart" false "context" $) }} +Params: + - secret - String - Required. Name of the secret where MongoDB® values are stored, e.g: "mongodb-passwords-secret" + - subchart - Boolean - Optional. Whether MongoDB® is used as subchart or not. Default: false +*/}} +{{- define "common.validations.values.mongodb.passwords" -}} + {{- $existingSecret := include "common.mongodb.values.auth.existingSecret" . -}} + {{- $enabled := include "common.mongodb.values.enabled" . -}} + {{- $authPrefix := include "common.mongodb.values.key.auth" . -}} + {{- $architecture := include "common.mongodb.values.architecture" . -}} + {{- $valueKeyRootPassword := printf "%s.rootPassword" $authPrefix -}} + {{- $valueKeyUsername := printf "%s.username" $authPrefix -}} + {{- $valueKeyDatabase := printf "%s.database" $authPrefix -}} + {{- $valueKeyPassword := printf "%s.password" $authPrefix -}} + {{- $valueKeyReplicaSetKey := printf "%s.replicaSetKey" $authPrefix -}} + {{- $valueKeyAuthEnabled := printf "%s.enabled" $authPrefix -}} + + {{- $authEnabled := include "common.utils.getValueFromKey" (dict "key" $valueKeyAuthEnabled "context" .context) -}} + + {{- if and (or (not $existingSecret) (eq $existingSecret "\"\"")) (eq $enabled "true") (eq $authEnabled "true") -}} + {{- $requiredPasswords := list -}} + + {{- $requiredRootPassword := dict "valueKey" $valueKeyRootPassword "secret" .secret "field" "mongodb-root-password" -}} + {{- $requiredPasswords = append $requiredPasswords $requiredRootPassword -}} + + {{- $valueUsername := include "common.utils.getValueFromKey" (dict "key" $valueKeyUsername "context" .context) }} + {{- $valueDatabase := include "common.utils.getValueFromKey" (dict "key" $valueKeyDatabase "context" .context) }} + {{- if and $valueUsername $valueDatabase -}} + {{- $requiredPassword := dict "valueKey" $valueKeyPassword "secret" .secret "field" "mongodb-password" -}} + {{- $requiredPasswords = append $requiredPasswords $requiredPassword -}} + {{- end -}} + + {{- if (eq $architecture "replicaset") -}} + {{- $requiredReplicaSetKey := dict "valueKey" $valueKeyReplicaSetKey "secret" .secret "field" "mongodb-replica-set-key" -}} + {{- $requiredPasswords = append $requiredPasswords $requiredReplicaSetKey -}} + {{- end -}} + + {{- include "common.validations.values.multiple.empty" (dict "required" $requiredPasswords "context" .context) -}} + + {{- end -}} +{{- end -}} + +{{/* +Auxiliary function to get the right value for existingSecret. + +Usage: +{{ include "common.mongodb.values.auth.existingSecret" (dict "context" $) }} +Params: + - subchart - Boolean - Optional. Whether MongoDb is used as subchart or not. Default: false +*/}} +{{- define "common.mongodb.values.auth.existingSecret" -}} + {{- if .subchart -}} + {{- .context.Values.mongodb.auth.existingSecret | quote -}} + {{- else -}} + {{- .context.Values.auth.existingSecret | quote -}} + {{- end -}} +{{- end -}} + +{{/* +Auxiliary function to get the right value for enabled mongodb. + +Usage: +{{ include "common.mongodb.values.enabled" (dict "context" $) }} +*/}} +{{- define "common.mongodb.values.enabled" -}} + {{- if .subchart -}} + {{- printf "%v" .context.Values.mongodb.enabled -}} + {{- else -}} + {{- printf "%v" (not .context.Values.enabled) -}} + {{- end -}} +{{- end -}} + +{{/* +Auxiliary function to get the right value for the key auth + +Usage: +{{ include "common.mongodb.values.key.auth" (dict "subchart" "true" "context" $) }} +Params: + - subchart - Boolean - Optional. Whether MongoDB® is used as subchart or not. Default: false +*/}} +{{- define "common.mongodb.values.key.auth" -}} + {{- if .subchart -}} + mongodb.auth + {{- else -}} + auth + {{- end -}} +{{- end -}} + +{{/* +Auxiliary function to get the right value for architecture + +Usage: +{{ include "common.mongodb.values.architecture" (dict "subchart" "true" "context" $) }} +Params: + - subchart - Boolean - Optional. Whether MongoDB® is used as subchart or not. Default: false +*/}} +{{- define "common.mongodb.values.architecture" -}} + {{- if .subchart -}} + {{- .context.Values.mongodb.architecture -}} + {{- else -}} + {{- .context.Values.architecture -}} + {{- end -}} +{{- end -}} diff --git a/charts/limesurvey-martial-ingress-v9/charts/mariadb/charts/common/templates/validations/_mysql.tpl b/charts/limesurvey-martial-ingress-v9/charts/mariadb/charts/common/templates/validations/_mysql.tpl new file mode 100644 index 0000000..74472a0 --- /dev/null +++ b/charts/limesurvey-martial-ingress-v9/charts/mariadb/charts/common/templates/validations/_mysql.tpl @@ -0,0 +1,103 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Validate MySQL required passwords are not empty. + +Usage: +{{ include "common.validations.values.mysql.passwords" (dict "secret" "secretName" "subchart" false "context" $) }} +Params: + - secret - String - Required. Name of the secret where MySQL values are stored, e.g: "mysql-passwords-secret" + - subchart - Boolean - Optional. Whether MySQL is used as subchart or not. Default: false +*/}} +{{- define "common.validations.values.mysql.passwords" -}} + {{- $existingSecret := include "common.mysql.values.auth.existingSecret" . -}} + {{- $enabled := include "common.mysql.values.enabled" . -}} + {{- $architecture := include "common.mysql.values.architecture" . -}} + {{- $authPrefix := include "common.mysql.values.key.auth" . -}} + {{- $valueKeyRootPassword := printf "%s.rootPassword" $authPrefix -}} + {{- $valueKeyUsername := printf "%s.username" $authPrefix -}} + {{- $valueKeyPassword := printf "%s.password" $authPrefix -}} + {{- $valueKeyReplicationPassword := printf "%s.replicationPassword" $authPrefix -}} + + {{- if and (or (not $existingSecret) (eq $existingSecret "\"\"")) (eq $enabled "true") -}} + {{- $requiredPasswords := list -}} + + {{- $requiredRootPassword := dict "valueKey" $valueKeyRootPassword "secret" .secret "field" "mysql-root-password" -}} + {{- $requiredPasswords = append $requiredPasswords $requiredRootPassword -}} + + {{- $valueUsername := include "common.utils.getValueFromKey" (dict "key" $valueKeyUsername "context" .context) }} + {{- if not (empty $valueUsername) -}} + {{- $requiredPassword := dict "valueKey" $valueKeyPassword "secret" .secret "field" "mysql-password" -}} + {{- $requiredPasswords = append $requiredPasswords $requiredPassword -}} + {{- end -}} + + {{- if (eq $architecture "replication") -}} + {{- $requiredReplicationPassword := dict "valueKey" $valueKeyReplicationPassword "secret" .secret "field" "mysql-replication-password" -}} + {{- $requiredPasswords = append $requiredPasswords $requiredReplicationPassword -}} + {{- end -}} + + {{- include "common.validations.values.multiple.empty" (dict "required" $requiredPasswords "context" .context) -}} + + {{- end -}} +{{- end -}} + +{{/* +Auxiliary function to get the right value for existingSecret. + +Usage: +{{ include "common.mysql.values.auth.existingSecret" (dict "context" $) }} +Params: + - subchart - Boolean - Optional. Whether MySQL is used as subchart or not. Default: false +*/}} +{{- define "common.mysql.values.auth.existingSecret" -}} + {{- if .subchart -}} + {{- .context.Values.mysql.auth.existingSecret | quote -}} + {{- else -}} + {{- .context.Values.auth.existingSecret | quote -}} + {{- end -}} +{{- end -}} + +{{/* +Auxiliary function to get the right value for enabled mysql. + +Usage: +{{ include "common.mysql.values.enabled" (dict "context" $) }} +*/}} +{{- define "common.mysql.values.enabled" -}} + {{- if .subchart -}} + {{- printf "%v" .context.Values.mysql.enabled -}} + {{- else -}} + {{- printf "%v" (not .context.Values.enabled) -}} + {{- end -}} +{{- end -}} + +{{/* +Auxiliary function to get the right value for architecture + +Usage: +{{ include "common.mysql.values.architecture" (dict "subchart" "true" "context" $) }} +Params: + - subchart - Boolean - Optional. Whether MySQL is used as subchart or not. Default: false +*/}} +{{- define "common.mysql.values.architecture" -}} + {{- if .subchart -}} + {{- .context.Values.mysql.architecture -}} + {{- else -}} + {{- .context.Values.architecture -}} + {{- end -}} +{{- end -}} + +{{/* +Auxiliary function to get the right value for the key auth + +Usage: +{{ include "common.mysql.values.key.auth" (dict "subchart" "true" "context" $) }} +Params: + - subchart - Boolean - Optional. Whether MySQL is used as subchart or not. Default: false +*/}} +{{- define "common.mysql.values.key.auth" -}} + {{- if .subchart -}} + mysql.auth + {{- else -}} + auth + {{- end -}} +{{- end -}} diff --git a/charts/limesurvey-martial-ingress-v9/charts/mariadb/charts/common/templates/validations/_postgresql.tpl b/charts/limesurvey-martial-ingress-v9/charts/mariadb/charts/common/templates/validations/_postgresql.tpl new file mode 100644 index 0000000..164ec0d --- /dev/null +++ b/charts/limesurvey-martial-ingress-v9/charts/mariadb/charts/common/templates/validations/_postgresql.tpl @@ -0,0 +1,129 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Validate PostgreSQL required passwords are not empty. + +Usage: +{{ include "common.validations.values.postgresql.passwords" (dict "secret" "secretName" "subchart" false "context" $) }} +Params: + - secret - String - Required. Name of the secret where postgresql values are stored, e.g: "postgresql-passwords-secret" + - subchart - Boolean - Optional. Whether postgresql is used as subchart or not. Default: false +*/}} +{{- define "common.validations.values.postgresql.passwords" -}} + {{- $existingSecret := include "common.postgresql.values.existingSecret" . -}} + {{- $enabled := include "common.postgresql.values.enabled" . -}} + {{- $valueKeyPostgresqlPassword := include "common.postgresql.values.key.postgressPassword" . -}} + {{- $valueKeyPostgresqlReplicationEnabled := include "common.postgresql.values.key.replicationPassword" . -}} + {{- if and (or (not $existingSecret) (eq $existingSecret "\"\"")) (eq $enabled "true") -}} + {{- $requiredPasswords := list -}} + {{- $requiredPostgresqlPassword := dict "valueKey" $valueKeyPostgresqlPassword "secret" .secret "field" "postgresql-password" -}} + {{- $requiredPasswords = append $requiredPasswords $requiredPostgresqlPassword -}} + + {{- $enabledReplication := include "common.postgresql.values.enabled.replication" . -}} + {{- if (eq $enabledReplication "true") -}} + {{- $requiredPostgresqlReplicationPassword := dict "valueKey" $valueKeyPostgresqlReplicationEnabled "secret" .secret "field" "postgresql-replication-password" -}} + {{- $requiredPasswords = append $requiredPasswords $requiredPostgresqlReplicationPassword -}} + {{- end -}} + + {{- include "common.validations.values.multiple.empty" (dict "required" $requiredPasswords "context" .context) -}} + {{- end -}} +{{- end -}} + +{{/* +Auxiliary function to decide whether evaluate global values. + +Usage: +{{ include "common.postgresql.values.use.global" (dict "key" "key-of-global" "context" $) }} +Params: + - key - String - Required. Field to be evaluated within global, e.g: "existingSecret" +*/}} +{{- define "common.postgresql.values.use.global" -}} + {{- if .context.Values.global -}} + {{- if .context.Values.global.postgresql -}} + {{- index .context.Values.global.postgresql .key | quote -}} + {{- end -}} + {{- end -}} +{{- end -}} + +{{/* +Auxiliary function to get the right value for existingSecret. + +Usage: +{{ include "common.postgresql.values.existingSecret" (dict "context" $) }} +*/}} +{{- define "common.postgresql.values.existingSecret" -}} + {{- $globalValue := include "common.postgresql.values.use.global" (dict "key" "existingSecret" "context" .context) -}} + + {{- if .subchart -}} + {{- default (.context.Values.postgresql.existingSecret | quote) $globalValue -}} + {{- else -}} + {{- default (.context.Values.existingSecret | quote) $globalValue -}} + {{- end -}} +{{- end -}} + +{{/* +Auxiliary function to get the right value for enabled postgresql. + +Usage: +{{ include "common.postgresql.values.enabled" (dict "context" $) }} +*/}} +{{- define "common.postgresql.values.enabled" -}} + {{- if .subchart -}} + {{- printf "%v" .context.Values.postgresql.enabled -}} + {{- else -}} + {{- printf "%v" (not .context.Values.enabled) -}} + {{- end -}} +{{- end -}} + +{{/* +Auxiliary function to get the right value for the key postgressPassword. + +Usage: +{{ include "common.postgresql.values.key.postgressPassword" (dict "subchart" "true" "context" $) }} +Params: + - subchart - Boolean - Optional. Whether postgresql is used as subchart or not. Default: false +*/}} +{{- define "common.postgresql.values.key.postgressPassword" -}} + {{- $globalValue := include "common.postgresql.values.use.global" (dict "key" "postgresqlUsername" "context" .context) -}} + + {{- if not $globalValue -}} + {{- if .subchart -}} + postgresql.postgresqlPassword + {{- else -}} + postgresqlPassword + {{- end -}} + {{- else -}} + global.postgresql.postgresqlPassword + {{- end -}} +{{- end -}} + +{{/* +Auxiliary function to get the right value for enabled.replication. + +Usage: +{{ include "common.postgresql.values.enabled.replication" (dict "subchart" "true" "context" $) }} +Params: + - subchart - Boolean - Optional. Whether postgresql is used as subchart or not. Default: false +*/}} +{{- define "common.postgresql.values.enabled.replication" -}} + {{- if .subchart -}} + {{- printf "%v" .context.Values.postgresql.replication.enabled -}} + {{- else -}} + {{- printf "%v" .context.Values.replication.enabled -}} + {{- end -}} +{{- end -}} + +{{/* +Auxiliary function to get the right value for the key replication.password. + +Usage: +{{ include "common.postgresql.values.key.replicationPassword" (dict "subchart" "true" "context" $) }} +Params: + - subchart - Boolean - Optional. Whether postgresql is used as subchart or not. Default: false +*/}} +{{- define "common.postgresql.values.key.replicationPassword" -}} + {{- if .subchart -}} + postgresql.replication.password + {{- else -}} + replication.password + {{- end -}} +{{- end -}} diff --git a/charts/limesurvey-martial-ingress-v9/charts/mariadb/charts/common/templates/validations/_redis.tpl b/charts/limesurvey-martial-ingress-v9/charts/mariadb/charts/common/templates/validations/_redis.tpl new file mode 100644 index 0000000..dcccfc1 --- /dev/null +++ b/charts/limesurvey-martial-ingress-v9/charts/mariadb/charts/common/templates/validations/_redis.tpl @@ -0,0 +1,76 @@ + +{{/* vim: set filetype=mustache: */}} +{{/* +Validate Redis® required passwords are not empty. + +Usage: +{{ include "common.validations.values.redis.passwords" (dict "secret" "secretName" "subchart" false "context" $) }} +Params: + - secret - String - Required. Name of the secret where redis values are stored, e.g: "redis-passwords-secret" + - subchart - Boolean - Optional. Whether redis is used as subchart or not. Default: false +*/}} +{{- define "common.validations.values.redis.passwords" -}} + {{- $enabled := include "common.redis.values.enabled" . -}} + {{- $valueKeyPrefix := include "common.redis.values.keys.prefix" . -}} + {{- $standarizedVersion := include "common.redis.values.standarized.version" . }} + + {{- $existingSecret := ternary (printf "%s%s" $valueKeyPrefix "auth.existingSecret") (printf "%s%s" $valueKeyPrefix "existingSecret") (eq $standarizedVersion "true") }} + {{- $existingSecretValue := include "common.utils.getValueFromKey" (dict "key" $existingSecret "context" .context) }} + + {{- $valueKeyRedisPassword := ternary (printf "%s%s" $valueKeyPrefix "auth.password") (printf "%s%s" $valueKeyPrefix "password") (eq $standarizedVersion "true") }} + {{- $valueKeyRedisUseAuth := ternary (printf "%s%s" $valueKeyPrefix "auth.enabled") (printf "%s%s" $valueKeyPrefix "usePassword") (eq $standarizedVersion "true") }} + + {{- if and (or (not $existingSecret) (eq $existingSecret "\"\"")) (eq $enabled "true") -}} + {{- $requiredPasswords := list -}} + + {{- $useAuth := include "common.utils.getValueFromKey" (dict "key" $valueKeyRedisUseAuth "context" .context) -}} + {{- if eq $useAuth "true" -}} + {{- $requiredRedisPassword := dict "valueKey" $valueKeyRedisPassword "secret" .secret "field" "redis-password" -}} + {{- $requiredPasswords = append $requiredPasswords $requiredRedisPassword -}} + {{- end -}} + + {{- include "common.validations.values.multiple.empty" (dict "required" $requiredPasswords "context" .context) -}} + {{- end -}} +{{- end -}} + +{{/* +Auxiliary function to get the right value for enabled redis. + +Usage: +{{ include "common.redis.values.enabled" (dict "context" $) }} +*/}} +{{- define "common.redis.values.enabled" -}} + {{- if .subchart -}} + {{- printf "%v" .context.Values.redis.enabled -}} + {{- else -}} + {{- printf "%v" (not .context.Values.enabled) -}} + {{- end -}} +{{- end -}} + +{{/* +Auxiliary function to get the right prefix path for the values + +Usage: +{{ include "common.redis.values.key.prefix" (dict "subchart" "true" "context" $) }} +Params: + - subchart - Boolean - Optional. Whether redis is used as subchart or not. Default: false +*/}} +{{- define "common.redis.values.keys.prefix" -}} + {{- if .subchart -}}redis.{{- else -}}{{- end -}} +{{- end -}} + +{{/* +Checks whether the redis chart's includes the standarizations (version >= 14) + +Usage: +{{ include "common.redis.values.standarized.version" (dict "context" $) }} +*/}} +{{- define "common.redis.values.standarized.version" -}} + + {{- $standarizedAuth := printf "%s%s" (include "common.redis.values.keys.prefix" .) "auth" -}} + {{- $standarizedAuthValues := include "common.utils.getValueFromKey" (dict "key" $standarizedAuth "context" .context) }} + + {{- if $standarizedAuthValues -}} + {{- true -}} + {{- end -}} +{{- end -}} diff --git a/charts/limesurvey-martial-ingress-v9/charts/mariadb/charts/common/templates/validations/_validations.tpl b/charts/limesurvey-martial-ingress-v9/charts/mariadb/charts/common/templates/validations/_validations.tpl new file mode 100644 index 0000000..9a814cf --- /dev/null +++ b/charts/limesurvey-martial-ingress-v9/charts/mariadb/charts/common/templates/validations/_validations.tpl @@ -0,0 +1,46 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Validate values must not be empty. + +Usage: +{{- $validateValueConf00 := (dict "valueKey" "path.to.value" "secret" "secretName" "field" "password-00") -}} +{{- $validateValueConf01 := (dict "valueKey" "path.to.value" "secret" "secretName" "field" "password-01") -}} +{{ include "common.validations.values.empty" (dict "required" (list $validateValueConf00 $validateValueConf01) "context" $) }} + +Validate value params: + - valueKey - String - Required. The path to the validating value in the values.yaml, e.g: "mysql.password" + - secret - String - Optional. Name of the secret where the validating value is generated/stored, e.g: "mysql-passwords-secret" + - field - String - Optional. Name of the field in the secret data, e.g: "mysql-password" +*/}} +{{- define "common.validations.values.multiple.empty" -}} + {{- range .required -}} + {{- include "common.validations.values.single.empty" (dict "valueKey" .valueKey "secret" .secret "field" .field "context" $.context) -}} + {{- end -}} +{{- end -}} + +{{/* +Validate a value must not be empty. + +Usage: +{{ include "common.validations.value.empty" (dict "valueKey" "mariadb.password" "secret" "secretName" "field" "my-password" "subchart" "subchart" "context" $) }} + +Validate value params: + - valueKey - String - Required. The path to the validating value in the values.yaml, e.g: "mysql.password" + - secret - String - Optional. Name of the secret where the validating value is generated/stored, e.g: "mysql-passwords-secret" + - field - String - Optional. Name of the field in the secret data, e.g: "mysql-password" + - subchart - String - Optional - Name of the subchart that the validated password is part of. +*/}} +{{- define "common.validations.values.single.empty" -}} + {{- $value := include "common.utils.getValueFromKey" (dict "key" .valueKey "context" .context) }} + {{- $subchart := ternary "" (printf "%s." .subchart) (empty .subchart) }} + + {{- if not $value -}} + {{- $varname := "my-value" -}} + {{- $getCurrentValue := "" -}} + {{- if and .secret .field -}} + {{- $varname = include "common.utils.fieldToEnvVar" . -}} + {{- $getCurrentValue = printf " To get the current value:\n\n %s\n" (include "common.utils.secret.getvalue" .) -}} + {{- end -}} + {{- printf "\n '%s' must not be empty, please add '--set %s%s=$%s' to the command.%s" .valueKey $subchart .valueKey $varname $getCurrentValue -}} + {{- end -}} +{{- end -}} diff --git a/charts/limesurvey-martial-ingress-v9/charts/mariadb/charts/common/values.yaml b/charts/limesurvey-martial-ingress-v9/charts/mariadb/charts/common/values.yaml new file mode 100644 index 0000000..f2df68e --- /dev/null +++ b/charts/limesurvey-martial-ingress-v9/charts/mariadb/charts/common/values.yaml @@ -0,0 +1,5 @@ +## bitnami/common +## It is required by CI/CD tools and processes. +## @skip exampleValue +## +exampleValue: common-chart diff --git a/charts/limesurvey-martial-ingress-v9/charts/mariadb/templates/NOTES.txt b/charts/limesurvey-martial-ingress-v9/charts/mariadb/templates/NOTES.txt new file mode 100644 index 0000000..c1039e6 --- /dev/null +++ b/charts/limesurvey-martial-ingress-v9/charts/mariadb/templates/NOTES.txt @@ -0,0 +1,75 @@ +CHART NAME: {{ .Chart.Name }} +CHART VERSION: {{ .Chart.Version }} +APP VERSION: {{ .Chart.AppVersion }} + +** Please be patient while the chart is being deployed ** + +{{- if .Values.diagnosticMode.enabled }} +The chart has been deployed in diagnostic mode. All probes have been disabled and the command has been overwritten with: + + command: {{- include "common.tplvalues.render" (dict "value" .Values.diagnosticMode.command "context" $) | nindent 4 }} + args: {{- include "common.tplvalues.render" (dict "value" .Values.diagnosticMode.args "context" $) | nindent 4 }} + +Get the list of pods by executing: + + kubectl get pods --namespace {{ .Release.Namespace }} -l app.kubernetes.io/instance={{ .Release.Name }} + +Access the pod you want to debug by executing + + kubectl exec --namespace {{ .Release.Namespace }} -ti -- bash + +In order to replicate the container startup scripts execute this command: + + /opt/bitnami/scripts/mariadb/entrypoint.sh /opt/bitnami/scripts/mariadb/run.sh + +{{- else }} + +Tip: + + Watch the deployment status using the command: kubectl get pods -w --namespace {{ .Release.Namespace }} -l app.kubernetes.io/instance={{ .Release.Name }} + +Services: + + echo Primary: {{ include "mariadb.primary.fullname" . }}.{{ .Release.Namespace }}.svc.{{ .Values.clusterDomain }}:{{ coalesce .Values.primary.service.ports.mysql .Values.primary.service.port }} +{{- if eq .Values.architecture "replication" }} + echo Secondary: {{ include "mariadb.secondary.fullname" . }}.{{ .Release.Namespace }}.svc.{{ .Values.clusterDomain }}:{{ coalesce .Values.secondary.service.ports.mysql .Values.secondary.service.port }} +{{- end }} + +Administrator credentials: + + Username: root + Password : $(kubectl get secret --namespace {{ .Release.Namespace }} {{ template "mariadb.secretName" . }} -o jsonpath="{.data.mariadb-root-password}" | base64 -d) + +To connect to your database: + + 1. Run a pod that you can use as a client: + + kubectl run {{ include "common.names.fullname" . }}-client --rm --tty -i --restart='Never' --image {{ template "mariadb.image" . }} --namespace {{ .Release.Namespace }} --command -- bash + + 2. To connect to primary service (read/write): + + mysql -h {{ include "mariadb.primary.fullname" . }}.{{ .Release.Namespace }}.svc.{{ .Values.clusterDomain }} -uroot -p {{ .Values.auth.database }} + +{{- if eq .Values.architecture "replication" }} + + 3. To connect to secondary service (read-only): + + mysql -h {{ include "mariadb.secondary.fullname" . }}.{{ .Release.Namespace }}.svc.{{ .Values.clusterDomain }} -uroot -p {{ .Values.auth.database }} +{{- end }} + +To upgrade this helm chart: + + 1. Obtain the password as described on the 'Administrator credentials' section and set the 'auth.rootPassword' parameter as shown below: + + ROOT_PASSWORD=$(kubectl get secret --namespace {{ .Release.Namespace }} {{ template "mariadb.secretName" . }} -o jsonpath="{.data.mariadb-root-password}" | base64 -d) + helm upgrade --namespace {{ .Release.Namespace }} {{ .Release.Name }} my-repo/mariadb --set auth.rootPassword=$ROOT_PASSWORD + +{{- include "common.warnings.rollingTag" .Values.image }} +{{- include "common.warnings.rollingTag" .Values.metrics.image }} +{{- include "common.warnings.rollingTag" .Values.volumePermissions.image }} +{{- include "mariadb.validateValues" . }} +{{- if not .Values.auth.customPasswordFiles -}} + {{- $passwordValidationErrors := include "common.validations.values.mariadb.passwords" (dict "secret" (include "common.names.fullname" .) "context" $) -}} + {{- include "common.errors.upgrade.passwords.empty" (dict "validationErrors" (list $passwordValidationErrors) "context" $) -}} +{{- end }} +{{- end }} diff --git a/charts/limesurvey-martial-ingress-v9/charts/mariadb/templates/_helpers.tpl b/charts/limesurvey-martial-ingress-v9/charts/mariadb/templates/_helpers.tpl new file mode 100644 index 0000000..5a67bd5 --- /dev/null +++ b/charts/limesurvey-martial-ingress-v9/charts/mariadb/templates/_helpers.tpl @@ -0,0 +1,149 @@ +{{/* vim: set filetype=mustache: */}} + +{{- define "mariadb.primary.fullname" -}} +{{- if eq .Values.architecture "replication" }} +{{- printf "%s-%s" (include "common.names.fullname" .) .Values.primary.name | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- include "common.names.fullname" . -}} +{{- end -}} +{{- end -}} + +{{- define "mariadb.secondary.fullname" -}} +{{- printf "%s-%s" (include "common.names.fullname" .) .Values.secondary.name | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Return the proper MariaDB image name +*/}} +{{- define "mariadb.image" -}} +{{ include "common.images.image" (dict "imageRoot" .Values.image "global" .Values.global) }} +{{- end -}} + +{{/* +Return the proper metrics image name +*/}} +{{- define "mariadb.metrics.image" -}} +{{ include "common.images.image" (dict "imageRoot" .Values.metrics.image "global" .Values.global) }} +{{- end -}} + +{{/* +Return the proper image name (for the init container volume-permissions image) +*/}} +{{- define "mariadb.volumePermissions.image" -}} +{{ include "common.images.image" (dict "imageRoot" .Values.volumePermissions.image "global" .Values.global) }} +{{- end -}} + +{{/* +Return the proper Docker Image Registry Secret Names +*/}} +{{- define "mariadb.imagePullSecrets" -}} +{{ include "common.images.pullSecrets" (dict "images" (list .Values.image .Values.metrics.image .Values.volumePermissions.image) "global" .Values.global) }} +{{- end -}} + +{{ template "mariadb.initdbScriptsCM" . }} +{{/* +Get the initialization scripts ConfigMap name. +*/}} +{{- define "mariadb.initdbScriptsCM" -}} +{{- if .Values.initdbScriptsConfigMap -}} +{{- printf "%s" .Values.initdbScriptsConfigMap -}} +{{- else -}} +{{- printf "%s-init-scripts" (include "mariadb.primary.fullname" .) -}} +{{- end -}} +{{- end -}} + +{{/* +Create the name of the service account to use +*/}} +{{- define "mariadb.serviceAccountName" -}} +{{- if .Values.serviceAccount.create -}} + {{ default (include "common.names.fullname" .) .Values.serviceAccount.name }} +{{- else -}} + {{ default "default" .Values.serviceAccount.name }} +{{- end -}} +{{- end -}} + +{{/* +Return the configmap with the MariaDB Primary configuration +*/}} +{{- define "mariadb.primary.configmapName" -}} +{{- if .Values.primary.existingConfigmap -}} + {{- printf "%s" (tpl .Values.primary.existingConfigmap $) -}} +{{- else -}} + {{- printf "%s" (include "mariadb.primary.fullname" .) -}} +{{- end -}} +{{- end -}} + +{{/* +Return true if a configmap object should be created for MariaDB Secondary +*/}} +{{- define "mariadb.primary.createConfigmap" -}} +{{- if and .Values.primary.configuration (not .Values.primary.existingConfigmap) }} + {{- true -}} +{{- else -}} +{{- end -}} +{{- end -}} + +{{/* +Return the configmap with the MariaDB Primary configuration +*/}} +{{- define "mariadb.secondary.configmapName" -}} +{{- if .Values.secondary.existingConfigmap -}} + {{- printf "%s" (tpl .Values.secondary.existingConfigmap $) -}} +{{- else -}} + {{- printf "%s" (include "mariadb.secondary.fullname" .) -}} +{{- end -}} +{{- end -}} + +{{/* +Return true if a configmap object should be created for MariaDB Secondary +*/}} +{{- define "mariadb.secondary.createConfigmap" -}} +{{- if and (eq .Values.architecture "replication") .Values.secondary.configuration (not .Values.secondary.existingConfigmap) }} + {{- true -}} +{{- else -}} +{{- end -}} +{{- end -}} + +{{/* +Return the secret with MariaDB credentials +*/}} +{{- define "mariadb.secretName" -}} + {{- if .Values.auth.existingSecret -}} + {{- printf "%s" .Values.auth.existingSecret -}} + {{- else -}} + {{- printf "%s" (include "common.names.fullname" .) -}} + {{- end -}} +{{- end -}} + +{{/* +Return true if a secret object should be created for MariaDB +*/}} +{{- define "mariadb.createSecret" -}} +{{- if not (or .Values.auth.existingSecret .Values.auth.customPasswordFiles) }} + {{- true -}} +{{- end -}} +{{- end -}} + +{{/* +Compile all warnings into a single message, and call fail. +*/}} +{{- define "mariadb.validateValues" -}} +{{- $messages := list -}} +{{- $messages := append $messages (include "mariadb.validateValues.architecture" .) -}} +{{- $messages := without $messages "" -}} +{{- $message := join "\n" $messages -}} + +{{- if $message -}} +{{- printf "\nVALUES VALIDATION:\n%s" $message | fail -}} +{{- end -}} +{{- end -}} + +{{/* Validate values of MariaDB - must provide a valid architecture */}} +{{- define "mariadb.validateValues.architecture" -}} +{{- if and (ne .Values.architecture "standalone") (ne .Values.architecture "replication") -}} +mariadb: architecture + Invalid architecture selected. Valid values are "standalone" and + "replication". Please set a valid architecture (--set architecture="xxxx") +{{- end -}} +{{- end -}} diff --git a/charts/limesurvey-martial-ingress-v9/charts/mariadb/templates/extra-list.yaml b/charts/limesurvey-martial-ingress-v9/charts/mariadb/templates/extra-list.yaml new file mode 100644 index 0000000..9ac65f9 --- /dev/null +++ b/charts/limesurvey-martial-ingress-v9/charts/mariadb/templates/extra-list.yaml @@ -0,0 +1,4 @@ +{{- range .Values.extraDeploy }} +--- +{{ include "common.tplvalues.render" (dict "value" . "context" $) }} +{{- end }} diff --git a/charts/limesurvey-martial-ingress-v9/charts/mariadb/templates/networkpolicy-egress.yaml b/charts/limesurvey-martial-ingress-v9/charts/mariadb/templates/networkpolicy-egress.yaml new file mode 100644 index 0000000..84f5d83 --- /dev/null +++ b/charts/limesurvey-martial-ingress-v9/charts/mariadb/templates/networkpolicy-egress.yaml @@ -0,0 +1,33 @@ +{{- if and .Values.networkPolicy.enabled (or .Values.networkPolicy.egressRules.denyConnectionsToExternal .Values.networkPolicy.egressRules.customRules) }} +apiVersion: {{ include "common.capabilities.networkPolicy.apiVersion" . }} +kind: NetworkPolicy +metadata: + name: {{ printf "%s-egress" (include "common.names.fullname" .) }} + namespace: {{ .Release.Namespace | quote }} + labels: {{- include "common.labels.standard" . | nindent 4 }} + {{- if .Values.commonLabels }} + {{- include "common.tplvalues.render" ( dict "value" .Values.commonLabels "context" $ ) | nindent 4 }} + {{- end }} + {{- if .Values.commonAnnotations }} + annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} + {{- end }} +spec: + podSelector: + matchLabels: + {{- include "common.labels.standard" . | nindent 6 }} + policyTypes: + - Egress + egress: + {{- if .Values.networkPolicy.egressRules.denyConnectionsToExternal }} + - ports: + - port: 53 + protocol: UDP + - port: 53 + protocol: TCP + - to: + - namespaceSelector: {} + {{- end }} + {{- if .Values.networkPolicy.egressRules.customRules }} + {{- include "common.tplvalues.render" (dict "value" .Values.networkPolicy.egressRules.customRules "context" $) | nindent 4 }} + {{- end }} +{{- end }} diff --git a/charts/limesurvey-martial-ingress-v9/charts/mariadb/templates/primary/configmap.yaml b/charts/limesurvey-martial-ingress-v9/charts/mariadb/templates/primary/configmap.yaml new file mode 100644 index 0000000..ae4d5b1 --- /dev/null +++ b/charts/limesurvey-martial-ingress-v9/charts/mariadb/templates/primary/configmap.yaml @@ -0,0 +1,18 @@ +{{- if (include "mariadb.primary.createConfigmap" .) }} +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ include "mariadb.primary.fullname" . }} + namespace: {{ .Release.Namespace | quote }} + labels: {{- include "common.labels.standard" . | nindent 4 }} + app.kubernetes.io/component: primary + {{- if .Values.commonLabels }} + {{- include "common.tplvalues.render" ( dict "value" .Values.commonLabels "context" $ ) | nindent 4 }} + {{- end }} + {{- if .Values.commonAnnotations }} + annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} + {{- end }} +data: + my.cnf: |- +{{ .Values.primary.configuration | indent 4 }} +{{- end -}} diff --git a/charts/limesurvey-martial-ingress-v9/charts/mariadb/templates/primary/initialization-configmap.yaml b/charts/limesurvey-martial-ingress-v9/charts/mariadb/templates/primary/initialization-configmap.yaml new file mode 100644 index 0000000..f85903c --- /dev/null +++ b/charts/limesurvey-martial-ingress-v9/charts/mariadb/templates/primary/initialization-configmap.yaml @@ -0,0 +1,11 @@ +{{- if and .Values.initdbScripts (not .Values.initdbScriptsConfigMap) }} +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ printf "%s-init-scripts" (include "mariadb.primary.fullname" .) }} + namespace: {{ .Release.Namespace | quote }} + labels: {{- include "common.labels.standard" . | nindent 4 }} + app.kubernetes.io/component: primary +data: +{{- include "common.tplvalues.render" (dict "value" .Values.initdbScripts "context" .) | nindent 2 }} +{{ end }} diff --git a/charts/limesurvey-martial-ingress-v9/charts/mariadb/templates/primary/networkpolicy-ingress.yaml b/charts/limesurvey-martial-ingress-v9/charts/mariadb/templates/primary/networkpolicy-ingress.yaml new file mode 100644 index 0000000..125d0dd --- /dev/null +++ b/charts/limesurvey-martial-ingress-v9/charts/mariadb/templates/primary/networkpolicy-ingress.yaml @@ -0,0 +1,56 @@ +{{- if and .Values.networkPolicy.enabled (or .Values.networkPolicy.metrics.enabled .Values.networkPolicy.ingressRules.primaryAccessOnlyFrom.enabled) }} +apiVersion: {{ include "common.capabilities.networkPolicy.apiVersion" . }} +kind: NetworkPolicy +metadata: + name: {{ printf "%s-ingress" (include "common.names.fullname" .) }} + namespace: {{ .Release.Namespace | quote }} + labels: {{- include "common.labels.standard" . | nindent 4 }} + {{- if .Values.commonLabels }} + {{- include "common.tplvalues.render" ( dict "value" .Values.commonLabels "context" $ ) | nindent 4 }} + {{- end }} + {{- if .Values.commonAnnotations }} + annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} + {{- end }} +spec: + podSelector: + matchLabels: + app.kubernetes.io/component: primary + {{- include "common.labels.standard" . | nindent 6 }} + ingress: + {{- if and .Values.metrics.enabled .Values.networkPolicy.metrics.enabled (or .Values.networkPolicy.metrics.namespaceSelector .Values.networkPolicy.metrics.podSelector) }} + - from: + {{- if .Values.networkPolicy.metrics.namespaceSelector }} + - namespaceSelector: + matchLabels: + {{- include "common.tplvalues.render" (dict "value" .Values.networkPolicy.metrics.namespaceSelector "context" $) | nindent 14 }} + {{- end }} + {{- if .Values.networkPolicy.metrics.podSelector }} + - podSelector: + matchLabels: + {{- include "common.tplvalues.render" (dict "value" .Values.networkPolicy.metrics.podSelector "context" $) | nindent 14 }} + {{- end }} + {{- end }} + {{- if and .Values.networkPolicy.ingressRules.primaryAccessOnlyFrom.enabled (or .Values.networkPolicy.ingressRules.primaryAccessOnlyFrom.namespaceSelector .Values.networkPolicy.ingressRules.primaryAccessOnlyFrom.podSelector) }} + - from: + {{- if .Values.networkPolicy.ingressRules.primaryAccessOnlyFrom.namespaceSelector }} + - namespaceSelector: + matchLabels: + {{- include "common.tplvalues.render" (dict "value" .Values.networkPolicy.ingressRules.primaryAccessOnlyFrom.namespaceSelector "context" $) | nindent 14 }} + {{- end }} + {{- if .Values.networkPolicy.ingressRules.primaryAccessOnlyFrom.podSelector }} + - podSelector: + matchLabels: + {{- include "common.tplvalues.render" (dict "value" .Values.networkPolicy.ingressRules.primaryAccessOnlyFrom.podSelector "context" $) | nindent 14 }} + {{- end }} + {{- end }} + {{- if and .Values.networkPolicy.ingressRules.primaryAccessOnlyFrom.enabled (eq .Values.architecture "replication") }} + - from: + - podSelector: + matchLabels: + app.kubernetes.io/component: secondary + {{- include "common.labels.standard" . | nindent 14 }} + {{- end }} + {{- if .Values.networkPolicy.ingressRules.primaryAccessOnlyFrom.customRules }} + {{- include "common.tplvalues.render" (dict "value" .Values.networkPolicy.ingressRules.primaryAccessOnlyFrom.customRules "context" $) | nindent 4 }} + {{- end }} +{{- end }} diff --git a/charts/limesurvey-martial-ingress-v9/charts/mariadb/templates/primary/pdb.yaml b/charts/limesurvey-martial-ingress-v9/charts/mariadb/templates/primary/pdb.yaml new file mode 100644 index 0000000..d923058 --- /dev/null +++ b/charts/limesurvey-martial-ingress-v9/charts/mariadb/templates/primary/pdb.yaml @@ -0,0 +1,25 @@ +{{- if .Values.primary.pdb.create }} +apiVersion: {{ include "common.capabilities.policy.apiVersion" . }} +kind: PodDisruptionBudget +metadata: + name: {{ include "mariadb.primary.fullname" . }} + namespace: {{ .Release.Namespace | quote }} + labels: {{- include "common.labels.standard" . | nindent 4 }} + app.kubernetes.io/component: primary + {{- if .Values.commonLabels }} + {{- include "common.tplvalues.render" ( dict "value" .Values.commonLabels "context" $ ) | nindent 4 }} + {{- end }} + {{- if .Values.commonAnnotations }} + annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} + {{- end }} +spec: + {{- if .Values.primary.pdb.minAvailable }} + minAvailable: {{ .Values.primary.pdb.minAvailable }} + {{- end }} + {{- if .Values.primary.pdb.maxUnavailable }} + maxUnavailable: {{ .Values.primary.pdb.maxUnavailable }} + {{- end }} + selector: + matchLabels: {{ include "common.labels.matchLabels" . | nindent 6 }} + app.kubernetes.io/component: primary +{{- end }} diff --git a/charts/limesurvey-martial-ingress-v9/charts/mariadb/templates/primary/statefulset.yaml b/charts/limesurvey-martial-ingress-v9/charts/mariadb/templates/primary/statefulset.yaml new file mode 100644 index 0000000..fd26089 --- /dev/null +++ b/charts/limesurvey-martial-ingress-v9/charts/mariadb/templates/primary/statefulset.yaml @@ -0,0 +1,394 @@ +apiVersion: {{ include "common.capabilities.statefulset.apiVersion" . }} +kind: StatefulSet +metadata: + name: {{ include "mariadb.primary.fullname" . }} + namespace: {{ .Release.Namespace | quote }} + labels: {{- include "common.labels.standard" . | nindent 4 }} + app.kubernetes.io/component: primary + {{- if .Values.commonLabels }} + {{- include "common.tplvalues.render" ( dict "value" .Values.commonLabels "context" $ ) | nindent 4 }} + {{- end }} + {{- if .Values.commonAnnotations }} + annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} + {{- end }} +spec: + replicas: 1 + revisionHistoryLimit: {{ .Values.primary.revisionHistoryLimit }} + selector: + matchLabels: {{ include "common.labels.matchLabels" . | nindent 6 }} + app.kubernetes.io/component: primary + serviceName: {{ include "mariadb.primary.fullname" . }} + {{- if .Values.primary.updateStrategy }} + updateStrategy: {{- toYaml .Values.primary.updateStrategy | nindent 4 }} + {{- end }} + template: + metadata: + annotations: + {{- if (include "mariadb.primary.createConfigmap" .) }} + checksum/configuration: {{ include (print $.Template.BasePath "/primary/configmap.yaml") . | sha256sum }} + {{- end }} + {{- if .Values.primary.podAnnotations }} + {{- include "common.tplvalues.render" (dict "value" .Values.primary.podAnnotations "context" $) | nindent 8 }} + {{- end }} + labels: {{- include "common.labels.standard" . | nindent 8 }} + app.kubernetes.io/component: primary + {{- if .Values.primary.podLabels }} + {{- include "common.tplvalues.render" (dict "value" .Values.primary.podLabels "context" $) | nindent 8 }} + {{- end }} + {{- if .Values.commonLabels }} + {{- include "common.tplvalues.render" ( dict "value" .Values.commonLabels "context" $ ) | nindent 8 }} + {{- end }} + spec: + {{- include "mariadb.imagePullSecrets" . | nindent 6 }} + {{- if .Values.primary.hostAliases }} + hostAliases: {{- include "common.tplvalues.render" (dict "value" .Values.primary.hostAliases "context" $) | nindent 8 }} + {{- end }} + {{- if or .Values.primary.schedulerName .Values.schedulerName }} + schedulerName: {{ (coalesce .Values.primary.schedulerName .Values.schedulerName) | quote }} + {{- end }} + serviceAccountName: {{ template "mariadb.serviceAccountName" . }} + {{- if .Values.primary.affinity }} + affinity: {{- include "common.tplvalues.render" (dict "value" .Values.primary.affinity "context" $) | nindent 8 }} + {{- else }} + affinity: + podAffinity: {{- include "common.affinities.pods" (dict "type" .Values.primary.podAffinityPreset "component" "primary" "context" $) | nindent 10 }} + podAntiAffinity: {{- include "common.affinities.pods" (dict "type" .Values.primary.podAntiAffinityPreset "component" "primary" "context" $) | nindent 10 }} + nodeAffinity: {{- include "common.affinities.nodes" (dict "type" .Values.primary.nodeAffinityPreset.type "key" .Values.primary.nodeAffinityPreset.key "values" .Values.primary.nodeAffinityPreset.values) | nindent 10 }} + {{- end }} + {{- if .Values.primary.nodeSelector }} + nodeSelector: {{- include "common.tplvalues.render" (dict "value" .Values.primary.nodeSelector "context" $) | nindent 8 }} + {{- end }} + {{- if .Values.primary.tolerations }} + tolerations: {{- include "common.tplvalues.render" (dict "value" .Values.primary.tolerations "context" $) | nindent 8 }} + {{- end }} + {{- if .Values.primary.schedulerName }} + schedulerName: {{ .Values.primary.schedulerName }} + {{- end }} + {{- if .Values.primary.topologySpreadConstraints }} + topologySpreadConstraints: {{- include "common.tplvalues.render" (dict "value" .Values.primary.topologySpreadConstraints "context" $) | nindent 8 }} + {{- end }} + {{- if .Values.primary.priorityClassName }} + priorityClassName: {{ .Values.primary.priorityClassName | quote }} + {{- else if .Values.priorityClassName }} + priorityClassName: {{ .Values.priorityClassName | quote }} + {{- end }} + {{- if .Values.primary.runtimeClassName }} + runtimeClassName: {{ .Values.primary.runtimeClassName | quote }} + {{- else if .Values.runtimeClassName }} + runtimeClassName: {{ .Values.runtimeClassName | quote }} + {{- end }} + {{- if .Values.primary.podSecurityContext.enabled }} + securityContext: {{- omit .Values.primary.podSecurityContext "enabled" | toYaml | nindent 8 }} + {{- end }} + {{- if or .Values.primary.initContainers (and .Values.primary.podSecurityContext.enabled .Values.volumePermissions.enabled .Values.primary.persistence.enabled) }} + initContainers: + {{- if .Values.primary.initContainers }} + {{- include "common.tplvalues.render" (dict "value" .Values.primary.initContainers "context" $) | nindent 8 }} + {{- end }} + {{- if and .Values.primary.podSecurityContext.enabled .Values.volumePermissions.enabled .Values.primary.persistence.enabled }} + - name: volume-permissions + image: {{ include "mariadb.volumePermissions.image" . }} + imagePullPolicy: {{ .Values.volumePermissions.image.pullPolicy | quote }} + command: + - /bin/bash + - -ec + - | + chown -R {{ .Values.primary.containerSecurityContext.runAsUser }}:{{ .Values.primary.podSecurityContext.fsGroup }} /bitnami/mariadb + securityContext: + runAsUser: 0 + {{- if .Values.volumePermissions.resources }} + resources: {{- toYaml .Values.volumePermissions.resources | nindent 12 }} + {{- end }} + volumeMounts: + - name: data + mountPath: /bitnami/mariadb + {{- if .Values.primary.persistence.subPath }} + subPath: {{ .Values.primary.persistence.subPath }} + {{- end }} + {{- end }} + {{- end }} + containers: + - name: mariadb + image: {{ include "mariadb.image" . }} + imagePullPolicy: {{ .Values.image.pullPolicy | quote }} + {{- if .Values.primary.containerSecurityContext.enabled }} + securityContext: {{- omit .Values.primary.containerSecurityContext "enabled" | toYaml | nindent 12 }} + {{- end }} + {{- if .Values.diagnosticMode.enabled }} + command: {{- include "common.tplvalues.render" (dict "value" .Values.diagnosticMode.command "context" $) | nindent 12 }} + {{- else if .Values.primary.command }} + command: {{- include "common.tplvalues.render" (dict "value" .Values.primary.command "context" $) | nindent 12 }} + {{- end }} + {{- if .Values.diagnosticMode.enabled }} + args: {{- include "common.tplvalues.render" (dict "value" .Values.diagnosticMode.args "context" $) | nindent 12 }} + {{- else if .Values.primary.args }} + args: {{- include "common.tplvalues.render" (dict "value" .Values.primary.args "context" $) | nindent 12 }} + {{- end }} + {{- if .Values.primary.lifecycleHooks }} + lifecycle: {{- include "common.tplvalues.render" (dict "value" .Values.primary.lifecycleHooks "context" $) | nindent 12 }} + {{- end }} + env: + - name: BITNAMI_DEBUG + value: {{ ternary "true" "false" (or .Values.image.debug .Values.diagnosticMode.enabled) | quote }} + {{- if .Values.auth.usePasswordFiles }} + - name: MARIADB_ROOT_PASSWORD_FILE + value: {{ default "/opt/bitnami/mariadb/secrets/mariadb-root-password" .Values.auth.customPasswordFiles.root }} + {{- else }} + - name: MARIADB_ROOT_PASSWORD + valueFrom: + secretKeyRef: + name: {{ template "mariadb.secretName" . }} + key: mariadb-root-password + {{- end }} + {{- if not (empty .Values.auth.username) }} + - name: MARIADB_USER + value: {{ .Values.auth.username | quote }} + {{- if .Values.auth.usePasswordFiles }} + - name: MARIADB_PASSWORD_FILE + value: {{ default "/opt/bitnami/mariadb/secrets/mariadb-password" .Values.auth.customPasswordFiles.user }} + {{- else }} + - name: MARIADB_PASSWORD + valueFrom: + secretKeyRef: + name: {{ template "mariadb.secretName" . }} + key: mariadb-password + {{- end }} + {{- end }} + - name: MARIADB_DATABASE + value: {{ .Values.auth.database | quote }} + {{- if eq .Values.architecture "replication" }} + - name: MARIADB_REPLICATION_MODE + value: "master" + - name: MARIADB_REPLICATION_USER + value: {{ .Values.auth.replicationUser | quote }} + {{- if .Values.auth.usePasswordFiles }} + - name: MARIADB_REPLICATION_PASSWORD_FILE + value: {{ default "/opt/bitnami/mariadb/secrets/mariadb-replication-password" .Values.auth.customPasswordFiles.replicator }} + {{- else }} + - name: MARIADB_REPLICATION_PASSWORD + valueFrom: + secretKeyRef: + name: {{ template "mariadb.secretName" . }} + key: mariadb-replication-password + {{- end }} + {{- end }} + {{- if .Values.primary.extraFlags }} + - name: MARIADB_EXTRA_FLAGS + value: "{{ .Values.primary.extraFlags }}" + {{- end }} + {{- if .Values.primary.startupWaitOptions }} + - name: MARIADB_STARTUP_WAIT_RETRIES + value: "{{ .Values.primary.startupWaitOptions.retries | default 300 }}" + - name: MARIADB_STARTUP_WAIT_SLEEP_TIME + value: "{{ .Values.primary.startupWaitOptions.sleepTime | default 2 }}" + {{- end }} + {{- if .Values.primary.extraEnvVars }} + {{- include "common.tplvalues.render" (dict "value" .Values.primary.extraEnvVars "context" $) | nindent 12 }} + {{- end }} + {{- if or .Values.primary.extraEnvVarsCM .Values.primary.extraEnvVarsSecret }} + envFrom: + {{- if .Values.primary.extraEnvVarsCM }} + - configMapRef: + name: {{ .Values.primary.extraEnvVarsCM }} + {{- end }} + {{- if .Values.primary.extraEnvVarsSecret }} + - secretRef: + name: {{ .Values.primary.extraEnvVarsSecret }} + {{- end }} + {{- end }} + ports: + - name: mysql + containerPort: 3306 + {{- if not .Values.diagnosticMode.enabled }} + {{- if .Values.primary.customStartupProbe }} + startupProbe: {{- include "common.tplvalues.render" (dict "value" .Values.primary.customStartupProbe "context" $) | nindent 12 }} + {{- else if .Values.primary.startupProbe.enabled }} + startupProbe: {{- omit .Values.primary.startupProbe "enabled" | toYaml | nindent 12 }} + exec: + command: + - /bin/bash + - -ec + - | + password_aux="${MARIADB_ROOT_PASSWORD:-}" + if [[ -f "${MARIADB_ROOT_PASSWORD_FILE:-}" ]]; then + password_aux=$(cat "$MARIADB_ROOT_PASSWORD_FILE") + fi + mysqladmin status -uroot -p"${password_aux}" + {{- end }} + {{- if .Values.primary.customLivenessProbe }} + livenessProbe: {{- include "common.tplvalues.render" (dict "value" .Values.primary.customLivenessProbe "context" $) | nindent 12 }} + {{- else if .Values.primary.livenessProbe.enabled }} + livenessProbe: {{- omit .Values.primary.livenessProbe "enabled" | toYaml | nindent 12 }} + exec: + command: + - /bin/bash + - -ec + - | + password_aux="${MARIADB_ROOT_PASSWORD:-}" + if [[ -f "${MARIADB_ROOT_PASSWORD_FILE:-}" ]]; then + password_aux=$(cat "$MARIADB_ROOT_PASSWORD_FILE") + fi + mysqladmin status -uroot -p"${password_aux}" + {{- end }} + {{- if .Values.primary.customReadinessProbe }} + readinessProbe: {{- include "common.tplvalues.render" (dict "value" .Values.primary.customReadinessProbe "context" $) | nindent 12 }} + {{- else if .Values.primary.readinessProbe.enabled }} + readinessProbe: {{- omit .Values.primary.readinessProbe "enabled" | toYaml | nindent 12 }} + exec: + command: + - /bin/bash + - -ec + - | + password_aux="${MARIADB_ROOT_PASSWORD:-}" + if [[ -f "${MARIADB_ROOT_PASSWORD_FILE:-}" ]]; then + password_aux=$(cat "$MARIADB_ROOT_PASSWORD_FILE") + fi + mysqladmin status -uroot -p"${password_aux}" + {{- end }} + {{- end }} + {{- if .Values.primary.resources }} + resources: {{ toYaml .Values.primary.resources | nindent 12 }} + {{- end }} + volumeMounts: + - name: data + mountPath: /bitnami/mariadb + {{- if .Values.primary.persistence.subPath }} + subPath: {{ .Values.primary.persistence.subPath }} + {{- end }} + {{- if or .Values.initdbScriptsConfigMap .Values.initdbScripts }} + - name: custom-init-scripts + mountPath: /docker-entrypoint-initdb.d + {{- end }} + {{- if or .Values.primary.configuration .Values.primary.existingConfigmap }} + - name: config + mountPath: /opt/bitnami/mariadb/conf/my.cnf + subPath: my.cnf + {{- end }} + {{- if and .Values.auth.usePasswordFiles (not .Values.auth.customPasswordFiles) }} + - name: mariadb-credentials + mountPath: /opt/bitnami/mariadb/secrets/ + {{- end }} + {{- if .Values.primary.extraVolumeMounts }} + {{- include "common.tplvalues.render" (dict "value" .Values.primary.extraVolumeMounts "context" $) | nindent 12 }} + {{- end }} + {{- if .Values.metrics.enabled }} + - name: metrics + image: {{ include "mariadb.metrics.image" . }} + imagePullPolicy: {{ .Values.metrics.image.pullPolicy | quote }} + {{- if .Values.metrics.containerSecurityContext.enabled }} + securityContext: {{- omit .Values.metrics.containerSecurityContext "enabled" | toYaml | nindent 12 }} + {{- end }} + env: + {{- if .Values.auth.usePasswordFiles }} + - name: MARIADB_ROOT_PASSWORD_FILE + value: {{ default "/opt/bitnami/mysqld-exporter/secrets/mariadb-root-password" .Values.auth.customPasswordFiles.root }} + {{- else }} + - name: MARIADB_ROOT_PASSWORD + valueFrom: + secretKeyRef: + name: {{ template "mariadb.secretName" . }} + key: mariadb-root-password + {{- end }} + {{- if .Values.diagnosticMode.enabled }} + command: {{- include "common.tplvalues.render" (dict "value" .Values.diagnosticMode.command "context" $) | nindent 12 }} + args: {{- include "common.tplvalues.render" (dict "value" .Values.diagnosticMode.args "context" $) | nindent 12 }} + {{- else }} + command: + - /bin/bash + - -ec + - | + password_aux="${MARIADB_ROOT_PASSWORD:-}" + if [[ -f "${MARIADB_ROOT_PASSWORD_FILE:-}" ]]; then + password_aux=$(cat "$MARIADB_ROOT_PASSWORD_FILE") + fi + DATA_SOURCE_NAME="root:${password_aux}@(localhost:3306)/" /bin/mysqld_exporter {{- range .Values.metrics.extraArgs.primary }} {{ . }} {{- end }} + {{- end }} + ports: + - name: metrics + containerPort: 9104 + {{- if not .Values.diagnosticMode.enabled }} + {{- if .Values.metrics.livenessProbe.enabled }} + livenessProbe: {{- omit .Values.metrics.livenessProbe "enabled" | toYaml | nindent 12 }} + httpGet: + path: /metrics + port: metrics + {{- end }} + {{- if .Values.metrics.readinessProbe.enabled }} + readinessProbe: {{- omit .Values.metrics.readinessProbe "enabled" | toYaml | nindent 12 }} + httpGet: + path: /metrics + port: metrics + {{- end }} + {{- end }} + {{- if .Values.metrics.resources }} + resources: {{- toYaml .Values.metrics.resources | nindent 12 }} + {{- end }} + volumeMounts: + {{- if and .Values.auth.usePasswordFiles (not .Values.auth.customPasswordFiles) }} + - name: mariadb-credentials + mountPath: /opt/bitnami/mysqld-exporter/secrets/ + {{- end }} + {{- if .Values.metrics.extraVolumeMounts.primary }} + {{- include "common.tplvalues.render" (dict "value" .Values.metrics.extraVolumeMounts.primary "context" $) | nindent 12 }} + {{- end }} + {{- end }} + {{- if .Values.primary.sidecars }} + {{- include "common.tplvalues.render" (dict "value" .Values.primary.sidecars "context" $) | nindent 8 }} + {{- end }} + volumes: + {{- if or .Values.primary.configuration .Values.primary.existingConfigmap }} + - name: config + configMap: + name: {{ include "mariadb.primary.configmapName" . }} + {{- end }} + {{- if or .Values.initdbScriptsConfigMap .Values.initdbScripts }} + - name: custom-init-scripts + configMap: + name: {{ template "mariadb.initdbScriptsCM" . }} + {{- end }} + {{- if and .Values.auth.usePasswordFiles (not .Values.auth.customPasswordFiles) }} + - name: mariadb-credentials + secret: + secretName: {{ template "mariadb.secretName" . }} + items: + - key: mariadb-root-password + path: mariadb-root-password + - key: mariadb-password + path: mariadb-password + {{- if eq .Values.architecture "replication" }} + - key: mariadb-replication-password + path: mariadb-replication-password + {{- end }} + {{- end }} + {{- if .Values.primary.extraVolumes }} + {{- include "common.tplvalues.render" (dict "value" .Values.primary.extraVolumes "context" $) | nindent 8 }} + {{- end }} + {{- if and .Values.primary.persistence.enabled .Values.primary.persistence.existingClaim }} + - name: data + persistentVolumeClaim: + claimName: {{ tpl .Values.primary.persistence.existingClaim . }} + {{- else if not .Values.primary.persistence.enabled }} + - name: data + emptyDir: {} + {{- else if and .Values.primary.persistence.enabled (not .Values.primary.persistence.existingClaim) }} + volumeClaimTemplates: + - metadata: + name: data + labels: {{ include "common.labels.matchLabels" . | nindent 10 }} + app.kubernetes.io/component: primary + {{- if .Values.primary.persistence.annotations }} + annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.primary.persistence.annotations "context" $ ) | nindent 10 }} + {{- end }} + spec: + accessModes: + {{- range .Values.primary.persistence.accessModes }} + - {{ . | quote }} + {{- end }} + resources: + requests: + storage: {{ .Values.primary.persistence.size | quote }} + {{ include "common.storage.class" (dict "persistence" .Values.primary.persistence "global" .Values.global) }} + {{- if .Values.primary.persistence.selector }} + selector: {{- include "common.tplvalues.render" (dict "value" .Values.primary.persistence.selector "context" $) | nindent 10 }} + {{- end -}} + {{- end }} diff --git a/charts/limesurvey-martial-ingress-v9/charts/mariadb/templates/primary/svc.yaml b/charts/limesurvey-martial-ingress-v9/charts/mariadb/templates/primary/svc.yaml new file mode 100644 index 0000000..85d3156 --- /dev/null +++ b/charts/limesurvey-martial-ingress-v9/charts/mariadb/templates/primary/svc.yaml @@ -0,0 +1,61 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ include "mariadb.primary.fullname" . }} + namespace: {{ .Release.Namespace | quote }} + labels: {{- include "common.labels.standard" . | nindent 4 }} + app.kubernetes.io/component: primary + {{- if .Values.commonLabels }} + {{- include "common.tplvalues.render" ( dict "value" .Values.commonLabels "context" $ ) | nindent 4 }} + {{- end }} + annotations: + {{- if .Values.commonAnnotations }} + {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} + {{- end }} + {{- if .Values.primary.service.annotations }} + {{- include "common.tplvalues.render" ( dict "value" .Values.primary.service.annotations "context" $ ) | nindent 4 }} + {{- end }} + {{- if and .Values.metrics.enabled .Values.metrics.annotations }} + {{- include "common.tplvalues.render" ( dict "value" .Values.metrics.annotations "context" $ ) | nindent 4 }} + {{- end }} +spec: + type: {{ .Values.primary.service.type }} + {{- if and .Values.primary.service.clusterIP (eq .Values.primary.service.type "ClusterIP") }} + clusterIP: {{ .Values.primary.service.clusterIP }} + {{- end }} + {{- if and .Values.primary.service.externalTrafficPolicy (or (eq .Values.primary.service.type "LoadBalancer") (eq .Values.primary.service.type "NodePort")) }} + externalTrafficPolicy: {{ .Values.primary.service.externalTrafficPolicy | quote }} + {{- end }} + {{- if and (eq .Values.primary.service.type "LoadBalancer") .Values.primary.service.loadBalancerSourceRanges }} + loadBalancerSourceRanges: {{ .Values.primary.service.loadBalancerSourceRanges }} + {{ end }} + {{- if (and (eq .Values.primary.service.type "LoadBalancer") (not (empty .Values.primary.service.loadBalancerIP))) }} + loadBalancerIP: {{ .Values.primary.service.loadBalancerIP }} + {{- end }} + {{- if .Values.primary.service.sessionAffinity }} + sessionAffinity: {{ .Values.primary.service.sessionAffinity }} + {{- end }} + {{- if .Values.primary.service.sessionAffinityConfig }} + sessionAffinityConfig: {{- include "common.tplvalues.render" (dict "value" .Values.primary.service.sessionAffinityConfig "context" $) | nindent 4 }} + {{- end }} + ports: + - name: mysql + port: {{ coalesce .Values.primary.service.ports.mysql .Values.primary.service.port }} + protocol: TCP + targetPort: mysql + {{- if (and (or (eq .Values.primary.service.type "NodePort") (eq .Values.primary.service.type "LoadBalancer")) (coalesce .Values.primary.service.nodePorts.mysql .Values.primary.service.nodePort)) }} + nodePort: {{ coalesce .Values.primary.service.nodePorts.mysql .Values.primary.service.nodePort }} + {{- else if eq .Values.primary.service.type "ClusterIP" }} + nodePort: null + {{- end }} + {{- if and .Values.metrics.enabled (gt (.Values.primary.service.ports.metrics | int) 0) }} + - name: metrics + port: {{ .Values.primary.service.ports.metrics }} + protocol: TCP + targetPort: metrics + {{- end }} + {{- if .Values.primary.service.extraPorts }} + {{- include "common.tplvalues.render" (dict "value" .Values.primary.service.extraPorts "context" $) | nindent 4 }} + {{- end }} + selector: {{ include "common.labels.matchLabels" . | nindent 4 }} + app.kubernetes.io/component: primary diff --git a/charts/limesurvey-martial-ingress-v9/charts/mariadb/templates/prometheusrules.yaml b/charts/limesurvey-martial-ingress-v9/charts/mariadb/templates/prometheusrules.yaml new file mode 100644 index 0000000..523e533 --- /dev/null +++ b/charts/limesurvey-martial-ingress-v9/charts/mariadb/templates/prometheusrules.yaml @@ -0,0 +1,26 @@ +{{- if and .Values.metrics.enabled .Values.metrics.prometheusRule.enabled }} +apiVersion: monitoring.coreos.com/v1 +kind: PrometheusRule +metadata: + name: {{ include "common.names.fullname" . }} + {{- if .Values.metrics.prometheusRule.namespace }} + namespace: {{ .Values.metrics.prometheusRule.namespace }} + {{- else }} + namespace: {{ .Release.Namespace | quote }} + {{- end }} + labels: {{- include "common.labels.standard" . | nindent 4 }} + app.kubernetes.io/component: metrics + {{- if .Values.commonLabels }} + {{- include "common.tplvalues.render" ( dict "value" .Values.commonLabels "context" $ ) | nindent 4 }} + {{- end }} + {{- if .Values.metrics.prometheusRule.additionalLabels }} + {{- include "common.tplvalues.render" ( dict "value" .Values.metrics.prometheusRule.additionalLabels "context" $ ) | nindent 4 }} + {{- end }} + {{- if .Values.commonAnnotations }} + annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} + {{- end }} +spec: + groups: + - name: {{ include "common.names.fullname" . }} + rules: {{- include "common.tplvalues.render" ( dict "value" .Values.metrics.prometheusRule.rules "context" $ ) | nindent 6 }} +{{- end }} diff --git a/charts/limesurvey-martial-ingress-v9/charts/mariadb/templates/role.yaml b/charts/limesurvey-martial-ingress-v9/charts/mariadb/templates/role.yaml new file mode 100644 index 0000000..a561f51 --- /dev/null +++ b/charts/limesurvey-martial-ingress-v9/charts/mariadb/templates/role.yaml @@ -0,0 +1,21 @@ +{{- if and .Values.serviceAccount.create .Values.rbac.create }} +apiVersion: {{ include "common.capabilities.rbac.apiVersion" . }} +kind: Role +metadata: + name: {{ include "common.names.fullname" . }} + namespace: {{ .Release.Namespace | quote }} + labels: {{- include "common.labels.standard" . | nindent 4 }} + {{- if .Values.commonLabels }} + {{- include "common.tplvalues.render" ( dict "value" .Values.commonLabels "context" $ ) | nindent 4 }} + {{- end }} + {{- if .Values.commonAnnotations }} + annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} + {{- end }} +rules: + - apiGroups: + - "" + resources: + - endpoints + verbs: + - get +{{- end }} diff --git a/charts/limesurvey-martial-ingress-v9/charts/mariadb/templates/rolebinding.yaml b/charts/limesurvey-martial-ingress-v9/charts/mariadb/templates/rolebinding.yaml new file mode 100644 index 0000000..671aa6e --- /dev/null +++ b/charts/limesurvey-martial-ingress-v9/charts/mariadb/templates/rolebinding.yaml @@ -0,0 +1,21 @@ +{{- if and .Values.serviceAccount.create .Values.rbac.create }} +kind: RoleBinding +apiVersion: {{ include "common.capabilities.rbac.apiVersion" . }} +metadata: + name: {{ include "common.names.fullname" . }} + namespace: {{ .Release.Namespace | quote }} + labels: {{- include "common.labels.standard" . | nindent 4 }} + {{- if .Values.commonLabels }} + {{- include "common.tplvalues.render" ( dict "value" .Values.commonLabels "context" $ ) | nindent 4 }} + {{- end }} + {{- if .Values.commonAnnotations }} + annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} + {{- end }} +subjects: + - kind: ServiceAccount + name: {{ include "mariadb.serviceAccountName" . }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: {{ include "common.names.fullname" . -}} +{{- end }} diff --git a/charts/limesurvey-martial-ingress-v9/charts/mariadb/templates/secondary/configmap.yaml b/charts/limesurvey-martial-ingress-v9/charts/mariadb/templates/secondary/configmap.yaml new file mode 100644 index 0000000..4cfec64 --- /dev/null +++ b/charts/limesurvey-martial-ingress-v9/charts/mariadb/templates/secondary/configmap.yaml @@ -0,0 +1,18 @@ +{{- if (include "mariadb.secondary.createConfigmap" .) }} +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ include "mariadb.secondary.fullname" . }} + namespace: {{ .Release.Namespace | quote }} + labels: {{- include "common.labels.standard" . | nindent 4 }} + app.kubernetes.io/component: secondary + {{- if .Values.commonLabels }} + {{- include "common.tplvalues.render" ( dict "value" .Values.commonLabels "context" $ ) | nindent 4 }} + {{- end }} + {{- if .Values.commonAnnotations }} + annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} + {{- end }} +data: + my.cnf: |- +{{ .Values.secondary.configuration | indent 4 }} +{{- end -}} diff --git a/charts/limesurvey-martial-ingress-v9/charts/mariadb/templates/secondary/networkpolicy-ingress.yaml b/charts/limesurvey-martial-ingress-v9/charts/mariadb/templates/secondary/networkpolicy-ingress.yaml new file mode 100644 index 0000000..51a8885 --- /dev/null +++ b/charts/limesurvey-martial-ingress-v9/charts/mariadb/templates/secondary/networkpolicy-ingress.yaml @@ -0,0 +1,49 @@ +{{- if and .Values.networkPolicy.enabled (eq .Values.architecture "replication") (or .Values.networkPolicy.metrics.enabled .Values.networkPolicy.ingressRules.secondaryAccessOnlyFrom.enabled) }} +apiVersion: {{ include "common.capabilities.networkPolicy.apiVersion" . }} +kind: NetworkPolicy +metadata: + name: {{ printf "%s-ingress-secondary" (include "common.names.fullname" .) }} + namespace: {{ .Release.Namespace | quote }} + labels: {{- include "common.labels.standard" . | nindent 4 }} + {{- if .Values.commonLabels }} + {{- include "common.tplvalues.render" ( dict "value" .Values.commonLabels "context" $ ) | nindent 4 }} + {{- end }} + {{- if .Values.commonAnnotations }} + annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} + {{- end }} +spec: + podSelector: + matchLabels: + app.kubernetes.io/component: secondary + {{- include "common.labels.standard" . | nindent 6 }} + ingress: + {{- if and .Values.metrics.enabled .Values.networkPolicy.metrics.enabled (or .Values.networkPolicy.metrics.namespaceSelector .Values.networkPolicy.metrics.podSelector) }} + - from: + {{- if .Values.networkPolicy.metrics.namespaceSelector }} + - namespaceSelector: + matchLabels: + {{- include "common.tplvalues.render" (dict "value" .Values.networkPolicy.metrics.namespaceSelector "context" $) | nindent 14 }} + {{- end }} + {{- if .Values.networkPolicy.metrics.podSelector }} + - podSelector: + matchLabels: + {{- include "common.tplvalues.render" (dict "value" .Values.networkPolicy.metrics.podSelector "context" $) | nindent 14 }} + {{- end }} + {{- end }} + {{- if and .Values.networkPolicy.ingressRules.secondaryAccessOnlyFrom.enabled (or .Values.networkPolicy.ingressRules.secondaryAccessOnlyFrom.namespaceSelector .Values.networkPolicy.ingressRules.secondaryAccessOnlyFrom.podSelector) }} + - from: + {{- if .Values.networkPolicy.ingressRules.secondaryAccessOnlyFrom.namespaceSelector }} + - namespaceSelector: + matchLabels: + {{- include "common.tplvalues.render" (dict "value" .Values.networkPolicy.ingressRules.secondaryAccessOnlyFrom.namespaceSelector "context" $) | nindent 14 }} + {{- end }} + {{- if .Values.networkPolicy.ingressRules.secondaryAccessOnlyFrom.podSelector }} + - podSelector: + matchLabels: + {{- include "common.tplvalues.render" (dict "value" .Values.networkPolicy.ingressRules.secondaryAccessOnlyFrom.podSelector "context" $) | nindent 14 }} + {{- end }} + {{- end }} + {{- if .Values.networkPolicy.ingressRules.secondaryAccessOnlyFrom.customRules }} + {{- include "common.tplvalues.render" (dict "value" .Values.networkPolicy.ingressRules.secondaryAccessOnlyFrom.customRules "context" $) | nindent 4 }} + {{- end }} +{{- end }} diff --git a/charts/limesurvey-martial-ingress-v9/charts/mariadb/templates/secondary/pdb.yaml b/charts/limesurvey-martial-ingress-v9/charts/mariadb/templates/secondary/pdb.yaml new file mode 100644 index 0000000..cae28ff --- /dev/null +++ b/charts/limesurvey-martial-ingress-v9/charts/mariadb/templates/secondary/pdb.yaml @@ -0,0 +1,25 @@ +{{- if and (eq .Values.architecture "replication") .Values.secondary.pdb.create }} +apiVersion: {{ include "common.capabilities.policy.apiVersion" . }} +kind: PodDisruptionBudget +metadata: + name: {{ include "mariadb.secondary.fullname" . }} + namespace: {{ .Release.Namespace | quote }} + labels: {{- include "common.labels.standard" . | nindent 4 }} + app.kubernetes.io/component: secondary + {{- if .Values.commonLabels }} + {{- include "common.tplvalues.render" ( dict "value" .Values.commonLabels "context" $ ) | nindent 4 }} + {{- end }} + {{- if .Values.commonAnnotations }} + annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} + {{- end }} +spec: + {{- if .Values.secondary.pdb.minAvailable }} + minAvailable: {{ .Values.secondary.pdb.minAvailable }} + {{- end }} + {{- if .Values.secondary.pdb.maxUnavailable }} + maxUnavailable: {{ .Values.secondary.pdb.maxUnavailable }} + {{- end }} + selector: + matchLabels: {{ include "common.labels.matchLabels" . | nindent 6 }} + app.kubernetes.io/component: secondary +{{- end }} diff --git a/charts/limesurvey-martial-ingress-v9/charts/mariadb/templates/secondary/statefulset.yaml b/charts/limesurvey-martial-ingress-v9/charts/mariadb/templates/secondary/statefulset.yaml new file mode 100644 index 0000000..c88d4ad --- /dev/null +++ b/charts/limesurvey-martial-ingress-v9/charts/mariadb/templates/secondary/statefulset.yaml @@ -0,0 +1,365 @@ +{{- if eq .Values.architecture "replication" }} +apiVersion: {{ include "common.capabilities.statefulset.apiVersion" . }} +kind: StatefulSet +metadata: + name: {{ include "mariadb.secondary.fullname" . }} + namespace: {{ .Release.Namespace | quote }} + labels: {{- include "common.labels.standard" . | nindent 4 }} + app.kubernetes.io/component: secondary + {{- if .Values.commonLabels }} + {{- include "common.tplvalues.render" ( dict "value" .Values.commonLabels "context" $ ) | nindent 4 }} + {{- end }} + {{- if .Values.commonAnnotations }} + annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} + {{- end }} +spec: + replicas: {{ .Values.secondary.replicaCount }} + revisionHistoryLimit: {{ .Values.secondary.revisionHistoryLimit }} + selector: + matchLabels: {{ include "common.labels.matchLabels" . | nindent 6 }} + app.kubernetes.io/component: secondary + serviceName: {{ include "mariadb.secondary.fullname" . }} + podManagementPolicy: {{ .Values.secondary.podManagementPolicy }} + {{- if .Values.secondary.updateStrategy }} + updateStrategy: {{- toYaml .Values.secondary.updateStrategy | nindent 4 }} + {{- end }} + template: + metadata: + annotations: + {{- if (include "mariadb.secondary.createConfigmap" .) }} + checksum/configuration: {{ include (print $.Template.BasePath "/secondary/configmap.yaml") . | sha256sum }} + {{- end }} + {{- if .Values.secondary.podAnnotations }} + {{- include "common.tplvalues.render" (dict "value" .Values.secondary.podAnnotations "context" $) | nindent 8 }} + {{- end }} + labels: {{- include "common.labels.standard" . | nindent 8 }} + app.kubernetes.io/component: secondary + {{- if .Values.secondary.podLabels }} + {{- include "common.tplvalues.render" (dict "value" .Values.secondary.podLabels "context" $) | nindent 8 }} + {{- end }} + {{- if .Values.commonLabels }} + {{- include "common.tplvalues.render" ( dict "value" .Values.commonLabels "context" $ ) | nindent 8 }} + {{- end }} + spec: + {{- include "mariadb.imagePullSecrets" . | nindent 6 }} + {{- if or .Values.secondary.schedulerName .Values.schedulerName }} + schedulerName: {{ (coalesce .Values.secondary.schedulerName .Values.schedulerName) | quote }} + {{- end }} + serviceAccountName: {{ template "mariadb.serviceAccountName" . }} + {{- if .Values.secondary.hostAliases }} + hostAliases: {{- include "common.tplvalues.render" (dict "value" .Values.secondary.hostAliases "context" $) | nindent 8 }} + {{- end }} + {{- if .Values.secondary.affinity }} + affinity: {{- include "common.tplvalues.render" (dict "value" .Values.secondary.affinity "context" $) | nindent 8 }} + {{- else }} + affinity: + podAffinity: {{- include "common.affinities.pods" (dict "type" .Values.secondary.podAffinityPreset "component" "secondary" "context" $) | nindent 10 }} + podAntiAffinity: {{- include "common.affinities.pods" (dict "type" .Values.secondary.podAntiAffinityPreset "component" "secondary" "context" $) | nindent 10 }} + nodeAffinity: {{- include "common.affinities.nodes" (dict "type" .Values.secondary.nodeAffinityPreset.type "key" .Values.secondary.nodeAffinityPreset.key "values" .Values.secondary.nodeAffinityPreset.values) | nindent 10 }} + {{- end }} + {{- if .Values.secondary.nodeSelector }} + nodeSelector: {{- include "common.tplvalues.render" (dict "value" .Values.secondary.nodeSelector "context" $) | nindent 8 }} + {{- end }} + {{- if .Values.secondary.tolerations }} + tolerations: {{- include "common.tplvalues.render" (dict "value" .Values.secondary.tolerations "context" $) | nindent 8 }} + {{- end }} + {{- if .Values.secondary.topologySpreadConstraints }} + topologySpreadConstraints: {{- include "common.tplvalues.render" (dict "value" .Values.secondary.topologySpreadConstraints "context" $) | nindent 8 }} + {{- end }} + {{- if .Values.secondary.priorityClassName }} + priorityClassName: {{ .Values.secondary.priorityClassName | quote }} + {{- else if .Values.priorityClassName }} + priorityClassName: {{ .Values.priorityClassName | quote }} + {{- end }} + {{- if .Values.secondary.runtimeClassName }} + runtimeClassName: {{ .Values.secondary.runtimeClassName | quote }} + {{- else if .Values.runtimeClassName }} + runtimeClassName: {{ .Values.runtimeClassName | quote }} + {{- end }} + {{- if .Values.secondary.podSecurityContext.enabled }} + securityContext: {{- omit .Values.secondary.podSecurityContext "enabled" | toYaml | nindent 8 }} + {{- end }} + {{- if or .Values.secondary.initContainers (and .Values.secondary.podSecurityContext.enabled .Values.volumePermissions.enabled .Values.secondary.persistence.enabled) }} + initContainers: + {{- if .Values.secondary.initContainers }} + {{- include "common.tplvalues.render" (dict "value" .Values.secondary.initContainers "context" $) | nindent 8 }} + {{- end }} + {{- if and .Values.secondary.podSecurityContext.enabled .Values.volumePermissions.enabled .Values.secondary.persistence.enabled }} + - name: volume-permissions + image: {{ include "mariadb.volumePermissions.image" . }} + imagePullPolicy: {{ .Values.volumePermissions.image.pullPolicy | quote }} + command: + - /bin/bash + - -ec + - | + chown -R {{ .Values.secondary.containerSecurityContext.runAsUser }}:{{ .Values.secondary.podSecurityContext.fsGroup }} /bitnami/mariadb + securityContext: + runAsUser: 0 + {{- if .Values.volumePermissions.resources }} + resources: {{- toYaml .Values.volumePermissions.resources | nindent 12 }} + {{- end }} + volumeMounts: + - name: data + mountPath: /bitnami/mariadb + {{- if .Values.secondary.persistence.subPath }} + subPath: {{ .Values.secondary.persistence.subPath }} + {{- end }} + {{- end }} + {{- end }} + containers: + - name: mariadb + image: {{ include "mariadb.image" . }} + imagePullPolicy: {{ .Values.image.pullPolicy | quote }} + {{- if .Values.secondary.containerSecurityContext.enabled }} + securityContext: {{- omit .Values.secondary.containerSecurityContext "enabled" | toYaml | nindent 12 }} + {{- end }} + {{- if .Values.diagnosticMode.enabled }} + command: {{- include "common.tplvalues.render" (dict "value" .Values.diagnosticMode.command "context" $) | nindent 12 }} + {{- else if .Values.secondary.command }} + command: {{- include "common.tplvalues.render" (dict "value" .Values.secondary.command "context" $) | nindent 12 }} + {{- end }} + {{- if .Values.diagnosticMode.enabled }} + args: {{- include "common.tplvalues.render" (dict "value" .Values.diagnosticMode.args "context" $) | nindent 12 }} + {{- else if .Values.secondary.args }} + args: {{- include "common.tplvalues.render" (dict "value" .Values.secondary.args "context" $) | nindent 12 }} + {{- end }} + {{- if .Values.secondary.lifecycleHooks }} + lifecycle: {{- include "common.tplvalues.render" (dict "value" .Values.secondary.lifecycleHooks "context" $) | nindent 12 }} + {{- end }} + env: + - name: BITNAMI_DEBUG + value: {{ ternary "true" "false" (or .Values.image.debug .Values.diagnosticMode.enabled) | quote }} + - name: MARIADB_REPLICATION_MODE + value: "slave" + - name: MARIADB_MASTER_HOST + value: {{ include "mariadb.primary.fullname" . }} + - name: MARIADB_MASTER_PORT_NUMBER + value: {{ coalesce .Values.primary.service.ports.mysql .Values.primary.service.port | quote }} + - name: MARIADB_MASTER_ROOT_USER + value: "root" + {{- if .Values.auth.usePasswordFiles }} + - name: MARIADB_MASTER_ROOT_PASSWORD_FILE + value: {{ default "/opt/bitnami/mariadb/secrets/mariadb-root-password" .Values.auth.customPasswordFiles.root }} + {{- else }} + - name: MARIADB_MASTER_ROOT_PASSWORD + valueFrom: + secretKeyRef: + name: {{ template "mariadb.secretName" . }} + key: mariadb-root-password + {{- end }} + - name: MARIADB_REPLICATION_USER + value: {{ .Values.auth.replicationUser | quote }} + {{- if .Values.auth.usePasswordFiles }} + - name: MARIADB_REPLICATION_PASSWORD_FILE + value: {{ default "/opt/bitnami/mariadb/secrets/mariadb-replication-password" .Values.auth.customPasswordFiles.replicator }} + {{- else }} + - name: MARIADB_REPLICATION_PASSWORD + valueFrom: + secretKeyRef: + name: {{ template "mariadb.secretName" . }} + key: mariadb-replication-password + {{- end }} + {{- if .Values.secondary.extraFlags }} + - name: MARIADB_EXTRA_FLAGS + value: "{{ .Values.secondary.extraFlags }}" + {{- end }} + {{- if .Values.secondary.startupWaitOptions }} + - name: MARIADB_STARTUP_WAIT_RETRIES + value: "{{ .Values.secondary.startupWaitOptions.retries | default 300 }}" + - name: MARIADB_STARTUP_WAIT_SLEEP_TIME + value: "{{ .Values.secondary.startupWaitOptions.sleepTime | default 2 }}" + {{- end }} + {{- if .Values.secondary.extraEnvVars }} + {{- include "common.tplvalues.render" (dict "value" .Values.secondary.extraEnvVars "context" $) | nindent 12 }} + {{- end }} + {{- if or .Values.secondary.extraEnvVarsCM .Values.secondary.extraEnvVarsSecret }} + envFrom: + {{- if .Values.secondary.extraEnvVarsCM }} + - configMapRef: + name: {{ .Values.secondary.extraEnvVarsCM }} + {{- end }} + {{- if .Values.secondary.extraEnvVarsSecret }} + - secretRef: + name: {{ .Values.secondary.extraEnvVarsSecret }} + {{- end }} + {{- end }} + ports: + - name: mysql + containerPort: 3306 + {{- if not .Values.diagnosticMode.enabled }} + {{- if .Values.secondary.customStartupProbe }} + startupProbe: {{- include "common.tplvalues.render" (dict "value" .Values.secondary.customStartupProbe "context" $) | nindent 12 }} + {{- else if .Values.secondary.startupProbe.enabled }} + startupProbe: {{- omit .Values.secondary.startupProbe "enabled" | toYaml | nindent 12 }} + exec: + command: + - /bin/bash + - -ec + - | + password_aux="${MARIADB_MASTER_ROOT_PASSWORD:-}" + if [[ -f "${MARIADB_MASTER_ROOT_PASSWORD_FILE:-}" ]]; then + password_aux=$(cat "$MARIADB_MASTER_ROOT_PASSWORD_FILE") + fi + mysqladmin status -uroot -p"${password_aux}" + {{- end }} + {{- if .Values.secondary.customLivenessProbe }} + livenessProbe: {{- include "common.tplvalues.render" (dict "value" .Values.secondary.customLivenessProbe "context" $) | nindent 12 }} + {{- else if .Values.secondary.livenessProbe.enabled }} + livenessProbe: {{- omit .Values.secondary.livenessProbe "enabled" | toYaml | nindent 12 }} + exec: + command: + - /bin/bash + - -ec + - | + password_aux="${MARIADB_MASTER_ROOT_PASSWORD:-}" + if [[ -f "${MARIADB_MASTER_ROOT_PASSWORD_FILE:-}" ]]; then + password_aux=$(cat "$MARIADB_MASTER_ROOT_PASSWORD_FILE") + fi + mysqladmin status -uroot -p"${password_aux}" + {{- end }} + {{- if .Values.secondary.customReadinessProbe }} + readinessProbe: {{- include "common.tplvalues.render" (dict "value" .Values.secondary.customReadinessProbe "context" $) | nindent 12 }} + {{- else if .Values.secondary.readinessProbe.enabled }} + readinessProbe: {{- omit .Values.secondary.readinessProbe "enabled" | toYaml | nindent 12 }} + exec: + command: + - /bin/bash + - -ec + - | + password_aux="${MARIADB_MASTER_ROOT_PASSWORD:-}" + if [[ -f "${MARIADB_MASTER_ROOT_PASSWORD_FILE:-}" ]]; then + password_aux=$(cat "$MARIADB_MASTER_ROOT_PASSWORD_FILE") + fi + mysqladmin status -uroot -p"${password_aux}" + {{- end }} + {{- end }} + {{- if .Values.secondary.resources }} + resources: {{ toYaml .Values.secondary.resources | nindent 12 }} + {{- end }} + volumeMounts: + - name: data + mountPath: /bitnami/mariadb + {{- if .Values.secondary.persistence.subPath }} + subPath: {{ .Values.secondary.persistence.subPath }} + {{- end }} + {{- if or .Values.secondary.configuration .Values.secondary.existingConfigmap }} + - name: config + mountPath: /opt/bitnami/mariadb/conf/my.cnf + subPath: my.cnf + {{- end }} + {{- if and .Values.auth.usePasswordFiles (not .Values.auth.customPasswordFiles) }} + - name: mariadb-credentials + mountPath: /opt/bitnami/mariadb/secrets/ + {{- end }} + {{- if .Values.secondary.extraVolumeMounts }} + {{- include "common.tplvalues.render" (dict "value" .Values.secondary.extraVolumeMounts "context" $) | nindent 12 }} + {{- end }} + {{- if .Values.metrics.enabled }} + - name: metrics + image: {{ include "mariadb.metrics.image" . }} + imagePullPolicy: {{ .Values.metrics.image.pullPolicy | quote }} + {{- if .Values.metrics.containerSecurityContext.enabled }} + securityContext: {{- omit .Values.metrics.containerSecurityContext "enabled" | toYaml | nindent 12 }} + {{- end }} + env: + {{- if .Values.auth.usePasswordFiles }} + - name: MARIADB_ROOT_PASSWORD_FILE + value: {{ default "/opt/bitnami/mysqld-exporter/secrets/mariadb-root-password" .Values.auth.customPasswordFiles.root }} + {{- else }} + - name: MARIADB_ROOT_PASSWORD + valueFrom: + secretKeyRef: + name: {{ template "mariadb.secretName" . }} + key: mariadb-root-password + {{- end }} + {{- if .Values.diagnosticMode.enabled }} + command: {{- include "common.tplvalues.render" (dict "value" .Values.diagnosticMode.command "context" $) | nindent 12 }} + args: {{- include "common.tplvalues.render" (dict "value" .Values.diagnosticMode.args "context" $) | nindent 12 }} + {{- else }} + command: + - /bin/bash + - -ec + - | + password_aux="${MARIADB_ROOT_PASSWORD:-}" + if [[ -f "${MARIADB_ROOT_PASSWORD_FILE:-}" ]]; then + password_aux=$(cat "$MARIADB_ROOT_PASSWORD_FILE") + fi + DATA_SOURCE_NAME="root:${password_aux}@(localhost:3306)/" /bin/mysqld_exporter {{- range .Values.metrics.extraArgs.secondary }} {{ . }} {{- end }} + {{- end }} + ports: + - name: metrics + containerPort: 9104 + {{- if not .Values.diagnosticMode.enabled }} + {{- if .Values.metrics.livenessProbe.enabled }} + livenessProbe: {{- omit .Values.metrics.livenessProbe "enabled" | toYaml | nindent 12 }} + httpGet: + path: /metrics + port: metrics + {{- end }} + {{- if .Values.metrics.readinessProbe.enabled }} + readinessProbe: {{- omit .Values.metrics.readinessProbe "enabled" | toYaml | nindent 12 }} + httpGet: + path: /metrics + port: metrics + {{- end }} + {{- end }} + {{- if .Values.metrics.resources }} + resources: {{- toYaml .Values.metrics.resources | nindent 12 }} + {{- end }} + volumeMounts: + {{- if and .Values.auth.usePasswordFiles (not .Values.auth.customPasswordFiles) }} + - name: mariadb-credentials + mountPath: /opt/bitnami/mysqld-exporter/secrets/ + {{- end }} + {{- if .Values.metrics.extraVolumeMounts.secondary }} + {{- include "common.tplvalues.render" (dict "value" .Values.metrics.extraVolumeMounts.secondary "context" $) | nindent 12 }} + {{- end }} + {{- end }} + {{- if .Values.secondary.sidecars }} + {{- include "common.tplvalues.render" (dict "value" .Values.secondary.sidecars "context" $) | nindent 8 }} + {{- end }} + volumes: + {{- if or .Values.secondary.configuration .Values.secondary.existingConfigmap }} + - name: config + configMap: + name: {{ include "mariadb.secondary.configmapName" . }} + {{- end }} + {{- if and .Values.auth.usePasswordFiles (not .Values.auth.customPasswordFiles) }} + - name: mariadb-credentials + secret: + secretName: {{ template "mariadb.secretName" . }} + items: + - key: mariadb-root-password + path: mariadb-root-password + - key: mariadb-replication-password + path: mariadb-replication-password + {{- end }} + {{- if .Values.secondary.extraVolumes }} + {{- include "common.tplvalues.render" (dict "value" .Values.secondary.extraVolumes "context" $) | nindent 8 }} + {{- end }} + {{- if not .Values.secondary.persistence.enabled }} + - name: data + emptyDir: {} + {{- else }} + volumeClaimTemplates: + - metadata: + name: data + labels: {{ include "common.labels.matchLabels" . | nindent 10 }} + app.kubernetes.io/component: secondary + {{- if .Values.secondary.persistence.annotations }} + annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.secondary.persistence.annotations "context" $ ) | nindent 10 }} + {{- end }} + spec: + accessModes: + {{- range .Values.secondary.persistence.accessModes }} + - {{ . | quote }} + {{- end }} + resources: + requests: + storage: {{ .Values.secondary.persistence.size | quote }} + {{ include "common.storage.class" (dict "persistence" .Values.secondary.persistence "global" .Values.global) }} + {{- if .Values.secondary.persistence.selector }} + selector: {{- include "common.tplvalues.render" (dict "value" .Values.secondary.persistence.selector "context" $) | nindent 10 }} + {{- end -}} + {{- end }} +{{- end }} diff --git a/charts/limesurvey-martial-ingress-v9/charts/mariadb/templates/secondary/svc.yaml b/charts/limesurvey-martial-ingress-v9/charts/mariadb/templates/secondary/svc.yaml new file mode 100644 index 0000000..3d72171 --- /dev/null +++ b/charts/limesurvey-martial-ingress-v9/charts/mariadb/templates/secondary/svc.yaml @@ -0,0 +1,63 @@ +{{- if eq .Values.architecture "replication" }} +apiVersion: v1 +kind: Service +metadata: + name: {{ include "mariadb.secondary.fullname" . }} + namespace: {{ .Release.Namespace | quote }} + labels: {{- include "common.labels.standard" . | nindent 4 }} + app.kubernetes.io/component: secondary + {{- if .Values.commonLabels }} + {{- include "common.tplvalues.render" ( dict "value" .Values.commonLabels "context" $ ) | nindent 4 }} + {{- end }} + annotations: + {{- if .Values.commonAnnotations }} + {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} + {{- end }} + {{- if .Values.secondary.service.annotations }} + {{- include "common.tplvalues.render" ( dict "value" .Values.secondary.service.annotations "context" $ ) | nindent 4 }} + {{- end }} + {{- if and .Values.metrics.enabled .Values.metrics.annotations }} + {{- include "common.tplvalues.render" ( dict "value" .Values.metrics.annotations "context" $ ) | nindent 4 }} + {{- end }} +spec: + type: {{ .Values.secondary.service.type }} + {{- if and .Values.secondary.service.clusterIP (eq .Values.secondary.service.type "ClusterIP") }} + clusterIP: {{ .Values.secondary.service.clusterIP }} + {{- end }} + {{- if and .Values.secondary.service.externalTrafficPolicy (or (eq .Values.secondary.service.type "LoadBalancer") (eq .Values.secondary.service.type "NodePort")) }} + externalTrafficPolicy: {{ .Values.secondary.service.externalTrafficPolicy | quote }} + {{- end }} + {{- if and (eq .Values.secondary.service.type "LoadBalancer") .Values.secondary.service.loadBalancerSourceRanges }} + loadBalancerSourceRanges: {{ .Values.secondary.service.loadBalancerSourceRanges }} + {{ end }} + {{- if and (eq .Values.secondary.service.type "LoadBalancer") (not (empty .Values.secondary.service.loadBalancerIP)) }} + loadBalancerIP: {{ .Values.secondary.service.loadBalancerIP }} + {{- end }} + {{- if .Values.secondary.service.sessionAffinity }} + sessionAffinity: {{ .Values.secondary.service.sessionAffinity }} + {{- end }} + {{- if .Values.secondary.service.sessionAffinityConfig }} + sessionAffinityConfig: {{- include "common.tplvalues.render" (dict "value" .Values.secondary.service.sessionAffinityConfig "context" $) | nindent 4 }} + {{- end }} + ports: + - name: mysql + port: {{ coalesce .Values.secondary.service.ports.mysql .Values.secondary.service.port }} + protocol: TCP + targetPort: mysql + {{- if (and (or (eq .Values.secondary.service.type "NodePort") (eq .Values.secondary.service.type "LoadBalancer")) (coalesce .Values.secondary.service.nodePorts.mysql .Values.secondary.service.nodePort)) }} + nodePort: {{ coalesce .Values.secondary.service.nodePorts.mysql .Values.secondary.service.nodePort }} + {{- else if eq .Values.secondary.service.type "ClusterIP" }} + nodePort: null + {{- end }} + {{- if and .Values.metrics.enabled (gt (.Values.secondary.service.ports.metrics | int) 0) }} + - name: metrics + port: {{ .Values.secondary.service.ports.metrics }} + protocol: TCP + targetPort: metrics + {{- end }} + {{- if .Values.secondary.service.extraPorts }} + {{- include "common.tplvalues.render" (dict "value" .Values.secondary.service.extraPorts "context" $) | nindent 4 }} + {{- end }} + selector: {{ include "common.labels.matchLabels" . | nindent 4 }} + app.kubernetes.io/component: secondary +{{- end }} diff --git a/charts/limesurvey-martial-ingress-v9/charts/mariadb/templates/secrets.yaml b/charts/limesurvey-martial-ingress-v9/charts/mariadb/templates/secrets.yaml new file mode 100644 index 0000000..2ff62ed --- /dev/null +++ b/charts/limesurvey-martial-ingress-v9/charts/mariadb/templates/secrets.yaml @@ -0,0 +1,35 @@ +{{- if eq (include "mariadb.createSecret" .) "true" }} +apiVersion: v1 +kind: Secret +metadata: + name: {{ include "common.names.fullname" . }} + namespace: {{ .Release.Namespace | quote }} + labels: {{- include "common.labels.standard" . | nindent 4 }} + {{- if .Values.commonLabels }} + {{- include "common.tplvalues.render" ( dict "value" .Values.commonLabels "context" $ ) | nindent 4 }} + {{- end }} + {{- if .Values.commonAnnotations }} + annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} + {{- end }} +type: Opaque +data: + {{- if (not .Values.auth.forcePassword) }} + mariadb-root-password: {{ include "common.secrets.passwords.manage" (dict "secret" (include "common.names.fullname" .) "key" "mariadb-root-password" "providedValues" (list "auth.rootPassword") "context" $) }} + {{- else }} + mariadb-root-password: {{ required "A MariaDB Root Password is required!" .Values.auth.rootPassword | b64enc | quote }} + {{- end }} + {{- if (not (empty .Values.auth.username)) }} + {{- if (not .Values.auth.forcePassword) }} + mariadb-password: {{ include "common.secrets.passwords.manage" (dict "secret" (include "common.names.fullname" .) "key" "mariadb-password" "providedValues" (list "auth.password") "context" $) }} + {{- else }} + mariadb-password: {{ required "A MariaDB Database Password is required!" .Values.auth.password | b64enc | quote }} + {{- end }} + {{- end }} + {{- if eq .Values.architecture "replication" }} + {{- if (not .Values.auth.forcePassword) }} + mariadb-replication-password: {{ include "common.secrets.passwords.manage" (dict "secret" (include "common.names.fullname" .) "key" "mariadb-replication-password" "providedValues" (list "auth.replicationPassword") "context" $) }} + {{- else }} + mariadb-replication-password: {{ required "A MariaDB Replication Password is required!" .Values.auth.replicationPassword | b64enc | quote }} + {{- end }} + {{- end }} +{{- end }} diff --git a/charts/limesurvey-martial-ingress-v9/charts/mariadb/templates/serviceaccount.yaml b/charts/limesurvey-martial-ingress-v9/charts/mariadb/templates/serviceaccount.yaml new file mode 100644 index 0000000..03a6b4e --- /dev/null +++ b/charts/limesurvey-martial-ingress-v9/charts/mariadb/templates/serviceaccount.yaml @@ -0,0 +1,19 @@ +{{- if .Values.serviceAccount.create }} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "mariadb.serviceAccountName" . }} + namespace: {{ .Release.Namespace | quote }} + labels: {{- include "common.labels.standard" . | nindent 4 }} + {{- if .Values.commonLabels }} + {{- include "common.tplvalues.render" ( dict "value" .Values.commonLabels "context" $ ) | nindent 4 }} + {{- end }} + annotations: + {{- if .Values.serviceAccount.annotations }} + {{- include "common.tplvalues.render" ( dict "value" .Values.serviceAccount.annotations "context" $ ) | nindent 4 }} + {{- end }} + {{- if .Values.commonAnnotations }} + {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} + {{- end }} +automountServiceAccountToken: {{ .Values.serviceAccount.automountServiceAccountToken }} +{{- end }} diff --git a/charts/limesurvey-martial-ingress-v9/charts/mariadb/templates/servicemonitor.yaml b/charts/limesurvey-martial-ingress-v9/charts/mariadb/templates/servicemonitor.yaml new file mode 100644 index 0000000..ca5bf7c --- /dev/null +++ b/charts/limesurvey-martial-ingress-v9/charts/mariadb/templates/servicemonitor.yaml @@ -0,0 +1,48 @@ +{{- if and .Values.metrics.enabled .Values.metrics.serviceMonitor.enabled }} +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: {{ include "common.names.fullname" . }} + {{- if .Values.metrics.serviceMonitor.namespace }} + namespace: {{ .Values.metrics.serviceMonitor.namespace }} + {{- else }} + namespace: {{ .Release.Namespace | quote }} + {{- end }} + labels: {{- include "common.labels.standard" . | nindent 4 }} + {{- if .Values.commonLabels }} + {{- include "common.tplvalues.render" ( dict "value" .Values.commonLabels "context" $ ) | nindent 4 }} + {{- end }} + {{- if .Values.metrics.serviceMonitor.labels }} + {{- include "common.tplvalues.render" (dict "value" .Values.metrics.serviceMonitor.labels "context" $) | nindent 4 }} + {{- end }} + {{- if .Values.commonAnnotations }} + annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} + {{- end }} +spec: + jobLabel: {{ .Values.metrics.serviceMonitor.jobLabel | quote }} + endpoints: + - port: metrics + {{- if .Values.metrics.serviceMonitor.interval }} + interval: {{ .Values.metrics.serviceMonitor.interval }} + {{- end }} + {{- if .Values.metrics.serviceMonitor.scrapeTimeout }} + scrapeTimeout: {{ .Values.metrics.serviceMonitor.scrapeTimeout }} + {{- end }} + {{- if .Values.metrics.serviceMonitor.honorLabels }} + honorLabels: {{ .Values.metrics.serviceMonitor.honorLabels }} + {{- end }} + {{- if .Values.metrics.serviceMonitor.metricRelabelings }} + metricRelabelings: {{- include "common.tplvalues.render" ( dict "value" .Values.metrics.serviceMonitor.metricRelabelings "context" $) | nindent 8 }} + {{- end }} + {{- if .Values.metrics.serviceMonitor.relabelings }} + relabelings: {{- include "common.tplvalues.render" ( dict "value" .Values.metrics.serviceMonitor.relabelings "context" $) | nindent 8 }} + {{- end }} + namespaceSelector: + matchNames: + - {{ .Release.Namespace | quote }} + selector: + matchLabels: {{- include "common.labels.matchLabels" . | nindent 6 }} + {{- if .Values.metrics.serviceMonitor.selector }} + {{- include "common.tplvalues.render" (dict "value" .Values.metrics.serviceMonitor.selector "context" $) | nindent 6 }} + {{- end }} +{{- end }} diff --git a/charts/limesurvey-martial-ingress-v9/charts/mariadb/values.schema.json b/charts/limesurvey-martial-ingress-v9/charts/mariadb/values.schema.json new file mode 100644 index 0000000..500c4eb --- /dev/null +++ b/charts/limesurvey-martial-ingress-v9/charts/mariadb/values.schema.json @@ -0,0 +1,176 @@ +{ + "$schema": "http://json-schema.org/schema#", + "type": "object", + "properties": { + "architecture": { + "type": "string", + "title": "MariaDB architecture", + "form": true, + "description": "Allowed values: `standalone` or `replication`" + }, + "auth": { + "type": "object", + "title": "Authentication configuration", + "form": true, + "properties": { + "rootPassword": { + "type": "string", + "title": "MariaDB root password", + "form": true, + "description": "Defaults to a random 10-character alphanumeric string if not set" + }, + "database": { + "type": "string", + "title": "MariaDB custom database", + "description": "Name of the custom database to be created during the 1st initialization of MariaDB", + "form": true + }, + "username": { + "type": "string", + "title": "MariaDB custom user", + "description": "Name of the custom user to be created during the 1st initialization of MariaDB. This user only has permissions on the MariaDB custom database", + "form": true + }, + "password": { + "type": "string", + "title": "Password for MariaDB custom user", + "description": "Defaults to a random 10-character alphanumeric string if not set", + "form": true, + "hidden": { + "value": false, + "path": "usePassword" + } + }, + "replicationUser": { + "type": "string", + "title": "MariaDB replication user", + "description": "Name of user used to manage replication.", + "form": true, + "hidden": { + "value": "standalone", + "path": "architecture" + } + }, + "replicationPassword": { + "type": "string", + "title": "Password for MariaDB replication user", + "description": "Defaults to a random 10-character alphanumeric string if not set", + "form": true, + "hidden": { + "value": "standalone", + "path": "architecture" + } + } + } + }, + "primary": { + "type": "object", + "title": "Primary replicas settings", + "form": true, + "properties": { + "persistence": { + "type": "object", + "title": "Persistence for primary replicas", + "form": true, + "properties": { + "enabled": { + "type": "boolean", + "form": true, + "title": "Enable persistence", + "description": "Enable persistence using Persistent Volume Claims" + }, + "size": { + "type": "string", + "title": "Persistent Volume Size", + "form": true, + "render": "slider", + "sliderMin": 1, + "sliderMax": 100, + "sliderUnit": "Gi", + "hidden": { + "value": false, + "path": "persistence/enabled" + } + } + } + } + } + }, + "secondary": { + "type": "object", + "title": "Secondary replicas settings", + "form": true, + "hidden": { + "value": false, + "path": "replication/enabled" + }, + "properties": { + "persistence": { + "type": "object", + "title": "Persistence for secondary replicas", + "form": true, + "properties": { + "enabled": { + "type": "boolean", + "form": true, + "title": "Enable persistence", + "description": "Enable persistence using Persistent Volume Claims" + }, + "size": { + "type": "string", + "title": "Persistent Volume Size", + "form": true, + "render": "slider", + "sliderMin": 1, + "sliderMax": 100, + "sliderUnit": "Gi", + "hidden": { + "value": false, + "path": "persistence/enabled" + } + } + } + } + } + }, + "volumePermissions": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean", + "form": true, + "title": "Enable Init Containers", + "description": "Use an init container to set required folder permissions on the data volume before mounting it in the final destination" + } + } + }, + "metrics": { + "type": "object", + "form": true, + "title": "Prometheus metrics details", + "properties": { + "enabled": { + "type": "boolean", + "title": "Create Prometheus metrics exporter", + "description": "Create a side-car container to expose Prometheus metrics", + "form": true + }, + "serviceMonitor": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean", + "title": "Create Prometheus Operator ServiceMonitor", + "description": "Create a ServiceMonitor to track metrics using Prometheus Operator", + "form": true, + "hidden": { + "value": false, + "path": "metrics/enabled" + } + } + } + } + } + } + } +} diff --git a/charts/limesurvey-martial-ingress-v9/charts/mariadb/values.yaml b/charts/limesurvey-martial-ingress-v9/charts/mariadb/values.yaml new file mode 100644 index 0000000..7d3dae9 --- /dev/null +++ b/charts/limesurvey-martial-ingress-v9/charts/mariadb/values.yaml @@ -0,0 +1,1311 @@ +## @section Global parameters +## Global Docker image parameters +## Please, note that this will override the image parameters, including dependencies, configured to use the global value +## Current available global Docker image parameters: imageRegistry, imagePullSecrets and storageClass +## + +## @param global.imageRegistry Global Docker Image registry +## @param global.imagePullSecrets Global Docker registry secret names as an array +## @param global.storageClass Global storage class for dynamic provisioning +## +global: + imageRegistry: "" + ## E.g. + ## imagePullSecrets: + ## - myRegistryKeySecretName + ## + imagePullSecrets: [] + storageClass: "" + +## @section Common parameters +## + +## @param kubeVersion Force target Kubernetes version (using Helm capabilities if not set) +## +kubeVersion: "" +## @param nameOverride String to partially override mariadb.fullname +## +nameOverride: "" +## @param fullnameOverride String to fully override mariadb.fullname +## +fullnameOverride: "" +## @param clusterDomain Default Kubernetes cluster domain +## +clusterDomain: cluster.local +## @param commonAnnotations Common annotations to add to all MariaDB resources (sub-charts are not considered) +## +commonAnnotations: {} +## @param commonLabels Common labels to add to all MariaDB resources (sub-charts are not considered) +## +commonLabels: {} +## @param schedulerName Name of the scheduler (other than default) to dispatch pods +## ref: https://kubernetes.io/docs/tasks/administer-cluster/configure-multiple-schedulers/ +## +schedulerName: "" +## @param runtimeClassName Name of the Runtime Class for all MariaDB pods +## ref: https://kubernetes.io/docs/concepts/containers/runtime-class/ +## +runtimeClassName: "" +## @param extraDeploy Array of extra objects to deploy with the release (evaluated as a template) +## +extraDeploy: [] + +## Enable diagnostic mode in the deployment +## +diagnosticMode: + ## @param diagnosticMode.enabled Enable diagnostic mode (all probes will be disabled and the command will be overridden) + ## + enabled: false + ## @param diagnosticMode.command Command to override all containers in the deployment + ## + command: + - sleep + ## @param diagnosticMode.args Args to override all containers in the deployment + ## + args: + - infinity + +## @section MariaDB common parameters +## + +## Bitnami MariaDB image +## ref: https://hub.docker.com/r/bitnami/mariadb/tags/ +## @param image.registry MariaDB image registry +## @param image.repository MariaDB image repository +## @param image.tag MariaDB image tag (immutable tags are recommended) +## @param image.digest MariaDB image digest in the way sha256:aa.... Please note this parameter, if set, will override the tag +## @param image.pullPolicy MariaDB image pull policy +## @param image.pullSecrets Specify docker-registry secret names as an array +## @param image.debug Specify if debug logs should be enabled +## +image: + registry: docker.io + repository: bitnami/mariadb + tag: 10.6.11-debian-11-r12 + digest: "" + ## Specify a imagePullPolicy + ## Defaults to 'Always' if image tag is 'latest', else set to 'IfNotPresent' + ## ref: https://kubernetes.io/docs/user-guide/images/#pre-pulling-images + ## + pullPolicy: IfNotPresent + ## Optionally specify an array of imagePullSecrets (secrets must be manually created in the namespace) + ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/ + ## Example: + ## pullSecrets: + ## - myRegistryKeySecretName + ## + pullSecrets: [] + ## Set to true if you would like to see extra information on logs + ## It turns BASH and/or NAMI debugging in the image + ## + debug: false +## @param architecture MariaDB architecture (`standalone` or `replication`) +## +architecture: standalone +## MariaDB Authentication parameters +## +auth: + ## @param auth.rootPassword Password for the `root` user. Ignored if existing secret is provided. + ## ref: https://github.com/bitnami/containers/tree/main/bitnami/mariadb#setting-the-root-password-on-first-run + ## + rootPassword: "limesurvey" + ## @param auth.database Name for a custom database to create + ## ref: https://github.com/bitnami/containers/blob/main/bitnami/mariadb/README.md#creating-a-database-on-first-run + ## + database: limesurvey + ## @param auth.username Name for a custom user to create + ## ref: https://github.com/bitnami/containers/blob/main/bitnami/mariadb/README.md#creating-a-database-user-on-first-run + ## + username: "limesurvey" + ## @param auth.password Password for the new user. Ignored if existing secret is provided + ## + password: "limesurvey" + ## @param auth.replicationUser MariaDB replication user + ## ref: https://github.com/bitnami/containers/tree/main/bitnami/mariadb#setting-up-a-replication-cluster + ## + replicationUser: replicator + ## @param auth.replicationPassword MariaDB replication user password. Ignored if existing secret is provided + ## ref: https://github.com/bitnami/containers/tree/main/bitnami/mariadb#setting-up-a-replication-cluster + ## + replicationPassword: "" + ## @param auth.existingSecret Use existing secret for password details (`auth.rootPassword`, `auth.password`, `auth.replicationPassword` will be ignored and picked up from this secret). The secret has to contain the keys `mariadb-root-password`, `mariadb-replication-password` and `mariadb-password` + ## + existingSecret: "" + ## @param auth.forcePassword Force users to specify required passwords + ## + forcePassword: false + ## @param auth.usePasswordFiles Mount credentials as files instead of using environment variables + ## + usePasswordFiles: false + ## @param auth.customPasswordFiles Use custom password files when `auth.usePasswordFiles` is set to `true`. Define path for keys `root` and `user`, also define `replicator` if `architecture` is set to `replication` + ## Example: + ## customPasswordFiles: + ## root: /vault/secrets/mariadb-root + ## user: /vault/secrets/mariadb-user + ## replicator: /vault/secrets/mariadb-replicator + ## + customPasswordFiles: {} +## @param initdbScripts Dictionary of initdb scripts +## Specify dictionary of scripts to be run at first boot +## Example: +## initdbScripts: +## my_init_script.sh: | +## #!/bin/bash +## echo "Do something." +## +initdbScripts: {} +## @param initdbScriptsConfigMap ConfigMap with the initdb scripts (Note: Overrides `initdbScripts`) +## +initdbScriptsConfigMap: "" + +## @section MariaDB Primary parameters +## + +## Mariadb Primary parameters +## +primary: + ## @param primary.name Name of the primary database (eg primary, master, leader, ...) + ## + name: primary + ## @param primary.command Override default container command on MariaDB Primary container(s) (useful when using custom images) + ## + command: [] + ## @param primary.args Override default container args on MariaDB Primary container(s) (useful when using custom images) + ## + args: [] + ## @param primary.lifecycleHooks for the MariaDB Primary container(s) to automate configuration before or after startup + ## + lifecycleHooks: {} + ## @param primary.hostAliases Add deployment host aliases + ## https://kubernetes.io/docs/concepts/services-networking/add-entries-to-pod-etc-hosts-with-host-aliases/ + ## + hostAliases: [] + ## @param primary.configuration [string] MariaDB Primary configuration to be injected as ConfigMap + ## ref: https://mysql.com/kb/en/mysql/configuring-mysql-with-mycnf/#example-of-configuration-file + ## + configuration: |- + [mysqld] + skip-name-resolve + explicit_defaults_for_timestamp + basedir=/opt/bitnami/mariadb + plugin_dir=/opt/bitnami/mariadb/plugin + port=3306 + socket=/opt/bitnami/mariadb/tmp/mysql.sock + tmpdir=/opt/bitnami/mariadb/tmp + max_allowed_packet=16M + bind-address=* + pid-file=/opt/bitnami/mariadb/tmp/mysqld.pid + log-error=/opt/bitnami/mariadb/logs/mysqld.log + character-set-server=UTF8 + collation-server=utf8_general_ci + slow_query_log=0 + slow_query_log_file=/opt/bitnami/mariadb/logs/mysqld.log + long_query_time=10.0 + + [client] + port=3306 + socket=/opt/bitnami/mariadb/tmp/mysql.sock + default-character-set=UTF8 + plugin_dir=/opt/bitnami/mariadb/plugin + + [manager] + port=3306 + socket=/opt/bitnami/mariadb/tmp/mysql.sock + pid-file=/opt/bitnami/mariadb/tmp/mysqld.pid + ## @param primary.existingConfigmap Name of existing ConfigMap with MariaDB Primary configuration. + ## NOTE: When it's set the 'configuration' parameter is ignored + ## + existingConfigmap: "" + ## @param primary.updateStrategy.type MariaDB primary statefulset strategy type + ## ref: https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/#update-strategies + ## + updateStrategy: + ## StrategyType + ## Can be set to RollingUpdate or OnDelete + ## + type: RollingUpdate + ## @param primary.rollingUpdatePartition Partition update strategy for Mariadb Primary statefulset + ## https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/#partitions + ## + rollingUpdatePartition: "" + ## @param primary.podAnnotations Additional pod annotations for MariaDB primary pods + ## ref: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/ + ## + podAnnotations: {} + ## @param primary.podLabels Extra labels for MariaDB primary pods + ## ref: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/ + ## + podLabels: {} + ## @param primary.podAffinityPreset MariaDB primary pod affinity preset. Ignored if `primary.affinity` is set. Allowed values: `soft` or `hard` + ## ref: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#inter-pod-affinity-and-anti-affinity + ## + podAffinityPreset: "" + ## @param primary.podAntiAffinityPreset MariaDB primary pod anti-affinity preset. Ignored if `primary.affinity` is set. Allowed values: `soft` or `hard` + ## Ref: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#inter-pod-affinity-and-anti-affinity + ## + podAntiAffinityPreset: soft + ## Mariadb Primary node affinity preset + ## Ref: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#node-affinity + ## + nodeAffinityPreset: + ## @param primary.nodeAffinityPreset.type MariaDB primary node affinity preset type. Ignored if `primary.affinity` is set. Allowed values: `soft` or `hard` + ## + type: "" + ## @param primary.nodeAffinityPreset.key MariaDB primary node label key to match Ignored if `primary.affinity` is set. + ## E.g. + ## key: "kubernetes.io/e2e-az-name" + ## + key: "" + ## @param primary.nodeAffinityPreset.values MariaDB primary node label values to match. Ignored if `primary.affinity` is set. + ## E.g. + ## values: + ## - e2e-az1 + ## - e2e-az2 + ## + values: [] + ## @param primary.affinity Affinity for MariaDB primary pods assignment + ## Ref: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#affinity-and-anti-affinity + ## Note: podAffinityPreset, podAntiAffinityPreset, and nodeAffinityPreset will be ignored when it's set + ## + affinity: {} + ## @param primary.nodeSelector Node labels for MariaDB primary pods assignment + ## Ref: https://kubernetes.io/docs/user-guide/node-selection/ + ## + nodeSelector: {} + ## @param primary.tolerations Tolerations for MariaDB primary pods assignment + ## Ref: https://kubernetes.io/docs/concepts/configuration/taint-and-toleration/ + ## + tolerations: [] + ## @param primary.schedulerName Name of the k8s scheduler (other than default) + ## ref: https://kubernetes.io/docs/tasks/administer-cluster/configure-multiple-schedulers/ + ## + schedulerName: "" + ## @param primary.podManagementPolicy podManagementPolicy to manage scaling operation of MariaDB primary pods + ## ref: https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/#pod-management-policies + ## + podManagementPolicy: "" + ## @param primary.topologySpreadConstraints Topology Spread Constraints for MariaDB primary pods assignment + ## ref: https://kubernetes.io/docs/concepts/workloads/pods/pod-topology-spread-constraints/ + ## E.g. + ## topologySpreadConstraints: + ## - maxSkew: 1 + ## topologyKey: topology.kubernetes.io/zone + ## whenUnsatisfiable: DoNotSchedule + ## + topologySpreadConstraints: [] + ## @param primary.priorityClassName Priority class for MariaDB primary pods assignment + ## Ref: https://kubernetes.io/docs/concepts/configuration/pod-priority-preemption/ + ## + priorityClassName: "" + ## @param primary.runtimeClassName Runtime Class for MariaDB primary pods + ## Ref: https://kubernetes.io/docs/concepts/containers/runtime-class/ + ## + runtimeClassName: "" + ## MariaDB primary Pod security context + ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/#set-the-security-context-for-a-pod + ## @param primary.podSecurityContext.enabled Enable security context for MariaDB primary pods + ## @param primary.podSecurityContext.fsGroup Group ID for the mounted volumes' filesystem + ## + podSecurityContext: + enabled: true + fsGroup: 1001 + ## MariaDB primary container security context + ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/#set-the-security-context-for-a-container + ## @param primary.containerSecurityContext.enabled MariaDB primary container securityContext + ## @param primary.containerSecurityContext.runAsUser User ID for the MariaDB primary container + ## @param primary.containerSecurityContext.runAsNonRoot Set Controller container's Security Context runAsNonRoot + ## + containerSecurityContext: + enabled: true + runAsUser: 1001 + runAsNonRoot: true + ## MariaDB primary container's resource requests and limits + ## ref: https://kubernetes.io/docs/user-guide/compute-resources/ + ## We usually recommend not to specify default resources and to leave this as a conscious + ## choice for the user. This also increases chances charts run on environments with little + ## resources, such as Minikube. If you do want to specify resources, uncomment the following + ## lines, adjust them as necessary, and remove the curly braces after 'resources:'. + ## @param primary.resources.limits The resources limits for MariaDB primary containers + ## @param primary.resources.requests The requested resources for MariaDB primary containers + ## + resources: + ## Example: + ## limits: + ## cpu: 100m + ## memory: 256Mi + ## + limits: {} + ## Examples: + ## requests: + ## cpu: 100m + ## memory: 256Mi + ## + requests: {} + ## Configure extra options for MariaDB primary containers' liveness, readiness and startup probes + ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-probes/#configure-probes) + ## @param primary.startupProbe.enabled Enable startupProbe + ## @param primary.startupProbe.initialDelaySeconds Initial delay seconds for startupProbe + ## @param primary.startupProbe.periodSeconds Period seconds for startupProbe + ## @param primary.startupProbe.timeoutSeconds Timeout seconds for startupProbe + ## @param primary.startupProbe.failureThreshold Failure threshold for startupProbe + ## @param primary.startupProbe.successThreshold Success threshold for startupProbe + ## + startupProbe: + enabled: false + initialDelaySeconds: 120 + periodSeconds: 15 + timeoutSeconds: 5 + failureThreshold: 10 + successThreshold: 1 + ## Configure extra options for liveness probe + ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-probes/#configure-probes + ## @param primary.livenessProbe.enabled Enable livenessProbe + ## @param primary.livenessProbe.initialDelaySeconds Initial delay seconds for livenessProbe + ## @param primary.livenessProbe.periodSeconds Period seconds for livenessProbe + ## @param primary.livenessProbe.timeoutSeconds Timeout seconds for livenessProbe + ## @param primary.livenessProbe.failureThreshold Failure threshold for livenessProbe + ## @param primary.livenessProbe.successThreshold Success threshold for livenessProbe + ## + livenessProbe: + enabled: true + initialDelaySeconds: 120 + periodSeconds: 10 + timeoutSeconds: 1 + failureThreshold: 3 + successThreshold: 1 + ## @param primary.readinessProbe.enabled Enable readinessProbe + ## @param primary.readinessProbe.initialDelaySeconds Initial delay seconds for readinessProbe + ## @param primary.readinessProbe.periodSeconds Period seconds for readinessProbe + ## @param primary.readinessProbe.timeoutSeconds Timeout seconds for readinessProbe + ## @param primary.readinessProbe.failureThreshold Failure threshold for readinessProbe + ## @param primary.readinessProbe.successThreshold Success threshold for readinessProbe + ## + readinessProbe: + enabled: true + initialDelaySeconds: 30 + periodSeconds: 10 + timeoutSeconds: 1 + failureThreshold: 3 + successThreshold: 1 + ## @param primary.customStartupProbe Override default startup probe for MariaDB primary containers + ## + customStartupProbe: {} + ## @param primary.customLivenessProbe Override default liveness probe for MariaDB primary containers + ## + customLivenessProbe: {} + ## @param primary.customReadinessProbe Override default readiness probe for MariaDB primary containers + ## + customReadinessProbe: {} + ## @param primary.startupWaitOptions Override default builtin startup wait check options for MariaDB primary containers + ## `bitnami/mariadb` Docker image has built-in startup check mechanism, + ## which periodically checks if MariaDB service has started up and stops it + ## if all checks have failed after X tries. Use these to control these checks. + ## ref: https://github.com/bitnami/containers/tree/main/bitnami/mariadb/pull/240 + ## Example (with default options): + ## startupWaitOptions: + ## retries: 300 + ## waitTime: 2 + ## + startupWaitOptions: {} + ## @param primary.extraFlags MariaDB primary additional command line flags + ## Can be used to specify command line flags, for example: + ## E.g. + ## extraFlags: "--max-connect-errors=1000 --max_connections=155" + ## + extraFlags: "" + ## @param primary.extraEnvVars Extra environment variables to be set on MariaDB primary containers + ## E.g. + ## extraEnvVars: + ## - name: TZ + ## value: "Europe/Paris" + ## + extraEnvVars: [] + ## @param primary.extraEnvVarsCM Name of existing ConfigMap containing extra env vars for MariaDB primary containers + ## + extraEnvVarsCM: "" + ## @param primary.extraEnvVarsSecret Name of existing Secret containing extra env vars for MariaDB primary containers + ## + extraEnvVarsSecret: "" + ## Enable persistence using Persistent Volume Claims + ## ref: https://kubernetes.io/docs/user-guide/persistent-volumes/ + ## + persistence: + ## @param primary.persistence.enabled Enable persistence on MariaDB primary replicas using a `PersistentVolumeClaim`. If false, use emptyDir + ## + enabled: true + ## @param primary.persistence.existingClaim Name of an existing `PersistentVolumeClaim` for MariaDB primary replicas + ## NOTE: When it's set the rest of persistence parameters are ignored + ## + existingClaim: "" + ## @param primary.persistence.subPath Subdirectory of the volume to mount at + ## + subPath: "" + ## @param primary.persistence.storageClass MariaDB primary persistent volume storage Class + ## If defined, storageClassName: + ## If set to "-", storageClassName: "", which disables dynamic provisioning + ## If undefined (the default) or set to null, no storageClassName spec is + ## set, choosing the default provisioner. (gp2 on AWS, standard on + ## GKE, AWS & OpenStack) + ## + storageClass: "" + ## @param primary.persistence.annotations MariaDB primary persistent volume claim annotations + ## + annotations: {} + ## @param primary.persistence.accessModes MariaDB primary persistent volume access Modes + ## + accessModes: + - ReadWriteOnce + ## @param primary.persistence.size MariaDB primary persistent volume size + ## + size: 8Gi + ## @param primary.persistence.selector Selector to match an existing Persistent Volume + ## selector: + ## matchLabels: + ## app: my-app + ## + selector: {} + ## @param primary.extraVolumes Optionally specify extra list of additional volumes to the MariaDB Primary pod(s) + ## + extraVolumes: [] + ## @param primary.extraVolumeMounts Optionally specify extra list of additional volumeMounts for the MariaDB Primary container(s) + ## + extraVolumeMounts: [] + ## @param primary.initContainers Add additional init containers for the MariaDB Primary pod(s) + ## + initContainers: [] + ## @param primary.sidecars Add additional sidecar containers for the MariaDB Primary pod(s) + ## + sidecars: [] + ## MariaDB Primary Service parameters + ## + service: + ## @param primary.service.type MariaDB Primary Kubernetes service type + ## + type: ClusterIP + ports: + ## @param primary.service.ports.mysql MariaDB Primary Kubernetes service port for MariaDB + ## + mysql: 3306 + ## @param primary.service.ports.metrics MariaDB Primary Kubernetes service port for metrics + ## + metrics: 9104 + ## @param primary.service.nodePorts.mysql MariaDB Primary Kubernetes service node port + ## ref: https://kubernetes.io/docs/concepts/services-networking/service/#type-nodeport + ## + nodePorts: + mysql: "" + ## @param primary.service.clusterIP MariaDB Primary Kubernetes service clusterIP IP + ## + clusterIP: "" + ## @param primary.service.loadBalancerIP MariaDB Primary loadBalancerIP if service type is `LoadBalancer` + ## ref: https://kubernetes.io/docs/concepts/services-networking/service/#internal-load-balancer + ## + loadBalancerIP: "" + ## @param primary.service.externalTrafficPolicy Enable client source IP preservation + ## ref https://kubernetes.io/docs/tasks/access-application-cluster/create-external-load-balancer/#preserving-the-client-source-ip + ## + externalTrafficPolicy: Cluster + ## @param primary.service.loadBalancerSourceRanges Address that are allowed when MariaDB Primary service is LoadBalancer + ## https://kubernetes.io/docs/tasks/access-application-cluster/configure-cloud-provider-firewall/#restrict-access-for-loadbalancer-service + ## E.g. + ## loadBalancerSourceRanges: + ## - 10.10.10.0/24 + ## + loadBalancerSourceRanges: [] + ## @param primary.service.extraPorts Extra ports to expose (normally used with the `sidecar` value) + ## + extraPorts: [] + ## @param primary.service.annotations Provide any additional annotations which may be required + ## + annotations: {} + ## @param primary.service.sessionAffinity Session Affinity for Kubernetes service, can be "None" or "ClientIP" + ## If "ClientIP", consecutive client requests will be directed to the same Pod + ## ref: https://kubernetes.io/docs/concepts/services-networking/service/#virtual-ips-and-service-proxies + ## + sessionAffinity: None + ## @param primary.service.sessionAffinityConfig Additional settings for the sessionAffinity + ## sessionAffinityConfig: + ## clientIP: + ## timeoutSeconds: 300 + ## + sessionAffinityConfig: {} + ## MariaDB primary Pod Disruption Budget configuration + ## ref: https://kubernetes.io/docs/tasks/run-application/configure-pdb/ + ## + pdb: + ## @param primary.pdb.create Enable/disable a Pod Disruption Budget creation for MariaDB primary pods + ## + create: false + ## @param primary.pdb.minAvailable Minimum number/percentage of MariaDB primary pods that must still be available after the eviction + ## + minAvailable: 1 + ## @param primary.pdb.maxUnavailable Maximum number/percentage of MariaDB primary pods that can be unavailable after the eviction + ## + maxUnavailable: "" + ## @param primary.revisionHistoryLimit Maximum number of revisions that will be maintained in the StatefulSet + ## + revisionHistoryLimit: 10 + +## @section MariaDB Secondary parameters +## + +## Mariadb Secondary parameters +## +secondary: + ## @param secondary.name Name of the secondary database (eg secondary, slave, ...) + ## + name: secondary + ## @param secondary.replicaCount Number of MariaDB secondary replicas + ## + replicaCount: 1 + ## @param secondary.command Override default container command on MariaDB Secondary container(s) (useful when using custom images) + ## + command: [] + ## @param secondary.args Override default container args on MariaDB Secondary container(s) (useful when using custom images) + ## + args: [] + ## @param secondary.lifecycleHooks for the MariaDB Secondary container(s) to automate configuration before or after startup + ## + lifecycleHooks: {} + ## @param secondary.hostAliases Add deployment host aliases + ## https://kubernetes.io/docs/concepts/services-networking/add-entries-to-pod-etc-hosts-with-host-aliases/ + ## + hostAliases: [] + ## @param secondary.configuration [string] MariaDB Secondary configuration to be injected as ConfigMap + ## ref: https://mysql.com/kb/en/mysql/configuring-mysql-with-mycnf/#example-of-configuration-file + ## + configuration: |- + [mysqld] + skip-name-resolve + explicit_defaults_for_timestamp + basedir=/opt/bitnami/mariadb + port=3306 + socket=/opt/bitnami/mariadb/tmp/mysql.sock + tmpdir=/opt/bitnami/mariadb/tmp + max_allowed_packet=16M + bind-address=0.0.0.0 + pid-file=/opt/bitnami/mariadb/tmp/mysqld.pid + log-error=/opt/bitnami/mariadb/logs/mysqld.log + character-set-server=UTF8 + collation-server=utf8_general_ci + slow_query_log=0 + slow_query_log_file=/opt/bitnami/mariadb/logs/mysqld.log + long_query_time=10.0 + + [client] + port=3306 + socket=/opt/bitnami/mariadb/tmp/mysql.sock + default-character-set=UTF8 + + [manager] + port=3306 + socket=/opt/bitnami/mariadb/tmp/mysql.sock + pid-file=/opt/bitnami/mariadb/tmp/mysqld.pid + ## @param secondary.existingConfigmap Name of existing ConfigMap with MariaDB Secondary configuration. + ## NOTE: When it's set the 'configuration' parameter is ignored + ## + existingConfigmap: "" + ## @param secondary.updateStrategy.type MariaDB secondary statefulset strategy type + ## ref: https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/#update-strategies + ## + updateStrategy: + ## StrategyType + ## Can be set to RollingUpdate or OnDelete + ## + type: RollingUpdate + ## @param secondary.rollingUpdatePartition Partition update strategy for Mariadb Secondary statefulset + ## https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/#partitions + ## + rollingUpdatePartition: "" + ## @param secondary.podAnnotations Additional pod annotations for MariaDB secondary pods + ## ref: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/ + ## + podAnnotations: {} + ## @param secondary.podLabels Extra labels for MariaDB secondary pods + ## ref: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/ + ## + podLabels: {} + ## @param secondary.podAffinityPreset MariaDB secondary pod affinity preset. Ignored if `secondary.affinity` is set. Allowed values: `soft` or `hard` + ## ref: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#inter-pod-affinity-and-anti-affinity + ## + podAffinityPreset: "" + ## @param secondary.podAntiAffinityPreset MariaDB secondary pod anti-affinity preset. Ignored if `secondary.affinity` is set. Allowed values: `soft` or `hard` + ## Ref: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#inter-pod-affinity-and-anti-affinity + ## + podAntiAffinityPreset: soft + ## Mariadb Secondary node affinity preset + ## Ref: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#node-affinity + ## + nodeAffinityPreset: + ## @param secondary.nodeAffinityPreset.type MariaDB secondary node affinity preset type. Ignored if `secondary.affinity` is set. Allowed values: `soft` or `hard` + ## + type: "" + ## @param secondary.nodeAffinityPreset.key MariaDB secondary node label key to match Ignored if `secondary.affinity` is set. + ## E.g. + ## key: "kubernetes.io/e2e-az-name" + ## + key: "" + ## @param secondary.nodeAffinityPreset.values MariaDB secondary node label values to match. Ignored if `secondary.affinity` is set. + ## E.g. + ## values: + ## - e2e-az1 + ## - e2e-az2 + ## + values: [] + ## @param secondary.affinity Affinity for MariaDB secondary pods assignment + ## Ref: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#affinity-and-anti-affinity + ## Note: podAffinityPreset, podAntiAffinityPreset, and nodeAffinityPreset will be ignored when it's set + ## + affinity: {} + ## @param secondary.nodeSelector Node labels for MariaDB secondary pods assignment + ## Ref: https://kubernetes.io/docs/user-guide/node-selection/ + ## + nodeSelector: {} + ## @param secondary.tolerations Tolerations for MariaDB secondary pods assignment + ## Ref: https://kubernetes.io/docs/concepts/configuration/taint-and-toleration/ + ## + tolerations: [] + ## @param secondary.topologySpreadConstraints Topology Spread Constraints for MariaDB secondary pods assignment + ## ref: https://kubernetes.io/docs/concepts/workloads/pods/pod-topology-spread-constraints/ + ## E.g. + ## topologySpreadConstraints: + ## - maxSkew: 1 + ## topologyKey: topology.kubernetes.io/zone + ## whenUnsatisfiable: DoNotSchedule + ## + topologySpreadConstraints: [] + ## @param secondary.priorityClassName Priority class for MariaDB secondary pods assignment + ## Ref: https://kubernetes.io/docs/concepts/configuration/pod-priority-preemption/ + ## + priorityClassName: "" + ## @param secondary.runtimeClassName Runtime Class for MariaDB secondary pods + ## Ref: https://kubernetes.io/docs/concepts/containers/runtime-class/ + ## + runtimeClassName: "" + ## @param secondary.schedulerName Name of the k8s scheduler (other than default) + ## ref: https://kubernetes.io/docs/tasks/administer-cluster/configure-multiple-schedulers/ + ## + schedulerName: "" + ## @param secondary.podManagementPolicy podManagementPolicy to manage scaling operation of MariaDB secondary pods + ## ref: https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/#pod-management-policies + ## + podManagementPolicy: "" + ## MariaDB secondary Pod security context + ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/#set-the-security-context-for-a-pod + ## @param secondary.podSecurityContext.enabled Enable security context for MariaDB secondary pods + ## @param secondary.podSecurityContext.fsGroup Group ID for the mounted volumes' filesystem + ## + podSecurityContext: + enabled: true + fsGroup: 1001 + ## MariaDB secondary container security context + ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/#set-the-security-context-for-a-container + ## @param secondary.containerSecurityContext.enabled MariaDB secondary container securityContext + ## @param secondary.containerSecurityContext.runAsUser User ID for the MariaDB secondary container + ## @param secondary.containerSecurityContext.runAsNonRoot Set Controller container's Security Context runAsNonRoot + ## + containerSecurityContext: + enabled: true + runAsUser: 1001 + runAsNonRoot: true + ## MariaDB secondary container's resource requests and limits + ## ref: https://kubernetes.io/docs/user-guide/compute-resources/ + ## We usually recommend not to specify default resources and to leave this as a conscious + ## choice for the user. This also increases chances charts run on environments with little + ## resources, such as Minikube. If you do want to specify resources, uncomment the following + ## lines, adjust them as necessary, and remove the curly braces after 'resources:'. + ## @param secondary.resources.limits The resources limits for MariaDB secondary containers + ## @param secondary.resources.requests The requested resources for MariaDB secondary containers + ## + resources: + ## Example: + ## limits: + ## cpu: 100m + ## memory: 256Mi + ## + limits: {} + ## Examples: + ## requests: + ## cpu: 100m + ## memory: 256Mi + ## + requests: {} + ## Configure extra options for MariaDB Secondary containers' liveness, readiness and startup probes + ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-probes/#configure-probes) + ## @param secondary.startupProbe.enabled Enable startupProbe + ## @param secondary.startupProbe.initialDelaySeconds Initial delay seconds for startupProbe + ## @param secondary.startupProbe.periodSeconds Period seconds for startupProbe + ## @param secondary.startupProbe.timeoutSeconds Timeout seconds for startupProbe + ## @param secondary.startupProbe.failureThreshold Failure threshold for startupProbe + ## @param secondary.startupProbe.successThreshold Success threshold for startupProbe + ## + startupProbe: + enabled: false + initialDelaySeconds: 120 + periodSeconds: 15 + timeoutSeconds: 5 + failureThreshold: 10 + successThreshold: 1 + ## Configure extra options for liveness probe + ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-probes/#configure-probes + ## @param secondary.livenessProbe.enabled Enable livenessProbe + ## @param secondary.livenessProbe.initialDelaySeconds Initial delay seconds for livenessProbe + ## @param secondary.livenessProbe.periodSeconds Period seconds for livenessProbe + ## @param secondary.livenessProbe.timeoutSeconds Timeout seconds for livenessProbe + ## @param secondary.livenessProbe.failureThreshold Failure threshold for livenessProbe + ## @param secondary.livenessProbe.successThreshold Success threshold for livenessProbe + ## + livenessProbe: + enabled: true + initialDelaySeconds: 120 + periodSeconds: 10 + timeoutSeconds: 1 + failureThreshold: 3 + successThreshold: 1 + ## @param secondary.readinessProbe.enabled Enable readinessProbe + ## @param secondary.readinessProbe.initialDelaySeconds Initial delay seconds for readinessProbe + ## @param secondary.readinessProbe.periodSeconds Period seconds for readinessProbe + ## @param secondary.readinessProbe.timeoutSeconds Timeout seconds for readinessProbe + ## @param secondary.readinessProbe.failureThreshold Failure threshold for readinessProbe + ## @param secondary.readinessProbe.successThreshold Success threshold for readinessProbe + ## + readinessProbe: + enabled: true + initialDelaySeconds: 30 + periodSeconds: 10 + timeoutSeconds: 1 + failureThreshold: 3 + successThreshold: 1 + ## @param secondary.customStartupProbe Override default startup probe for MariaDB secondary containers + ## + customStartupProbe: {} + ## @param secondary.customLivenessProbe Override default liveness probe for MariaDB secondary containers + ## + customLivenessProbe: {} + ## @param secondary.customReadinessProbe Override default readiness probe for MariaDB secondary containers + ## + customReadinessProbe: {} + ## @param secondary.startupWaitOptions Override default builtin startup wait check options for MariaDB secondary containers + ## `bitnami/mariadb` Docker image has built-in startup check mechanism, + ## which periodically checks if MariaDB service has started up and stops it + ## if all checks have failed after X tries. Use these to control these checks. + ## ref: https://github.com/bitnami/containers/tree/main/bitnami/mariadb/pull/240 + ## Example (with default options): + ## startupWaitOptions: + ## retries: 300 + ## waitTime: 2 + ## + startupWaitOptions: {} + ## @param secondary.extraFlags MariaDB secondary additional command line flags + ## Can be used to specify command line flags, for example: + ## E.g. + ## extraFlags: "--max-connect-errors=1000 --max_connections=155" + ## + extraFlags: "" + ## @param secondary.extraEnvVars Extra environment variables to be set on MariaDB secondary containers + ## E.g. + ## extraEnvVars: + ## - name: TZ + ## value: "Europe/Paris" + ## + extraEnvVars: [] + ## @param secondary.extraEnvVarsCM Name of existing ConfigMap containing extra env vars for MariaDB secondary containers + ## + extraEnvVarsCM: "" + ## @param secondary.extraEnvVarsSecret Name of existing Secret containing extra env vars for MariaDB secondary containers + ## + extraEnvVarsSecret: "" + ## Enable persistence using Persistent Volume Claims + ## ref: https://kubernetes.io/docs/user-guide/persistent-volumes/ + ## + persistence: + ## @param secondary.persistence.enabled Enable persistence on MariaDB secondary replicas using a `PersistentVolumeClaim` + ## + enabled: true + ## @param secondary.persistence.subPath Subdirectory of the volume to mount at + ## + subPath: "" + ## @param secondary.persistence.storageClass MariaDB secondary persistent volume storage Class + ## If defined, storageClassName: + ## If set to "-", storageClassName: "", which disables dynamic provisioning + ## If undefined (the default) or set to null, no storageClassName spec is + ## set, choosing the default provisioner. (gp2 on AWS, standard on + ## GKE, AWS & OpenStack) + ## + storageClass: "" + ## @param secondary.persistence.annotations MariaDB secondary persistent volume claim annotations + ## + annotations: {} + ## @param secondary.persistence.accessModes MariaDB secondary persistent volume access Modes + ## + accessModes: + - ReadWriteOnce + ## @param secondary.persistence.size MariaDB secondary persistent volume size + ## + size: 8Gi + ## @param secondary.persistence.selector Selector to match an existing Persistent Volume + ## selector: + ## matchLabels: + ## app: my-app + ## + selector: {} + ## @param secondary.extraVolumes Optionally specify extra list of additional volumes to the MariaDB secondary pod(s) + ## + extraVolumes: [] + ## @param secondary.extraVolumeMounts Optionally specify extra list of additional volumeMounts for the MariaDB secondary container(s) + ## + extraVolumeMounts: [] + ## @param secondary.initContainers Add additional init containers for the MariaDB secondary pod(s) + ## + initContainers: [] + ## @param secondary.sidecars Add additional sidecar containers for the MariaDB secondary pod(s) + ## + sidecars: [] + ## MariaDB Secondary Service parameters + ## + service: + ## @param secondary.service.type MariaDB secondary Kubernetes service type + ## + type: ClusterIP + ports: + ## @param secondary.service.ports.mysql MariaDB secondary Kubernetes service port for MariaDB + ## + mysql: 3306 + ## @param secondary.service.ports.metrics MariaDB secondary Kubernetes service port for metrics + ## + metrics: 9104 + ## @param secondary.service.nodePorts.mysql MariaDB secondary Kubernetes service node port + ## ref: https://kubernetes.io/docs/concepts/services-networking/service/#type-nodeport + ## + nodePorts: + mysql: "" + ## @param secondary.service.clusterIP MariaDB secondary Kubernetes service clusterIP IP + ## e.g: + ## clusterIP: None + ## + clusterIP: "" + ## @param secondary.service.loadBalancerIP MariaDB secondary loadBalancerIP if service type is `LoadBalancer` + ## ref: https://kubernetes.io/docs/concepts/services-networking/service/#internal-load-balancer + ## + loadBalancerIP: "" + ## @param secondary.service.externalTrafficPolicy Enable client source IP preservation + ## ref https://kubernetes.io/docs/tasks/access-application-cluster/create-external-load-balancer/#preserving-the-client-source-ip + ## + externalTrafficPolicy: Cluster + ## @param secondary.service.loadBalancerSourceRanges Address that are allowed when MariaDB secondary service is LoadBalancer + ## https://kubernetes.io/docs/tasks/access-application-cluster/configure-cloud-provider-firewall/#restrict-access-for-loadbalancer-service + ## E.g. + ## loadBalancerSourceRanges: + ## - 10.10.10.0/24 + ## + loadBalancerSourceRanges: [] + ## @param secondary.service.extraPorts Extra ports to expose (normally used with the `sidecar` value) + ## + extraPorts: [] + ## @param secondary.service.annotations Provide any additional annotations which may be required + ## + annotations: {} + ## @param secondary.service.sessionAffinity Session Affinity for Kubernetes service, can be "None" or "ClientIP" + ## If "ClientIP", consecutive client requests will be directed to the same Pod + ## ref: https://kubernetes.io/docs/concepts/services-networking/service/#virtual-ips-and-service-proxies + ## + sessionAffinity: None + ## @param secondary.service.sessionAffinityConfig Additional settings for the sessionAffinity + ## sessionAffinityConfig: + ## clientIP: + ## timeoutSeconds: 300 + ## + sessionAffinityConfig: {} + ## MariaDB secondary Pod Disruption Budget configuration + ## ref: https://kubernetes.io/docs/tasks/run-application/configure-pdb/ + ## + pdb: + ## @param secondary.pdb.create Enable/disable a Pod Disruption Budget creation for MariaDB secondary pods + ## + create: false + ## @param secondary.pdb.minAvailable Minimum number/percentage of MariaDB secondary pods that should remain scheduled + ## + minAvailable: 1 + ## @param secondary.pdb.maxUnavailable Maximum number/percentage of MariaDB secondary pods that may be made unavailable + ## + maxUnavailable: "" + ## @param secondary.revisionHistoryLimit Maximum number of revisions that will be maintained in the StatefulSet + ## + revisionHistoryLimit: 10 + +## @section RBAC parameters +## + +## MariaDB pods ServiceAccount +## ref: https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/ +## +serviceAccount: + ## @param serviceAccount.create Enable the creation of a ServiceAccount for MariaDB pods + ## + create: true + ## @param serviceAccount.name Name of the created ServiceAccount + ## If not set and create is true, a name is generated using the mariadb.fullname template + ## + name: "" + ## @param serviceAccount.annotations Annotations for MariaDB Service Account + ## + annotations: {} + ## @param serviceAccount.automountServiceAccountToken Automount service account token for the server service account + ## + automountServiceAccountToken: false +## Role Based Access +## ref: https://kubernetes.io/docs/admin/authorization/rbac/ +## +rbac: + ## @param rbac.create Whether to create and use RBAC resources or not + ## + create: false + +## @section Volume Permissions parameters +## + +## Init containers parameters: +## volumePermissions: Change the owner and group of the persistent volume mountpoint to runAsUser:fsGroup values from the securityContext section. +## +volumePermissions: + ## @param volumePermissions.enabled Enable init container that changes the owner and group of the persistent volume(s) mountpoint to `runAsUser:fsGroup` + ## + enabled: false + ## @param volumePermissions.image.registry Init container volume-permissions image registry + ## @param volumePermissions.image.repository Init container volume-permissions image repository + ## @param volumePermissions.image.tag Init container volume-permissions image tag (immutable tags are recommended) + ## @param volumePermissions.image.digest Init container volume-permissions image digest in the way sha256:aa.... Please note this parameter, if set, will override the tag + ## @param volumePermissions.image.pullPolicy Init container volume-permissions image pull policy + ## @param volumePermissions.image.pullSecrets Specify docker-registry secret names as an array + ## + image: + registry: docker.io + repository: bitnami/bitnami-shell + tag: 11-debian-11-r61 + digest: "" + pullPolicy: IfNotPresent + ## Optionally specify an array of imagePullSecrets (secrets must be manually created in the namespace) + ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/ + ## Example: + ## pullSecrets: + ## - myRegistryKeySecretName + ## + pullSecrets: [] + ## @param volumePermissions.resources.limits Init container volume-permissions resource limits + ## @param volumePermissions.resources.requests Init container volume-permissions resource requests + ## + resources: + limits: {} + requests: {} + +## @section Metrics parameters +## + +## Mysqld Prometheus exporter parameters +## +metrics: + ## @param metrics.enabled Start a side-car prometheus exporter + ## + enabled: false + ## @param metrics.image.registry Exporter image registry + ## @param metrics.image.repository Exporter image repository + ## @param metrics.image.tag Exporter image tag (immutable tags are recommended) + ## @param metrics.image.digest Exporter image digest in the way sha256:aa.... Please note this parameter, if set, will override the tag + ## @param metrics.image.pullPolicy Exporter image pull policy + ## @param metrics.image.pullSecrets Specify docker-registry secret names as an array + ## + image: + registry: docker.io + repository: bitnami/mysqld-exporter + tag: 0.14.0-debian-11-r67 + digest: "" + pullPolicy: IfNotPresent + ## Optionally specify an array of imagePullSecrets (secrets must be manually created in the namespace) + ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/ + ## Example: + ## pullSecrets: + ## - myRegistryKeySecretName + ## + pullSecrets: [] + ## @param metrics.annotations [object] Annotations for the Exporter pod + ## + annotations: + prometheus.io/scrape: "true" + prometheus.io/port: "9104" + ## @param metrics.extraArgs [object] Extra args to be passed to mysqld_exporter + ## ref: https://github.com/prometheus/mysqld_exporter/ + ## E.g. + ## - --collect.auto_increment.columns + ## - --collect.binlog_size + ## - --collect.engine_innodb_status + ## - --collect.engine_tokudb_status + ## - --collect.global_status + ## - --collect.global_variables + ## - --collect.info_schema.clientstats + ## - --collect.info_schema.innodb_metrics + ## - --collect.info_schema.innodb_tablespaces + ## - --collect.info_schema.innodb_cmp + ## - --collect.info_schema.innodb_cmpmem + ## - --collect.info_schema.processlist + ## - --collect.info_schema.processlist.min_time + ## - --collect.info_schema.query_response_time + ## - --collect.info_schema.tables + ## - --collect.info_schema.tables.databases + ## - --collect.info_schema.tablestats + ## - --collect.info_schema.userstats + ## - --collect.perf_schema.eventsstatements + ## - --collect.perf_schema.eventsstatements.digest_text_limit + ## - --collect.perf_schema.eventsstatements.limit + ## - --collect.perf_schema.eventsstatements.timelimit + ## - --collect.perf_schema.eventswaits + ## - --collect.perf_schema.file_events + ## - --collect.perf_schema.file_instances + ## - --collect.perf_schema.indexiowaits + ## - --collect.perf_schema.tableiowaits + ## - --collect.perf_schema.tablelocks + ## - --collect.perf_schema.replication_group_member_stats + ## - --collect.slave_status + ## - --collect.slave_hosts + ## - --collect.heartbeat + ## - --collect.heartbeat.database + ## - --collect.heartbeat.table + ## + extraArgs: + primary: [] + secondary: [] + ## @param metrics.extraVolumeMounts [object] Optionally specify extra list of additional volumeMounts for the MariaDB metrics container(s) + ## + extraVolumeMounts: + primary: [] + secondary: [] + ## MariaDB metrics container Security Context + ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/#set-the-security-context-for-a-container + ## @param metrics.containerSecurityContext.enabled Enable security context for MariaDB metrics container + ## Example: + ## containerSecurityContext: + ## enabled: true + ## capabilities: + ## drop: ["NET_RAW"] + ## readOnlyRootFilesystem: true + ## + containerSecurityContext: + enabled: false + ## Mysqld Prometheus exporter resource requests and limits + ## ref: https://kubernetes.io/docs/user-guide/compute-resources/ + ## We usually recommend not to specify default resources and to leave this as a conscious + ## choice for the user. This also increases chances charts run on environments with little + ## resources, such as Minikube. If you do want to specify resources, uncomment the following + ## lines, adjust them as necessary, and remove the curly braces after 'resources:'. + ## @param metrics.resources.limits The resources limits for MariaDB prometheus exporter containers + ## @param metrics.resources.requests The requested resources for MariaDB prometheus exporter containers + ## + resources: + ## Example: + ## limits: + ## cpu: 100m + ## memory: 256Mi + ## + limits: {} + ## Examples: + ## requests: + ## cpu: 100m + ## memory: 256Mi + ## + requests: {} + ## Configure extra options for liveness probe + ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-probes/#configure-probes + ## @param metrics.livenessProbe.enabled Enable livenessProbe + ## @param metrics.livenessProbe.initialDelaySeconds Initial delay seconds for livenessProbe + ## @param metrics.livenessProbe.periodSeconds Period seconds for livenessProbe + ## @param metrics.livenessProbe.timeoutSeconds Timeout seconds for livenessProbe + ## @param metrics.livenessProbe.failureThreshold Failure threshold for livenessProbe + ## @param metrics.livenessProbe.successThreshold Success threshold for livenessProbe + ## + livenessProbe: + enabled: true + initialDelaySeconds: 120 + periodSeconds: 10 + timeoutSeconds: 1 + successThreshold: 1 + failureThreshold: 3 + ## Configure extra options for readiness probe + ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-probes/#configure-probes + ## @param metrics.readinessProbe.enabled Enable readinessProbe + ## @param metrics.readinessProbe.initialDelaySeconds Initial delay seconds for readinessProbe + ## @param metrics.readinessProbe.periodSeconds Period seconds for readinessProbe + ## @param metrics.readinessProbe.timeoutSeconds Timeout seconds for readinessProbe + ## @param metrics.readinessProbe.failureThreshold Failure threshold for readinessProbe + ## @param metrics.readinessProbe.successThreshold Success threshold for readinessProbe + ## + readinessProbe: + enabled: true + initialDelaySeconds: 30 + periodSeconds: 10 + timeoutSeconds: 1 + successThreshold: 1 + failureThreshold: 3 + ## Prometheus Service Monitor + ## ref: https://github.com/coreos/prometheus-operator + ## + serviceMonitor: + ## @param metrics.serviceMonitor.enabled Create ServiceMonitor Resource for scraping metrics using PrometheusOperator + ## + enabled: false + ## @param metrics.serviceMonitor.namespace Namespace which Prometheus is running in + ## + namespace: "" + ## @param metrics.serviceMonitor.jobLabel The name of the label on the target service to use as the job name in prometheus. + ## + jobLabel: "" + ## @param metrics.serviceMonitor.interval Interval at which metrics should be scraped + ## + interval: 30s + ## @param metrics.serviceMonitor.scrapeTimeout Specify the timeout after which the scrape is ended + ## e.g: + ## scrapeTimeout: 30s + ## + scrapeTimeout: "" + ## @param metrics.serviceMonitor.relabelings RelabelConfigs to apply to samples before scraping + ## ref: https://github.com/coreos/prometheus-operator/blob/master/Documentation/api.md#relabelconfig + ## + relabelings: [] + ## @param metrics.serviceMonitor.metricRelabelings MetricRelabelConfigs to apply to samples before ingestion + ## ref: https://github.com/coreos/prometheus-operator/blob/master/Documentation/api.md#relabelconfig + ## + metricRelabelings: [] + ## @param metrics.serviceMonitor.honorLabels honorLabels chooses the metric's labels on collisions with target labels + ## + honorLabels: false + ## @param metrics.serviceMonitor.selector ServiceMonitor selector labels + ## ref: https://github.com/bitnami/charts/tree/main/bitnami/prometheus-operator#prometheus-configuration + ## + ## selector: + ## prometheus: my-prometheus + ## + selector: {} + ## @param metrics.serviceMonitor.labels Extra labels for the ServiceMonitor + ## + labels: {} + ## Prometheus Operator PrometheusRule configuration + ## + prometheusRule: + ## @param metrics.prometheusRule.enabled if `true`, creates a Prometheus Operator PrometheusRule (also requires `metrics.enabled` to be `true` and `metrics.prometheusRule.rules`) + ## + enabled: false + ## @param metrics.prometheusRule.namespace Namespace for the PrometheusRule Resource (defaults to the Release Namespace) + ## + namespace: "" + ## @param metrics.prometheusRule.additionalLabels Additional labels that can be used so PrometheusRule will be discovered by Prometheus + ## + additionalLabels: {} + ## @param metrics.prometheusRule.rules Prometheus Rule definitions + ## - alert: MariaDB-Down + ## expr: absent(up{job="mariadb"} == 1) + ## for: 5m + ## labels: + ## severity: warning + ## service: mariadb + ## annotations: + ## message: 'MariaDB instance {{ `{{` }} $labels.instance {{ `}}` }} is down' + ## summary: MariaDB instance is down + ## + rules: [] + +## @section NetworkPolicy parameters +## + +## Add networkpolicies +## +networkPolicy: + ## @param networkPolicy.enabled Enable network policies + ## + enabled: false + ## @param networkPolicy.metrics.enabled Enable network policy for metrics (prometheus) + ## @param networkPolicy.metrics.namespaceSelector [object] Monitoring namespace selector labels. These labels will be used to identify the prometheus' namespace. + ## @param networkPolicy.metrics.podSelector [object] Monitoring pod selector labels. These labels will be used to identify the Prometheus pods. + ## + metrics: + enabled: false + ## e.g: + ## podSelector: + ## label: monitoring + ## + podSelector: {} + ## e.g: + ## namespaceSelector: + ## label: monitoring + ## + namespaceSelector: {} + ## @param networkPolicy.ingressRules.primaryAccessOnlyFrom.enabled Enable ingress rule that makes primary mariadb nodes only accessible from a particular origin. + ## @param networkPolicy.ingressRules.primaryAccessOnlyFrom.namespaceSelector [object] Namespace selector label that is allowed to access the primary node. This label will be used to identified the allowed namespace(s). + ## @param networkPolicy.ingressRules.primaryAccessOnlyFrom.podSelector [object] Pods selector label that is allowed to access the primary node. This label will be used to identified the allowed pod(s). + ## @param networkPolicy.ingressRules.primaryAccessOnlyFrom.customRules [object] Custom network policy for the primary node. + ## @param networkPolicy.ingressRules.secondaryAccessOnlyFrom.enabled Enable ingress rule that makes primary mariadb nodes only accessible from a particular origin. + ## @param networkPolicy.ingressRules.secondaryAccessOnlyFrom.namespaceSelector [object] Namespace selector label that is allowed to acces the secondary nodes. This label will be used to identified the allowed namespace(s). + ## @param networkPolicy.ingressRules.secondaryAccessOnlyFrom.podSelector [object] Pods selector label that is allowed to access the secondary nodes. This label will be used to identified the allowed pod(s). + ## @param networkPolicy.ingressRules.secondaryAccessOnlyFrom.customRules [object] Custom network policy for the secondary nodes. + ## + ingressRules: + ## Allow access to the primary node only from the indicated: + ## + primaryAccessOnlyFrom: + enabled: false + ## e.g: + ## namespaceSelector: + ## label: ingress + ## + namespaceSelector: {} + ## e.g: + ## podSelector: + ## label: access + ## + podSelector: {} + ## custom ingress rules + ## e.g: + ## customRules: + ## - from: + ## - namespaceSelector: + ## matchLabels: + ## label: example + ## + customRules: {} + + ## Allow access to the secondary node only from the indicated: + ## + secondaryAccessOnlyFrom: + enabled: false + ## e.g: + ## namespaceSelector: + ## label: ingress + ## + namespaceSelector: {} + ## e.g: + ## podSelector: + ## label: access + ## + podSelector: {} + ## custom ingress rules + ## e.g: + ## CustomRules: + ## - from: + ## - namespaceSelector: + ## matchLabels: + ## label: example + ## + customRules: {} + + ## @param networkPolicy.egressRules.denyConnectionsToExternal Enable egress rule that denies outgoing traffic outside the cluster, except for DNS (port 53). + ## @param networkPolicy.egressRules.customRules [object] Custom network policy rule + ## + egressRules: + # Deny connections to external. This is not compatible with an external database. + denyConnectionsToExternal: false + ## Additional custom egress rules + ## e.g: + ## customRules: + ## - to: + ## - namespaceSelector: + ## matchLabels: + ## label: example + ## + customRules: {} diff --git a/charts/limesurvey-martial-ingress-v9/icon.png b/charts/limesurvey-martial-ingress-v9/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..90014a72d36fd41a81dd199c435c1cab076b169e GIT binary patch literal 8080 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 N0!US+O3L)h{{feI7Rdkr literal 0 HcmV?d00001 diff --git a/charts/limesurvey-martial-ingress-v9/limesurvey-martial-ingress-v9-0.8.0.tgz b/charts/limesurvey-martial-ingress-v9/limesurvey-martial-ingress-v9-0.8.0.tgz new file mode 100644 index 0000000000000000000000000000000000000000..3f0a453fe5c4d30ed763c370ddf17e22f9c8bf35 GIT binary patch literal 114058 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 I=>SR#00UI`VE_OC literal 0 HcmV?d00001 diff --git a/charts/limesurvey-martial-ingress-v9/template.txt b/charts/limesurvey-martial-ingress-v9/template.txt new file mode 100644 index 0000000..c6b783f --- /dev/null +++ b/charts/limesurvey-martial-ingress-v9/template.txt @@ -0,0 +1,444 @@ +--- +# Source: limesurvey-martial/charts/mariadb/templates/serviceaccount.yaml +apiVersion: v1 +kind: ServiceAccount +metadata: + name: kk-mariadb + namespace: "default" + labels: + app.kubernetes.io/name: mariadb + helm.sh/chart: mariadb-11.4.2 + app.kubernetes.io/instance: kk + app.kubernetes.io/managed-by: Helm + annotations: +automountServiceAccountToken: false +--- +# Source: limesurvey-martial/templates/serviceaccount.yaml +apiVersion: v1 +kind: ServiceAccount +metadata: + name: kk-limesurvey-martial + labels: + helm.sh/chart: limesurvey-martial-0.8.2 + app.kubernetes.io/name: limesurvey-martial + app.kubernetes.io/instance: kk + app.kubernetes.io/version: "5-apache" + app.kubernetes.io/managed-by: Helm +--- +# Source: limesurvey-martial/charts/mariadb/templates/secrets.yaml +apiVersion: v1 +kind: Secret +metadata: + name: kk-mariadb + namespace: "default" + labels: + app.kubernetes.io/name: mariadb + helm.sh/chart: mariadb-11.4.2 + app.kubernetes.io/instance: kk + app.kubernetes.io/managed-by: Helm +type: Opaque +data: + mariadb-root-password: "bGltZXN1cnZleQ==" + mariadb-password: "bGltZXN1cnZleQ==" +--- +# Source: limesurvey-martial/templates/secrets.yaml +apiVersion: v1 +kind: Secret +metadata: + name: kk-limesurvey-martial-app-secrets + namespace: "default" + labels: + helm.sh/chart: limesurvey-martial-0.8.2 + app.kubernetes.io/name: limesurvey-martial + app.kubernetes.io/instance: kk + app.kubernetes.io/version: "5-apache" + app.kubernetes.io/managed-by: Helm +type: Opaque +data: + limesurvey-admin-password: "cDlVak84cEswN0FsT2hP" +--- +# Source: limesurvey-martial/charts/mariadb/templates/primary/configmap.yaml +apiVersion: v1 +kind: ConfigMap +metadata: + name: kk-mariadb + namespace: "default" + labels: + app.kubernetes.io/name: mariadb + helm.sh/chart: mariadb-11.4.2 + app.kubernetes.io/instance: kk + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/component: primary +data: + my.cnf: |- + [mysqld] + skip-name-resolve + explicit_defaults_for_timestamp + basedir=/opt/bitnami/mariadb + plugin_dir=/opt/bitnami/mariadb/plugin + port=3306 + socket=/opt/bitnami/mariadb/tmp/mysql.sock + tmpdir=/opt/bitnami/mariadb/tmp + max_allowed_packet=16M + bind-address=* + pid-file=/opt/bitnami/mariadb/tmp/mysqld.pid + log-error=/opt/bitnami/mariadb/logs/mysqld.log + character-set-server=UTF8 + collation-server=utf8_general_ci + slow_query_log=0 + slow_query_log_file=/opt/bitnami/mariadb/logs/mysqld.log + long_query_time=10.0 + + [client] + port=3306 + socket=/opt/bitnami/mariadb/tmp/mysql.sock + default-character-set=UTF8 + plugin_dir=/opt/bitnami/mariadb/plugin + + [manager] + port=3306 + socket=/opt/bitnami/mariadb/tmp/mysql.sock + pid-file=/opt/bitnami/mariadb/tmp/mysqld.pid +--- +# Source: limesurvey-martial/templates/pvc.yaml +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: kk-limesurvey-martial + labels: + helm.sh/chart: limesurvey-martial-0.8.2 + app.kubernetes.io/name: limesurvey-martial + app.kubernetes.io/instance: kk + app.kubernetes.io/version: "5-apache" + app.kubernetes.io/managed-by: Helm + finalizers: + - kubernetes.io/pvc-protection +spec: + accessModes: + - "ReadWriteOnce" + resources: + requests: + storage: "5Gi" +--- +# Source: limesurvey-martial/charts/mariadb/templates/primary/svc.yaml +apiVersion: v1 +kind: Service +metadata: + name: kk-mariadb + namespace: "default" + labels: + app.kubernetes.io/name: mariadb + helm.sh/chart: mariadb-11.4.2 + app.kubernetes.io/instance: kk + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/component: primary + annotations: +spec: + type: ClusterIP + sessionAffinity: None + ports: + - name: mysql + port: 3306 + protocol: TCP + targetPort: mysql + nodePort: null + selector: + app.kubernetes.io/name: mariadb + app.kubernetes.io/instance: kk + app.kubernetes.io/component: primary +--- +# Source: limesurvey-martial/templates/service.yaml +apiVersion: v1 +kind: Service +metadata: + name: kk-limesurvey-martial + labels: + helm.sh/chart: limesurvey-martial-0.8.2 + app.kubernetes.io/name: limesurvey-martial + app.kubernetes.io/instance: kk + app.kubernetes.io/version: "5-apache" + app.kubernetes.io/managed-by: Helm +spec: + type: ClusterIP + ports: + - port: 80 + targetPort: http + protocol: TCP + name: http + selector: + app.kubernetes.io/name: limesurvey-martial + app.kubernetes.io/instance: kk +--- +# Source: limesurvey-martial/templates/deployment.yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: kk-limesurvey-martial + labels: + helm.sh/chart: limesurvey-martial-0.8.2 + app.kubernetes.io/name: limesurvey-martial + app.kubernetes.io/instance: kk + app.kubernetes.io/version: "5-apache" + app.kubernetes.io/managed-by: Helm +spec: + replicas: 1 + selector: + matchLabels: + app.kubernetes.io/name: limesurvey-martial + app.kubernetes.io/instance: kk + strategy: + type: RollingUpdate + template: + metadata: + labels: + app.kubernetes.io/name: limesurvey-martial + app.kubernetes.io/instance: kk + spec: + serviceAccountName: kk-limesurvey-martial + securityContext: + fsGroup: 33 + runAsGroup: 33 + runAsUser: 33 + initContainers: + - name: wait-for-db + image: docker.io/martialblog/limesurvey:5-apache + securityContext: + allowPrivilegeEscalation: false + imagePullPolicy: IfNotPresent + command: ['/bin/sh', '-c', + 'until nc -z -v -w30 "$DB_HOST" "$DB_PORT"; do + echo "Info: Waiting for database connection..."; + sleep 5; + done'] + resources: + limits: {} + requests: + cpu: 300m + memory: 512Mi + env: + - name: DB_HOST + value: kk-mariadb + - name: DB_PORT + value: "3306" + containers: + - name: limesurvey-apache + image: docker.io/martialblog/limesurvey:5-apache + imagePullPolicy: IfNotPresent + securityContext: + allowPrivilegeEscalation: false + ports: + - name: http + containerPort: 8080 + protocol: TCP + livenessProbe: + httpGet: + path: / + port: http + readinessProbe: + httpGet: + path: / + port: http + resources: + limits: {} + requests: + cpu: 300m + memory: 512Mi + volumeMounts: + - name: storage + mountPath: "/var/www/html/upload/" + env: + - name: DB_TYPE + value: "mysql" + - name: DB_HOST + value: kk-mariadb + - name: DB_PORT + value: "3306" + - name: DB_PASSWORD + valueFrom: + secretKeyRef: + name: kk-mariadb + key: mariadb-password + - name: DB_USERNAME + value: limesurvey + - name: DB_NAME + value: limesurvey + - name: DB_TABLE_PREFIX + value: "lime_" + - name: DB_MYSQL_ENGINE + value: MyISAM + - name: ADMIN_PASSWORD + valueFrom: + secretKeyRef: + name: kk-limesurvey-martial-app-secrets + key: limesurvey-admin-password + - name: ADMIN_USER + value: admin + - name: ADMIN_NAME + value: Administrator + - name: ADMIN_EMAIL + value: admin@example.com + - name: LISTEN_PORT + value: "8080" + - name: URL_FORMAT + value: path + - name: DEBUG + value: "0" + - name: DEBUG_SQL + value: "0" + volumes: + - name: storage + persistentVolumeClaim: + claimName: kk-limesurvey-martial +--- +# Source: limesurvey-martial/charts/mariadb/templates/primary/statefulset.yaml +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: kk-mariadb + namespace: "default" + labels: + app.kubernetes.io/name: mariadb + helm.sh/chart: mariadb-11.4.2 + app.kubernetes.io/instance: kk + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/component: primary +spec: + replicas: 1 + revisionHistoryLimit: 10 + selector: + matchLabels: + app.kubernetes.io/name: mariadb + app.kubernetes.io/instance: kk + app.kubernetes.io/component: primary + serviceName: kk-mariadb + updateStrategy: + type: RollingUpdate + template: + metadata: + annotations: + checksum/configuration: b3411557986920434145fefbbb8e1a0360e22dcecd5084ab5a4ecab3e2b6d6a4 + labels: + app.kubernetes.io/name: mariadb + helm.sh/chart: mariadb-11.4.2 + app.kubernetes.io/instance: kk + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/component: primary + spec: + + serviceAccountName: kk-mariadb + affinity: + podAffinity: + + podAntiAffinity: + preferredDuringSchedulingIgnoredDuringExecution: + - podAffinityTerm: + labelSelector: + matchLabels: + app.kubernetes.io/name: mariadb + app.kubernetes.io/instance: kk + app.kubernetes.io/component: primary + topologyKey: kubernetes.io/hostname + weight: 1 + nodeAffinity: + + securityContext: + fsGroup: 1001 + containers: + - name: mariadb + image: docker.io/bitnami/mariadb:10.6.11-debian-11-r12 + imagePullPolicy: "IfNotPresent" + securityContext: + runAsNonRoot: true + runAsUser: 1001 + env: + - name: BITNAMI_DEBUG + value: "false" + - name: MARIADB_ROOT_PASSWORD + valueFrom: + secretKeyRef: + name: kk-mariadb + key: mariadb-root-password + - name: MARIADB_USER + value: "limesurvey" + - name: MARIADB_PASSWORD + valueFrom: + secretKeyRef: + name: kk-mariadb + key: mariadb-password + - name: MARIADB_DATABASE + value: "limesurvey" + ports: + - name: mysql + containerPort: 3306 + livenessProbe: + failureThreshold: 3 + initialDelaySeconds: 120 + periodSeconds: 10 + successThreshold: 1 + timeoutSeconds: 1 + exec: + command: + - /bin/bash + - -ec + - | + password_aux="${MARIADB_ROOT_PASSWORD:-}" + if [[ -f "${MARIADB_ROOT_PASSWORD_FILE:-}" ]]; then + password_aux=$(cat "$MARIADB_ROOT_PASSWORD_FILE") + fi + mysqladmin status -uroot -p"${password_aux}" + readinessProbe: + failureThreshold: 3 + initialDelaySeconds: 30 + periodSeconds: 10 + successThreshold: 1 + timeoutSeconds: 1 + exec: + command: + - /bin/bash + - -ec + - | + password_aux="${MARIADB_ROOT_PASSWORD:-}" + if [[ -f "${MARIADB_ROOT_PASSWORD_FILE:-}" ]]; then + password_aux=$(cat "$MARIADB_ROOT_PASSWORD_FILE") + fi + mysqladmin status -uroot -p"${password_aux}" + resources: + limits: {} + requests: {} + volumeMounts: + - name: data + mountPath: /bitnami/mariadb + - name: config + mountPath: /opt/bitnami/mariadb/conf/my.cnf + subPath: my.cnf + volumes: + - name: config + configMap: + name: kk-mariadb + volumeClaimTemplates: + - metadata: + name: data + labels: + app.kubernetes.io/name: mariadb + app.kubernetes.io/instance: kk + app.kubernetes.io/component: primary + spec: + accessModes: + - "ReadWriteOnce" + resources: + requests: + storage: "8Gi" +--- +# Source: limesurvey-martial/templates/ingress.yaml +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: kk-limesurvey-martial + labels: + helm.sh/chart: limesurvey-martial-0.8.2 + app.kubernetes.io/name: limesurvey-martial + app.kubernetes.io/instance: kk + app.kubernetes.io/version: "5-apache" + app.kubernetes.io/managed-by: Helm +spec: + rules: diff --git a/charts/limesurvey-martial-ingress-v9/templates/NOTES.txt b/charts/limesurvey-martial-ingress-v9/templates/NOTES.txt new file mode 100644 index 0000000..6036a82 --- /dev/null +++ b/charts/limesurvey-martial-ingress-v9/templates/NOTES.txt @@ -0,0 +1,29 @@ +{{- if .Values.ingress.enabled }} +Your LimeSurvey instance is available at the following Ingress URL: +{{- range $host := .Values.ingress.hosts }} + {{- range .paths }} + http{{ if $.Values.ingress.tls }}s{{ end }}://{{ $host.host }}{{ .path }} + {{- end }} +{{- end }} +{{- else if contains "NodePort" .Values.service.type }} +Your LimeSurvey instance is exposed via NodePorts. +Get the application URL by running these commands: + export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "limesurvey.fullname" . }}) + export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}") + echo http://$NODE_IP:$NODE_PORT +{{- else if contains "LoadBalancer" .Values.service.type }} +Your Limesurvey instance is exposed via LoadBalancers. +Get the application URL by running these commands: + + NOTE: It may take a few minutes for the LoadBalancer IP to be available. + You can watch the status of by running 'kubectl get --namespace {{ .Release.Namespace }} svc -w {{ include "limesurvey.fullname" . }}' + export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "limesurvey.fullname" . }} --template "{{"{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}"}}") + echo http://$SERVICE_IP:{{ .Values.service.port }} +{{- else if contains "ClusterIP" .Values.service.type }} +Your LimeSurvey instance is not exposed. +Run the following commands to get access to your application: + + export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include "limesurvey.name" . }},app.kubernetes.io/instance={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}") + echo "Visit http://127.0.0.1:8080 to use your application" + kubectl --namespace {{ .Release.Namespace }} port-forward $POD_NAME 8080:8080 +{{- end }} diff --git a/charts/limesurvey-martial-ingress-v9/templates/_helpers.tpl b/charts/limesurvey-martial-ingress-v9/templates/_helpers.tpl new file mode 100644 index 0000000..d428f9a --- /dev/null +++ b/charts/limesurvey-martial-ingress-v9/templates/_helpers.tpl @@ -0,0 +1,108 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "limesurvey.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 "limesurvey.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 }} + +{{- define "limesurvey.mariadb.fullname" -}} +{{- printf "%s-mariadb" .Release.Name | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "limesurvey.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "limesurvey.labels" -}} +helm.sh/chart: {{ include "limesurvey.chart" . }} +{{ include "limesurvey.selectorLabels" . }} +app.kubernetes.io/version: {{ coalesce .Values.image.tag .Chart.AppVersion | quote }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "limesurvey.selectorLabels" -}} +app.kubernetes.io/name: {{ include "limesurvey.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} + +{{/* +Create the name of the service account to use +*/}} +{{- define "limesurvey.serviceAccountName" -}} +{{- if .Values.serviceAccount.create }} +{{- default (include "limesurvey.fullname" .) .Values.serviceAccount.name }} +{{- else }} +{{- default "default" .Values.serviceAccount.name }} +{{- end }} +{{- end }} + +{{/* +Return the MariaDB Secret Name +*/}} +{{- define "limesurvey.databaseSecretName" -}} +{{- if .Values.mariadb.enabled }} + {{- if .Values.mariadb.auth.existingSecret -}} + {{- printf "%s" .Values.mariadb.auth.existingSecret -}} + {{- else -}} + {{- printf "%s" (include "limesurvey.mariadb.fullname" .) -}} + {{- end -}} +{{- else if .Values.externalDatabase.existingSecret -}} + {{- printf "%s" .Values.externalDatabase.existingSecret -}} +{{- else -}} + {{- printf "%s-db-secrets" (include "limesurvey.fullname" .) -}} +{{- end -}} +{{- end -}} + +{{/* +Return the LimeSurvey Secret Name +*/}} +{{- define "limesurvey.secretName" -}} +{{- if .Values.existingSecret }} + {{- printf "%s" .Values.existingSecret -}} +{{- else -}} + {{- printf "%s-app-secrets" (include "limesurvey.fullname" .) -}} +{{- end -}} +{{- end -}} + +{{/* +Return the full URL of the LimeSurvey image (including registry, image and tag) +*/}} +{{- define "limesurvey.imageUrl" }} +{{- $registry := .Values.global.imageRegistry | default .Values.image.registry }} +{{- $registry = trimSuffix "/" $registry }} +{{- $image := .Values.image.repository }} +{{- $tag := .Values.image.tag | default .Chart.AppVersion }} +{{- if eq $registry "" -}} + {{/* useful when you want to use a locally built image */}} + {{- printf "%s:%s" $image $tag -}} +{{- else -}} + {{- printf "%s/%s:%s" $registry $image $tag -}} +{{- end -}} +{{- end }} diff --git a/charts/limesurvey-martial-ingress-v9/templates/deployment.yaml b/charts/limesurvey-martial-ingress-v9/templates/deployment.yaml new file mode 100644 index 0000000..8bebdfa --- /dev/null +++ b/charts/limesurvey-martial-ingress-v9/templates/deployment.yaml @@ -0,0 +1,272 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "limesurvey.fullname" . }} + labels: + {{- include "limesurvey.labels" . | nindent 4 }} +spec: + {{- if not .Values.autoscaling.enabled }} + replicas: {{ .Values.replicaCount }} + {{- end }} + selector: + matchLabels: + {{- include "limesurvey.selectorLabels" . | nindent 6 }} + {{- if .Values.updateStrategy }} + strategy: {{- toYaml .Values.updateStrategy | nindent 4 }} + {{- end }} + template: + metadata: + {{- with .Values.podAnnotations }} + annotations: + {{- toYaml . | nindent 8 }} + {{- end }} + labels: + {{- include "limesurvey.selectorLabels" . | nindent 8 }} + spec: + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + serviceAccountName: {{ include "limesurvey.serviceAccountName" . }} + securityContext: + {{- toYaml .Values.podSecurityContext | nindent 8 }} + initContainers: + - name: wait-for-db + image: {{ include "limesurvey.imageUrl" . }} + {{- if .Values.containerSecurityContext.enabled }} + securityContext: {{- omit .Values.containerSecurityContext "enabled" | toYaml | nindent 12 }} + {{- end }} + imagePullPolicy: {{ .Values.image.pullPolicy }} + command: ['/bin/sh', '-c', + 'until nc -z -v -w30 "$DB_HOST" "$DB_PORT"; do + echo "Info: Waiting for database connection..."; + sleep 5; + done'] + resources: + {{- toYaml .Values.resources | nindent 12 }} + env: + - name: DB_HOST + {{- if eq .Values.mariadb.enabled true }} + value: {{ include "limesurvey.mariadb.fullname" . }} + {{- else }} + value: {{ .Values.externalDatabase.host }} + {{- end }} + - name: DB_PORT + {{- if eq .Values.mariadb.enabled true }} + value: {{ coalesce .Values.mariadb.primary.service.ports.mysql .Values.mariadb.primary.service.port 3306 | quote }} + {{- else }} + value: {{ coalesce .Values.externalDatabase.port 3306 | quote }} + {{- end }} + containers: + - name: limesurvey-apache + image: {{ include "limesurvey.imageUrl" . }} + imagePullPolicy: {{ .Values.image.pullPolicy }} + {{- if .Values.containerSecurityContext.enabled }} + securityContext: {{- omit .Values.containerSecurityContext "enabled" | toYaml | nindent 12 }} + {{- end }} + ports: + - name: http + containerPort: 8080 + protocol: TCP + {{- if .Values.limesurvey.livenessProbe.enabled }} + livenessProbe: + httpGet: + path: / + port: http + {{- end }} + {{- if .Values.limesurvey.readinessProbe.enabled }} + readinessProbe: + httpGet: + path: / + port: http + {{- end }} + resources: + {{- toYaml .Values.resources | nindent 12 }} + volumeMounts: + - name: storage + mountPath: "/var/www/html/upload/" + {{- if .Values.persistence.subPath }} + subPath: {{ .Values.persistence.subPath }} + {{- end }} + {{- range .Values.extraVolumeMounts }} + - name: {{ .name }} + mountPath: {{ .mountPath }} + subPath: {{ .subPath | default "" }} + readOnly: {{ .readOnly }} + {{- end }} + {{- range .Values.extraEmptyDirMounts }} + - name: {{ .name }} + mountPath: {{ .mountPath }} + {{- end }} + env: + - name: DB_TYPE + {{- if eq .Values.mariadb.enabled true }} + value: "mysql" + {{- else }} + value: {{ .Values.externalDatabase.type }} + {{- end }} + - name: DB_HOST + {{- if eq .Values.mariadb.enabled true }} + value: {{ include "limesurvey.mariadb.fullname" . }} + {{- else }} + value: {{ .Values.externalDatabase.host }} + {{- end }} + - name: DB_PORT + {{- if eq .Values.mariadb.enabled true }} + value: {{ coalesce .Values.mariadb.primary.service.ports.mysql .Values.mariadb.primary.service.port 3306 | quote }} + {{- else }} + value: {{ coalesce .Values.externalDatabase.port 3306 | quote }} + {{- end }} + - name: DB_PASSWORD + valueFrom: + secretKeyRef: + name: {{ include "limesurvey.databaseSecretName" . }} + {{- if .Values.mariadb.enabled }} + key: mariadb-password + {{- else }} + key: {{ .Values.externalDatabase.existingSecretConfig.passwordField }} + {{- end }} + - name: DB_USERNAME + {{- if eq .Values.mariadb.enabled true }} + value: {{ .Values.mariadb.auth.username }} + {{- else }} + {{- if .Values.externalDatabase.existingSecretConfig.usernameField }} + valueFrom: + secretKeyRef: + name: {{ include "limesurvey.databaseSecretName" . }} + key: {{ .Values.externalDatabase.existingSecretConfig.usernameField }} + {{- else}} + value: {{ .Values.externalDatabase.username }} + {{- end }} + {{- end }} + - name: DB_NAME + {{- if eq .Values.mariadb.enabled true }} + value: {{ .Values.mariadb.auth.database }} + {{- else }} + {{- if .Values.externalDatabase.existingSecretConfig.databaseField }} + valueFrom: + secretKeyRef: + name: {{ include "limesurvey.databaseSecretName" . }} + key: {{ .Values.externalDatabase.existingSecretConfig.databaseField}} + {{- else }} + value: {{ .Values.externalDatabase.database }} + {{- end }} + {{- end }} + - name: DB_TABLE_PREFIX + value: {{ .Values.limesurvey.tablePrefix | quote }} + - name: DB_MYSQL_ENGINE + value: {{ .Values.limesurvey.mysqlEngine }} + - name: ADMIN_PASSWORD + valueFrom: + secretKeyRef: + name: {{ include "limesurvey.secretName" . }} + key: limesurvey-admin-password + - name: ADMIN_USER + value: {{ .Values.limesurvey.admin.user }} + - name: ADMIN_NAME + value: {{ .Values.limesurvey.admin.name }} + - name: ADMIN_EMAIL + value: {{ .Values.limesurvey.admin.email }} + - name: LISTEN_PORT + value: {{ .Values.limesurvey.listenPort | quote }} + {{- if .Values.limesurvey.baseUrl }} + - name: BASE_URL + value: {{ .Values.limesurvey.baseUrl }} + {{- end }} + {{- if .Values.limesurvey.publicUrl }} + - name: PUBLIC_URL + value: {{ .Values.limesurvey.publicUrl }} + {{- end }} + - name: URL_FORMAT + value: {{ .Values.limesurvey.urlFormat }} + {{- if eq .Values.limesurvey.tableSession true }} + - name: TABLE_SESSION + value: {{ .Values.limesurvey.tableSession }} + {{- end }} + {{- if .Values.limesurvey.showScriptName }} + - name: SHOW_SCRIPT_NAME + value: {{ .Values.limesurvey.showScriptName | quote }} + {{- end }} + {{- if (or .Values.limesurvey.encrypt.keypair .Values.limesurvey.existingSecret) }} + - name: ENCRYPT_KEYPAIR + valueFrom: + secretKeyRef: + name: {{ include "limesurvey.secretName" . }} + key: limesurvey-encrypt-keypair + {{- end }} + {{- if (or .Values.limesurvey.encrypt.publicKey .Values.limesurvey.existingSecret) }} + - name: ENCRYPT_PUBLIC_KEY + valueFrom: + secretKeyRef: + name: {{ include "limesurvey.secretName" . }} + key: limesurvey-encrypt-publickey + {{- end }} + {{- if (or .Values.limesurvey.encrypt.secretKey .Values.limesurvey.existingSecret) }} + - name: ENCRYPT_SECRET_KEY + valueFrom: + secretKeyRef: + name: {{ include "limesurvey.secretName" . }} + key: limesurvey-encrypt-secretkey + {{- end }} + {{- if (or .Values.limesurvey.encrypt.nonce .Values.limesurvey.existingSecret) }} + - name: ENCRYPT_NONCE + valueFrom: + secretKeyRef: + name: {{ include "limesurvey.secretName" . }} + key: limesurvey-encrypt-nonce + {{- end }} + {{- if (or .Values.limesurvey.encrypt.secretBoxKey .Values.limesurvey.existingSecret) }} + - name: ENCRYPT_SECRET_BOX_KEY + valueFrom: + secretKeyRef: + name: {{ include "limesurvey.secretName" . }} + key: limesurvey-encrypt-secretboxkey + {{- end }} + - name: DEBUG + value: "{{ .Values.limesurvey.debug }}" + - name: DEBUG_SQL + value: "{{ .Values.limesurvey.debugSql }}" + + {{- with .Values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} + volumes: + - name: storage + {{- if .Values.persistence.enabled }} + persistentVolumeClaim: + claimName: {{ .Values.persistence.existingClaim | default (include "limesurvey.fullname" .) }} + {{- else }} + emptyDir: {} + {{- end -}} + {{- range .Values.extraVolumeMounts }} + - name: {{ .name }} + {{- if .existingClaim }} + persistentVolumeClaim: + claimName: {{ .existingClaim }} + {{- else if .hostPath }} + hostPath: + path: {{ .hostPath }} + {{- else if .configMap }} + configMap: + name: {{ .configMap }} + {{- with .items }} + items: + {{- toYaml . | nindent 14 }} + {{- end }} + {{- else }} + emptyDir: {} + {{- end }} + {{- end }} + {{- range .Values.extraEmptyDirMounts }} + - name: {{ .name }} + emptyDir: {} + {{- end -}} diff --git a/charts/limesurvey-martial-ingress-v9/templates/hpa.yaml b/charts/limesurvey-martial-ingress-v9/templates/hpa.yaml new file mode 100644 index 0000000..86c133a --- /dev/null +++ b/charts/limesurvey-martial-ingress-v9/templates/hpa.yaml @@ -0,0 +1,28 @@ +{{- if .Values.autoscaling.enabled }} +apiVersion: autoscaling/v2beta1 +kind: HorizontalPodAutoscaler +metadata: + name: {{ include "limesurvey.fullname" . }} + labels: + {{- include "limesurvey.labels" . | nindent 4 }} +spec: + scaleTargetRef: + apiVersion: apps/v1 + kind: Deployment + name: {{ include "limesurvey.fullname" . }} + minReplicas: {{ .Values.autoscaling.minReplicas }} + maxReplicas: {{ .Values.autoscaling.maxReplicas }} + metrics: + {{- if .Values.autoscaling.targetCPUUtilizationPercentage }} + - type: Resource + resource: + name: cpu + targetAverageUtilization: {{ .Values.autoscaling.targetCPUUtilizationPercentage }} + {{- end }} + {{- if .Values.autoscaling.targetMemoryUtilizationPercentage }} + - type: Resource + resource: + name: memory + targetAverageUtilization: {{ .Values.autoscaling.targetMemoryUtilizationPercentage }} + {{- end }} +{{- end }} diff --git a/charts/limesurvey-martial-ingress-v9/templates/ingress.yaml b/charts/limesurvey-martial-ingress-v9/templates/ingress.yaml new file mode 100644 index 0000000..cbee7cd --- /dev/null +++ b/charts/limesurvey-martial-ingress-v9/templates/ingress.yaml @@ -0,0 +1,55 @@ +{{- if .Values.ingress.enabled -}} +{{- $fullName := include "limesurvey.fullname" . -}} +{{- $svcPort := .Values.service.port -}} +{{- if and .Values.ingress.className (not (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion)) }} + {{- if not (hasKey .Values.ingress.annotations "kubernetes.io/ingress.class") }} + {{- $_ := set .Values.ingress.annotations "kubernetes.io/ingress.class" .Values.ingress.className}} + {{- end }} +{{- end }} +{{- if semverCompare ">=1.19-0" .Capabilities.KubeVersion.GitVersion -}} +apiVersion: networking.k8s.io/v1 +{{- else if semverCompare ">=1.14-0" .Capabilities.KubeVersion.GitVersion -}} +apiVersion: networking.k8s.io/v1beta1 +{{- else -}} +apiVersion: extensions/v1beta1 +{{- end }} +kind: Ingress +metadata: + name: {{ $fullName }} + labels: + {{- include "limesurvey.labels" . | nindent 4 }} + {{- with .Values.ingress.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + {{- if and .Values.ingress.className (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion) }} + ingressClassName: {{ .Values.ingress.className }} + {{- end }} + {{- if .Values.ingress.tls }} + tls: + {{- range .Values.ingress.tls }} + - hosts: + {{- range .hosts }} + - {{ . | quote }} + {{- end }} + secretName: {{ .secretName }} + {{- end }} + {{- end }} + rules: + - host: {{ .Values.ingress.hostname | quote }} + http: + paths: + - path: / + pathType: ImplementationSpecific + backend: + {{- if semverCompare ">=1.19-0" $.Capabilities.KubeVersion.GitVersion }} + service: + name: {{ $fullName }} + port: + number: {{ $svcPort }} + {{- else }} + serviceName: {{ $fullName }} + servicePort: {{ $svcPort }} + {{- end }} +{{- end }} diff --git a/charts/limesurvey-martial-ingress-v9/templates/pvc.yaml b/charts/limesurvey-martial-ingress-v9/templates/pvc.yaml new file mode 100644 index 0000000..5cbdcc9 --- /dev/null +++ b/charts/limesurvey-martial-ingress-v9/templates/pvc.yaml @@ -0,0 +1,32 @@ +{{- if and .Values.persistence.enabled (not .Values.persistence.existingClaim) }} +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: {{ template "limesurvey.fullname" . }} + labels: + {{- include "limesurvey.labels" . | nindent 4 }} + {{- with .Values.persistence.annotations }} + annotations: +{{ toYaml . | indent 4 }} + {{- end }} + {{- with .Values.persistence.finalizers }} + finalizers: +{{ toYaml . | indent 4 }} + {{- end }} +spec: + accessModes: + {{- range .Values.persistence.accessModes }} + - {{ . | quote }} + {{- end }} + resources: + requests: + storage: {{ .Values.persistence.size | quote }} + {{- if .Values.persistence.storageClassName }} + storageClassName: {{ .Values.persistence.storageClassName }} + {{- end -}} + {{- with .Values.persistence.selectorLabels }} + selector: + matchLabels: +{{ toYaml . | indent 6 }} + {{- end }} +{{- end -}} diff --git a/charts/limesurvey-martial-ingress-v9/templates/secrets.yaml b/charts/limesurvey-martial-ingress-v9/templates/secrets.yaml new file mode 100644 index 0000000..edd9fe1 --- /dev/null +++ b/charts/limesurvey-martial-ingress-v9/templates/secrets.yaml @@ -0,0 +1,46 @@ +{{- if not .Values.limesurvey.existingSecret }} +--- +apiVersion: v1 +kind: Secret +metadata: + name: {{ include "limesurvey.secretName" . }} + namespace: {{ .Release.Namespace | quote }} + labels: + {{- include "limesurvey.labels" . | nindent 4 }} +type: Opaque +data: + {{- if .Values.limesurvey.admin.password }} + limesurvey-admin-password: {{ .Values.limesurvey.admin.password | b64enc | quote }} + {{- else }} + limesurvey-admin-password: {{ randAlphaNum 15 | b64enc | quote }} + {{- end }} + {{- if .Values.limesurvey.encrypt.keypair }} + limesurvey-encrypt-keypair: {{ .Values.limesurvey.encrypt.keypair | b64enc | quote }} + {{- end }} + {{- if .Values.limesurvey.encrypt.publicKey }} + limesurvey-encrypt-publickey: {{ .Values.limesurvey.encrypt.publicKey | b64enc | quote }} + {{- end }} + {{- if .Values.limesurvey.encrypt.secretKey }} + limesurvey-encrypt-secretkey: {{ .Values.limesurvey.encrypt.secretKey | b64enc | quote }} + {{- end }} + {{- if .Values.limesurvey.encrypt.nonce }} + limesurvey-encrypt-nonce: {{ .Values.limesurvey.encrypt.nonce | b64enc | quote }} + {{- end }} + {{- if .Values.limesurvey.encrypt.secretBoxKey }} + limesurvey-encrypt-secretboxkey: {{ .Values.limesurvey.encrypt.secretBoxKey | b64enc | quote }} + {{- end }} +{{- end }} + +{{- if not (or .Values.mariadb.enabled .Values.externalDatabase.existingSecret) }} +--- +apiVersion: v1 +kind: Secret +metadata: + name: {{ include "limesurvey.databaseSecretName" . }} + namespace: {{ .Release.Namespace | quote }} + labels: + {{- include "limesurvey.labels" . | nindent 4 }} +type: Opaque +data: + db-password: {{ required "externalDatabase.password is required" .Values.externalDatabase.password | b64enc | quote }} +{{- end }} diff --git a/charts/limesurvey-martial-ingress-v9/templates/service.yaml b/charts/limesurvey-martial-ingress-v9/templates/service.yaml new file mode 100644 index 0000000..1546fec --- /dev/null +++ b/charts/limesurvey-martial-ingress-v9/templates/service.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ include "limesurvey.fullname" . }} + labels: + {{- include "limesurvey.labels" . | nindent 4 }} +spec: + type: {{ .Values.service.type }} + ports: + - port: {{ .Values.service.port }} + targetPort: http + protocol: TCP + name: http + selector: + {{- include "limesurvey.selectorLabels" . | nindent 4 }} diff --git a/charts/limesurvey-martial-ingress-v9/templates/serviceaccount.yaml b/charts/limesurvey-martial-ingress-v9/templates/serviceaccount.yaml new file mode 100644 index 0000000..53b708d --- /dev/null +++ b/charts/limesurvey-martial-ingress-v9/templates/serviceaccount.yaml @@ -0,0 +1,12 @@ +{{- if .Values.serviceAccount.create -}} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "limesurvey.serviceAccountName" . }} + labels: + {{- include "limesurvey.labels" . | nindent 4 }} + {{- with .Values.serviceAccount.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +{{- end }} diff --git a/charts/limesurvey-martial-ingress-v9/templates/tests/test-connection.yaml b/charts/limesurvey-martial-ingress-v9/templates/tests/test-connection.yaml new file mode 100644 index 0000000..5216f9d --- /dev/null +++ b/charts/limesurvey-martial-ingress-v9/templates/tests/test-connection.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Pod +metadata: + name: "{{ include "..fullname" . }}-test-connection" + labels: + {{- include "..labels" . | nindent 4 }} + annotations: + "helm.sh/hook": test +spec: + containers: + - name: wget + image: busybox + command: ['wget'] + args: ['{{ include "..fullname" . }}:{{ .Values.service.port }}'] + restartPolicy: Never diff --git a/charts/limesurvey-martial-ingress-v9/values.schema.json b/charts/limesurvey-martial-ingress-v9/values.schema.json new file mode 100644 index 0000000..4f15a9a --- /dev/null +++ b/charts/limesurvey-martial-ingress-v9/values.schema.json @@ -0,0 +1,183 @@ +{ + "$schema": "http://json-schema.org/schema#", + "type": "object", + "properties": { + "ingress": { + "type": "object", + "form": true, + "title": "Ingress Details", + "properties": { + "enabled": { + "description": "Enable Ingress", + "type": "boolean", + "default": true, + "x-onyxia": { + "hidden": true, + "overwriteSchemaWith": "k8s.ingress" + } + }, + "hostname": { + "type": "string", + "form": true, + "title": "Hostname", + "x-onyxia": { + "hidden": false, + "overwriteSchemaWith": "{{project.id}}-{{k8s.randomSubdomain}}-0.{{k8s.domain}}" + } + } + } + }, + "persistence": { + "description": "Configuration for persistence", + "type": "object", + "properties": { + "enabled": { + "type": "boolean", + "description": "Create a persistent volume", + "default": true + }, + "size": { + "type": "string", + "title": "Persistent volume size", + "description": "Size of the persistent volume", + "default": "10Gi", + "form": true, + "render": "slider", + "sliderMin": 1, + "sliderMax": 100, + "sliderStep": 1, + "sliderUnit": "Gi" + } + } + }, + "resources": { + "description": "Your service will have at least the requested resources and never more than its limits. No limit for a resource and you can consume everything left on the host machine.", + "type": "object", + "properties": { + "requests": { + "description": "Guaranteed resources", + "type": "object", + "properties": { + "cpu": { + "description": "The amount of cpu guaranteed", + "title": "CPU", + "type": "string", + "default": "100m", + "render": "slider", + "sliderMin": 50, + "sliderMax": 40000, + "sliderStep": 50, + "sliderUnit": "m", + "sliderExtremity": "down", + "sliderExtremitySemantic": "guaranteed", + "sliderRangeId": "cpu" + }, + "memory": { + "description": "The amount of memory guaranteed", + "title": "memory", + "type": "string", + "default": "2Gi", + "render": "slider", + "sliderMin": 1, + "sliderMax": 200, + "sliderStep": 1, + "sliderUnit": "Gi", + "sliderExtremity": "down", + "sliderExtremitySemantic": "guaranteed", + "sliderRangeId": "memory" + } + } + }, + "limits": { + "description": "max resources", + "type": "object", + "properties": { + "cpu": { + "description": "The maximum amount of cpu", + "title": "CPU", + "type": "string", + "default": "30000m", + "render": "slider", + "sliderMin": 50, + "sliderMax": 40000, + "sliderStep": 50, + "sliderUnit": "m", + "sliderExtremity": "up", + "sliderExtremitySemantic": "Maximum", + "sliderRangeId": "cpu" + }, + "memory": { + "description": "The maximum amount of memory", + "title": "Memory", + "type": "string", + "default": "50Gi", + "render": "slider", + "sliderMin": 1, + "sliderMax": 200, + "sliderStep": 1, + "sliderUnit": "Gi", + "sliderExtremity": "up", + "sliderExtremitySemantic": "Maximum", + "sliderRangeId": "memory" + } + } + } + } + }, + "security": { + "description": "security specific configuration", + "type": "object", + "properties": { + "networkPolicy": { + "type": "object", + "description": "Define access policy to the service", + "properties": { + "enabled": { + "type": "boolean", + "title": "Enable network policy", + "description": "Only pod from the same namespace will be allowed", + "default": true, + "x-form": { + "value": "{{region.defaultNetworkPolicy}}" + }, + "x-onyxia": { + "overwriteSchemaWith": "region.defaultNetworkPolicy" + } + } + } + } + } + }, + "limesurvey": { + "type": "object", + "properties": { + "admin": { + "type": "object", + "properties": { + "user": { + "type": "string", + "title": "Admin Username", + "description": "The username for the LimeSurvey administrator.", + "default": "admin" + }, + "password": { + "type": "string", + "title": "Admin Password", + "description": "The password for the LimeSurvey administrator.", + "default": "admin" + }, + "email": { + "type": "string", + "title": "Admin Email", + "description": "The email address of the LimeSurvey administrator.", + "default": "admin@example.com" + } + } + + } + } + + } + } + +} diff --git a/charts/limesurvey-martial-ingress-v9/values.yaml b/charts/limesurvey-martial-ingress-v9/values.yaml new file mode 100644 index 0000000..7797bb2 --- /dev/null +++ b/charts/limesurvey-martial-ingress-v9/values.yaml @@ -0,0 +1,214 @@ +# Default values for LimeSurvey. + +global: + imageRegistry: "" + +image: + registry: docker.io + repository: martialblog/limesurvey + # Specify a imagePullPolicy + pullPolicy: IfNotPresent + # Overrides the image tag whose default is the chart appVersion + tag: null + +# Optionally specify an array of imagePullSecrets +# Secrets must be manually created in the namespace +imagePullSecrets: [] +nameOverride: "" +fullnameOverride: "" + +serviceAccount: + # Specifies whether a service account should be created + create: true + annotations: {} + name: "" + +## MariaDB chart configuration +mariadb: + # Deploy a MariaDB server to satisfy the database requirements + enabled: true + # for all possible configuration values, see: + # https://github.com/bitnami/charts/blob/master/bitnami/mariadb/values.yaml + auth: + # MariaDB root password + rootPassword: "limesurvey" + # MariaDB custom database + database: my_database + # MariaDB custom user name + username: limesurvey + # MariaDB custom user password + password: "limesurvey" + +## Use an externally provisioned database instance +## Ignored when mariadb.enabled is set to true +externalDatabase: + # Type of external database ("mysql" or "pgsql") + type: mysql + # External Database server host + host: mariadb.example.com + # External Database server port + port: 3306 + # External Database username (use existingSecretConfig.usernameField to load from secret) + username: limesurvey + # External Database user password + # (ignored when existingSecret is set, use existingSecretConfig.passwordField to change key) + password: null + # External Database database name (use existingSecretConfig.databaseField to load from secret) + database: limesurvey + # Use an existing secret for retrieving the database password. + # The secret must contain the field "db-password" (field name configurable via existingSecretConfig.passwordField) + existingSecret: null + existingSecretConfig: + passwordField: db-password + usernameField: null + databaseField: null + +# Limesurvey Application configuration +limesurvey: + # LimeSurvey initial Administrator Account + admin: + user: admin + password: "admin" + name: Administrator + email: admin@example.com + # LimeSurvey permits the encryption of personal data + # These values will be created as secret + # https://manual.limesurvey.org/Data_encryption + # Not required for LimeSurvey 3 + encrypt: + keypair: "" + publicKey: "" + secretKey: "" + nonce: "" + # Create with: php -r "var_dump(sodium_bin2hex(sodium_crypto_secretbox_keygen()));" + secretBoxKey: "" + existingSecret: null + listenPort: 8080 + publicUrl: "" + baseUrl: "" + urlFormat: "path" + showScriptName: "" + # Database table prefix; set this to a single whitespace if you don't want a table prefix. + tablePrefix: "lime_" + # Enable table sessions (Storing sessions in the database) + tableSession: false + # LimeSurvey Debug level (0, 1, 2) + debug: 0 + # LimeSurvey SQL Debug level (0, 1, 2) + debugSql: 0 + # Value should be either MyISAM or InnoDB + mysqlEngine: MyISAM + # Probes, disable them when you enable global ssl enforcement, because they won't work with the redirect to https + livenessProbe: + enabled: true + readinessProbe: + enabled: true + +## Enable persistence using Persistent Volume Claims +## ref: http://kubernetes.io/docs/user-guide/persistent-volumes/ +## Used for LimeSurvey Uploads +persistence: + # Enable persistence with PVC. If false, uses emptyDir instead. + enabled: true + storageClassName: null + accessModes: + - ReadWriteOnce + size: 5Gi + annotations: {} + finalizers: + - kubernetes.io/pvc-protection + selectorLabels: {} + subPath: "" + existingClaim: null + +## This allows you to mount additional volumes +## into the Limesurvey container +extraVolumeMounts: [] +# - name: extra-volume-0 +# mountPath: /mnt/volume0 +# readOnly: true +# existingClaim: volume-claim +# - name: extra-volume-1 +# mountPath: /mnt/volume1 +# readOnly: true +# hostPath: /usr/shared/ +# - name: extra-volume-configmap +# configMap: limesurvey +# items: +# - key: config.php +# path: application/config/config.php + +## This allows you to mount additional "emptyDirs" +## into the Limesurvey container +extraEmptyDirMounts: [] +# - name: extra-empty-dir +# mountPath: /var/lib/foobar + +## Number of LimeSurvey replicas to deploy +## Multiple replicas may require table sessions to be enabled +replicaCount: 1 + +service: + type: ClusterIP + port: 80 + +#ingress: +# enabled: false +# className: "" +# annotations: {} +# hosts: +# - host: limesurvey.local +# paths: +# - path: / +# pathType: ImplementationSpecific +# tls: [] + +ingress: + enabled: true + className: "" + annotations: {} + # kubernetes.io/ingress.class: nginx + # kubernetes.io/tls-acme: "true" + hostname: limesurvey-genes.lab.groupe-genes.fr + # -- Ingress tls + tls: [] + # - secretName: chart-example-tls + # hosts: + # - chart-example.local + +resources: + limits: {} + requests: + memory: 512Mi + cpu: 300m + +## Deployment strategy type and parameters +## Set it to `Recreate` if you use a PV that cannot be mounted on multiple pods +updateStrategy: + type: RollingUpdate + +autoscaling: + enabled: false + minReplicas: 1 + maxReplicas: 11 + targetCPUUtilizationPercentage: 80 + +containerSecurityContext: + enabled: true + allowPrivilegeEscalation: false + +nodeSelector: {} + +tolerations: [] + +affinity: {} + +podAnnotations: {} + +## Specify privileges and access control settings +## ref: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/ +## 33 is the www-data user in Debian-based images +podSecurityContext: + runAsUser: 33 + runAsGroup: 33 + fsGroup: 33